claude-use 0.3.6 → 0.5.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.
package/README.md CHANGED
@@ -74,6 +74,7 @@ Select an identity with:
74
74
  - `claude @<name>` — equivalent, once `claude-use shim enable` has been run (see [Install](#install))
75
75
  - `CLAUDE_ACCOUNT=<name> claude` — equivalent, via environment variable (this is `claude-use`'s own variable, read by its launcher; Anthropic's own multi-account convention is a plain `CLAUDE_CONFIG_DIR=<path> claude`, which `claude-use` builds on top of rather than replaces) — also needs the shim enabled first
76
76
  - `claude-use identity use <name>` — persistently, until changed again
77
+ - `claude-use @<name>` — the same, terser: shorthand for `claude-use identity use <name>`, matching the `@name` convention the other forms above already use. Deliberately requires the `@` prefix and requires `@<name>` to be the *only* argument — identity names are user-chosen and unconstrained against `claude-use`'s own subcommand vocabulary (`identity`, `profile`, `rules`, `check`, `configure`, `doctor`, `shim`, `run`), so a bare `claude-use <name>` (no `@`) is deliberately left alone as an "unknown command" error rather than risking a future identity name colliding with a future subcommand name
77
78
 
78
79
  A directory rule (see below) can also pin a specific identity to a path, overriding whichever one is otherwise active — useful as a safety net so a particular client's directory always uses the right login regardless of habit.
79
80
 
@@ -126,6 +127,8 @@ Every top-level entry in `~/.claude` is classified into one of five categories,
126
127
 
127
128
  This is a safe-by-default posture: only `knowledge` and `settings` are shared out of the box. A configuration profile can open up `history` (or anything else) wholesale, or share individual items within a closed category.
128
129
 
130
+ **`all` is shorthand for every overridable category at once**, for a profile that wants "share everything except credentials" without hand-listing `runtime`, `history`, `knowledge`, and `settings` individually — `{ "categories": { "all": true } }` expands to exactly those four set to `true`. `secret` can never be included, by construction: `all` only ever expands over the four categories a configuration layer is allowed to toggle in the first place, the same restriction a hand-written `categories` object is already under. An explicit named category always wins over `all` in the same object regardless of which one is written first, so `{ "all": true, "runtime": false }` means "share everything except runtime" — the general `all` setting, narrowed by the specific override, matching how a more specific layer already beats a less specific one everywhere else in this cascade. The same shorthand works identically from `--category all=true`/`CLAUDE_USE_CATEGORY_OVERRIDE=all=true` and `claude-use profile set <name> --category all=true`, not just profile JSON files — one expansion, shared by all three input paths.
131
+
129
132
  `secret`'s "never, cannot be overridden" is an absolute check `resolve/decide.ts` makes *before* running the two-phase cascade at all — not merely the least-specific layer in that cascade, the way every other category is. This matters because [The cascade](#the-cascade-how-everything-composes)'s general rule is that a specific `entries` override always beats a category default; `secret` is the one deliberate exception, so an explicit `entries: { "secret/.credentials.json": true }` anywhere in any layer is rejected outright, the same as a bare `categories: { secret: true }` would be — path-specificity never gets a chance to apply to this one category.
130
133
 
131
134
  **`~/.claude.json` isn't in this table at all, because — unlike `backups/` above — it isn't sourced from `~/.claude` the way everything else here is.** It's a sibling *file* next to the `~/.claude` directory, not an entry inside it: the OAuth session, personal (user/local-scope) MCP server definitions, and per-project trust decisions (which directories you've approved Claude Code to run in, and what it's allowed to do there). It fully relocates to `$CLAUDE_CONFIG_DIR/.claude.json` when set, the same as everything else — confirmed both in Anthropic's own Agent SDK documentation and empirically in this project's own development. Because it's generated fresh by Claude Code itself the moment it first runs under a new `CLAUDE_CONFIG_DIR`, `claude-use` treats it the same way as `secret`: always identity-local, never part of the shared cascade, and — since it isn't even a descendant of `~/.claude` — never something the resolver's directory walk encounters at all, rather than something explicitly excluded by category. `~/.claude/backups/` holds rolling timestamped copies of it (capped at five, auto-rotating) for Claude Code's own config-migration safety; being a genuine descendant of `~/.claude`, it *is* something the resolver walks past, which is exactly why it's listed under `secret` in the table above rather than merely assumed safe.
@@ -275,7 +278,7 @@ claude-use identity set <name> --allow-ambient-credential # persistently, for
275
278
 
276
279
  | What you're setting | Global (persistent) | Temporary (this run only) | Directory-scoped (persistent) |
277
280
  |---|---|---|---|
278
- | **Identity** | `claude-use identity use <name>` (writes `~/.claude-use/active-identity`) | `claude-use run @<name>` / `claude @<name>` (needs `claude-use shim enable`) / `CLAUDE_ACCOUNT=<name> claude` (same) | `claude-use rules add <path> --identity <name>`; or `.claude-use.json`'s `"identity"` |
281
+ | **Identity** | `claude-use identity use <name>` / `claude-use @<name>` (writes `~/.claude-use/active-identity`) | `claude-use run @<name>` / `claude @<name>` (needs `claude-use shim enable`) / `CLAUDE_ACCOUNT=<name> claude` (same) | `claude-use rules add <path> --identity <name>`; or `.claude-use.json`'s `"identity"` |
279
282
  | **Configuration profile** | `claude-use profile set-default <name>`; or `claude-use identity set-default-profile <identity> <profile>` | `claude --config-profile <name>` / `CLAUDE_USE_CONFIG_PROFILE=<name> claude` | `claude-use rules add <path> --profile <name>`; or `.claude-use.json`'s `"configProfile"` |
280
283
  | **A category** | `claude-use profile set <name> --category history=true`; or `claude-use configure <identity>` | `claude --category history=true[,knowledge=false,...]` / `CLAUDE_USE_CATEGORY_OVERRIDE="history=true,knowledge=false"` | `claude-use configure <identity>` run from inside the ruled directory; or `.claude-use.json`'s `"categories"` |
281
284
  | **An individual entry** | `claude-use profile set <name> --entry "path"=true`; or `claude-use configure <identity> <path>` | `claude --share <path>[,<path>,...]` / `claude --hide <path>[,<path>,...]` / `CLAUDE_USE_ENTRY_OVERRIDE="path=true,otherpath=false"` | `claude-use configure <identity> <path>` run from inside the ruled directory; or `.claude-use.json`'s `"entries"` |
@@ -289,6 +292,7 @@ The scriptable `claude-use profile set ...` commands exist alongside the interac
289
292
  ```
290
293
  claude-use identity add <name>
291
294
  claude-use identity use <name>
295
+ claude-use @<name> # shorthand for `identity use <name>`
292
296
  claude-use identity list
293
297
  claude-use identity set-default-profile <identity> <profile>
294
298
  claude-use identity set <name> [--allow-ambient-credential | --no-allow-ambient-credential]
@@ -493,7 +497,7 @@ install.sh # downloads the latest release's binary for the runni
493
497
  # checksum, and installs it as both `claude` and `claude-use` in ~/.local/bin
494
498
  ```
495
499
 
496
- `schema.ts` models `categories` and `entries` differently despite their identical JSON-object appearance in every example above, because they have opposite key cardinality: `categories` only ever touches the four overridable names in the [category table](#category-based-sharing), so it's a closed `z.strictObject({ runtime: z.boolean().optional(), history: z.boolean().optional(), knowledge: z.boolean().optional(), settings: z.boolean().optional() })` — deliberately omitting `secret` from the shape entirely, so an attempted `secret` key is rejected at parse time rather than relying only on the runtime check described above — while `entries` is genuinely open-ended (any literal or glob path, each required to carry its `<category>/` prefix per the [Category-based sharing](#category-based-sharing) section above) and stays a `z.record(z.string().regex(ENTRY_KEY_RE), EntryValueSchema)`. The closed shape for `categories` also gives editors real key-name autocomplete from the published JSON Schema (the `schema/` directory above), which a record type can't offer.
500
+ `schema.ts` models `categories` and `entries` differently despite their identical JSON-object appearance in every example above, because they have opposite key cardinality: `categories` only ever touches the four overridable names in the [category table](#category-based-sharing) plus the `all` shorthand, so it's a closed `z.strictObject({ all: z.boolean().optional(), runtime: z.boolean().optional(), history: z.boolean().optional(), knowledge: z.boolean().optional(), settings: z.boolean().optional() })` piped through a `.transform()` that expands `all` into the four real categories and drops it from the result — deliberately omitting `secret` from the shape entirely, so an attempted `secret` key is rejected at parse time rather than relying only on the runtime check described above — while `entries` is genuinely open-ended (any literal or glob path, each required to carry its `<category>/` prefix per the [Category-based sharing](#category-based-sharing) section above) and stays a `z.record(z.string().regex(ENTRY_KEY_RE), EntryValueSchema)`. The closed shape for `categories` also gives editors real key-name autocomplete from the published JSON Schema (the `schema/` directory above) — generated with Zod's `io: "input"` option specifically because a schema with a `.transform()` can't be represented in JSON Schema at all under the default `"output"` mode, and `"input"` is what a hand-written config actually needs describing anyway, which a record type couldn't offer either way.
497
501
 
498
502
  `ConfigProfile.extends` is a flat `z.array(z.string()).optional()` — a list of other profiles' *names*, resolved by `resolve/extends.ts` loading each named file and walking the resulting graph at runtime. It's correctly **not** a self-referential Zod schema (no `z.lazy()` needed): nothing in `ConfigProfile`'s own shape points back at `ConfigProfile`. Because each profile file validates in isolation, though, Zod has no way to catch a circular `extends` definition (`a` extends `b` extends `a`) — the walker in `resolve/extends.ts` needs its own cycle guard (a visited-set), independent of schema validation.
499
503
 
package/dist/cli.cjs CHANGED
@@ -221857,7 +221857,7 @@ var categories_default_default = {
221857
221857
  // package.json
221858
221858
  var package_default = {
221859
221859
  name: "claude-use",
221860
- version: "0.3.6",
221860
+ version: "0.5.0",
221861
221861
  description: "A profile manager and launcher for Claude Code that lets one person run multiple logins from one machine while controlling what gets shared between them.",
221862
221862
  license: "Apache-2.0",
221863
221863
  author: "Joseph Mearman <joseph@mearman.co.uk>",
@@ -236532,12 +236532,21 @@ function isOverridableCategory(name) {
236532
236532
  function isCategoryName(name) {
236533
236533
  return CATEGORY_NAMES.some((category) => category === name);
236534
236534
  }
236535
+ function expandAllCategoryKey(pairs) {
236536
+ const { all, ...rest } = pairs;
236537
+ if (all === void 0) {
236538
+ return { ...rest };
236539
+ }
236540
+ const expanded = Object.fromEntries(OVERRIDABLE_CATEGORIES.map((category) => [category, all]));
236541
+ return { ...expanded, ...rest };
236542
+ }
236535
236543
  var CategoryMapSchema = external_exports.strictObject({
236544
+ all: external_exports.boolean().optional(),
236536
236545
  runtime: external_exports.boolean().optional(),
236537
236546
  history: external_exports.boolean().optional(),
236538
236547
  knowledge: external_exports.boolean().optional(),
236539
236548
  settings: external_exports.boolean().optional()
236540
- });
236549
+ }).transform((input) => expandAllCategoryKey(input));
236541
236550
  var DURATION_RE = /^(?:0|[1-9][0-9]*)(?:ms|s|m|h|d|w)$/;
236542
236551
  var DurationSchema = external_exports.string().regex(DURATION_RE);
236543
236552
  var WhenSchema = external_exports.strictObject({
@@ -240187,6 +240196,19 @@ function useIdentity(paths, name) {
240187
240196
  writeTextAtomic(paths.activeIdentityFile, `${name}
240188
240197
  `);
240189
240198
  }
240199
+ function tryRunAtIdentityShortcut(paths, argv) {
240200
+ if (argv.length !== 1) {
240201
+ return false;
240202
+ }
240203
+ const [token] = argv;
240204
+ if (token === void 0 || !token.startsWith("@") || token.length === 1) {
240205
+ return false;
240206
+ }
240207
+ const name = token.slice(1);
240208
+ useIdentity(paths, name);
240209
+ console.log(`Active identity is now "${name}".`);
240210
+ return true;
240211
+ }
240190
240212
  function readActiveIdentity(paths) {
240191
240213
  if (!import_node_fs4.default.existsSync(paths.activeIdentityFile)) {
240192
240214
  return void 0;
@@ -240394,9 +240416,10 @@ function validateCategoryNames(patch) {
240394
240416
  }
240395
240417
  function setProfileCategories(paths, name, patch) {
240396
240418
  requireProfileExists(paths, name);
240397
- validateCategoryNames(patch);
240419
+ const expandedPatch = expandAllCategoryKey(patch);
240420
+ validateCategoryNames(expandedPatch);
240398
240421
  const existing = readProfile(paths, name) ?? {};
240399
- const mergedCategories = { ...existing.categories, ...patch };
240422
+ const mergedCategories = { ...existing.categories, ...expandedPatch };
240400
240423
  return applyPatch(profileJsonPath(paths, name), ConfigProfileSchema, { categories: mergedCategories });
240401
240424
  }
240402
240425
  function setProfileEntries(paths, name, patch) {
@@ -241459,8 +241482,9 @@ var InvalidCliEntryKeyError = class extends Error {
241459
241482
  key;
241460
241483
  };
241461
241484
  function toCategoryMap(pairs) {
241485
+ const expanded = expandAllCategoryKey(pairs);
241462
241486
  const result = {};
241463
- for (const [key, value] of Object.entries(pairs)) {
241487
+ for (const [key, value] of Object.entries(expanded)) {
241464
241488
  if (!isOverridableCategory(key)) {
241465
241489
  throw new InvalidCliCategoryError(key);
241466
241490
  }
@@ -241785,7 +241809,7 @@ function main() {
241785
241809
  const invokedName = import_node_path20.default.basename(process.argv[1] ?? "claude-use");
241786
241810
  if (isInvokedAsClaude(invokedName)) {
241787
241811
  runClaude();
241788
- } else {
241812
+ } else if (!tryRunAtIdentityShortcut(resolveLayoutPaths(), process.argv.slice(2))) {
241789
241813
  buildClaudeUseProgram().parse(process.argv);
241790
241814
  }
241791
241815
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-use",
3
- "version": "0.3.6",
3
+ "version": "0.5.0",
4
4
  "description": "A profile manager and launcher for Claude Code that lets one person run multiple logins from one machine while controlling what gets shared between them.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Joseph Mearman <joseph@mearman.co.uk>",