mirror of
https://github.com/agentclientprotocol/claude-agent-acp.git
synced 2026-11-10 11:21:06 +00:00
When Claude Code refuses to start (invalid proxy URL, wrong organization sign-in, a required sandbox that can't run, …), `session/new`, `session/load`, `session/resume` and `session/fork` used to fail with a generic `Claude Code process exited with code 1. stderr: …` error. This sets `CLAUDE_CODE_STARTUP_FAILURE_RESULTS=1` on the query env, so the CLI writes an error result with a `startup_failure_reason` before exiting on a known startup failure. The SDK then rejects `initializationResult()` with an error that carries `startupFailureReason`. The new `src/startup-failure.ts` maps it to an ACP error: | `startupFailureReason` | ACP error | |---|---| | `gateway_signin_required`, `org_pin_mismatch`, `org_config_refused` | `authRequired` (signing in again, or with another account, fixes it) | | `cwd_unavailable` | `invalidParams` (matches the existing cwd validation) | | any other reason | `internalError` | The message is the CLI's own text, which says what to fix (e.g. `Invalid proxy URL in HTTPS_PROXY: … Fix or unset HTTPS_PROXY and restart Claude Code.`), and `data.startupFailureReason` carries the reason. Errors without a reason (older CLIs, unknown causes) pass through unchanged, and the existing `sessionNotFound` mapping for resumes is untouched. Checked against the real CLI (SDK 0.3.316): with `HTTPS_PROXY="not a url"`, `initializationResult()` rejects with `startupFailureReason: "proxy_invalid"` when the variable is set, and with a plain exit-code error without it. ## Testing - v1: `create-session-options.test.ts` covers the env var, each mapping, and pass-through of errors without a reason. - v2: `acp-v2.test.ts` covers the `session/new` error over the wire. - `npm run build`, `npm run check`, `npm run test:run` pass. The subprocess integration tests also passed locally with this change. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude <noreply@anthropic.com>
43 lines
2.0 KiB
TypeScript
43 lines
2.0 KiB
TypeScript
import { RequestError } from "@agentclientprotocol/sdk/unstable";
|
|
import type { SDKStartupFailureReason } from "@anthropic-ai/claude-agent-sdk";
|
|
|
|
/** Makes the CLI write an `error_during_execution` result with a
|
|
* `startup_failure_reason` before it exits on a known startup failure. Without
|
|
* it, some failures (e.g. `proxy_invalid`) end with stderr and an exit code
|
|
* alone. The SDK then rejects `initializationResult()` with an error that
|
|
* carries the reason as `startupFailureReason`. */
|
|
export const STARTUP_FAILURE_RESULTS_ENV = { CLAUDE_CODE_STARTUP_FAILURE_RESULTS: "1" };
|
|
|
|
/** The SDK's prefix on the message of an error built from an error result. */
|
|
const ERROR_RESULT_PREFIX = "Claude Code returned an error result: ";
|
|
|
|
/** Reasons that signing in again, or with another account, can fix. */
|
|
const AUTH_REQUIRED_REASONS: ReadonlySet<SDKStartupFailureReason> = new Set([
|
|
"gateway_signin_required",
|
|
"org_pin_mismatch",
|
|
"org_config_refused",
|
|
]);
|
|
|
|
/** The ACP error for a CLI that refused to start, or `undefined` when `error`
|
|
* carries no `startupFailureReason` (older CLIs, failures without a known
|
|
* cause). The message is the CLI's own, which says what to fix, e.g.
|
|
* `Invalid proxy URL in HTTPS_PROXY: … Fix or unset HTTPS_PROXY and restart
|
|
* Claude Code.`; `data.startupFailureReason` carries the reason. */
|
|
export function startupFailureError(error: unknown): RequestError | undefined {
|
|
if (!(error instanceof Error)) return undefined;
|
|
const reason = (error as { startupFailureReason?: unknown }).startupFailureReason;
|
|
if (typeof reason !== "string" || reason === "") return undefined;
|
|
|
|
const message = error.message.startsWith(ERROR_RESULT_PREFIX)
|
|
? error.message.slice(ERROR_RESULT_PREFIX.length)
|
|
: error.message;
|
|
const data = { startupFailureReason: reason };
|
|
if (AUTH_REQUIRED_REASONS.has(reason as SDKStartupFailureReason)) {
|
|
return RequestError.authRequired(data, message);
|
|
}
|
|
if (reason === "cwd_unavailable") {
|
|
return RequestError.invalidParams(data, message);
|
|
}
|
|
return RequestError.internalError(data, message);
|
|
}
|