feat(multi-account): account picker, claude tab completion, naming & rename (Batch 2c-lite)#126
feat(multi-account): account picker, claude tab completion, naming & rename (Batch 2c-lite)#126grimmerk wants to merge 23 commits into
Conversation
Alt+Cmd+Enter on a project opens a small account picker (arrow keys + Enter, Esc cancels, click works too); the chosen account launches with an explicit CLAUDE_CONFIG_DIR + `command claude`, bypassing the shell dispatcher — mirroring buildResumeCommand. - Plain Cmd+Enter is unchanged: instant launch under the global default (bare `claude` -> dispatcher). Single-account or registry-less setups never see the picker (falls through to a normal launch). - launchNewClaudeSession gains an optional accountLabel; the codev embedded terminal and VS Code paths ignore it (logged) — the picker targets external terminals. - The overlay reuses the data-settings-panel escape hatch so the focus-stealing click handler leaves it alone. - Cross-account RESUME stays deferred to Batch 3 (copy-fork design). tsc 0 errors; 17/17 tests. Bump 1.0.80 + CHANGELOG + design doc. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017kCK4t5JSVynVZxGcrTGGp
📝 WalkthroughWalkthroughThis PR adds account-aware new-session launching, an ⌥⌘+Enter account picker, account label rename and shell completion support, live account UI updates, multi-account documentation, and package version 1.0.80. ChangesMulti-account account management and launch
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant SwitcherUI
participant Preload
participant MainProcess
participant SessionUtility
SwitcherUI->>SwitcherUI: user presses ⌥⌘+Enter
SwitcherUI->>SwitcherUI: fetch accounts and select accountLabel
SwitcherUI->>Preload: launchNewClaudeSession(projectPath, accountLabel)
Preload->>MainProcess: send launch-new-claude-session(projectPath, accountLabel)
MainProcess->>SessionUtility: launchNewClaudeSession(..., accountLabel)
SessionUtility->>SessionUtility: build account-specific Claude command
SessionUtility->>SessionUtility: runCommandInTerminal(claudeCmd)
Possibly related issues
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 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: 1
🧹 Nitpick comments (1)
src/claude-session-utility.ts (1)
11-15: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueNamed imports are not alphabetically ordered.
Per coding guidelines, imports should be organized alphabetically. The current order is
getScannableAccounts, getProjectsDir, getAccountByLabel; it should begetAccountByLabel, getProjectsDir, getScannableAccounts.♻️ Proposed fix
import { + getAccountByLabel, getProjectsDir, - getScannableAccounts, - getAccountByLabel, + getScannableAccounts, } from './accounts';🤖 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/claude-session-utility.ts` around lines 11 - 15, The named imports in the claude-session-utility module are not alphabetically ordered. Update the import list from accounts so the symbols getAccountByLabel, getProjectsDir, and getScannableAccounts are sorted alphabetically within the same import statement.Source: Coding guidelines
🤖 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/claude-session-utility.ts`:
- Line 1442: The account override is being lost because `runCommandInTerminal`
is called with the literal `'claude'` instead of the constructed `claudeCmd`, so
terminals that use the second argument directly (notably the ghostty and cmux
paths) drop the `CLAUDE_CONFIG_DIR` prefix. Update the `runCommandInTerminal`
call in `claude-session-utility.ts` to pass the `claudeCmd` variable as the
command argument, matching the behavior expected by the ghostty/cmux branches
and preserving the active account override.
---
Nitpick comments:
In `@src/claude-session-utility.ts`:
- Around line 11-15: The named imports in the claude-session-utility module are
not alphabetically ordered. Update the import list from accounts so the symbols
getAccountByLabel, getProjectsDir, and getScannableAccounts are sorted
alphabetically within the same import statement.
🪄 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: 2a98555f-4cbb-4523-880b-1d32e0a904b5
📒 Files selected for processing (8)
CHANGELOG.mddocs/multi-account-support-design.mdpackage.jsonsrc/claude-session-utility.tssrc/electron-api.d.tssrc/main.tssrc/preload.tssrc/switcher-ui.tsx
There was a problem hiding this comment.
All reported issues were addressed across 8 files
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
Search-bar hint becomes '⌘+Enter: New Claude · ⌥⌘+Enter: pick account' when more than one account is registered; single-account users keep the unchanged short hint (no clutter — user's concern). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017kCK4t5JSVynVZxGcrTGGp
One folder routinely hosts sessions from multiple accounts (the real testing pattern), so a folder->account default would guess wrong where the choice matters most; 2e global default + 2c-lite picker cover the need. Feasible (a default, not a constraint) but dropped on value. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017kCK4t5JSVynVZxGcrTGGp
There was a problem hiding this comment.
All reported issues were addressed across 1 file (changes from recent commits).
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
- CRITICAL: pass claudeCmd (not literal 'claude') as the 2nd arg to runCommandInTerminal — Ghostty/cmux build their launch scripts from it, so the picker's account env prefix was silently dropped there (iTerm2/Terminal.app were unaffected; resume already passed it) - picker: on getAccounts failure, don't guess an identity — log and abort instead of silently launching the global default - hint updates live: re-check the account count on a same-window codev-accounts-changed event (fired by the Settings popup after mutations) and on window focus (covers CLI-side changes) — no app restart needed (user-reported) - hide react-select's default IndicatorSeparator (the stray '|' that looks like a cursor before the hint; user-reported) - docs: mark 2e as shipped in §7 (review nit) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017kCK4t5JSVynVZxGcrTGGp
claude-<label> function names already complete natively (command position), but the dispatcher's first arg didn't — register a labels completion for claude, guarded by _comps so an official Claude Code completion (if one ever ships) wins automatically. Independent of appPath. (user request) +1 test. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017kCK4t5JSVynVZxGcrTGGp
Registering our claude completion claimed the whole slot, which would have killed zsh's default file completion at every other position (e.g. claude -p ./path<TAB>) — fall back to _files there. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017kCK4t5JSVynVZxGcrTGGp
README gains the Multi-Account section: setup, shell commands table, codev account CLI table, UI map, session-probe gotcha. Changelog covers the full PR scope (picker, live hint, completions, separator, 2d drop). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017kCK4t5JSVynVZxGcrTGGp
Removing an account only unregisters it: folder, login, and session history stay on disk, and re-adding the same name reattaches them (verified during #124 testing). Noted in the README CLI table, the Remove button tooltip, and the post-remove notice. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017kCK4t5JSVynVZxGcrTGGp
add <name> just registers name -> ~/.claude-<name> (the account's CLAUDE_CONFIG_DIR); Claude Code fills the folder on first login. Noted in the README callout; the UI shows the dir in the add notice and as a hover tooltip on each account row. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017kCK4t5JSVynVZxGcrTGGp
'each account also has a function form, e.g. claude-work' read as if only claude-work existed — now says claude work / claude-work are two equivalent forms. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017kCK4t5JSVynVZxGcrTGGp
'work' in the footer read like a fixed keyword — derive the example from the user's actual accounts (prefer a non-default one) and phrase it as 'launch any account above by its name'. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017kCK4t5JSVynVZxGcrTGGp
The empty-registry fallback showed a hardcoded 'work' example whose commands don't exist; now the example clause only renders when at least one account is registered (default-only shows its real name). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017kCK4t5JSVynVZxGcrTGGp
The anchor's auto-seeded 'personal' label was otherwise permanent (the anchor can't be removed, so remove+add doesn't apply). rename changes only the label — the folder is never moved (dir is stored in the registry) — updates defaultAccount if it pointed at the old name, and regenerates. Completion offers all labels for rename. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017kCK4t5JSVynVZxGcrTGGp
Covers: existing-user first open (empty tab, auto-seeded personal), renaming/naming the default up front (add --dir ~/.claude), add-then- login bootstrap, attaching a hand-maintained account from any folder (--dir; convention is only a default), and rename semantics. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017kCK4t5JSVynVZxGcrTGGp
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017kCK4t5JSVynVZxGcrTGGp
There was a problem hiding this comment.
All reported issues were addressed across 9 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
- addAccount rejects a folder that's already registered under another name (one folder = one account; a duplicate mapping would double-scan sessions and blur attribution) — gap found by user Q&A - remove notice shows the kept FOLDER and folder-suffix reattach guidance instead of 'add <label> back', which was wrong after a rename (label no longer matches the folder; add would target an empty new dir) — user hit this with work->ff->remove - default row shows both launch forms: 'claude (or claude personal)' - README: rename-then-remove reattach caveat in the callout Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017kCK4t5JSVynVZxGcrTGGp
Name and folder are separate things (name is mutable via rename; folders never move). Make that visible: rows show '· folder: <dir>' whenever dir diverges from ~/.claude-<name> (renamed accounts, and the anchor), and the add row gains a caption explaining add = create-or- attach ~/.claude-<name>, with --dir for existing custom folders. Alias concept intentionally NOT introduced (rename replaces the old name); folders can't move on rename because credentials are keyed by config-dir path. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017kCK4t5JSVynVZxGcrTGGp
Empty state pre-announces that the existing login will appear auto- named 'personal' (renameable); the anchor row's tooltip says the name is just a label with the rename command. 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/switcher-ui.tsx (1)
1758-1837: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick winRestore focus to search input after closing the account picker.
When the picker closes via Escape or backdrop click, the modal is removed from the DOM and focus falls to
body— the search input loses focus. The backdrop'sdata-settings-panelattribute causes the document click handler (Line 597) to skipforceFocusOnInput(), and Escape'se.stopPropagation()prevents the global handler from running. Users must click manually to resume searching.🔧 Proposed fix: restore focus on close
onKeyDown={(e) => { e.stopPropagation(); if (e.key === 'Escape') { setLaunchPicker(null); + forceFocusOnInput(); } else if (e.key === 'ArrowDown') {data-settings-panel - onClick={() => setLaunchPicker(null)} + onClick={() => { setLaunchPicker(null); forceFocusOnInput(); }} style={{🤖 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/switcher-ui.tsx` around lines 1758 - 1837, Restore focus to the search input whenever the launch picker closes, including Escape and backdrop clicks. Update the launch picker close paths in the `data-settings-panel` overlay and its `onKeyDown` handler to close the picker and explicitly invoke the existing search-input focus mechanism after unmounting, using the component’s established input ref or focus helper; ensure the behavior also applies to any shared `pickLaunchAccount` close path.
🧹 Nitpick comments (2)
src/switcher-ui.tsx (1)
610-617: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse async/await in
refreshMultiAccountHintper coding guidelines.The function uses
.then().catch()for an async operation, whileopenAccountPickerForLaunchin the same file uses async/await. As per coding guidelines, async/await should be used for asynchronous operations insrc/**/*.{ts,tsx}files.♻️ Proposed refactor
- const refreshMultiAccountHint = () => { - window.electronAPI - .getAccounts() - .then((r) => { - if (r.ok) setIsMultiAccountUI(((r.accounts || []) as unknown[]).length > 1); - }) - .catch(() => {}); - }; + const refreshMultiAccountHint = async () => { + try { + const r = await window.electronAPI.getAccounts(); + if (r.ok) setIsMultiAccountUI(((r.accounts || []) as unknown[]).length > 1); + } catch {} + };🤖 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/switcher-ui.tsx` around lines 610 - 617, Refactor refreshMultiAccountHint to use async/await instead of the current then/catch chain. Mark the function async, await window.electronAPI.getAccounts(), preserve the existing successful response handling, and retain equivalent error swallowing behavior with try/catch.Source: Coding guidelines
src/cli/account-manager.ts (1)
513-537: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd tests for
renameAccountand the duplicate-directory guard.Both are new mutation paths with no test coverage in the changed ranges.
renameAccountmodifies the registry and regenerates shell integration; the duplicate-dir guard inaddAccount(lines 436-445) prevents session attribution corruption. The existingreg()fixture makes these straightforward to add.🧪 Suggested test cases
describe('renameAccount', () => { it('renames a non-default account', () => { // mock readRegistry → reg(), call renameAccount('work', 'company') // assert: acct.label === 'company', defaultAccount unchanged, writeRegistry + regenerate called }); it('updates defaultAccount when renaming the default', () => { // call renameAccount('personal', 'main') // assert: reg.defaultAccount === 'main' }); it('rejects invalid newLabel', () => { // assert renameAccount('work', '1bad') throws }); it('rejects non-existent oldLabel', () => { // assert renameAccount('nope', 'x') throws /No account/ }); it('rejects duplicate newLabel', () => { // assert renameAccount('personal', 'work') throws /already exists/ }); }); describe('addAccount duplicate-dir guard', () => { it('rejects a dir already registered', () => { // mock readRegistry → reg(), call addAccount('dup', { dir: '~/.claude-work' }) // assert throws /already registered as "work"/ }); });🤖 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/cli/account-manager.ts` around lines 513 - 537, Add comprehensive tests for the new mutation paths: cover renameAccount for successful non-default and default renames, invalid or missing labels, duplicate labels, registry updates, and writeRegistry/regenerate calls; also test addAccount’s duplicate-directory guard using the existing reg() fixture, asserting it rejects an already registered directory and identifies the existing account.
🤖 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/switcher-ui.tsx`:
- Around line 1758-1837: Restore focus to the search input whenever the launch
picker closes, including Escape and backdrop clicks. Update the launch picker
close paths in the `data-settings-panel` overlay and its `onKeyDown` handler to
close the picker and explicitly invoke the existing search-input focus mechanism
after unmounting, using the component’s established input ref or focus helper;
ensure the behavior also applies to any shared `pickLaunchAccount` close path.
---
Nitpick comments:
In `@src/cli/account-manager.ts`:
- Around line 513-537: Add comprehensive tests for the new mutation paths: cover
renameAccount for successful non-default and default renames, invalid or missing
labels, duplicate labels, registry updates, and writeRegistry/regenerate calls;
also test addAccount’s duplicate-directory guard using the existing reg()
fixture, asserting it rejects an already registered directory and identifies the
existing account.
In `@src/switcher-ui.tsx`:
- Around line 610-617: Refactor refreshMultiAccountHint to use async/await
instead of the current then/catch chain. Mark the function async, await
window.electronAPI.getAccounts(), preserve the existing successful response
handling, and retain equivalent error swallowing behavior with try/catch.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 5a6679eb-0476-41be-9cc6-7c5e8eddc429
📒 Files selected for processing (9)
CHANGELOG.mdREADME.mddocs/multi-account-support-design.mdsrc/claude-session-utility.tssrc/cli/account-manager.test.tssrc/cli/account-manager.tssrc/cli/codev-account.tssrc/popup.tsxsrc/switcher-ui.tsx
✅ Files skipped from review due to trivial changes (2)
- CHANGELOG.md
- docs/multi-account-support-design.md
…h forms, #128 - Name vs folder callout: name is a mutable label, folder fixed at creation; divergence shown in UI; folders never move on rename because credentials are keyed by the config-dir path - One folder = one account (duplicate-dir registration rejected) - Default account's three equivalent launch forms - Not-yet-supported line now also links #128 (copy-fork) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017kCK4t5JSVynVZxGcrTGGp
- P1: picker launch validates the label (stale/removed label aborts instead of silently falling back to the default identity); explicit default-account pick uses `env -u CLAUDE_CONFIG_DIR claude` so an inherited env can't reroute it - claude completion: compadd || _files so a path prefix at position 2 still gets file completion - rename hint: recommend a NEW shell (source keeps the old claude-<old> function defined) - Accounts footer: shell-command example only when shell integration is installed, else points at the Install button - docs accuracy: CHANGELOG per-pick launch forms; design doc narrows 'bypass the dispatcher' to account-explicit operations; README notes custom --dir re-add, external-terminals-only override, and the polite completion registration Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017kCK4t5JSVynVZxGcrTGGp
There was a problem hiding this comment.
All reported issues were addressed across 3 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
- First-ever add asks what to name the existing ~/.claude login: UI
shows a prefilled field ('main' — a neutral prefill, never assume
'personal'; the machine's first login may be a company account),
CLI gains --anchor-name (fallback main/primary) and prints what the
anchor was named
- Per-row Rename button (inline input, Enter/Esc), wired to a new
accounts-rename IPC over renameAccount
- 'default' is now a RESERVED label (add + rename + anchor name): it
already names the dispatcher's global-default concept, so an account
called default would permanently collide with the badge/command
- Visible model text (per feedback that tooltips are not discoverable):
the tab header states 'Names are renameable labels; folders never
move'; empty state explains the anchor gets named by the field below
- Docs: README scenarios reworked (naming at first add, rename row,
reserved name); CHANGELOG; design doc 2c-lite entry
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017kCK4t5JSVynVZxGcrTGGp
There was a problem hiding this comment.
All reported issues were addressed across 10 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
- popup no longer force-passes 'main': the anchor field defaults to empty (placeholder main) and passes undefined when untouched, so the manager's main/primary fallback applies — naming the new account 'main' now works in the UI exactly like the CLI instead of erroring; the notice computes the effective anchor name - CLI usage documents the conditional default (main, or primary when the new account is itself named main) - design doc: 2c-lite launch wording covers the anchor pick (env -u CLAUDE_CONFIG_DIR claude); 2b bullet no longer contradicts the shipped rename; prefilled->defaults wording in docs/changelog 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)
864-961: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick winFix Prettier formatting errors before merge.
Static analysis reports numerous
prettier/prettierindentation errors across lines 832–1013. The PR description mentionstsc --noEmitandyarn testpassing, but these formatting errors would likely fail a lint CI step. Runyarn prettier --write src/popup.tsx(or the project's format script) to resolve all reported issues at once.The underlying logic in this segment — folder divergence detection, rename controls with keyboard handling, and conditional button visibility — is sound.
🤖 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 864 - 961, Prettier formatting is inconsistent throughout the account-management JSX segment, causing indentation lint failures. Run the repository’s Prettier formatter on src/popup.tsx, or the project format script, and verify the affected JSX around the account list, rename controls, and conditional buttons is reformatted without changing its logic.Source: Linters/SAST tools
🧹 Nitpick comments (3)
src/popup.tsx (1)
175-195: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAvoid duplicating backend fallback logic in the frontend.
effectiveAnchoron lines 181–183 reimplements the backend's anchor-name fallback ('main', or'primary'when the new account is namedmain) purely for the success notice. If the backend fallback rules change, this display logic will silently diverge and show the wrong anchor name to the user.Consider having the
accounts-addIPC response include the resolved anchor name (theaccountobject already returned could carry it), then use that directly in the notice instead of recomputing it client-side.🤖 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 175 - 195, Remove the frontend fallback computation in the account-add flow: eliminate effectiveAnchor’s duplicated logic near the addAccount call, update the accounts-add IPC/backend response to include the resolved anchor name on the returned account, and build anchorNote from that response value so the success notice uses the backend’s authoritative result.src/electron-api.d.ts (1)
26-35: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winFix prettier formatting on
addAccountsignature.ESLint flags this as a
prettier/prettiererror: the parameter list should be multi-line with a trailing comma. As per coding guidelines, trailing commas should be used in multi-line constructs.♻️ Prettier fix
- addAccount: (label: string, anchorName?: string) => Promise<{ + addAccount: ( + label: string, + anchorName?: string, + ) => Promise<{ ok: boolean; error?: string; account?: CodevAccountInfo; }>;🤖 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 26 - 35, Update the addAccount declaration in the Electron API type so its parameters use Prettier’s multi-line formatting, placing each parameter on its own line and adding a trailing comma after the optional anchorName parameter.Sources: Coding guidelines, Linters/SAST tools
src/preload.ts (1)
10-14: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winFix prettier formatting flagged by ESLint.
ESLint reports a
prettier/prettiererror at line 12. Runprettier --write src/preload.tsto resolve.🤖 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 10 - 14, Format the IPC methods in the preload API, including addAccount, removeAccount, and renameAccount, according to the repository’s Prettier configuration; run Prettier on the file and ensure the resulting formatting satisfies the prettier/prettier ESLint rule.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 864-961: Prettier formatting is inconsistent throughout the
account-management JSX segment, causing indentation lint failures. Run the
repository’s Prettier formatter on src/popup.tsx, or the project format script,
and verify the affected JSX around the account list, rename controls, and
conditional buttons is reformatted without changing its logic.
---
Nitpick comments:
In `@src/electron-api.d.ts`:
- Around line 26-35: Update the addAccount declaration in the Electron API type
so its parameters use Prettier’s multi-line formatting, placing each parameter
on its own line and adding a trailing comma after the optional anchorName
parameter.
In `@src/popup.tsx`:
- Around line 175-195: Remove the frontend fallback computation in the
account-add flow: eliminate effectiveAnchor’s duplicated logic near the
addAccount call, update the accounts-add IPC/backend response to include the
resolved anchor name on the returned account, and build anchorNote from that
response value so the success notice uses the backend’s authoritative result.
In `@src/preload.ts`:
- Around line 10-14: Format the IPC methods in the preload API, including
addAccount, removeAccount, and renameAccount, according to the repository’s
Prettier configuration; run Prettier on the file and ensure the resulting
formatting satisfies the prettier/prettier ESLint rule.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 49b40f7e-0925-4392-bfdd-f584839abb52
📒 Files selected for processing (10)
CHANGELOG.mdREADME.mddocs/multi-account-support-design.mdsrc/claude-session-utility.tssrc/cli/account-manager.tssrc/cli/codev-account.tssrc/electron-api.d.tssrc/main.tssrc/popup.tsxsrc/preload.ts
✅ Files skipped from review due to trivial changes (1)
- CHANGELOG.md
🚧 Files skipped from review as they are similar to previous changes (1)
- docs/multi-account-support-design.md
There was a problem hiding this comment.
All reported issues were addressed across 5 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017kCK4t5JSVynVZxGcrTGGp
Summary
Batch 2c-lite (follows #125): pick the account when launching a new Claude session —
⌥⌘+Enteron a project opens a small account picker; plain⌘+Enterstays exactly as before.Design decision (per discussion): the picker is behind a modifier, never forced — quick-launch speed is preserved, and "which account does bare
⌘+Enteruse" remains the global default (codev account default/ Settings → Accounts), which shipped with 2e. Cross-account resume is deliberately NOT here — a session's transcript lives in its own account'sprojects/dir, so "resume under another account" must be an explicit copy-fork (Batch 3), never a link.Behavior
⌘+Enterclaude→ dispatcher)⇧+Enter⌥⌘+Enterdefaultmarker + email shown) → launches with explicitCLAUDE_CONFIG_DIR='…' command claude(dispatcher bypassed, mirroring resume)⌥⌘+Enter, single account / no registryImplementation
launchNewClaudeSession(projectPath, terminalApp, terminalMode, accountLabel?)— with a label, builds the env-prefixedcommand claude(single-quote-escaped); without, bareclaudeas before. VS Code (Multi-account: VS Code (claude-vscode) sessions can't be pinned to a Claude account #121) and the embedded codev terminal ignore the label (logged).launch-new-claude-session+ preload + types gain the optional label.launchClaudeRefgains'external-pick'; the picker overlay reuses thedata-settings-panelescape hatch so the global focus-stealing click handler leaves it alone;Esccloses only the picker (stopPropagation).⌥⌘+Enter.Also in this PR (grew during review/testing)
runCommandInTerminalnow receivesclaudeCmdas its 2nd arg — Ghostty/cmux build their launch scripts from it, so the picked account's env prefix reaches those terminals too (iTerm2/Terminal.app were unaffected; resume already did this).· ⌥⌘+Enter: pick accountonly for multi-account setups, and refreshes after account add/remove (same-windowcodev-accounts-changedevent + window-focus re-check) — no app restart (user-reported).getAccounts()fails, the picker logs and aborts instead of silently launching the global default.claude <name>:claude <TAB>completes account labels; registered only when nothing else completesclaude(_compsguard — a future official completion wins automatically); other argument positions keep zsh's default file completion (_filesfallback).IndicatorSeparator(the stray|before the hint; user-reported).codev accountCLI table, UI map, common-scenarios table, session-probe gotcha); design doc marks 2e as shipped and drops 2d (folder→account auto-switch) — one folder legitimately hosts sessions from multiple accounts, so a folder default would guess wrong exactly where it matters; 2e global default + this picker cover the need.Account naming & rename (second wave, from a design session on the name/folder model)
The model: an account is a name → config-folder mapping. The name is a mutable label; the folder is fixed at creation and never moves (credentials are keyed by the folder path). The UI now states this and shows
· folder: …on a row whenever they diverge.codev account rename <old> <new>(CLI) + a per-row Rename button (UI, inline input with Enter/Esc). This is also the only way to rename the anchor (~/.claude) account, which can't be removed.~/.claudelogin — a prefilled field (main) in the UI,--anchor-namein the CLI — replacing the old auto-assumedpersonal(the machine's first login may well be a company account).defaultis a reserved name (add/rename/anchor-name all reject it): it already denotes the dispatcher's global-default concept (thedefaultbadge,codev account default), so an account nameddefaultwould permanently collide.isDefault→isAnchorschema rename agreed as a separate small PR.How to test (needs
yarn make)⌥⌘+Enter→ picker shows personal/work (+default marker, emails).!command claude auth statusshows the work identity (!claude auth statuswould show the global default — see feat(multi-account): codev account CLI + global-default (Batch 2a + 2e) #123's gotcha).Esccloses the picker; clicking the dimmed backdrop closes it;⌘+Enterstill launches instantly.|before the hint is gone.codev account regenerate+ a new shell,claude w<TAB>completeswork;claude -p ./<TAB>still completes files.⌥⌘+Enterand verify with!command claude auth status(this path carried the critical fix).· folder: …while diverged); renaming anything todefaultis rejected (reserved).cp ~/.config/codev/accounts.json /tmp/bak && rm ~/.config/codev/accounts.json→ Accounts tab shows the anchor-naming field (prefilledmain) → add a test account → both rows appear (anchor named as chosen). Restore:cp /tmp/bak ~/.config/codev/accounts.json && codev account regenerate.tsc --noEmit0 errors;yarn test18/18.🤖 Generated with Claude Code
Summary by cubic
Adds an account picker for new Claude sessions, zsh completion for
claude <TAB>, and account naming/rename. Improves multi-account safety, external-terminal launches, and docs.New Features
CLAUDE_CONFIG_DIR+command claude; a default pick usesenv -u CLAUDE_CONFIG_DIR claude. The search-bar hint shows the picker shortcut only when multiple accounts exist and updates live.claude <TAB>completes account labels; registers only if no existingclaudecompletion; other positions fall back to_files.codev account rename <old> <new>and a per-row Rename in the UI. On first add, you choose a name for the existing~/.claudeaccount (empty uses a safe default:main, orprimarywhen the new account is namedmain);defaultis reserved. The UI shows the config folder when name ≠ folder suffix; add explains create‑or‑attach (~/.claude-<name>) and rejects duplicate folder mappings.Bug Fixes
claudeCmdso the picked account’s env is preserved; explicit default picks clearCLAUDE_CONFIG_DIR; the picker aborts on account‑load failure or a stale/removed label.IndicatorSeparator; remove is non‑destructive and now shows the kept folder with re‑attach guidance; README and design docs updated (2d dropped; 2c‑lite clarifies themain→primaryfallback).Written for commit 0434d2e. Summary will update on new commits.
Summary by CodeRabbit
New Features
codev account rename <old> <new>plus improved account management (anchor options, richer account hints, per-row rename).claude <TAB>label completion and updated shell completion behavior.Bug Fixes
Documentation