Skip to content

feat(multi-account): account picker, claude tab completion, naming & rename (Batch 2c-lite)#126

Open
grimmerk wants to merge 23 commits into
mainfrom
feat/new-session-account-picker
Open

feat(multi-account): account picker, claude tab completion, naming & rename (Batch 2c-lite)#126
grimmerk wants to merge 23 commits into
mainfrom
feat/new-session-account-picker

Conversation

@grimmerk

@grimmerk grimmerk commented Jul 9, 2026

Copy link
Copy Markdown
Owner

Summary

Batch 2c-lite (follows #125): pick the account when launching a new Claude session⌥⌘+Enter on a project opens a small account picker; plain ⌘+Enter stays 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 ⌘+Enter use" 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's projects/ dir, so "resume under another account" must be an explicit copy-fork (Batch 3), never a link.

Behavior

Gesture Result
⌘+Enter unchanged — instant launch under the global default (bare claude → dispatcher)
⇧+Enter unchanged — launch in the CodeV embedded terminal
⌥⌘+Enter account picker (↑↓ / Enter / Esc, click and hover work; default marker + email shown) → launches with explicit CLAUDE_CONFIG_DIR='…' command claude (dispatcher bypassed, mirroring resume)
⌥⌘+Enter, single account / no registry no picker — falls through to a normal launch

Implementation

  • launchNewClaudeSession(projectPath, terminalApp, terminalMode, accountLabel?) — with a label, builds the env-prefixed command claude (single-quote-escaped); without, bare claude as 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).
  • IPC launch-new-claude-session + preload + types gain the optional label.
  • Renderer: launchClaudeRef gains 'external-pick'; the picker overlay reuses the data-settings-panel escape hatch so the global focus-stealing click handler leaves it alone; Esc closes only the picker (stopPropagation).
  • Hover tooltip on the "⌘+Enter: New Claude" hint advertises ⌥⌘+Enter.

