Quote the apiKeyHelper path, and say why the helper failed
apiKeyHelper is a shell command line, not a path, so the raw value written into settings.json was split at the first space. A Windows profile named "Mohammed Ahmed" produced an attempt to run C:\Users\Mohammed, surfacing as "your apiKeyHelper script is failing" with nothing to go on. Quote the value when it contains anything a shell cares about, and leave it bare otherwise so no existing settings.json churns on the next switch. The POSIX port had the same bug against a /Users/First Last home; shlex.quote has exactly the wanted "leave ordinary paths alone" behaviour. doctor could not see any of this. It quoted the path itself before running it, so it exercised a command line Claude Code never uses and passed while the real one failed. It now reads the string out of settings.json, reports it when it is not what a switch would write, and runs that string through a shell. The helper itself exited 1 in silence on four distinct faults - no state, no preset, no key, undecryptable key - collapsing them into one indistinguishable message. Each now names itself on stderr, which is what /status displays. The DPAPI case says what it actually means: a key stored by a different Windows account than the one Claude Code runs as. Success paths stay silent, so stdout still carries the key and nothing else. Also make install.ps1 survive a Restricted execution policy: piped through iex it is not subject to the policy, but invoking the installed script for the key prompt is, which is where a fresh install died. Set Process scope for the install, offer to set CurrentUser to RemoteSigned, and clear the mark-of-the-web that Expand-Archive can leave on the extracted scripts. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -92,6 +92,37 @@ nothing when state says `anthropic` — belt and braces. LM Studio's `lmstudio`
|
||||
token is a placeholder, not a secret, so it's written inline and the helper stays
|
||||
out of it.
|
||||
|
||||
### When the helper "is failing"
|
||||
|
||||
Claude Code reports a broken helper as *your apiKeyHelper script is failing* and
|
||||
shows its stderr under `/status`. Two causes account for nearly all of it.
|
||||
|
||||
**A space in your home directory.** `apiKeyHelper` is a shell *command line*, not
|
||||
a path, so `C:\Users\Firstname Lastname\.claude-mode\bin\claude-key-helper.cmd`
|
||||
is split at the space and cmd tries to run `C:\Users\Firstname`. The value is now
|
||||
quoted when it needs to be, on both ports — `shlex.quote` on POSIX, where a
|
||||
`/Users/Firstname Lastname` home does the same thing. Paths that need no quoting
|
||||
are written bare exactly as before, so no existing `settings.json` churns.
|
||||
|
||||
`doctor` used to miss this, because it quoted the path itself before running it
|
||||
and so tested something Claude Code never sees. It now reads the string out of
|
||||
`settings.json`, says so when that string is not what a switch would write, and
|
||||
executes *that* string through a shell. Re-running the switch rewrites it:
|
||||
|
||||
```
|
||||
claude-mode openrouter default
|
||||
claude-mode doctor
|
||||
```
|
||||
|
||||
**A key stored by a different Windows account.** The vault is DPAPI `CurrentUser`
|
||||
scope, so a key stored from an elevated or *run as* shell cannot be decrypted by
|
||||
the account Claude Code runs as. Re-run `claude-mode set-key <ref>` unelevated,
|
||||
as yourself.
|
||||
|
||||
Every helper failure path now names itself on stderr rather than exiting 1 in
|
||||
silence, so `/status` distinguishes these from a missing preset or an empty
|
||||
vault. The success paths stay silent — stdout carries the key and nothing else.
|
||||
|
||||
## Commands
|
||||
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user