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

Merged
GR
4mo ago
+268-4

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 extraResource → CodeV.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.

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.