Also in this PR (grew during review/testing)

  • Fix (critical, review-caught): runCommandInTerminal now receives claudeCmd as 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).
  • Live hint: the search-bar hint shows · ⌥⌘+Enter: pick account only for multi-account setups, and refreshes after account add/remove (same-window codev-accounts-changed event + window-focus re-check) — no app restart (user-reported).
  • Picker error handling: if getAccounts() fails, the picker logs and aborts instead of silently launching the global default.
  • Tab completion for claude <name>: claude <TAB> completes account labels; registered only when nothing else completes claude (_comps guard — a future official completion wins automatically); other argument positions keep zsh's default file completion (_files fallback).
  • UI polish: removed react-select's default IndicatorSeparator (the stray | before the hint; user-reported).
  • Docs: README gains a full Multi-Account section (setup, shell-command table, codev account CLI 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.
  • First-ever add asks what to name your existing ~/.claude login — a prefilled field (main) in the UI, --anchor-name in the CLI — replacing the old auto-assumed personal (the machine's first login may well be a company account).
  • default is a reserved name (add/rename/anchor-name all reject it): it already denotes the dispatcher's global-default concept (the default badge, codev account default), so an account named default would permanently collide.
  • One folder = one account: registering an already-registered folder under a second name is rejected (a duplicate mapping would double-scan sessions and blur attribution).
  • Remove notice now shows the kept folder and folder-suffix reattach guidance (after a rename, "add the old label back" would have targeted a wrong, empty folder).
  • Follow-ups filed: onboarding niceties (detect existing config dirs & one-click register, wrapper-collision warning) in Multi-account onboarding: detect existing config dirs, name-your-default UI, wrapper-collision warning #127; cross-account copy-fork resume in Cross-account resume as copy-fork (deferred: transcript sessionId/history workarounds needed) #128. Internal isDefaultisAnchor schema rename agreed as a separate small PR.

How to test (needs yarn make)

  1. Projects tab → select a project → ⌥⌘+Enter → picker shows personal/work (+default marker, emails).
  2. Pick work → terminal opens a new claude in that project → !command claude auth status shows the work identity (!claude auth status would show the global default — see feat(multi-account): codev account CLI + global-default (Batch 2a + 2e) #123's gotcha).
  3. Pick personal → same check, personal identity.
  4. Esc closes the picker; clicking the dimmed backdrop closes it; ⌘+Enter still launches instantly.
  5. Settings → Accounts: add/remove an account → the search-bar hint switches between the short/long form without restarting the app; the stray | before the hint is gone.
  6. Shell: after codev account regenerate + a new shell, claude w<TAB> completes work; claude -p ./<TAB> still completes files.
  7. If you use Ghostty or cmux as the session terminal: pick an account via ⌥⌘+Enter and verify with !command claude auth status (this path carried the critical fix).
  8. Rename: per-row Rename → change a name and back (folder shown unchanged via · folder: … while diverged); renaming anything to default is rejected (reserved).
  9. First-add flow (fresh-registry simulation): cp ~/.config/codev/accounts.json /tmp/bak && rm ~/.config/codev/accounts.json → Accounts tab shows the anchor-naming field (prefilled main) → add a test account → both rows appear (anchor named as chosen). Restore: cp /tmp/bak ~/.config/codev/accounts.json && codev account regenerate.

tsc --noEmit 0 errors; yarn test 18/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

    • ⌥⌘+Enter opens an account picker for new sessions; single-account skips. External terminals launch via explicit CLAUDE_CONFIG_DIR + command claude; a default pick uses env -u CLAUDE_CONFIG_DIR claude. The search-bar hint shows the picker shortcut only when multiple accounts exist and updates live.
    • zsh: claude <TAB> completes account labels; registers only if no existing claude completion; other positions fall back to _files.
    • Naming & rename: codev account rename <old> <new> and a per-row Rename in the UI. On first add, you choose a name for the existing ~/.claude account (empty uses a safe default: main, or primary when the new account is named main); default is 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

    • External terminals (Ghostty/cmux): pass the computed claudeCmd so the picked account’s env is preserved; explicit default picks clear CLAUDE_CONFIG_DIR; the picker aborts on account‑load failure or a stale/removed label.
    • UI/Docs: hide the stray 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 the mainprimary fallback).

Written for commit 0434d2e. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features

    • Added multi-account “account-first” session picker for ⌥⌘+Enter (keyboard/mouse) with session launch using the selected account; ⌘+Enter keeps default behavior.
    • Added codev account rename <old> <new> plus improved account management (anchor options, richer account hints, per-row rename).
    • Added claude <TAB> label completion and updated shell completion behavior.
  • Bug Fixes

    • Improved live hint/account updates without restart and refined picker hint text.
  • Documentation

    • Updated README with Multi-Account Support details and revised Batch 2 phasing guidance.

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
@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This 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.

Changes

Multi-account account management and launch

Layer / File(s) Summary
Account rename and shell completion
src/cli/account-manager.ts, src/cli/codev-account.ts, src/cli/account-manager.test.ts
Adds label renaming, reserved-label and duplicate-directory validation, claude <label> completion, and related CLI/test updates.
Account-aware new-session launch
src/electron-api.d.ts, src/preload.ts, src/main.ts, src/claude-session-utility.ts
Propagates an optional account label through IPC and launches selected accounts with explicit configuration-directory commands.
Switcher account picker
src/switcher-ui.tsx
Adds ⌥⌘+Enter account selection, dynamic shortcut visibility, and keyboard/mouse picker controls.
Account UI and documentation
src/popup.tsx, README.md, docs/multi-account-support-design.md, CHANGELOG.md, package.json
Updates account onboarding and notices, documents multi-account behavior and roadmap changes, and bumps the package version.

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)
Loading

Possibly related issues

Possibly related PRs

  • grimmerk/codev#102: Establishes the quick-launch IPC and terminal command path extended here with accountLabel.
  • grimmerk/codev#122: Provides the multi-account configuration-directory model used by this account-specific launch flow.
  • grimmerk/codev#124: Introduces the Accounts-tab IPC and renderer plumbing extended here for rename and account-aware launching.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main multi-account account-picker, tab-completion, and rename changes.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/new-session-account-picker

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/claude-session-utility.ts (1)

11-15: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Named imports are not alphabetically ordered.

Per coding guidelines, imports should be organized alphabetically. The current order is getScannableAccounts, getProjectsDir, getAccountByLabel; it should be getAccountByLabel, 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

📥 Commits

Reviewing files that changed from the base of the PR and between 4945f01 and 67eb8e4.

📒 Files selected for processing (8)
  • CHANGELOG.md
  • docs/multi-account-support-design.md
  • package.json
  • src/claude-session-utility.ts
  • src/electron-api.d.ts
  • src/main.ts
  • src/preload.ts
  • src/switcher-ui.tsx

Comment thread src/claude-session-utility.ts Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 8 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread src/claude-session-utility.ts Outdated
Comment thread docs/multi-account-support-design.md
Comment thread src/switcher-ui.tsx Outdated
grimmerk and others added 2 commits July 10, 2026 02:32
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

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 1 file (changes from recent commits).

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread src/switcher-ui.tsx Outdated
grimmerk and others added 4 commits July 10, 2026 02:44
- 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
@grimmerk grimmerk changed the title feat(multi-account): new-session account picker via modifier (Batch 2c-lite) feat(multi-account): new-session account picker + claude tab completion (Batch 2c-lite) Jul 9, 2026
grimmerk and others added 7 commits July 10, 2026 02:58
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

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Comment thread src/claude-session-utility.ts
Comment thread docs/multi-account-support-design.md
Comment thread CHANGELOG.md Outdated
Comment thread src/popup.tsx
Comment thread src/cli/account-manager.ts
Comment thread src/cli/account-manager.ts Outdated
Comment thread README.md Outdated
Comment thread README.md
Comment thread README.md Outdated
Comment thread src/cli/codev-account.ts
- 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
grimmerk and others added 2 commits July 10, 2026 14:13
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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 win

Restore 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's data-settings-panel attribute causes the document click handler (Line 597) to skip forceFocusOnInput(), and Escape's e.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 win

Use async/await in refreshMultiAccountHint per coding guidelines.

The function uses .then().catch() for an async operation, while openAccountPickerForLaunch in the same file uses async/await. As per coding guidelines, async/await should be used for asynchronous operations in src/**/*.{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 win

Add tests for renameAccount and the duplicate-directory guard.

Both are new mutation paths with no test coverage in the changed ranges. renameAccount modifies the registry and regenerates shell integration; the duplicate-dir guard in addAccount (lines 436-445) prevents session attribution corruption. The existing reg() 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

📥 Commits

Reviewing files that changed from the base of the PR and between 67eb8e4 and 6143f2d.

📒 Files selected for processing (9)
  • CHANGELOG.md
  • README.md
  • docs/multi-account-support-design.md
  • src/claude-session-utility.ts
  • src/cli/account-manager.test.ts
  • src/cli/account-manager.ts
  • src/cli/codev-account.ts
  • src/popup.tsx
  • src/switcher-ui.tsx
✅ Files skipped from review due to trivial changes (2)
  • CHANGELOG.md
  • docs/multi-account-support-design.md

grimmerk and others added 2 commits July 10, 2026 14:17
…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

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Comment thread src/popup.tsx Outdated
- 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
@grimmerk grimmerk changed the title feat(multi-account): new-session account picker + claude tab completion (Batch 2c-lite) feat(multi-account): account picker, claude tab completion, naming & rename (Batch 2c-lite) Jul 10, 2026

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Comment thread src/cli/codev-account.ts Outdated
Comment thread src/popup.tsx
Comment thread docs/multi-account-support-design.md Outdated
Comment thread docs/multi-account-support-design.md
- 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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 win

Fix Prettier formatting errors before merge.

Static analysis reports numerous prettier/prettier indentation errors across lines 832–1013. The PR description mentions tsc --noEmit and yarn test passing, but these formatting errors would likely fail a lint CI step. Run yarn 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 win

Avoid duplicating backend fallback logic in the frontend.

effectiveAnchor on lines 181–183 reimplements the backend's anchor-name fallback ('main', or 'primary' when the new account is named main) 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-add IPC response include the resolved anchor name (the account object 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 win

Fix prettier formatting on addAccount signature.

ESLint flags this as a prettier/prettier error: 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 win

Fix prettier formatting flagged by ESLint.

ESLint reports a prettier/prettier error at line 12. Run prettier --write src/preload.ts to 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

📥 Commits

Reviewing files that changed from the base of the PR and between 6143f2d and e3ce81b.

📒 Files selected for processing (10)
  • CHANGELOG.md
  • README.md
  • docs/multi-account-support-design.md
  • src/claude-session-utility.ts
  • src/cli/account-manager.ts
  • src/cli/codev-account.ts
  • src/electron-api.d.ts
  • src/main.ts
  • src/popup.tsx
  • src/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

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Comment thread docs/multi-account-support-design.md Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant