Skip to content

feat(multi-account): codev command via bundled CLI (Batch 2b part 2)#125

Merged
grimmerk merged 10 commits into
mainfrom
feat/codev-path-binary
Jul 9, 2026
Merged

feat(multi-account): codev command via bundled CLI (Batch 2b part 2)#125
grimmerk merged 10 commits into
mainfrom
feat/codev-path-binary

Conversation

@grimmerk

@grimmerk grimmerk commented Jul 9, 2026

Copy link
Copy Markdown
Owner

Summary

Batch 2b part 2 (follows #124): the codev command — run codev account <cmd> from any zsh shell, no repo checkout / no system Node / no sudo required.

Also carries the §6.C supported-shells docs note (written during #124, moved here per review-batching).

How it works

  1. Bundled CLI: forge's generateAssets hook tsc-compiles src/cli/*.ts (plain fs/os/path — no bundling needed) into resources/cli/, shipped inside the app via extraResourceCodeV.app/Contents/Resources/cli/.

  2. codev() launcher in accounts.sh: the generator emits

    codev() {
      ELECTRON_RUN_AS_NODE=1 "<app>/Contents/MacOS/CodeV" "<app>/Contents/Resources/cli/codev-account.js" "$@"
    }
    

    ELECTRON_RUN_AS_NODE makes the app binary act as plain Node (the VS Code code trick) — so the CLI runs on the app's own runtime. It rides the existing shell-integration install: zero sudo, zero PATH edits.

  3. No hardcoded /Applications (review point from planning): the app records its real .app bundle root in the registry (appPath) on every launch and regenerates accounts.sh. Moving the app self-heals on next CodeV launch; generator-template updates (like the earlier claude-whoami fix) now propagate automatically too. No-op for single-account users (no registry → no writes).

  4. The CLI accepts the account prefix, so codev account list (installed form) and yarn account list (dev form) both work.

Verification

  • Simulated the exact packaged invocation locally: ELECTRON_RUN_AS_NODE=1 node_modules/electron/dist/.../Electron resources/cli/codev-account.js account list against the real registry → correct output.
  • tsc --noEmit 0 errors; yarn test 15/15 (+2: codev() emitted when appPath recorded, omitted otherwise).

How to test (needs yarn make)

  1. yarn make → launch the built app once (it records appPath into ~/.config/codev/accounts.json and refreshes accounts.sh — check the file gains the codev() function).
  2. Open a new shell (or source ~/.zshrc) → run codev account list → same output as yarn account list.
  3. codev account show, codev account help etc. all work anywhere (no repo cwd needed).
  4. Optional: move CodeV.app somewhere else → relaunch it → new shell → codev account list still works (self-heal).

Tab completion

accounts.sh also ships zsh completion for codev: codev <TAB>account, codev account <TAB> → subcommands, codev account default|remove <TAB> → account labels (baked in, refreshed on regenerate; remove offers only non-anchor labels). Registration is guarded (zsh + loaded compinit) so the file stays bash-sourceable — verified with both zsh -n and bash -n.

MAS builds (why the launcher is skipped there)

  • Mac App Store builds are sandboxed and ELECTRON_RUN_AS_NODE is unsupported in MAS Electron — the bundled CLI could never run from a MAS install (exec'ing the app binary from a terminal still enforces its embedded sandbox).
  • CodeV therefore skips recording appPath on MAS (!isMAS() gate), so accounts.sh never advertises a broken codev().
  • Context: the wider ~/.claude-reading feature set (Sessions tab etc.) has the same sandbox constraint — pre-existing, not introduced here; and no MAS build with the Claude-sessions feature set has shipped. Build-wise, yarn make and yarn make_mas both compile/bundle the CLI fine — the gate is runtime-only.

Notes

  • The codev function only exists in shells that source accounts.sh (consistent with the zsh-only support documented in this PR); a "real file on PATH" shim (/usr/local/bin, admin prompt) can be a later upgrade if scripts need it.
  • resources/cli is a build artifact (gitignored).

🤖 Generated with Claude Code


Summary by cubic

Adds a bundled codev command so you can run codev account <cmd> from any zsh shell without Node, sudo, or PATH edits. The app records its real install path, regenerates accounts.sh on launch and account changes, adds zsh tab completion, survives .app renames via appExec, and fully suppresses the launcher on MAS builds.

  • Bug Fixes
    • MAS: clear stale appPath/appExec and regenerate accounts.sh unconditionally so codev() is never advertised on MAS.
    • Accounts tab: show the empty-state only after a successful load; no flashing or mixed error states.
    • Completion: add the rm alias to subcommand suggestions.

Written for commit 4266022. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features

    • Added support for launching the app’s account CLI directly from the app without requiring a separate Node installation.
    • Improved the Accounts view with clearer guidance, a new header explaining per-account config storage, and a message when no accounts are set up.
  • Bug Fixes

    • Account setup and management now keep shell integration in sync after adding, removing, or changing the default account.
    • Launcher paths now stay accurate even if the app is moved or renamed.

grimmerk and others added 2 commits July 10, 2026 00:48
zsh only for the rc install (accounts.sh itself is bash-compatible,
fish unsupported); account-aware resume covers all CodeV terminals;
VS Code sessions can't switch accounts (#121).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017kCK4t5JSVynVZxGcrTGGp
`codev account <cmd>` now works in the terminal without a repo checkout:

- accounts.sh gains a codev() launcher that runs the CLI bundled inside
  CodeV.app with ELECTRON_RUN_AS_NODE (app binary doubles as Node — no
  system Node, no sudo, no PATH edits; rides the existing shell
  integration)
- the app records its real .app bundle root in the registry (appPath)
  on every launch and regenerates accounts.sh, so moving the app
  self-heals the path and generator updates propagate automatically
  (no-op for single-account users — no registry, no writes)
- forge generateAssets tsc-compiles src/cli/*.ts into resources/cli
  (new extraResource); the CLI accepts the `account` prefix so both
  `codev account list` and dev `yarn account list` work

Verified locally: simulated the packaged invocation via the dev
Electron binary (ELECTRON_RUN_AS_NODE=1 Electron resources/cli/
codev-account.js account list) against the real registry. tsc 0;
15/15 tests (+2 for codev() emission).

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 update introduces a bundled codev CLI compiled at build time into resources/cli, packaged with the Electron app. It records the app's real bundle path in the accounts registry, generates a codev() shell function using that path, and syncs this across IPC handlers, startup, popup UI, docs, and changelog.

Changes

Bundled CLI and app-path self-healing

Layer / File(s) Summary
Build-time CLI compilation and packaging
forge.config.ts, .gitignore
Forge asset generation compiles account-manager.ts/codev-account.ts via tsc into resources/cli, adds it to packagerConfig.extraResource, and ignores the generated output in Git.
Registry app-path fields and codev() launcher
src/cli/account-manager.ts, src/cli/codev-account.ts, src/cli/account-manager.test.ts
Registry gains appPath/appExec; generateAccountsSh conditionally emits a codev() function invoking the bundled CLI via ELECTRON_RUN_AS_NODE; new setAppPath persists these fields; CLI argv parsing accepts the installed account invocation form; tests cover launcher emission and appExec usage.
Main-process app-path sync
src/main.ts
New syncAccountsAppPath() records the app's bundle path and regenerates accounts.sh, called after add/remove/set-default account actions, before shell-hook install, and at app startup.
Popup UI, docs and changelog
src/popup.tsx, docs/multi-account-support-design.md, CHANGELOG.md, package.json
Popup shows shell-install-aware guidance and an empty-accounts state; design doc documents supported shells and the codev() self-healing mechanism; changelog and version bumped to 1.0.79.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

  • grimmerk/codev#123: Modifies the same generateAccountsSh/Registry shell-integration logic and codev-account.ts CLI routing extended by this PR.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.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 summarizes the main change: adding a bundled codev command for multi-account support.
✨ 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/codev-path-binary

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.

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

1 issue found across 9 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="forge.config.ts">

<violation number="1" location="forge.config.ts:29">
P3: Stale `.js` files accumulate in `resources/cli` across builds — tsc with `--outDir` and explicit source files never removes old output. If a source file is renamed, both `old-name.js` and `new-name.js` ship in the app bundle because the old `.js` is never cleaned up.</violation>
</file>

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

Re-trigger cubic

Comment thread src/cli/account-manager.ts Outdated
Comment thread src/main.ts Outdated
Comment thread src/main.ts Outdated
Comment thread forge.config.ts
grimmerk and others added 3 commits July 10, 2026 01:11
- registry records appExec (the real binary path) alongside appPath;
  the codev() launcher prefers it — the executable inside
  Contents/MacOS keeps its name when the .app bundle is renamed, so
  deriving it from the bundle name broke on rename (user-spotted)
- Accounts tab gains a header clarifying these are Claude Code
  (Anthropic) accounts, not CodeV accounts
+1 test (16 total)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017kCK4t5JSVynVZxGcrTGGp
- syncAccountsAppPath helper runs at launch AND after add/remove/
  set-default/install — covers the fresh-install case where the
  registry is first created mid-run, so the very first accounts.sh
  already contains the codev() launcher (was: only after next launch)
- add-notice tells fresh users to install Shell integration first
  when the ~/.zshrc block isn't present yet
- empty Accounts list shows an explainer instead of a blank area

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017kCK4t5JSVynVZxGcrTGGp
tsc never removes stale output, so a renamed source file would ship
both old and new .js in the app bundle (cubic P3).

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.

Actionable comments posted: 1

🤖 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/popup.tsx`:
- Around line 768-776: The new Accounts tab JSX block in popup.tsx needs to be
reformatted to satisfy Prettier. Reflow the descriptive text inside the Accounts
section and the conditional {accounts.length === 0 && (...)} block so the JSX
matches the project’s formatting conventions, keeping the structure around the
Accounts tab content intact.
🪄 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: c463ec38-d87d-49f7-ad0f-18f743e2c494

📥 Commits

Reviewing files that changed from the base of the PR and between 80fa52d and b4c82bd.

📒 Files selected for processing (10)
  • .gitignore
  • CHANGELOG.md
  • docs/multi-account-support-design.md
  • forge.config.ts
  • package.json
  • src/cli/account-manager.test.ts
  • src/cli/account-manager.ts
  • src/cli/codev-account.ts
  • src/main.ts
  • src/popup.tsx

Comment thread src/popup.tsx Outdated
grimmerk and others added 3 commits July 10, 2026 01:26
MAS builds are sandboxed and ELECTRON_RUN_AS_NODE is unsupported there,
so a codev() launcher pointing at a MAS install could never run — skip
recording appPath on MAS (same gating family as auto-update).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017kCK4t5JSVynVZxGcrTGGp
- accounts.sh gains _codev completion: subcommands + account labels
  (baked in, refreshed on regenerate; remove offers only non-anchor
  labels). Registration guarded for zsh+compinit so the file stays
  bash-sourceable — verified with zsh -n AND bash -n
- docs: MAS builds can't run the bundled CLI (sandbox +
  ELECTRON_RUN_AS_NODE unsupported) — appPath skipped there

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017kCK4t5JSVynVZxGcrTGGp
Reflow the header + empty-state blocks per the review's ESLint output
(changed lines only — the file as a whole predates the prettier rule).

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 7 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
Comment thread src/main.ts
Comment thread src/cli/account-manager.ts Outdated
- empty-state renders only after a successful load and never alongside
  an error (accountsLoaded flag) — no flash while the IPC is in flight
- MAS: clear stale appPath/appExec left by a previous direct-download
  install and regenerate, fully suppressing the codev() launcher
- completion: add the rm alias to the subcommand compadd list

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 4 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread src/main.ts
clearAppPath()-gated regeneration could leave a stale accounts.sh
forever (registry already clean but a prior regenerate failed). Match
the non-MAS branch: always regenerate when a registry exists.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017kCK4t5JSVynVZxGcrTGGp
@grimmerk grimmerk merged commit 4945f01 into main Jul 9, 2026
3 checks passed
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