Living roadmap and task tracker for gh-manager-cli. Use this file as the single source of truth for planned work, WIP, and completed items.
Legend:
- Todo
- [~] In progress
- Done
-
Code refactoring (completed)
- Extract modal components to separate files
- Organize components in structured directories
- Create reusable utility functions
- Improve component separation of concerns
- Components extracted:
src/ui/components/modals/- All modal dialogssrc/ui/components/repo/- Repository list componentssrc/ui/components/common/- Shared UI elementssrc/utils.ts- Utility functions
-
Density toggle (row spacing)
- Key
tcycles: Compact (0), Cozy (1), Comfy (2) blank lines - Update virtualization math to reflect spacing
- Persist preference in config (and read on boot)
- Key
-
Persist UI preferences (s/d/t)
- Store sort field (
s), sort direction (d), and density (t) in config - Read on startup and apply to initial state; write on each toggle
- Backward‑compatible defaults when values are missing
- Store sort field (
-
Change repository visibility
- Assigned key:
Ctrl+Vto open visibility change modal ✓ - Modal shows available visibility options (Public, Private, Internal for enterprise) ✓
- Fork repositories show explanation that visibility cannot be changed ✓
- Confirmation modal with Left/Right button navigation ✓
- Execute via GitHub REST API (PATCH /repos/{owner}/{repo}) ✓
- Updates local cache and respects active visibility filter ✓
- Removes repo from view if new visibility doesn't match filter ✓
- Error handling with retry option ✓
- Assigned key:
-
Enterprise GitHub support
- Detection of enterprise organizations using
enterpriseOwnersGraphQL field ✓ - ENT badge shown in header and organization switcher ✓
- Support for INTERNAL repository visibility ✓
- Internal repos show with magenta "Internal" badge ✓
- Visibility filter shows "Private/Internal" for enterprise orgs ✓
- Change visibility modal includes Internal option for enterprise ✓
- Proper handling of GitHub API limitations with INTERNAL visibility ✓
- Detection of enterprise organizations using
-
Stars mode (Personal Account only)
- Special mode to list repositories that the user has starred
- Available only when viewing Personal Account (not organizations)
- Key binding to trigger unstar action for selected repository
- GraphQL query to fetch starred repositories
- Display similar to regular repo list but with unstar action instead of delete
- Consider showing when/why starred if metadata available
-
Repo actions with confirmations
- Archive / Unarchive repositories
- Key mapping:
Ctrl+Ato open archive/unarchive modal - GraphQL mutations:
archiveRepositoryandunarchiveRepository - Confirmation modal with Left/Right focus navigation and button styling
- Update local state (
isArchivedfield) after successful operation - Handle API errors gracefully with error messages
- Key mapping:
- Archive badge in repository list
- Show "Archived" badge next to archived repositories in main listing
- Use gray/dim styling to visually distinguish archived repos
- Delete (dangerous; detailed confirm flow)
- Key trigger:
DelorBackspacefrom the list view - Full-screen modal overlay with repo info (nameWithOwner, visibility, stars, forks, updatedAt)
- Two-stage confirmation:
- Stage 1: User types 4-character uppercase validation code (excluding 'C')
- Stage 2: Final warning with Left/Right button focus and multiple confirm options
- Execute delete via GitHub REST API (DELETE /repos/{owner}/{repo})
- On success: close modal, remove repo from list, refresh totalCount
- On failure: show error in modal with proper error handling
- Key trigger:
- Archive / Unarchive repositories
-
Sync fork with upstream
- Assigned key
Ctrl+Sto trigger sync - Only shown for forked repositories that are behind upstream
- Confirmation modal showing:
- Fork name and upstream repository
- Number of commits behind
- Warning about potential conflicts
- Execute sync via GitHub REST API (POST /repos/{owner}/{repo}/merge-upstream)
- Requires
contents:writescope and push permissions - Request body:
{ "branch": "main" }(or current default branch)
- Requires
- On success:
- Update local repo state to show 0 commits behind
- Show success message with number of commits pulled
- Close modal and refresh the repository display
- On conflict (409 response):
- Show error explaining manual merge needed
- Suggest creating a pull request to resolve conflicts
- On other failure: show error with retry option
- Assigned key
-
Rename repository
- Assigned key
Ctrl+Rto trigger rename modal - Modal overlay with text input prefilled with current repo name
- Real-time validation: name cannot be empty, must match GitHub naming rules
- GraphQL mutation
renameRepositorywith automatic Apollo cache update - Success: updates local state and cache without server refetch
- Error handling with retry option and clear error messages
- Cache update also refreshes nameWithOwner field
- Assigned key
-
[~] Add automated test suite
- Test infrastructure setup (Vitest with TypeScript support)
- Added
pnpm testscript for running tests - Integrate into CI (GitHub Actions)
Unit Tests:
-
utils.ts- truncate and formatDate functions (13 tests) -
apolloMeta.ts- cache key generation and TTL logic (2 tests) -
config.ts- configuration loading and saving (23 tests) -
github.ts- API interaction helpers (8 tests) - State management and reducers in RepoList
Component Tests:
-
RepoRow- Basic rendering test (1 test) - Updated spacing logic tested -
DeleteModal- Logic tests for verification code (4 tests) -
RepoListHeader- Header rendering and stats display (8 tests) -
RepoListHeaderVisibility- Visibility filter display tests (new test file) -
FilterInput- Input handling and filter logic (6 tests - mocked TextInput) -
SlowSpinner- Animation component (5 tests) -
ArchiveModal- Archive/unarchive confirmation flow (6 tests - mocked useInput) - [~]
SyncModal- Fork sync confirmation flow (not implemented) -
LogoutModal- Logout confirmation flow (6 tests - mocked useInput) - [~]
InfoModal- Repository information display (not implemented) -
SortModal- Sort selection modal (needs tests) -
VisibilityModal- Visibility filter modal (needs tests) -
RepoList- Main component integration tests -
OrgSwitcher- Organization switching logic
Integration Tests:
- Modal flow tests with simulated keyboard input (limited by testing framework)
- Infinite scroll behavior
- Search functionality
- Sorting and filtering combinations
- Rate limit handling
Current Progress:
- Total test files: 12 (added RepoListHeaderVisibility.test.tsx)
- Total tests passing: 82+
- Components with tests: 8/13 (62%) - Added 2 new modals needing tests
- Utilities with tests: 4/4 (100%)
Testing Approach for useInput Components: Successfully implemented mocking strategy for components using
useInputhook:- Mock the
inkmodule'suseInputfunction directly - Use dynamic imports to avoid ESM/CommonJS issues
- Test rendering and basic UI display
- Note: Interactive keyboard behavior tests are limited but UI rendering tests work well
-
Organization support
- Switch between personal and organizations
- List orgs (viewer.organizations) and browse their repos
- Owner affiliation filters (OWNER, COLLABORATOR, ORGANIZATION_MEMBER)
- Switching UI
- Show a picker overlay listing:
- Personal Account (@your_github_handle)
- Organizations (name and @login)
- Keyboard: assign
W(Workspace/Who) to open the switcher; Up/Down to select; Enter to switch; Esc to cancel - Persist last-selected context and show it in header (e.g., "Repositories — Personal Account" or "Repositories — org: @acme")
- Apply context to repo queries (scoped owner/org), and refresh list/totalCount on switch
- Show a picker overlay listing:
- Implemented features:
- OrgSwitcher component with organization listing
- Context persistence in UI preferences
- Dynamic GraphQL queries for personal vs org repositories
- Header displays current context (org/@user or @user)
- Automatic affiliation switching (OWNER for personal, ORGANIZATION_MEMBER for orgs)
-
Bulk selection and actions
- Multi-select mode
- Enter multi-select with a key (e.g.,
M) - Use Up/Down to navigate; Space toggles selection;
*selects all in view;Uunselects all - Show selected count in header/footer
- Enter multi-select with a key (e.g.,
- Bulk operations
- Bulk archive/unarchive selected
- Bulk delete selected (with aggregate confirmation including per-repo list)
- Two-step confirm for destructive operations; follow modal UX (Left/Right, Enter, Y/C)
- Performance and UX
- Use batched REST/GraphQL calls; display progress with spinner and per-item status
- On success: update local list states (archived flag or removal) without full refetch
- On failure: show summary with failed items and suggested remediation
- Multi-select mode
-
Infinite scroll improvements
- Inline loading indicator at end of list
- When user reaches end of loaded repos, show spinner/loading message inline
- Display "Loading more repositories..." with animated spinner at bottom of list
- Keep existing repos visible while fetching next page
- Smarter prefetching trigger
- Changed prefetch trigger from "5 items from end" to "80% from bottom"
- Calculates: trigger when
cursor >= Math.floor(loadedItems.length * 0.8) - Prevents user from ever reaching actual end before more data loads
- Smoother infinite scroll experience with earlier prefetching
- Added debug messages to track when prefetching occurs
- Inline loading indicator at end of list
-
Footer reorganization and UI improvements
- Reorganized footer into 3 logical lines for better organization
- Line 1: Navigation controls (Refresh, Org Switch, Logout, Quit)
- Line 2: View/Filter controls (Top, Bottom, Search, Sort, Direction, Density, Fork Status, Visibility)
- Line 3: Repository actions (Info, Cache Info, Archive, Delete, Sync Fork)
- Updated Delete key binding to Del/Backspace (no Ctrl required)
- Renamed "Forks - Commits Behind" to "Fork Status - Commits Behind"
- Balanced repository item spacing (1 line above, 1 line below)
- Reorganized footer into 3 logical lines for better organization
-
Server‑side search
- Support GitHub search for repos (beyond loaded pages) ✓
- Integrate with
/filter bar; show mode indicator ✓ - Implemented Apollo Client + apollo3-cache-persist for normalized caching and persistence ✓
- Migrated GraphQL calls to ApolloClient with InMemoryCache ✓
- Persist cache to files under app data dir via custom fs storage ✓
- Added TTL overlay for stale-while-revalidate on startup ✓
- Search requires 3+ characters to trigger server-side query ✓
- ESC key clears search and returns to normal listing ✓
- Down arrow from search input acts like Enter to start browsing results ✓
- No auto-selection of first result - user must explicitly navigate ✓
- Organization context support: uses
org:prefix for org searches ✓ - Label changed from "Filter:" to "Search:" for clarity ✓
-
Sorting enhancements
- Persist sort field + direction in config (implemented in UI preferences)
- Sort modal interface with descriptive options (updated, pushed, name, stars)
- Additional fields (created, size)
-
Packaging for Homebrew (completed via custom tap)
- Formula name:
gh-manager-cli✓ - Published to custom tap:
wiiiimm/tap✓ - Install command:
brew tap wiiiimm/tap && brew install gh-manager-cli✓ - Install strategy: uses npm tarball from registry ✓
- Dependencies:
noderequirement specified ✓ - Binary properly symlinked and executable ✓
- Version flag implemented for testing ✓
- SHA256 verification in formula ✓
- Successfully tested on macOS ARM and Intel ✓
- Note: Using custom tap instead of homebrew-core for easier maintenance
- Formula name:
-
Smart repository data caching system (implemented with Apollo Client)
- Implemented with Apollo Client and apollo3-cache-persist ✓
- Normalized cache with InMemoryCache for automatic deduplication ✓
- Persistent cache stored in
apollo-cache.jsonfile ✓ - Cache key generation for different query combinations ✓
- TTL-based cache invalidation with 30-minute default ✓
- Smart cache policies: cache-first, network-only, cache-and-network ✓
- Cache inspection with
Kkey showing size and recent entries ✓ - Cache purging on refresh (
Rkey) for fresh data ✓ - Debug mode (
GH_MANAGER_DEBUG=1) shows cache hit/miss metrics ✓ - Efficient caching across sort/filter combinations ✓
-
Rate‑limit improvements
- Show rate limit usage with delta changes: API: remaining/limit (+/-delta)
- Color thresholds (yellow when low)
- Toggle to show/hide "commits behind" for forks
- Key binding:
fto toggle fork commit tracking on/off - When disabled: exclude expensive commit history queries from GraphQL
- Saves significant API rate limit usage (removes defaultBranchRef.target.history queries)
- Show toggle state in header: "Forks: ON/OFF"
- Persist preference in config alongside other UI settings
- When toggled on: smart refresh to populate commit counts if data missing
- Visual indicator: forks show "Fork of parent" without behind count when disabled
- Show "up to date" for forks with 0 commits behind when tracking enabled
- Key binding:
-
Window resize handling
- Terminal width detection via
useStdout().columns - Dynamic width adjustment for modals and repo rows
- Responsive layout that adapts to terminal size
- Implemented in App.tsx with resize event listener
- Terminal width detection via
-
Copy repository URL to clipboard
- Assigned key
Cto open copy URL modal - Modal UI with SSH and HTTPS options
- Left/Right arrow keys for button navigation
- Keyboard shortcuts:
Sfor SSH,Hfor HTTPS - Cross-platform clipboard support using
clipboardy - Fallback to OS commands (pbcopy, clip, xclip/xsel/wl-copy)
- Success/error toast messages with clear feedback
- Assigned key
-
OAuth login flow (alternative to token) ✓ COMPLETED
- GitHub OAuth App authentication as alternative to Personal Access Token ✓
- Implementation details:
- Uses GitHub Device Authorization Grant flow (no client secret needed) ✓
- Client ID: Ov23li1pOAO5GZmxBF1L ✓
- Device code displayed prominently in yellow box during auth ✓
- Auto-opens browser to GitHub's device authorization page ✓
- Polls for token after user authorizes (5-second intervals) ✓
- Stores OAuth token with same 0600 permissions as PAT ✓
- User experience:
- Auth method selector: OAuth shown as recommended option ✓
- Clear device code display with step-by-step instructions ✓
- Real-time status updates (waiting, polling, success, error) ✓
- Escape key handler for stuck flows ✓
- Q/Esc to quit from auth method selector ✓
- Advanced features:
- Comprehensive OAuth scopes (repo, read:org, user, delete_repo, workflow, packages) ✓
- Organisation access management (Ctrl+W in org switcher opens GitHub settings) ✓
- Refresh organisations list after granting permissions (R key) ✓
- British English throughout interface (organisation, authorisation, colour) ✓
- Benefits: No manual PAT creation, automatic scoping, better security, improved UX ✓
-
Logout (clear stored token)
- Assigned key:
Ctrl+Lto open logout prompt - Confirmation modal: "Are you sure you want to log out?"
EscorN= cancelYorEnter= confirm
- On confirm:
- Remove token from config (delete token field or whole file if only token is stored)
- Clear in-memory token and return to the Authentication Required prompt (token bootstrap screen)
- Show success toast (e.g., "Logged out. Token cleared.")
- Handle errors gracefully and keep user in current state on failure
- Assigned key:
-
Visibility filtering with modal interface
- Assigned key:
Vto open visibility filter modal ✓ - Modal shows options: All, Public, Private/Internal (combined for enterprise) ✓
- Detection of enterprise accounts via
enterpriseOwnersfield ✓ - Shows ENT badge for enterprise organizations ✓
- Server-side filtering using GitHub's
privacyparameter ✓ - Local filtering for INTERNAL repos (API limitation workaround) ✓
- Persistence of visibility filter preference in config ✓
- Modal navigation with arrow keys, Enter to select, Esc to cancel ✓
- Fixed issue with private repository filtering not working ✓
- Refactored to use RepoListHeader component consistently ✓
- Compact modal design to save screen space ✓
- Assigned key:
-
Language filter and indicators
- Quick language cycling; language legend in footer
-
Bulk actions
- Multi‑select and apply action to selection
-
[~] CLI flags (partial implementation)
-
--version/-vflag to show version -
--help/-hflag to show usage -
--orgto start with specific organization- Launch with
--org <slug>to jump to that organisation context if accessible; otherwise ignored - Works with already authenticated session; overrides persisted context for the run
- Launch with
-
--token/-tto provide a token for this run- Accepts
--token <pat>and--token=<pat>(and-tforms) - Overrides env/config for the current process only; does not persist
- Show a brief security note about shell history; prefer env var or interactive prompt
- Accepts
-
--sortto set initial sort field -
--filterto set initial filter -
--page-sizeto override default page size
-
-
Extended repo metadata
- License, topics, issues count, watchers
-
Testing
- Unit tests for formatting and reducers
- Snapshot tests for row rendering (where feasible)
- Token bootstrap: prompt → validate → persist (0600)
- List personal repos with metadata
- Infinite scroll with page prefetch and dynamic totalCount
- Client‑side filter (
/) - Sorting toggles (
sfield,ddirection) with server-side refresh - Open selected repo in browser (Enter /
o) - Rate‑limit indicator (remaining/limit) with delta changes
- Row spacing via Box height with virtualization fix
- Environment-based page sizes (development: 15, production: 25)
- Dotenv loading for development configuration
- Fork commit tracking toggle ('f' key) with smart refresh
- Fork status display: "Fork of upstream" with commits behind/up to date
- Archive/unarchive repositories with confirmation modals
- Delete repositories with two-stage confirmation and REST API
- Archive status badges in repository listings
- UI preference persistence (sort, density, fork tracking)
- Repository deletion via REST API (GraphQL unsupported)
- Modal focus navigation and keyboard shortcuts
- Smart loading states for sort changes and refreshes
- Comprehensive feature documentation added to README
- Repository sync with upstream planning (REST API research completed)
- OAuth login alternative research and planning
- Version display planning (next to app title)
- Automated release workflow with compiled binaries
- Enhanced GitHub Actions workflow to build cross-platform binaries (Linux, macOS, Windows)
- Used pkg to create standalone executables for each platform
- Configured semantic-release to attach binaries to GitHub releases automatically
- Added build:binaries script for local binary creation
- Updated documentation with installation instructions for pre-built binaries
- Sync fork with upstream (
Ctrl+S)- Shows modal with fork name, upstream repo, and commits behind
- Executes sync via GitHub REST API with proper error handling
- Updates local state and shows success/conflict messages
- Server-side search with Apollo Client
- Implemented Apollo Client with persistent cache
- Server-side search triggers at 3+ characters
- ESC key clears search and returns to normal listing
- Improved UX: no auto-selection, down arrow acts like Enter
- Logout functionality (
Ctrl+L)- Confirmation modal with Y/N options
- Clears stored token and returns to auth screen
- Graceful error handling
- Repository info modal (
Ikey)- Shows detailed repository metadata
- Displays size, language, timestamps, visibility
- Modal overlay with ESC to close
- Cache inspection (
K)- Inspects Apollo cache status
- Shows cache statistics and health
- Cache purging on refresh (
Rkey)- Purges Apollo cache files before refreshing
- Forces network-only fetch after purge
- Infinite scroll improvements
- Inline loading indicator showing "Loading more repositories..."
- Smarter prefetch at 80% threshold instead of 5 items from end
- Smoother scrolling experience with earlier data loading
- Packaging (npm)
- Published to npm with executable
gh-manager-cli - Verified bin field and shebang
- Release notes automated via semantic-release
- Published to npm with executable
- Visibility filtering with modal interface
- Modal-based visibility filter (All, Public, Private, Internal)
- Server-side filtering for accurate pagination
- Persistence in config
- Sort modal interface
- Modal-based sort selection with descriptions
- Better UX than cycling through options
- Footer and layout improvements
- Reorganized footer into 3 logical lines
- Balanced repository item spacing
- Updated keyboard shortcuts