feat(multi-account): Accounts tab in Settings (Batch 2b part 1)#124
Conversation
New Settings → Accounts tab: list accounts (identity + default marker), add (with log-in hint), remove, set the global default, and install/uninstall the ~/.zshrc shell integration. - main.ts: accounts-get/add/remove/set-default/shell-hook IPC handlers — thin wrappers over the shared manager (src/cli/account-manager.ts), the exact module the `codev account` CLI uses (one generator, no drift); mutations invalidate the accounts cache so the Sessions tab picks changes up - popup.tsx: the Accounts tab UI; preload.ts + electron-api.d.ts wiring - Rename deferred (labels name dirs; remove+add covers it). Remaining 2b item: a real `codev` binary on PATH. - Bump 1.0.78 + CHANGELOG + design-doc §7 tsc 0 errors; 13/13 tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017kCK4t5JSVynVZxGcrTGGp
📝 WalkthroughWalkthroughThis PR adds multi-account management to the Settings UI: an Accounts tab for listing, adding, removing, and setting defaults, plus shell-integration install/uninstall. It also adds the supporting Electron IPC surface, account-manager seeding logic, and release notes/docs/version updates. ChangesMulti-account management feature
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant Popup
participant Preload
participant MainProcess
participant AccountManager
Popup->>Preload: getAccounts()
Preload->>MainProcess: invoke('accounts-get')
MainProcess->>AccountManager: list accounts
AccountManager-->>MainProcess: accounts data
MainProcess-->>Preload: { ok, accounts, shellInstalled }
Preload-->>Popup: response
Popup->>Preload: setDefaultAccount(label)
Preload->>MainProcess: invoke('accounts-set-default', label)
MainProcess->>AccountManager: setDefaultAccount(label)
MainProcess->>MainProcess: invalidateAccountsCache()
MainProcess-->>Preload: { ok: true }
Preload-->>Popup: response
Popup->>Popup: refreshAccounts()
Popup->>Preload: setAccountsShellHook('install')
Preload->>MainProcess: invoke('accounts-shell-hook', 'install')
MainProcess-->>Preload: { ok, changed, path }
Preload-->>Popup: response
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (3)
src/preload.ts (1)
11-12: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valuePrettier formatting:
setDefaultAccountshould be on a single line.Static analysis flags line 11. The arrow function for
setDefaultAccountcan fit on one line.💅 Proposed formatting fix
- setDefaultAccount: (label: string) => - ipcRenderer.invoke('accounts-set-default', label), + setDefaultAccount: (label: string) => ipcRenderer.invoke('accounts-set-default', label),🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/preload.ts` around lines 11 - 12, The Prettier formatting issue is in the preload API object where setDefaultAccount is split across multiple lines even though it fits on one line. Update the setDefaultAccount arrow function in preload.ts to match the compact style used by removeAccount and keep the full ipcRenderer.invoke call on a single line.Source: Linters/SAST tools
src/electron-api.d.ts (1)
31-32: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winPrettier formatting: multi-line formatting needed for
removeAccountandsetDefaultAccountsignatures.Static analysis flags line 32 for prettier/prettier. Both
removeAccountandsetDefaultAccountshould be formatted with line breaks per the project's prettier config.💅 Proposed formatting fix
- removeAccount: (label: string) => Promise<{ ok: boolean; error?: string }>; - setDefaultAccount: (label: string) => Promise<{ ok: boolean; error?: string }>; + removeAccount: ( + label: string, + ) => Promise<{ ok: boolean; error?: string }>; + setDefaultAccount: ( + label: string, + ) => Promise<{ ok: boolean; error?: string }>;🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/electron-api.d.ts` around lines 31 - 32, The `removeAccount` and `setDefaultAccount` type signatures in `electron-api.d.ts` need to be reformatted to match the project’s Prettier multiline style. Update the surrounding interface/type declaration where these methods are defined so each signature is wrapped across lines consistently with other function types in this file, keeping the same return types and parameter names while applying the expected line breaks.Source: Linters/SAST tools
src/popup.tsx (1)
730-809: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winPrettier formatting: Accounts tab panel has numerous formatting violations.
Static analysis flags 50+ prettier/prettier errors across lines 730-809 (indentation, line wrapping for JSX attributes, multi-line style objects). Run prettier on this file to auto-fix.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/popup.tsx` around lines 730 - 809, The Accounts tab JSX in popup.tsx has widespread Prettier formatting violations. Reformat the entire accounts panel block around the settingsTab === 'accounts' render so indentation, wrapping, and multi-line style objects match the project’s Prettier output; use the existing JSX structure and symbols like accountsShellInstalled, handleAddAccount, handleSetDefaultAccount, and handleRemoveAccount, and apply the formatter rather than manual line-by-line edits.Source: Linters/SAST tools
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/electron-api.d.ts`:
- Around line 26-30: The addAccount IPC contract is returning a RegistryAccount
shape that does not satisfy CodevAccountInfo because it omits isCurrentDefault.
Update the main handler in the addAccount flow to return the enriched account
object with isCurrentDefault populated, using the existing account
lookup/listing path after accountManager.addAccount(), and keep the
electron-api.d.ts return type aligned with CodevAccountInfo so future consumers
receive the full shape.
In `@src/popup.tsx`:
- Around line 112-121: The refreshAccounts function in popup.tsx uses a .then()
chain without handling rejection, which can cause unhandled promise rejections
on IPC failure. Convert refreshAccounts to async/await, await
window.electronAPI.getAccounts(), and wrap the call in try/catch so both
response errors and thrown/rejected IPC errors are handled. Keep the existing
state updates for setAccounts, setAccountsShellInstalled, and setAccountsError,
but move the fallback error handling into the catch block and preserve the
current AccountRow typing.
---
Nitpick comments:
In `@src/electron-api.d.ts`:
- Around line 31-32: The `removeAccount` and `setDefaultAccount` type signatures
in `electron-api.d.ts` need to be reformatted to match the project’s Prettier
multiline style. Update the surrounding interface/type declaration where these
methods are defined so each signature is wrapped across lines consistently with
other function types in this file, keeping the same return types and parameter
names while applying the expected line breaks.
In `@src/popup.tsx`:
- Around line 730-809: The Accounts tab JSX in popup.tsx has widespread Prettier
formatting violations. Reformat the entire accounts panel block around the
settingsTab === 'accounts' render so indentation, wrapping, and multi-line style
objects match the project’s Prettier output; use the existing JSX structure and
symbols like accountsShellInstalled, handleAddAccount, handleSetDefaultAccount,
and handleRemoveAccount, and apply the formatter rather than manual line-by-line
edits.
In `@src/preload.ts`:
- Around line 11-12: The Prettier formatting issue is in the preload API object
where setDefaultAccount is split across multiple lines even though it fits on
one line. Update the setDefaultAccount arrow function in preload.ts to match the
compact style used by removeAccount and keep the full ipcRenderer.invoke call on
a single line.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: e8acb0f5-f79b-44ad-8d16-9f005f7f2221
📒 Files selected for processing (7)
CHANGELOG.mddocs/multi-account-support-design.mdpackage.jsonsrc/electron-api.d.tssrc/main.tssrc/popup.tsxsrc/preload.ts
There was a problem hiding this comment.
All reported issues were addressed across 7 files
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
- addAccount seeds the anchor (~/.claude) account when the registry is fresh and an EXTRA account is being added, so the machine's existing default install stays registered and keeps the global default (cubic P1; fixes the CLI path too) - accounts-add IPC returns the enriched listed shape (isCurrentDefault) so it matches the declared CodevAccountInfo contract - accounts-shell-hook validates the action — a malformed payload fails instead of silently uninstalling - popup: refreshAccounts is async/await with catch; stale notice/error cleared on tab open and in each branch; set-default notice says "install Shell integration" when the zshrc block isn't installed; accountsBusy guard disables buttons during in-flight ops (runAccountOp serializes mutations) tsc 0 errors; 13/13 tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017kCK4t5JSVynVZxGcrTGGp
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/popup.tsx (1)
788-833: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winFix prettier indentation errors flagged by static analysis.
Multiple lines in the Accounts tab UI have incorrect indentation per prettier. These will fail formatting checks if prettier is enforced in CI.
Run
npx prettier --write src/popup.tsxto auto-fix all flagged lines (788, 798, 818–825, 827–833).🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/popup.tsx` around lines 788 - 833, The Accounts tab JSX in popup.tsx has Prettier indentation issues that will fail formatting checks. Reformat the affected block in the accounts UI markup around the Set default, Remove, Add account, and Shell integration controls so it matches the project’s Prettier style; the easiest fix is to run Prettier on src/popup.tsx and keep the structure intact in the popup component.Source: Linters/SAST tools
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@src/popup.tsx`:
- Around line 788-833: The Accounts tab JSX in popup.tsx has Prettier
indentation issues that will fail formatting checks. Reformat the affected block
in the accounts UI markup around the Set default, Remove, Add account, and Shell
integration controls so it matches the project’s Prettier style; the easiest fix
is to run Prettier on src/popup.tsx and keep the structure intact in the popup
component.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 48bc4f17-29e2-44be-92b9-12f0bc944e6c
📒 Files selected for processing (3)
src/cli/account-manager.tssrc/main.tssrc/popup.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
- src/main.ts
There was a problem hiding this comment.
All reported issues were addressed across 3 files (changes from recent commits).
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
The defensive fallback returned a bare RegistryAccount, structurally violating the CodevAccountInfo IPC contract (cubic P3). Compute it via resolveDefaultLabel so both paths honor the type. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017kCK4t5JSVynVZxGcrTGGp
Each row now shows its real command (launch: claude work; the default shows bare claude) instead of abstract <label> wording; placeholder says 'account name'; footer uses a concrete claude-work example. (User feedback: 'label' is jargon — people don't know label = account name.) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017kCK4t5JSVynVZxGcrTGGp
Summary
Batch 2b (part 1) of multi-account support (follows #123): an Accounts tab in Settings — manage Claude Code accounts from the UI instead of the terminal.
defaultmarkeraccounts.sh; shows theclaude <label>log-in hint)~/.claudeaccount is protected)clauderesolves to (2e, now clickable)~/.zshrcsource block)Architecture
The tab is a set of thin IPC handlers (
accounts-get/add/remove/set-default/shell-hookinmain.ts) over the same shared manager (src/cli/account-manager.ts) that thecodev accountCLI uses — one generator foraccounts.json+accounts.sh, no drift between CLI and UI. Mutations invalidate the accounts cache so the Sessions tab picks up changes.src/popup.tsx— newaccountstab (state + handlers + UI, matching the existing tab style)src/preload.ts/src/electron-api.d.ts— API wiring +CodevAccountInfotypesrc/main.ts— IPC handlersScope notes
~/.claude-<label>), so rename implies a dir migration; remove+add covers the rare need.codevbinary on PATH is the remaining 2b item (next PR) — until then the CLI runs viayarn account <cmd>.Supported shells & terminals
codev account install): writes~/.zshrc— zsh only for now (the macOS default). The generatedaccounts.shis bash-compatible (bash users cansourceit from.bashrcmanually); fish is unsupported (different function syntax). Shell detection is future work (design doc §6.C).Checking which account a session runs under (gotcha)
Inside any Claude Code session,
!claude auth statusreports the global default, not the session's account — Claude Code snapshots your interactive shell's functions, so in-sessionclaudeis the accounts.sh dispatcher. Valid probes:!command claude auth status✅ —commandbypasses shell functions, so the real binary inherits the session process's ownCLAUDE_CONFIG_DIR→ the session's actual account!echo ${CLAUDE_CONFIG_DIR:-unset}✅ — the session's own config dir (unset= anchor account)Full write-up: #123's "Gotcha" section + design doc §6.A.
How to test
Needs
yarn make(main-process + renderer changes):defaultmarker; shell integration shows Uninstall (already installed).testaccount → appears as "not logged in — run: claude test"; registry +accounts.shregenerate.Set defaultontest→ notice appears;yarn account listshows*moved (restore after).test→ gone from list;~/.claude-testfolder stays.Automated:
yarn test13/13;tsc --noEmit0 errors.🤖 Generated with Claude Code
Summary by cubic
Adds a new Accounts tab in Settings so you can manage Claude Code accounts from the UI instead of the terminal. This lets you add/remove accounts, set the default for bare
claude, and toggle shell integration.New Features
claudeorclaude <name>).claude <name>), remove an account (keeps its folder), and set the global default.~/.zshrc.accounts-get/add/remove/set-default/shell-hook) wrap the sharedaccount-managerused by thecodev accountCLI; mutations invalidate the Sessions cache.~/.claudeaccount is protected; rename is deferred; remaining 2b item is a realcodevbinary on PATH.Bug Fixes
~/.claudeaccount on first extra add so the existing machine default stays registered and remains the global default.accounts-addreturns the enriched shape and derivesisCurrentDefaultin the fallback path to matchCodevAccountInfo; shell-hook action is validated (malformed payloads fail).Written for commit b3e94f6. Summary will update on new commits.
Summary by CodeRabbit