mirror of
https://github.com/agentclientprotocol/claude-agent-acp.git
synced 2026-10-27 04:30:59 +00:00
fix: pass --settings before the auth status subcommand (#1392)
`runCliAuthProbe` builds `["auth", "status", "--json"]` and, when the
session has a settings
override, appends `--settings <json>`. `--settings` is a global option
of the Claude Code CLI;
the `auth status` subcommand only accepts `--json` and `--text` (see
`claude auth status --help`).
So every probe with an override fails with `error: unknown option
'--settings'` and an empty
stdout. The catch branch logs `claude auth status failed: …` on every
call and returns
`undefined`. For sessions that pass `_meta.claudeCode.options.settings`,
the session-creation and
per-prompt refreshes therefore never update the auth status. Only the
initialize probe, which has
no override, still works.
This moves `--settings <json>` in front of the subcommand. Without an
override the argv is
unchanged.
**Reproduce** (no credentials needed; an empty config dir answers "not
logged in"):
```sh
d=$(mktemp -d)
env -i HOME="$d" PATH="$PATH" CLAUDE_CONFIG_DIR="$d/.claude" \
claude auth status --json --settings '{}'
# error: unknown option '--settings'
env -i HOME="$d" PATH="$PATH" CLAUDE_CONFIG_DIR="$d/.claude" \
claude --settings '{}' auth status --json
# {"loggedIn": false, "authMethod": "none", ...}
```
The option is applied in the global position, not just parsed:
`claude --settings '{"apiKeyHelper":"/bin/echo rt-fake-key"}' auth
status --json` reports
`"loggedIn": true, "authMethod": "api_key_helper"`.
Tested with 10 native Claude Code binaries (linux-x64), each in an empty
`HOME`:
| Claude Code | `auth status --json --settings '{}'` | `--settings '{}'
auth status --json` |
|---|---|---|
| 2.1.286 | unknown option | JSON |
| 2.1.294 | unknown option | JSON |
| 2.1.295, 2.1.296, 2.1.299 | unknown option | JSON |
| 2.1.300, 2.1.301, 2.1.302 | unknown option | JSON |
| 2.1.303 (the SDK's `claudeCodeVersion`) | unknown option | JSON |
| 2.1.304 | unknown option | JSON |
The existing test in `auth-status.test.ts` pinned the old order; it now
expects `--settings`
first. Its mock and `statusCalls()` matched probes by `args[1] ===
"status"`, which a leading
global option shifts, so both now locate the subcommand instead.
`npm run build`, `format:check`, `lint` and `test:run` pass, apart from
one test that fails
identically on `main` without this change.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -3430,7 +3430,9 @@ export class ClaudeAcpAgent {
|
|||||||
try {
|
try {
|
||||||
const cliPath = await claudeCliPath();
|
const cliPath = await claudeCliPath();
|
||||||
const args = ["auth", "status", "--json"];
|
const args = ["auth", "status", "--json"];
|
||||||
if (context?.override) args.push("--settings", JSON.stringify(context.override));
|
// `--settings` is a global CLI option: after the `auth status` subcommand the CLI rejects
|
||||||
|
// it with "unknown option '--settings'", so it has to come first.
|
||||||
|
if (context?.override) args.unshift("--settings", JSON.stringify(context.override));
|
||||||
({ stdout } = await execFileAsync(cliPath, args, {
|
({ stdout } = await execFileAsync(cliPath, args, {
|
||||||
timeout: AUTH_STATUS_PROBE_TIMEOUT_MS,
|
timeout: AUTH_STATUS_PROBE_TIMEOUT_MS,
|
||||||
cwd: context?.manager.getCwd() ?? process.cwd(),
|
cwd: context?.manager.getCwd() ?? process.cwd(),
|
||||||
|
|||||||
@@ -22,6 +22,11 @@ vi.mock("@anthropic-ai/claude-agent-sdk", async () => ({
|
|||||||
/** Shared spy for both `claude auth status --json` and `claude auth logout`.
|
/** Shared spy for both `claude auth status --json` and `claude auth logout`.
|
||||||
* Tests set `execFileResults` per invoked subcommand. */
|
* Tests set `execFileResults` per invoked subcommand. */
|
||||||
const execFileSpy = vi.hoisted(() => vi.fn());
|
const execFileSpy = vi.hoisted(() => vi.fn());
|
||||||
|
/** `auth status` probes, wherever global options such as `--settings` put the subcommand. */
|
||||||
|
function isStatusProbe(args: string[]): boolean {
|
||||||
|
const auth = args.indexOf("auth");
|
||||||
|
return auth >= 0 && args[auth + 1] === "status";
|
||||||
|
}
|
||||||
|
|
||||||
vi.mock("node:child_process", async () => {
|
vi.mock("node:child_process", async () => {
|
||||||
const actual = await vi.importActual<typeof import("node:child_process")>("node:child_process");
|
const actual = await vi.importActual<typeof import("node:child_process")>("node:child_process");
|
||||||
@@ -409,7 +414,7 @@ describe("auth status over ACP", () => {
|
|||||||
execFileSpy.mockImplementation((...invocation: unknown[]) => {
|
execFileSpy.mockImplementation((...invocation: unknown[]) => {
|
||||||
const args = invocation[1] as string[];
|
const args = invocation[1] as string[];
|
||||||
const cb = invocation[invocation.length - 1] as (...a: unknown[]) => void;
|
const cb = invocation[invocation.length - 1] as (...a: unknown[]) => void;
|
||||||
if (args[1] === "status") {
|
if (isStatusProbe(args)) {
|
||||||
const stdout = statusStdout;
|
const stdout = statusStdout;
|
||||||
const fails = statusFails;
|
const fails = statusFails;
|
||||||
const answer = () => {
|
const answer = () => {
|
||||||
@@ -451,7 +456,7 @@ describe("auth status over ACP", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function statusCalls() {
|
function statusCalls() {
|
||||||
return execFileSpy.mock.calls.filter((call) => (call[1] as string[])[1] === "status");
|
return execFileSpy.mock.calls.filter((call) => isStatusProbe(call[1] as string[]));
|
||||||
}
|
}
|
||||||
|
|
||||||
function updates() {
|
function updates() {
|
||||||
@@ -542,11 +547,11 @@ describe("auth status over ACP", () => {
|
|||||||
env: { ANTHROPIC_BASE_URL: "https://example.invalid/override" },
|
env: { ANTHROPIC_BASE_URL: "https://example.invalid/override" },
|
||||||
});
|
});
|
||||||
expect(statusCalls().at(-1)?.[1]).toEqual([
|
expect(statusCalls().at(-1)?.[1]).toEqual([
|
||||||
|
"--settings",
|
||||||
|
JSON.stringify({ apiKeyHelper: "central proxy start" }),
|
||||||
"auth",
|
"auth",
|
||||||
"status",
|
"status",
|
||||||
"--json",
|
"--json",
|
||||||
"--settings",
|
|
||||||
JSON.stringify({ apiKeyHelper: "central proxy start" }),
|
|
||||||
]);
|
]);
|
||||||
await promptOnce(sessionId);
|
await promptOnce(sessionId);
|
||||||
await flushStatus();
|
await flushStatus();
|
||||||
|
|||||||
Reference in New Issue
Block a user