diff --git a/docs/air-extensions.md b/docs/air-extensions.md index 667ea41e..c870ed65 100644 --- a/docs/air-extensions.md +++ b/docs/air-extensions.md @@ -228,7 +228,7 @@ The adapter keeps them where they are. ## Auth source display -The connection-scoped `_auth/status_update` continues to report agent-owned authentication, not client-owned `providers/set` routing. The adapter also reports the same identity through the ACP `auth/status` method and `auth/status_update` notification (advertised as `auth.status`), with `kind`, `detail` and `plan` under the account's `_meta.claudeCode`. Each notification is sent when its own payload changed. `auth/status` answers with the identity last reported and starts a new read, whose change arrives as a notification. When the active key source is `apiKeyHelper`, the adapter reads the effective helper command through SDK `resolveSettings` / the session's `SettingsManager`, including programmatic settings overrides. +The connection-scoped `_auth/status_update` continues to report agent-owned authentication, not client-owned `providers/set` routing. The adapter also reports the same identity through the ACP `auth/status` method and `auth/status_update` notification (advertised as `auth.status`), with `kind`, `detail` and `plan` under the account's `_meta.claudeCode`. The account's `label` also carries a `detail` in parentheses, e.g. `Anthropic API key (ANTHROPIC_API_KEY)`. Each notification is sent when its own payload changed. `auth/status` answers with the identity last reported and starts a new read, whose change arrives as a notification. When the active key source is `apiKeyHelper`, the adapter reads the effective helper command through SDK `resolveSettings` / the session's `SettingsManager`, including programmatic settings overrides. A command containing the whole word `central` and the word sequence `proxy start` is displayed as: diff --git a/src/auth-status.ts b/src/auth-status.ts index f4d99bad..6a0532f5 100644 --- a/src/auth-status.ts +++ b/src/auth-status.ts @@ -104,8 +104,10 @@ export type AcpAuthStatus = Pick; * - No identity read yet (`undefined`): `unknown`, no accounts. * - `kind: "none"`: `unauthenticated`, no accounts. * - Any other kind: `authenticated`, with the identity as the one account, - * marked `active`. `_meta.claudeCode` carries the `kind`, `detail` and - * `plan` that the account fields have no place for. + * marked `active`. The account has no field for `detail`, so its label + * carries it in parentheses, e.g. "Anthropic API key (ANTHROPIC_API_KEY)", + * for clients that show only the standard fields. `_meta.claudeCode` + * carries the `kind`, `detail` and `plan` on their own. * * `--hide-claude-auth` does not change the payload: it reports the login the * CLI holds, also when the subscription guard refuses to use it. @@ -117,7 +119,8 @@ export function toAcpAuthStatus(status: AuthStatus | undefined): AcpAuthStatus { if (status.kind === "none") { return { state: "unauthenticated" }; } - const account: AuthAccount = { label: status.label, active: true }; + const label = status.detail ? `${status.label} (${status.detail})` : status.label; + const account: AuthAccount = { label, active: true }; if (status.account?.email) account.email = status.account.email; if (status.account?.organization) account.organization = status.account.organization; account._meta = { diff --git a/src/tests/v1/auth-status.test.ts b/src/tests/v1/auth-status.test.ts index 9b18a7bb..bb60d070 100644 --- a/src/tests/v1/auth-status.test.ts +++ b/src/tests/v1/auth-status.test.ts @@ -220,7 +220,7 @@ describe("auth status mappers", () => { state: "authenticated", accounts: [ { - label: "Anthropic API key", + label: "Anthropic API key (env)", active: true, _meta: { claudeCode: { kind: "api_key", detail: "env" } }, }, @@ -765,7 +765,7 @@ describe("auth status over ACP", () => { state: "authenticated", accounts: [ { - label: "Custom model gateway", + label: "Custom model gateway (gw.example.com)", active: true, _meta: { claudeCode: { kind: "gateway", detail: "gw.example.com" } }, }, @@ -783,7 +783,7 @@ describe("auth status over ACP", () => { agent.setAuthStatus({ kind: "api_key", label: "Anthropic API key", detail: "env" }); expect(await agent.authStatusResponse()).toMatchObject({ state: "authenticated", - accounts: [{ label: "Anthropic API key" }], + accounts: [{ label: "Anthropic API key (env)" }], }); });