claude-use 1.3.1 → 1.4.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 +9 -3
- package/dist/cli.cjs +1285 -1047
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -468,9 +468,9 @@ One compiled binary backs both `claude` and `claude-use` — the entrypoint disp
|
|
|
468
468
|
```
|
|
469
469
|
src/
|
|
470
470
|
cli.ts # entrypoint; dispatches on invoked name -> launcher vs identity/profile-manager subcommands
|
|
471
|
+
cliError.ts # CliError — the base class every user-facing error extends, so main()'s top-level catch can print a clean message instead of a stack trace
|
|
471
472
|
paths.ts # CLAUDE_USE_HOME-aware layout paths — every other module resolves ~/.claude-use/... paths through this, never inline
|
|
472
473
|
pathNorm.ts # rule-path normalisation/ancestor helpers shared across the resolver and directory rules
|
|
473
|
-
exit.ts # exit code constants
|
|
474
474
|
versionDiscovery.ts # portable "find the real claude binary" logic
|
|
475
475
|
realPorts.ts # the real filesystem/spawn/proc/clock/git ports wired into runLauncher by cli.ts (tests wire fakes instead)
|
|
476
476
|
launcher.ts # runLauncher: thin orchestration over launcher/* below
|
|
@@ -529,6 +529,12 @@ install.sh # downloads the latest release's binary for the runni
|
|
|
529
529
|
# checksum, and installs it as both `claude` and `claude-use` in ~/.local/bin
|
|
530
530
|
```
|
|
531
531
|
|
|
532
|
+
### Error reporting: `CliError` vs. everything else
|
|
533
|
+
|
|
534
|
+
Every custom error this project throws to represent an expected, user-facing failure — a missing identity/profile/rule, a malformed config file, an invalid `--category`/`--share`/`--hide` flag — extends `CliError` (`src/cliError.ts`), an otherwise-empty abstract subclass of `Error`. `main()` in `src/cli.ts` wraps its whole body in one top-level `try`/`catch`: a `CliError` prints as `error.message` alone, with no stack trace, and exits `1`; anything else — a genuine, unanticipated bug — is rethrown and crashes with its full stack trace, which is more useful for diagnosing it than swallowing it would be. Before this existed, an error like `IdentityNotFoundError` thrown from the `@name` shortcut or from inside a Commander action (`identity use`, `profile create`, etc.) crashed with a raw Node.js stack trace instead of the one-line message its own constructor already built — the class carried the right text, nothing at the top ever caught it. `main()` calls `buildClaudeUseProgram().parseAsync(process.argv)`, not `.parse()`, specifically so an `async` action's rejection (e.g. `identity resolve <name>`, which awaits an interactive prompt) reaches this same catch too, rather than surfacing as an unhandled promise rejection Commander's synchronous `.parse()` never awaits.
|
|
535
|
+
|
|
536
|
+
`cliError.test.ts` asserts every one of these error classes actually extends `CliError` — the one regression `tsc`/`eslint` can never catch on their own, since a class silently reverting to `extends Error`, or a new one added without extending `CliError` at all, is still perfectly valid TypeScript.
|
|
537
|
+
|
|
532
538
|
`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.
|
|
533
539
|
|
|
534
540
|
`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.
|
|
@@ -563,7 +569,7 @@ Every push to `main` runs [semantic-release](https://github.com/semantic-release
|
|
|
563
569
|
|
|
564
570
|
One accepted quirk worth knowing rather than being surprised by: semantic-release creates the release tag pointing at the commit that already existed (the actual code change being released) *before* running `@semantic-release/git`'s commit step — so the changelog/version-bump commit lands on `main` **after** the tag, not folded into it. Every downstream job below checks out `ref: main` (not the commit that triggered the run) specifically to pick up this post-release state, matching how this org's other semantic-release repos handle the identical quirk.
|
|
565
571
|
|
|
566
|
-
**The six platform build jobs (`build-arm64` through `build-windows-arm64`) also run on every pull request, not only a published release.** Each
|
|
572
|
+
**The six platform build jobs (`build-arm64` through `build-windows-arm64`) also run on every pull request, not only a published release.** Each has its own dedicated `smoke-test-*` job — a separate job, not a step inside the build job, so a smoke-test failure shows as its own line in the PR checks list, distinct from "did it build" — that downloads the just-built artifact and directly executes it (`--version`, `--help`) on a runner of the same OS+architecture, since a binary built for one architecture cannot run on another. This is what would have caught, before merge rather than after a real release, an actual regression this project shipped once: a Turbo cache key that didn't distinguish `runner.arch`, letting one architecture's compiled binary silently serve for another (see `.github/actions/setup-and-run/action.yml`'s own comment). `release` depends on all five verified `smoke-test-*` jobs succeeding, not just their matching `build-*` jobs, so a smoke-test failure blocks the release the same way a build failure already did — `smoke-test-macos-x64-best-effort` is deliberately excluded from that gate, matching `build-x64-best-effort`'s own `continue-on-error: true`. On a PR, each build job checks out the PR's own head commit instead of `ref: main`, since there's no post-release state to pick up yet. Publishing itself — npm, GitHub Packages, the GitHub Release, and the Homebrew/Scoop tap updates — stays gated on `needs.semantic-release.outputs.published == 'true'` alone and never runs on a PR, since those all have real, one-way side effects.
|
|
567
573
|
|
|
568
574
|
**Branch/tag protection had to be disabled for this to work.** `main`'s branch-protection ruleset previously required every push go through a reviewed PR, and a separate ruleset blocked tag creation/deletion outright — both only bypassable by the Admin repository role. semantic-release's own git operations run as the workflow's default `GITHUB_TOKEN`, which doesn't hold that role, so both rulesets were disabled (not deleted — the rule definitions are preserved and can be re-enabled with a single API call or via the repo's Rules settings page) rather than routing around them with a separate bypass credential.
|
|
569
575
|
|
|
@@ -575,7 +581,7 @@ One accepted quirk worth knowing rather than being surprised by: semantic-releas
|
|
|
575
581
|
|
|
576
582
|
One gotcha worth knowing before reaching for this: **Homebrew's macOS Node build has the single-executable-application feature compiled out.** Running the build against a Homebrew-installed Node fails partway through with "Single executable application is disabled" — `scripts/build.mts` detects this specific error and rewrites it into an explanation naming the cause, rather than leaving a contributor to debug an opaque native error. Use a Node binary from a distribution that ships SEA support instead — the official nodejs.org build, or a version manager installing upstream builds (mise, nvm, volta, fnm) — ahead of Homebrew's on `PATH`.
|
|
577
583
|
|
|
578
|
-
macOS SEA support is tested and verified upstream on **arm64 only** — x64 is explicitly unsupported and skipped in Node core's own test suite. CI builds and publishes the arm64 binary as the verified release artefact; it also attempts an x64 build as a clearly-labelled best-effort convenience (allowed to fail without blocking the release, and published as `claude-use-macos-x64-unverified` when it succeeds), never presented as a supported target. This isn't just a theoretical caveat: v0.2.7 confirmed `claude-use --version` itself segfaults on real x64 macOS hardware, a crash
|
|
584
|
+
macOS SEA support is tested and verified upstream on **arm64 only** — x64 is explicitly unsupported and skipped in Node core's own test suite. CI builds and publishes the arm64 binary as the verified release artefact; it also attempts an x64 build as a clearly-labelled best-effort convenience (allowed to fail without blocking the release, and published as `claude-use-macos-x64-unverified` when it succeeds), never presented as a supported target. This isn't just a theoretical caveat: v0.2.7 confirmed `claude-use --version` itself segfaults on real x64 macOS hardware, a crash `smoke-test-macos-x64-best-effort` has silently swallowed via `|| true` until a dedicated install-and-run verify job (also best-effort, non-blocking) finally exercised the binary for real.
|
|
579
585
|
|
|
580
586
|
**Root cause, confirmed rather than assumed.** Reproduced locally under Rosetta with 100% fidelity to CI: `lldb` shows `EXC_BAD_ACCESS` inside `__cxx_global_var_init`, invoked by `dyld` while running C++ static initializers — before `main()` ever executes, with `rdi` (the faulting access) holding the literal value `0x2`. A trivial one-line `console.log(...)` script built through the exact same `--build-sea` + ad-hoc-codesign steps crashes identically, which rules out anything in claude-use's own bundle, build script, or code — this is `--build-sea` itself misbehaving on x64 macOS. This is a known, tracked, and deliberately unfixed upstream limitation: [nodejs/node#62893](https://github.com/nodejs/node/issues/62893) reproduces the identical crash and was closed as documentation-only ([nodejs/node#63181](https://github.com/nodejs/node/pull/63181)), with a Node core maintainer stating SEA on x64 macOS "is not supported and skipped in the tests... until someone volunteers to implement support for it." The deeper investigation thread ([nodejs/node#59553](https://github.com/nodejs/node/issues/59553)) floats an unconfirmed theory — that `postject`'s LIEF-based Mach-O binary injection corrupts the executable such that `dyld` misidentifies a segment as an oversized (>4GB) thread-local-storage region — but that thread closed stale, unfixed, with the same maintainer concluding it's "unlikely that anyone would invest time in fixing it for macOS" given x64 macOS's Tier 2 deprioritisation upstream. There is no available workaround (no alternate `codesign` invocation, `sea-config.json` option, or Node flag) — the fault is inside `--build-sea`'s own binary-injection step, before any code this project controls runs at all.
|
|
581
587
|
|