claude-use 2.1.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +17 -6
  2. package/dist/cli.cjs +5939 -5789
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -241,9 +241,11 @@ Running two or more sessions concurrently under one identity — two terminals,
241
241
 
242
242
  ### Resolving a retained superseded farm
243
243
 
244
- Swapping in a resynced farm carries the identity's own real local data (credentials, `identity.json`, daemon/runtime state — anything that isn't a symlink or a directory the previous resync itself materialised) across from the superseded farm into the new one. When a top-level name exists in both, the swap never overwrites in either direction — it leaves the superseded farm on disk and reports it (`FARM_PREVIOUS_RETAINED`, or `FARM_SWAP_RECOVERED` when a crash-recovery pass on a later launch rediscovers it) rather than guessing which copy is more important. This can only happen when the underlying data genuinely differs in a way the tool has no way to judge safely on its own — the category system only tracks whether data is *shared across identities*, not whether it's *precious vs. disposable*.
244
+ Swapping in a resynced farm carries the identity's own real local data (credentials, `identity.json`, daemon/runtime state — anything that isn't a symlink or a directory the previous resync itself materialised) across from the superseded farm into the new one. When a top-level name exists in both, the swap does not guess which copy matters more — for most categories the tool has no way to judge that safely: `categories` only tracks whether data is *shared across identities*, not whether it's *precious vs. disposable*, and overwriting either copy could discard something real.
245
245
 
246
- `claude-use identity resolve <name>` walks every retained `.{name}.previous.*` directory for that identity and resolves each collision interactively: keep the current farm's copy, keep the superseded farm's copy, or skip it for now (leaving it exactly as-is for a later run to ask about again). A superseded directory is only removed once every one of its own conflicts has been decided; skipping even one leaves the whole directory retained.
246
+ One category is the exception. `runtime`'s own definition (see the [category table](#category-based-sharing) above) is specifically "live per-process or per-machine artifacts" — a daemon lock, an MCP auth-needed cache, an update-check result — that make no sense being fought over at all, let alone asked about. A colliding name whose category resolves to `runtime` is discarded from the superseded copy automatically, with nothing kept from the old side and nothing asked: `keep-new` is not a judgement call for this category, it is what the category already means. This needs only the name's static classification, never the resolved shared/not-shared decision for the current directory — a `runtime` entry is disposable whether or not this identity currently chooses to share it.
247
+
248
+ For everything else, the swap leaves the superseded farm on disk and reports it (`FARM_PREVIOUS_RETAINED`, or `FARM_SWAP_RECOVERED` when a crash-recovery pass on a later launch rediscovers it, naming what it auto-resolved and what it could not) rather than guessing. `claude-use identity resolve <name>` walks every retained `.{name}.previous.*` directory for that identity, auto-resolving any further `runtime` collisions it finds the same way, and asks about the rest interactively: keep the current farm's copy, keep the superseded farm's copy, or skip it for now (leaving it exactly as-is for a later run to ask about again). A superseded directory is only removed once every one of its own conflicts has been decided; skipping even one leaves the whole directory retained.
247
249
 
248
250
  ## Portable config: `.claude-use.json`
249
251
 
@@ -363,6 +365,14 @@ In both modes, *where* a toggle is written depends on `$PWD` at invocation time,
363
365
 
364
366
  `claude-use check` (below) shows you which of the three would apply before you commit to a change, if you're unsure.
365
367
 
368
+ #### Which `claude-use` a bare command name resolves to
369
+
370
+ `doctor`'s PATH-resolution check answers a question no other check does: is the `claude-use` your shell runs the same executable as the one producing this report? It scans PATH for the filename a bare `claude-use` would resolve to, using the same `findPathShadow` scan `shim enable` already uses for `claude`, and compares the first hit against the running executable's own PATH-visible location — collapsing the verdict back to a pass when both names turn out to be the same real file reached through a symlink.
371
+
372
+ An earlier PATH entry winning is a **failure**, not a warning, because it invalidates the rest of the report rather than sitting alongside it: every other finding describes the binary that produced it, which in that state is not the binary your commands reach. The failure mode it exists to catch is entirely silent otherwise — a wrapper script or an abandoned install directory from an earlier channel keeps working at whatever version it was frozen at, so nothing looks broken until a config file written by the newer version trips the older one's own validation. That is not hypothetical: a hand-written wrapper from an earlier install channel, sitting ahead of `~/.local/bin` on PATH, kept re-execing a month-old binary whose copy of `IdentitySchema` predated the naming rule widening to allow `@` — so an `identity.json` a current claude-use had written was rejected outright, with nothing anywhere reporting that the running binary was not the installed one.
373
+
374
+ The two softer verdicts are warnings rather than failures. The running executable's own directory not being on PATH at all is legitimate (an absolute-path invocation, or `npx`), and an enabled `claude` shim being shadowed still leaves the launcher reachable as `claude-use run`.
375
+
366
376
  ### Debugging: `claude-use check`
