diff --git a/CHANGELOG.md b/CHANGELOG.md index 169a805..def9767 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 1.0.80 + +- Feat: multi-account Batch 2c-lite — pick the account when launching a new session + - `⌥⌘+Enter` on a project opens a small account picker (↑↓ / Enter / Esc, or click) — external terminals (iTerm2/Terminal.app/Ghostty/cmux); a non-default pick launches via explicit `CLAUDE_CONFIG_DIR` + `command claude`, a default-account pick via `env -u CLAUDE_CONFIG_DIR claude` + - Plain `⌘+Enter` unchanged: opens instantly under the global default; single-account (or registry-less) setups never see the picker + - Search-bar hint shows `⌥⌘+Enter: pick account` only for multi-account setups, and updates live after account changes (no app restart) + - Tab completion for `claude `: `claude ` completes account names (polite: skipped if another completion owns `claude`; other positions keep file completion) + - Removed the stray `|` (react-select's default separator) before the search-bar hint + - Accounts UI: per-row **Rename**; the first-ever add asks what to name your existing `~/.claude` login (defaults to `main`) instead of assuming `personal`; `default` is now a reserved account name + - `codev account rename ` (CLI) — labels are renameable; folders never move (credentials are keyed by the folder path) + - README gains a Multi-Account section (shell commands, `codev account` CLI, UI map) + - Roadmap: 2d (folder→account auto-switch) dropped — one folder legitimately hosts sessions from multiple accounts; cross-account *resume* stays deferred to Batch 3 (copy-fork design) + ## 1.0.79 - Feat: multi-account Batch 2b (part 2) — `codev` command in your shell diff --git a/README.md b/README.md index e5fc6d1..746a9a2 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,73 @@ For the full same-cwd accuracy matrix (detection + switch by launch method and t | cmux | Title match → TTY fallback | CLI new-workspace | Same as iTerm2 (requires cmux v0.63+); requires socket access in cmux Settings (`automation` or `allowAll`) | | VS Code | URI handler (session-level) | `open -b` + URI handler | Requires Claude Code VS Code extension v2.1.72+; `[VSCODE]` badge on active sessions; adaptive resume via IDE lock file polling (~0.5s if project already open) | +### Multi-Account Support (Claude Code) + +Run multiple Claude Code accounts (e.g. personal + work) on one machine. Each account gets its own config dir (via `CLAUDE_CONFIG_DIR`); the default account stays at `~/.claude` untouched. The Sessions tab aggregates sessions from every account (non-default ones get a purple account badge), and each session always resumes under the account it belongs to. + +**Setup** — Settings → Accounts: + +1. **Add** an account (e.g. `work`) — writes the registry (`~/.config/codev/accounts.json`) and generates `~/.config/codev/accounts.sh` +2. **Install** Shell integration — appends one marker-guarded `source` line to `~/.zshrc` (zsh; the generated file is bash-sourceable manually, fish unsupported) +3. Open a new shell and log in: `claude work` + +**Shell commands** (from the generated `accounts.sh`): + +| Command | What it does | +|---------|--------------| +| `claude` | Launches the **global default** account (configurable, see below) | +| `claude […]` | Launches that account, full passthrough (e.g. `claude work -r`) | +| `claude- […]` | Function form of the same (e.g. `claude-work mcp list`) | +| `claude-whoami` | Which account bare `claude` resolves to here, plus its auth status | +| `claude-accounts` | Quick list of configured accounts | + +Tab completion included (zsh): `claude ` completes account names; `codev account ` completes subcommands and labels. (The `claude` completion is registered only when nothing else completes `claude` — if you already have one, account names won't be injected into it.) + +The **default account** can be launched three equivalent ways: bare `claude`, `claude `, or `claude-` (the UI's row shows this). + +**`codev account` CLI** (the account manager — same generator the Settings UI uses): + +| Command | What it does | +|---------|--------------| +| `codev account list` (`ls`) | Accounts + identity; `*` marks the bare-`claude` default | +| `codev account add [--dir D]` | Register an account (default dir `~/.claude-`) | +| `codev account default ` | Point bare `claude` at an account | +| `codev account remove ` (`rm`) | Unregister; keeps its folder on disk | +| `codev account rename ` | Rename a label — the folder is not moved; also the way to rename the auto-seeded default account (`personal`) | +| `codev account regenerate` (`regen`) | Rewrite `accounts.sh` from the registry | +| `codev account show` (`preview`) | Dry-run print of the generated `accounts.sh` | +| `codev account install` / `uninstall` | Add / remove the `~/.zshrc` source block | + +> **Add is just a mapping.** `add ` registers *name → config folder* (default `~/.claude-` — that folder **is** the account's `CLAUDE_CONFIG_DIR`). Claude Code itself creates and fills the folder on first login (`claude `). One folder = one account: registering an already-registered folder under a second name is rejected. +> +> **Name vs folder.** The name is a mutable label; the folder is fixed at creation. They can diverge (after a rename) and the UI shows `· folder: …` on the row when they do. Folders deliberately never move on rename: Claude Code keys the account's credentials by the config-dir **path**, so moving the folder would orphan the login. +> +> **Remove is non-destructive.** It only unregisters that mapping: the account's folder, login, and session history all stay on disk. `codev account add ` (or the UI) later reattaches everything — identity and sessions reappear immediately, no re-login needed. **Caveat after a rename:** the folder keeps its *original* suffix (rename never moves folders), so re-attach with the folder-matching name — e.g. an account created as `work`, renamed to `ff`, then removed, re-attaches via `add work` (or any name with `--dir ~/.claude-work`), **not** `add ff`. Likewise, an account originally registered with a custom `--dir` always needs `--dir ` again on re-add. + +**Common scenarios:** + +| You are… | What happens / what to do | +|----------|---------------------------| +| An existing Claude Code user opening CodeV for the first time | Accounts tab is **empty** (zero footprint — no registry is created until you act); your `~/.claude` login keeps working as before. When you add a second account, **you name your existing login at the same time** (a field appears; empty = `main`) and both get registered together. | +| Renaming any account later | The **Rename** button on each row, or `codev account rename `. To pre-name your existing default before adding anything: `codev account add --dir ~/.claude` (registers the default itself; no extra account created). `default` is a reserved name. | +| Starting fresh: add first, log in later | Add a name (UI or CLI) → it shows "not logged in" → in a new shell, `claude ` runs Claude Code's login and creates the folder. | +| Already running a second account by hand (own shell function + custom folder) | Register it with `codev account add --dir ` — **any folder works**; `~/.claude-` is only the default. Identity and sessions attach immediately, no re-login. If your hand-rolled wrapper was named `claude`, retire it (it would fight the generated dispatcher). | +| Wondering why a name maps to a different folder | Renames change only the name side of the *name → folder* mapping; folders never move (credentials are keyed by the folder path) — the UI shows `· folder: …` on the row when they diverge. | + +> Not yet supported: auto-detecting existing config folders for one-click registration, and a warning when `accounts.sh` overrides a hand-rolled `claude()` shell function ([#127](https://github.com/grimmerk/codev/issues/127)); continuing an existing conversation under a *different* account — "copy-fork" — needs transcript-level workarounds first ([#128](https://github.com/grimmerk/codev/issues/128)). + +The `codev` command runs the CLI **bundled inside CodeV.app** (`ELECTRON_RUN_AS_NODE`) — no system Node, no sudo, no PATH edits. CodeV refreshes `accounts.sh` on every launch, so moving or renaming the app self-heals. (Not available in MAS builds — sandboxed.) + +**In the CodeV UI:** + +| Where | What | +|-------|------| +| Settings → Accounts | List/add/remove accounts, set the global default, install shell integration | +| Sessions tab | Sessions from all accounts with account badges; resume uses each session's own account | +| Projects tab: `⌥⌘+Enter` | Pick the account for a new session (`⌘+Enter` stays instant, under the global default). Account override applies to external terminals (iTerm2, Terminal.app, Ghostty, cmux); VS Code ([#121](https://github.com/grimmerk/codev/issues/121)) and the embedded Term tab ignore it | + +**Gotcha:** inside a Claude Code session, `!claude auth status` reports the *global default* (the shell snapshot carries the dispatcher function), not the session's account — use `!command claude auth status` instead. Full design + details: [docs/multi-account-support-design.md](docs/multi-account-support-design.md). + ### Embedded Terminal CodeV includes a built-in terminal tab (powered by xterm.js + node-pty, same technology as VS Code's integrated terminal). Press `⌃+⌘+T` from anywhere (global shortcut) or `⌘+3` when CodeV is in foreground to open it. diff --git a/docs/multi-account-support-design.md b/docs/multi-account-support-design.md index a92f38f..36ab149 100644 --- a/docs/multi-account-support-design.md +++ b/docs/multi-account-support-design.md @@ -453,18 +453,41 @@ and **(d)** for CodeV, backed by the same `projectMap` in the registry so both a registry + `accounts.sh` from one shared generator (§6.A/B); Vitest + CI added. - *2b (UI ✅, branch `feat/accounts-settings-ui`):* Accounts tab in Settings — list/add/remove + set-default + shell-integration toggle (§6.D), as IPC wrappers - over the shared manager (one generator with the CLI). Rename deferred (labels name - dirs; remove+add covers it). + over the shared manager (one generator with the CLI). (Rename was deferred here, + then shipped in 2c-lite below — CLI + per-row UI.) - *2b part 2 (✅, branch `feat/codev-path-binary`):* the `codev` command — a `codev()` function in accounts.sh runs the CLI bundled inside CodeV.app via `ELECTRON_RUN_AS_NODE` (no system Node; no sudo/PATH edits). The app records its real `.app` location in the registry (`appPath`) on every launch and refreshes accounts.sh, so app moves and generator updates self-heal. CLI is tsc-compiled into `resources/cli` (extraResource) at build time. - - *2c:* account picker / per-launch override (§6.G, 4.2). - - *2d:* pyenv-style folder auto-switch + terminal-side resume-to-right-account (§6.H). - - *2e:* configurable global-default (bare `claude` → chosen account) — last, since it - also needs the CLI/UI to manage. + - *2c-lite (✅, branch `feat/new-session-account-picker`):* NEW-session account + picker — ⌥⌘+Enter on a project opens a picker (⌘+Enter unchanged → global + default; single-account setups never see it); launches with explicit + `CLAUDE_CONFIG_DIR` + `command claude` (an anchor-account pick uses + `env -u CLAUDE_CONFIG_DIR claude` instead — §3.4). Post-review naming UX: per-row UI Rename + + `codev account rename` (label-only — folders never move; credentials are keyed by + the config-dir path); the first-ever add asks what to name the existing ~/.claude + login (defaults to `main` — or `primary` when the new account itself is named + `main` — replacing the presumptuous auto-`personal`); `default` is + a reserved label (it names the dispatcher-target concept). Cross-account *resume* + (the other half of §6.G) stays deferred to Batch 3 as explicit copy-fork — a transcript lives in + its own account's projects dir, so "resume under another account" must copy, never + link. "This repo always opens under X" belongs to 2d's projectMap. + - *2d — ❌ dropped (2026-07-10):* pyenv-style folder auto-switch (§6.H). Rationale: + in practice one folder hosts sessions from MULTIPLE accounts (we test exactly this + way), so a folder→account default would guess wrong precisely where the account + choice matters; stacking a third decision layer (global default → folder default → + picker) adds "why did bare claude open work here?" confusion for thin value. The + need is covered by 2e (global default) + 2c-lite (explicit per-launch picker). + Technically it was feasible (a default, not a constraint — resume always follows + the session's own account); dropped on value, not feasibility. + - *2e — ✅ shipped with 2a (PR #123, v1.0.77):* configurable global-default — + `codev account default