367
377
 
368
378
  `claude-use check [path] [--identity <name>]` resolves the full cascade for the given path (default `$PWD`) and identity (default the active one), and prints the result — every entry's resolved state, which layer decided it, and which condition (if any) was evaluated and how — without touching the farm or spawning `claude` at all. This is the primary way to answer "why is X shared/hidden here" without launching a session to find out. For any `history/projects/` glob override in scope, it also flags whenever the pattern's encoded form could plausibly match more than one real path (see [Pattern matching](#pattern-matching-against-claudeprojects)), rather than resolving that ambiguity silently.
@@ -375,7 +385,7 @@ It also runs three checks that don't depend on `path` at all, every time, so a r
375
385
 
376
386
  ### Debugging: `claude-use doctor`
377
387
 
378
- Where `claude-use check` resolves one directory+identity's cascade in detail, `claude-use doctor` audits the whole `~/.claude-use` config graph at once — identity/directory-agnostic, no arguments needed. It validates every identity's `identity.json`, every configuration profile's own `extends` chain (catching a missing profile name or a circular `extends` before a launch would), `directory-rules.json`, `config.json`, `categories.local.json`, and `active-identity`, each against its own Zod schema and cross-referenced against each other (an identity's `defaultConfigProfile`, a directory rule's `identity`/`configProfile`, actually pointing at something real) — plus whether a real Claude Code binary is discoverable at all, whether the `claude` command shim is enabled and its recorded location still exists, and the same ambient-credential check `check` runs. One malformed file is reported as its own failure rather than aborting the rest of the audit, and the command exits non-zero if anything failed — useful as a scriptable "is everything still consistent" gate, not just an interactive debugging aid.
388
+ Where `claude-use check` resolves one directory+identity's cascade in detail, `claude-use doctor` audits the whole `~/.claude-use` config graph at once — identity/directory-agnostic, no arguments needed. It validates every identity's `identity.json`, every configuration profile's own `extends` chain (catching a missing profile name or a circular `extends` before a launch would), `directory-rules.json`, `config.json`, `categories.local.json`, and `active-identity`, each against its own Zod schema and cross-referenced against each other (an identity's `defaultConfigProfile`, a directory rule's `identity`/`configProfile`, actually pointing at something real) — plus whether a real Claude Code binary is discoverable at all, whether the `claude` command shim is enabled and its recorded location still exists, **which `claude-use` a bare command name actually resolves to** (below), and the same ambient-credential check `check` runs. One malformed file is reported as its own failure rather than aborting the rest of the audit, and the command exits non-zero if anything failed — useful as a scriptable "is everything still consistent" gate, not just an interactive debugging aid.
379
389
 
380
390
  ## Examples
381
391
 
@@ -490,7 +500,7 @@ src/
490
500
  directoryRules.ts # `claude-use rules` subcommands
491
501
  configure.ts # `claude-use configure` interactive picker (@clack/prompts)
492
502
  check.ts # `claude-use check` dry-run inspector — cascade resolution, ambient-credential/Keychain/settings-secrets diagnostics — no farm writes, no spawn
493
- doctor.ts # `claude-use doctor` whole-tree audit — every identity/profile/extends-chain/directory-rules/config.json/categories.local.json/active-identity, aggregating rather than throwing on a broken file
503
+ doctor.ts # `claude-use doctor` whole-tree audit — every identity/profile/extends-chain/directory-rules/config.json/categories.local.json/active-identity, plus which `claude-use` PATH actually resolves to, aggregating rather than throwing on a broken file
494
504
  claudeShim.ts # `claude-use shim enable`/`disable` — the one explicit action that creates/removes a `claude`-named hardlink of the running executable; records claude-shim.json
495
505
  cli/
496
506
  parsers.ts # shared CLI-flag parsing helpers (splitTopLevelCommas, parsePair, repeatable-flag collectors)
@@ -616,12 +626,13 @@ the resolver's cascade and materialisation logic is exactly the kind of thing th
616
626
  - The exact two-phase merge algorithm: a shallow layer's specific entry surviving a later, deeper layer's blanket category flip on the same category; an exact literal key beating a glob from an earlier layer; two globs from different layers resolving to the later layer's value; two globs from the *same* layer resolving by longest-literal-prefix and then source order; two layers setting the identical category resolving to plain last-layer-wins
617
627
  - Conditional entries with injectable/fake mtimes, a fake resolved branch, and a fake env snapshot (never real filesystem/git/environment state, so tests aren't time-dependent, git-dependent, or slow) — a `newerThan` condition including a fresh file and excluding a stale one under the same glob, a `branch` condition applying only on a matching branch, an `env` condition applying only when the right variable is set, and a conditionally-matched subtree always being materialised rather than symlinked
618
628
  - A materialised directory reconciling any real (non-symlink) children written since the last resync back into `~/.claude` before re-deciding, and collapsing back into a plain symlink once its split condition no longer holds
629
+ - A `runtime`-category collision between a superseded farm and the current one resolving automatically (`carryOver`'s own `classification` parameter, covered directly, and end-to-end through both `resyncFarm`'s crash-recovery path and `resolveFarmConflicts`'s interactive one) — the decision never calling the caller's `decide`/prompt at all, a genuinely ambiguous collision alongside it in the same superseded farm still reaching that prompt, and the whole auto-resolution falling back to the old fully-manual behaviour when no `classification` is given
619
630
 
620
- `identityManager.ts`, `configProfiles.ts`, `directoryRules.ts`, and `configure.ts` stay thin adapters over the resolver, so most of their correctness rides on the resolver's own test coverage above. `launcher.ts` carries three separately-testable responsibilities of its own that aren't covered by the resolver's purity, and need their own coverage: translating a resolved `Map<path, boolean>` into real filesystem side effects (creating/removing symlinks, materialising/collapsing directories, diffing against the farm's prior state, the per-identity lock and atomic-swap behaviour from [Directory rules](#directory-rules)) against a fake/in-memory filesystem; invoking the real `claude` binary via an injected `spawn` function (argv/env construction, exit-code propagation), never a real subprocess in a unit test; and the ambient-credential guard — given a fake `process.env`, refusing to proceed when any of the six named variables is set and the active identity's `allowAmbientCredential` is unset/false, proceeding when it's true, and proceeding when `CLAUDE_USE_ALLOW_AMBIENT_CREDENTIAL=1` is set for that one call regardless of the identity's own setting.
631
+ `identityManager.ts`, `configProfiles.ts`, `directoryRules.ts`, and `configure.ts` stay thin adapters over the resolver, so most of their correctness rides on the resolver's own test coverage above. The one exception is `listIdentities`, whose own tests cover a deliberate departure from the "throw a validation error and let it propagate" convention: an `identity.json` that is present but unreadable — malformed JSON, or valid JSON this version's `IdentitySchema` rejects — is reported as that one identity's own unreadable entry, so a single bad file never hides every *other* identity from `claude-use identity list` at the moment they most need to be visible. Only those two content-shaped failures are absorbed; a permission error still propagates. A wholly *absent* `identity.json` remains a silent skip rather than a problem, and both it and `doctor`'s own enumeration filter out directories whose name starts with `.`, since `IdentitySchema` requires an identity name to start with a letter or digit and a resync's own `.<identity>.scratch.<suffix>`/`.<identity>.previous.<suffix>` directories are therefore never identities to report on. `launcher.ts` carries three separately-testable responsibilities of its own that aren't covered by the resolver's purity, and need their own coverage: translating a resolved `Map<path, boolean>` into real filesystem side effects (creating/removing symlinks, materialising/collapsing directories, diffing against the farm's prior state, the per-identity lock and atomic-swap behaviour from [Directory rules](#directory-rules)) against a fake/in-memory filesystem; invoking the real `claude` binary via an injected `spawn` function (argv/env construction, exit-code propagation), never a real subprocess in a unit test; and the ambient-credential guard — given a fake `process.env`, refusing to proceed when any of the six named variables is set and the active identity's `allowAmbientCredential` is unset/false, proceeding when it's true, and proceeding when `CLAUDE_USE_ALLOW_AMBIENT_CREDENTIAL=1` is set for that one call regardless of the identity's own setting.
621
632
 
622
633
  `check.ts`'s three always-on diagnostics get their own tests too, independent of path/cascade resolution: the ambient-credential check against a fake `process.env` (same fixture as `launcher.ts`'s guard, since they share the same detection logic); the settings-secrets advisory against a fake settings.json with populated `env`/`hooks` fields, confirming it reports counts and key names only, never values; and — since Keychain access is real OS state, not something to fake — a manual/integration-only note that the Keychain-name lookup is exercised against a real `security` call in CI on macOS runners, not unit-tested with a mock.
623
634
 
624
- `doctor.ts` deliberately breaks the "throw a validation error and let it propagate" convention every other command file follows, since aggregating every check into one report — rather than aborting on the first broken file — is the whole point of the command. Its own tests cover this directly: every input (identities, configuration profiles, `directory-rules.json`, `config.json`, `categories.local.json`, `active-identity`) fed simultaneously malformed at once, asserting `runDoctor` still returns a full report with one `fail` finding per broken input rather than throwing, plus a genuine `extends` cycle correctly failing and a genuine diamond correctly not being mistaken for one. Its wiring layer sets `process.exitCode` rather than throwing or calling `process.exit()` when the report contains any failure — this is new to the codebase and not unit-tested, matching `registerCheckCommand`'s own I/O wiring being untested for the same reason.
635
+ `doctor.ts` deliberately breaks the "throw a validation error and let it propagate" convention every other command file follows, since aggregating every check into one report — rather than aborting on the first broken file — is the whole point of the command. Its own tests cover this directly: every input (identities, configuration profiles, `directory-rules.json`, `config.json`, `categories.local.json`, `active-identity`) fed simultaneously malformed at once, asserting `runDoctor` still returns a full report with one `fail` finding per broken input rather than throwing, plus a genuine `extends` cycle correctly failing and a genuine diamond correctly not being mistaken for one. The PATH-resolution section gets its own coverage for each of its three verdicts at each of the two names it reports on (a shadowed `claude-use` failing and naming both paths, a not-on-PATH executable warning instead, and an enabled-but-shadowed `claude` shim warning rather than failing), alongside `refinePathShadow`'s own unit tests for the symlink case a directory comparison alone would misreport as a shadow of itself. Its wiring layer sets `process.exitCode` rather than throwing or calling `process.exit()` when the report contains any failure — this is new to the codebase and not unit-tested, matching `registerCheckCommand`'s own I/O wiring being untested for the same reason.
625
636
 
626
637
  `claudeShim.test.ts` follows `identityManager.test.ts`'s real-temp-directory convention (a fake "own executable" file standing in for the running `claude-use` binary), rather than `doctor.ts`'s pure-function style, since `enableClaudeShim`/`disableClaudeShim` are themselves real filesystem operations, not something to keep separate from a thin wiring layer. Coverage includes the version-drift case that motivates persisting `claude-shim.json` at all (the source file overwritten in place between two `shim enable` runs, proving the marker — not the inode — is what lets the second run refresh cleanly instead of refusing), a foreign file at the target being refused without `--force` and accepted with it, and the cross-device (`EXDEV`) copy-fallback path via a small injectable `LinkFs` seam (mirroring `config/store.ts`'s own `StoreFs`/`nodeStoreFs` pattern), since a real cross-filesystem rig isn't practical in CI. One test also reproduces Homebrew's actual layout (a symlink into a separate "Cellar" directory) to confirm the shim lands next to the symlink users invoke, not buried in the directory its realpath resolves to.
627
638