diff --git a/apps/marketing/app/globals.css b/apps/marketing/app/globals.css index 9297910a..334ee661 100644 --- a/apps/marketing/app/globals.css +++ b/apps/marketing/app/globals.css @@ -163,17 +163,6 @@ } } -/* Fractal noise texture overlay */ -body::after { - content: ""; - position: fixed; - inset: 0; - z-index: 9999; - pointer-events: none; - opacity: 0.035; - background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 512 512' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noiseFilter'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)'/%3E%3C/svg%3E"); -} - /* Heading scale */ h1 { font-size: clamp(2.25rem, 5vw, 3.75rem); diff --git a/apps/marketing/components/DynamicBackground.tsx b/apps/marketing/components/DynamicBackground.tsx index 9fe15a64..d3a62af4 100644 --- a/apps/marketing/components/DynamicBackground.tsx +++ b/apps/marketing/components/DynamicBackground.tsx @@ -1,136 +1,57 @@ -"use client"; - -import { motion } from "framer-motion"; - -/** - * Full-page animated background with floating gradient orbs, - * a subtle dot grid, and moving aurora streaks — all on deep black. - */ export function DynamicBackground() { return (
- {/* ── Dot grid ─────────────────────────────────────── */} -
+
- {/* ── Gradient orbs ────────────────────────────────── */} - {/* Top-left — cool purple */} - - - {/* Center-right — deep blue */} - - {/* Bottom-center — subtle warm accent */} - - {/* Mid-left — faint teal whisper */} - - {/* ── Aurora streaks ───────────────────────────────── */} - - - {/* ── Vignette — darkens edges toward pure black ──── */} + {/* Edge control */}
diff --git a/apps/marketing/components/GetStarted.tsx b/apps/marketing/components/GetStarted.tsx index 4f50e8d3..7a21d199 100644 --- a/apps/marketing/components/GetStarted.tsx +++ b/apps/marketing/components/GetStarted.tsx @@ -5,14 +5,6 @@ import { LINKS } from "./links"; export function GetStarted() { return (
- {/* Section glow */} -

Start building.

One command. Zero config.

diff --git a/apps/marketing/components/Hero.tsx b/apps/marketing/components/Hero.tsx index 002171d0..ec2d91fc 100644 --- a/apps/marketing/components/Hero.tsx +++ b/apps/marketing/components/Hero.tsx @@ -9,14 +9,10 @@ import { OKCodeMockup } from "./OKCodeMockup"; export function Hero() { return (
- {/* Ambient glow — amplified for true black */}
@@ -89,17 +85,6 @@ export function Hero() { >
- - {/* Subtle reflection glow under frame */} -
diff --git a/apps/server/src/doctor.ts b/apps/server/src/doctor.ts index 2330e300..1456032b 100644 --- a/apps/server/src/doctor.ts +++ b/apps/server/src/doctor.ts @@ -87,9 +87,7 @@ const doctorProgram = Effect.gen(function* () { console.log("No providers are ready. Set up at least one provider to start coding:"); console.log(""); console.log(" Codex: npm install -g @openai/codex && codex login"); - console.log( - " Claude Code: npm install -g @anthropic-ai/claude-code && claude auth login (or set ANTHROPIC_API_KEY / ANTHROPIC_AUTH_TOKEN)", - ); + console.log(" Claude Code: npm install -g @anthropic-ai/claude-code && claude auth login"); console.log(" Copilot: npm install -g @github/copilot && copilot login"); } else if (readyCount === statuses.length) { console.log("All providers are ready."); diff --git a/apps/server/src/provider/Layers/ClaudeAdapter.test.ts b/apps/server/src/provider/Layers/ClaudeAdapter.test.ts index 547c8a1b..4699647c 100644 --- a/apps/server/src/provider/Layers/ClaudeAdapter.test.ts +++ b/apps/server/src/provider/Layers/ClaudeAdapter.test.ts @@ -132,7 +132,6 @@ class FakeClaudeQuery implements AsyncIterable { function makeHarness(config?: { readonly nativeEventLogPath?: string; readonly nativeEventLogger?: ClaudeAdapterLiveOptions["nativeEventLogger"]; - readonly readAuthTokenFromHelperCommand?: ClaudeAdapterLiveOptions["readAuthTokenFromHelperCommand"]; readonly cwd?: string; readonly baseDir?: string; }) { @@ -149,11 +148,6 @@ function makeHarness(config?: { createInput = input; return query; }, - ...(config?.readAuthTokenFromHelperCommand - ? { - readAuthTokenFromHelperCommand: config.readAuthTokenFromHelperCommand, - } - : {}), ...(config?.nativeEventLogger ? { nativeEventLogger: config.nativeEventLogger, @@ -358,64 +352,8 @@ describe("ClaudeAdapterLive", () => { ); }); - it.effect("sources ANTHROPIC_AUTH_TOKEN from the configured helper command", () => { - const helperCommand = "op read op://shared/anthropic/token --no-newline"; - const helperToken = "helper-token"; - let helperCall: { - readonly command: string; - readonly options?: { readonly cwd?: string }; - } | null = null; - const helper: NonNullable = ( - command, - options, - ) => { - helperCall = { - command, - ...(options?.cwd ? { options: { cwd: options.cwd } } : {}), - }; - return helperToken; - }; - const harness = makeHarness({ - readAuthTokenFromHelperCommand: helper, - }); - - return Effect.gen(function* () { - const adapter = yield* ClaudeAdapter; - yield* adapter.startSession({ - threadId: THREAD_ID, - provider: "claudeAgent", - cwd: THREAD_CWD, - runtimeMode: "full-access", - env: { - ANTHROPIC_AUTH_TOKEN: "", - }, - providerOptions: { - claudeAgent: { - authTokenHelperCommand: helperCommand, - }, - }, - }); - - const createInput = harness.getLastCreateQueryInput(); - assert.equal(createInput?.options.env?.ANTHROPIC_AUTH_TOKEN, helperToken); - assert.equal(helperCall?.command, helperCommand); - assert.equal(helperCall?.options?.cwd, THREAD_CWD); - }).pipe( - Effect.provideService(Random.Random, makeDeterministicRandomService()), - Effect.provide(harness.layer), - ); - }); - - it.effect("prefers an explicit ANTHROPIC_AUTH_TOKEN over the helper command", () => { - let helperCallCount = 0; - const helper: NonNullable = () => { - helperCallCount += 1; - return "helper-token"; - }; - const harness = makeHarness({ - readAuthTokenFromHelperCommand: helper, - }); - + it.effect("strips Anthropic credential env vars before starting Claude Code", () => { + const harness = makeHarness(); return Effect.gen(function* () { const adapter = yield* ClaudeAdapter; yield* adapter.startSession({ @@ -424,18 +362,14 @@ describe("ClaudeAdapterLive", () => { cwd: THREAD_CWD, runtimeMode: "full-access", env: { + ANTHROPIC_API_KEY: "api-key", ANTHROPIC_AUTH_TOKEN: "env-token", }, - providerOptions: { - claudeAgent: { - authTokenHelperCommand: "op read op://shared/anthropic/token --no-newline", - }, - }, }); const createInput = harness.getLastCreateQueryInput(); - assert.equal(createInput?.options.env?.ANTHROPIC_AUTH_TOKEN, "env-token"); - assert.equal(helperCallCount, 0); + assert.equal(createInput?.options.env?.ANTHROPIC_API_KEY, undefined); + assert.equal(createInput?.options.env?.ANTHROPIC_AUTH_TOKEN, undefined); }).pipe( Effect.provideService(Random.Random, makeDeterministicRandomService()), Effect.provide(harness.layer), diff --git a/apps/server/src/provider/Layers/ClaudeAdapter.ts b/apps/server/src/provider/Layers/ClaudeAdapter.ts index edf7dce5..c2c44933 100644 --- a/apps/server/src/provider/Layers/ClaudeAdapter.ts +++ b/apps/server/src/provider/Layers/ClaudeAdapter.ts @@ -75,7 +75,6 @@ import { extractTextAttachmentContents, } from "../../attachmentText.ts"; import { ServerConfig } from "../../config.ts"; -import { readClaudeAuthTokenFromHelperCommand } from "../claudeAuthTokenHelper.ts"; import { ProviderAdapterProcessError, ProviderAdapterRequestError, @@ -187,7 +186,6 @@ export interface ClaudeAdapterLiveOptions { readonly prompt: AsyncIterable; readonly options: ClaudeQueryOptions; }) => ClaudeQueryRuntime; - readonly readAuthTokenFromHelperCommand?: typeof readClaudeAuthTokenFromHelperCommand; readonly nativeEventLogPath?: string; readonly nativeEventLogger?: EventNdjsonLogger; } @@ -211,12 +209,6 @@ function toError(cause: unknown, fallback: string): Error { return cause instanceof Error ? cause : new Error(toMessage(cause, fallback)); } -function nonEmptyTrimmed(value: string | undefined): string | undefined { - if (!value) return undefined; - const trimmed = value.trim(); - return trimmed.length > 0 ? trimmed : undefined; -} - function normalizeClaudeStreamMessages(cause: Cause.Cause): ReadonlyArray { const errors = Cause.prettyErrors(cause) .map((error) => error.message.trim()) @@ -263,7 +255,7 @@ function isClaudeAuthCause(cause: Cause.Cause): boolean { } function claudeAuthFailureMessage(): string { - return "Claude Code is not configured with a supported Anthropic credential. Set ANTHROPIC_API_KEY or ANTHROPIC_AUTH_TOKEN and try again."; + return "Claude Code must be authenticated with `claude auth login` before starting a session. API key and auth token credentials are not supported."; } function messageFromClaudeStreamCause(cause: Cause.Cause, fallback: string): string { @@ -1025,8 +1017,6 @@ function makeClaudeAdapter(options?: ClaudeAdapterLiveOptions) { stream: "native", }) : undefined); - const readAuthTokenFromHelperCommand = - options?.readAuthTokenFromHelperCommand ?? readClaudeAuthTokenFromHelperCommand; const createQuery = options?.createQuery ?? @@ -2832,28 +2822,11 @@ function makeClaudeAdapter(options?: ClaudeAdapterLiveOptions) { }; const runtimeEnv = input.env ? compactNodeProcessEnv(input.env) : undefined; const baseEnv = mergeNodeProcessEnv(process.env, runtimeEnv); - const explicitAuthToken = nonEmptyTrimmed(baseEnv.ANTHROPIC_AUTH_TOKEN); - const helperCommand = providerOptions?.authTokenHelperCommand; - let authToken = explicitAuthToken; - if (!authToken && helperCommand) { - authToken = yield* Effect.try({ - try: () => - readAuthTokenFromHelperCommand(helperCommand, { - ...(input.cwd ? { cwd: input.cwd } : {}), - env: baseEnv, - }), - catch: (cause) => - new ProviderAdapterProcessError({ - provider: PROVIDER, - threadId, - detail: `Failed to resolve Claude auth token from helper command: ${toMessage(cause, "unknown error")}`, - cause, - }), - }); - } - const queryEnv = authToken - ? mergeNodeProcessEnv(baseEnv, { ANTHROPIC_AUTH_TOKEN: authToken }) - : baseEnv; + const { + ANTHROPIC_API_KEY: _anthropicApiKey, + ANTHROPIC_AUTH_TOKEN: _anthropicAuthToken, + ...queryEnv + } = baseEnv; const queryOptions: ClaudeQueryOptions = { ...(input.cwd ? { cwd: input.cwd } : {}), diff --git a/apps/server/src/provider/Layers/ProviderHealth.test.ts b/apps/server/src/provider/Layers/ProviderHealth.test.ts index 6a342c35..a617f8b2 100644 --- a/apps/server/src/provider/Layers/ProviderHealth.test.ts +++ b/apps/server/src/provider/Layers/ProviderHealth.test.ts @@ -470,13 +470,17 @@ it.layer(NodeServices.layer)("ProviderHealth", (it) => { // ── checkClaudeProviderStatus tests ────────────────────────── describe("checkClaudeProviderStatus", () => { - it.effect("returns ready when claude is installed and authenticated", () => + it.effect("rejects Claude API-key auth and requires CLI login", () => Effect.gen(function* () { const status = yield* checkClaudeProviderStatus; assert.strictEqual(status.provider, "claudeAgent"); - assert.strictEqual(status.status, "ready"); + assert.strictEqual(status.status, "error"); assert.strictEqual(status.available, true); - assert.strictEqual(status.authStatus, "authenticated"); + assert.strictEqual(status.authStatus, "unauthenticated"); + assert.strictEqual( + status.message, + "Claude authentication status reported unsupported credential type 'apiKey'. Run `claude auth login` and try again. API key and auth token credentials are not supported.", + ); }).pipe( Effect.provide( mockSpawnerLayer((args) => { @@ -535,7 +539,7 @@ it.layer(NodeServices.layer)("ProviderHealth", (it) => { assert.strictEqual(status.authStatus, "unauthenticated"); assert.strictEqual( status.message, - "Claude is not configured with a supported Anthropic credential. Run `claude auth login`, or set ANTHROPIC_API_KEY / ANTHROPIC_AUTH_TOKEN, and try again.", + "Claude Code must be authenticated with `claude auth login` before starting a session. Run `claude auth login` and try again. API key and auth token credentials are not supported.", ); }).pipe( Effect.provide( @@ -561,7 +565,7 @@ it.layer(NodeServices.layer)("ProviderHealth", (it) => { assert.strictEqual(status.status, "ready"); assert.strictEqual(status.available, true); assert.strictEqual(status.authStatus, "authenticated"); - assert.strictEqual(status.message, "Claude Code CLI is ready via Claude.ai login."); + assert.strictEqual(status.message, "Claude Code CLI is ready via `claude auth login`."); }).pipe( Effect.provide( mockSpawnerLayer((args) => { @@ -626,10 +630,10 @@ it.layer(NodeServices.layer)("ProviderHealth", (it) => { // ── parseClaudeAuthStatusFromOutput pure tests ──────────────────── describe("parseClaudeAuthStatusFromOutput", () => { - it("exit code 0 with no auth markers is ready", () => { + it("exit code 0 with no auth markers is unknown", () => { const parsed = parseClaudeAuthStatusFromOutput({ stdout: "OK\n", stderr: "", code: 0 }); - assert.strictEqual(parsed.status, "ready"); - assert.strictEqual(parsed.authStatus, "authenticated"); + assert.strictEqual(parsed.status, "warning"); + assert.strictEqual(parsed.authStatus, "unknown"); }); it("JSON with loggedIn=true is authenticated", () => { @@ -640,7 +644,7 @@ it.layer(NodeServices.layer)("ProviderHealth", (it) => { }); assert.strictEqual(parsed.status, "ready"); assert.strictEqual(parsed.authStatus, "authenticated"); - assert.strictEqual(parsed.message, "Claude Code CLI is ready via Claude.ai login."); + assert.strictEqual(parsed.message, "Claude Code CLI is ready via `claude auth login`."); }); it("JSON with loggedIn=false is unauthenticated", () => { diff --git a/apps/server/src/provider/Layers/ProviderHealth.ts b/apps/server/src/provider/Layers/ProviderHealth.ts index f5f7c399..97f3861b 100644 --- a/apps/server/src/provider/Layers/ProviderHealth.ts +++ b/apps/server/src/provider/Layers/ProviderHealth.ts @@ -160,9 +160,8 @@ function hasGeminiHeadlessAuthEnv(): boolean { } const CLAUDE_CLI_AUTH_METHODS = new Set(["claude.ai", "oauth"]); -const CLAUDE_SUPPORTED_AUTH_METHODS = new Set(["apiKey", "authToken", "claude.ai", "oauth"]); const CLAUDE_AUTH_GUIDANCE = - "Run `claude auth login`, or set ANTHROPIC_API_KEY / ANTHROPIC_AUTH_TOKEN, and try again."; + "Run `claude auth login` and try again. API key and auth token credentials are not supported."; export function parseAuthStatusFromOutput(result: CommandResult): { readonly status: ServerProviderStatusState; @@ -660,14 +659,14 @@ export function parseClaudeAuthStatusFromOutput(result: CommandResult): { lowerOutput.includes("not logged in") || lowerOutput.includes("login required") || lowerOutput.includes("authentication required") || - lowerOutput.includes("oauth authentication is currently not supported") || lowerOutput.includes("run `claude login`") || - lowerOutput.includes("run claude login") + lowerOutput.includes("run claude login") || + lowerOutput.includes("api key and auth token credentials are not supported") ) { return { status: "error", authStatus: "unauthenticated", - message: `Claude is not configured with a supported Anthropic credential. ${CLAUDE_AUTH_GUIDANCE}`, + message: `Claude Code must be authenticated with \`claude auth login\` before starting a session. ${CLAUDE_AUTH_GUIDANCE}`, }; } @@ -700,35 +699,39 @@ export function parseClaudeAuthStatusFromOutput(result: CommandResult): { const authMethod = parsedAuth.authMethod?.trim(); const normalizedAuthMethod = authMethod?.toLowerCase(); if (parsedAuth.auth === true) { - if (authMethod && !CLAUDE_SUPPORTED_AUTH_METHODS.has(authMethod)) { + if (normalizedAuthMethod && !CLAUDE_CLI_AUTH_METHODS.has(normalizedAuthMethod)) { return { - status: "warning", - authStatus: "unknown", - message: `Claude authentication status reported an unsupported credential type '${authMethod}'. ${CLAUDE_AUTH_GUIDANCE}`, + status: "error", + authStatus: "unauthenticated", + message: `Claude authentication status reported unsupported credential type '${authMethod}'. ${CLAUDE_AUTH_GUIDANCE}`, }; } if (normalizedAuthMethod && CLAUDE_CLI_AUTH_METHODS.has(normalizedAuthMethod)) { return { status: "ready", authStatus: "authenticated", - message: "Claude Code CLI is ready via Claude.ai login.", + message: "Claude Code CLI is ready via `claude auth login`.", }; } - return { status: "ready", authStatus: "authenticated" }; + return { + status: "warning", + authStatus: "unknown", + message: "Could not verify Claude CLI authentication method from status output.", + }; } if (parsedAuth.auth === false) { return { status: "error", authStatus: "unauthenticated", - message: `Claude is not configured with a supported Anthropic credential. ${CLAUDE_AUTH_GUIDANCE}`, + message: `Claude Code must be authenticated with \`claude auth login\` before starting a session. ${CLAUDE_AUTH_GUIDANCE}`, }; } if (parsedAuth.attemptedJsonParse) { - if (authMethod && !CLAUDE_SUPPORTED_AUTH_METHODS.has(authMethod)) { + if (normalizedAuthMethod && !CLAUDE_CLI_AUTH_METHODS.has(normalizedAuthMethod)) { return { status: "error", authStatus: "unauthenticated", - message: `Claude authentication status reported an unsupported credential type '${authMethod}'. ${CLAUDE_AUTH_GUIDANCE}`, + message: `Claude authentication status reported unsupported credential type '${authMethod}'. ${CLAUDE_AUTH_GUIDANCE}`, }; } return { @@ -738,10 +741,6 @@ export function parseClaudeAuthStatusFromOutput(result: CommandResult): { "Could not verify Claude authentication status from JSON output (missing auth marker).", }; } - if (result.code === 0) { - return { status: "ready", authStatus: "authenticated" }; - } - const detail = detailFromResult(result); return { status: "warning", diff --git a/apps/server/src/provider/claudeAuthTokenHelper.test.ts b/apps/server/src/provider/claudeAuthTokenHelper.test.ts deleted file mode 100644 index 73da41ed..00000000 --- a/apps/server/src/provider/claudeAuthTokenHelper.test.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { describe, expect, it, vi } from "vitest"; - -import { readClaudeAuthTokenFromHelperCommand } from "./claudeAuthTokenHelper"; - -describe("readClaudeAuthTokenFromHelperCommand", () => { - it("runs the helper command through a shell and trims the token", () => { - const spawnSync = vi.fn(() => ({ - pid: 123, - output: ["", " token-from-helper \n", ""], - error: undefined, - status: 0, - signal: null, - stdout: " token-from-helper \n", - stderr: "", - })) as unknown as typeof import("node:child_process").spawnSync; - - const token = readClaudeAuthTokenFromHelperCommand("op read op://shared/anthropic/token", { - cwd: "/tmp/project", - env: { PATH: "/usr/bin" }, - platform: "linux", - spawnSync, - timeoutMs: 1234, - maxBuffer: 2048, - }); - - expect(token).toBe("token-from-helper"); - expect(spawnSync).toHaveBeenCalledWith( - "/bin/sh", - ["-lc", "op read op://shared/anthropic/token"], - expect.objectContaining({ - cwd: "/tmp/project", - encoding: "utf8", - env: { PATH: "/usr/bin" }, - maxBuffer: 2048, - timeout: 1234, - }), - ); - }); - - it("fails when the helper command exits non-zero", () => { - const spawnSync = vi.fn(() => ({ - pid: 123, - output: ["", "ignored-token\n", ""], - error: undefined, - status: 1, - signal: null, - stdout: "ignored-token\n", - stderr: "secret manager unavailable", - })) as unknown as typeof import("node:child_process").spawnSync; - - expect(() => - readClaudeAuthTokenFromHelperCommand("pass show anthropic/token", { - spawnSync, - platform: "linux", - }), - ).toThrow("secret manager unavailable"); - }); -}); diff --git a/apps/server/src/provider/claudeAuthTokenHelper.ts b/apps/server/src/provider/claudeAuthTokenHelper.ts deleted file mode 100644 index 2283e293..00000000 --- a/apps/server/src/provider/claudeAuthTokenHelper.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { spawnSync, type SpawnSyncReturns } from "node:child_process"; - -const DEFAULT_HELPER_TIMEOUT_MS = 5_000; -const DEFAULT_HELPER_MAX_BUFFER_BYTES = 64 * 1024; - -export interface ClaudeAuthTokenHelperExecutionOptions { - readonly cwd?: string; - readonly env?: NodeJS.ProcessEnv; - readonly maxBuffer?: number; - readonly platform?: NodeJS.Platform; - readonly spawnSync?: ( - command: string, - args: ReadonlyArray, - options: { - readonly cwd?: string; - readonly encoding: "utf8"; - readonly env?: NodeJS.ProcessEnv; - readonly maxBuffer: number; - readonly timeout: number; - }, - ) => SpawnSyncReturns; - readonly timeoutMs?: number; -} - -function trimSingleLineOutput(value: string): string { - const trimmed = value.trim(); - if (trimmed.length === 0) { - return ""; - } - if (trimmed.includes("\n") || trimmed.includes("\r")) { - throw new Error("Claude auth token helper command must print a single-line token."); - } - return trimmed; -} - -function shellCommandForPlatform(platform: NodeJS.Platform): { - readonly command: string; - readonly args: readonly string[]; -} { - if (platform === "win32") { - return { - command: "cmd.exe", - args: ["/d", "/s", "/c"], - }; - } - - return { - command: "/bin/sh", - args: ["-lc"], - }; -} - -function formatHelperFailureMessage(result: SpawnSyncReturns): string { - if (result.error instanceof Error) { - return result.error.message; - } - - const stderr = result.stderr.trim(); - if (stderr.length > 0) { - return stderr; - } - - if (result.status === null) { - return "Timed out while running Claude auth token helper command."; - } - - return `Claude auth token helper command exited with code ${result.status}.`; -} - -export function readClaudeAuthTokenFromHelperCommand( - helperCommand: string, - options?: ClaudeAuthTokenHelperExecutionOptions, -): string { - const command = helperCommand.trim(); - if (command.length === 0) { - throw new Error("Claude auth token helper command is empty."); - } - - const platform = options?.platform ?? process.platform; - const shell = shellCommandForPlatform(platform); - const spawn = options?.spawnSync ?? spawnSync; - const result = spawn(shell.command, [...shell.args, command], { - encoding: "utf8", - maxBuffer: options?.maxBuffer ?? DEFAULT_HELPER_MAX_BUFFER_BYTES, - timeout: options?.timeoutMs ?? DEFAULT_HELPER_TIMEOUT_MS, - ...(options?.cwd ? { cwd: options.cwd } : {}), - ...(options?.env ? { env: options.env } : {}), - }) as SpawnSyncReturns; - - if (result.error || result.status !== 0) { - throw new Error(formatHelperFailureMessage(result)); - } - - const token = trimSingleLineOutput(result.stdout); - if (token.length === 0) { - throw new Error("Claude auth token helper command returned no output."); - } - - return token; -} diff --git a/apps/server/src/sme/authValidation.ts b/apps/server/src/sme/authValidation.ts index 9d5e5bcc..2afa8ad8 100644 --- a/apps/server/src/sme/authValidation.ts +++ b/apps/server/src/sme/authValidation.ts @@ -21,7 +21,7 @@ import { const OPENAI_MODEL_PROVIDERS = new Set(["openai"]); const CLAUDE_SME_MISSING_CREDENTIALS_MESSAGE = - "Claude SME Chat uses direct Anthropic credentials, not the Claude CLI login. Set ANTHROPIC_API_KEY or ANTHROPIC_AUTH_TOKEN, or configure `authTokenHelperCommand` in Settings."; + "Claude SME Chat uses direct Anthropic credentials, not the Claude CLI login. Set ANTHROPIC_API_KEY or ANTHROPIC_AUTH_TOKEN."; export function getAllowedSmeAuthMethods(provider: ProviderKind): readonly SmeAuthMethod[] { switch (provider) { @@ -116,7 +116,7 @@ export function resolveClaudeSmeSetup(input: { ok: false, severity: "error", message: - "Claude SME Chat is set to Auth Token, but no ANTHROPIC_AUTH_TOKEN or auth token helper command is configured.", + "Claude SME Chat is set to Auth Token, but no ANTHROPIC_AUTH_TOKEN is configured.", resolvedAuthMethod: "authToken", resolvedAccountType: "unknown", }, diff --git a/apps/server/src/sme/backends/anthropic.ts b/apps/server/src/sme/backends/anthropic.ts index e9ea30c3..3d6a2e7c 100644 --- a/apps/server/src/sme/backends/anthropic.ts +++ b/apps/server/src/sme/backends/anthropic.ts @@ -3,7 +3,6 @@ import type { MessageParam } from "@anthropic-ai/sdk/resources"; import type { SmeMessageEvent } from "@okcode/contracts"; import { Effect } from "effect"; -import { readClaudeAuthTokenFromHelperCommand } from "../../provider/claudeAuthTokenHelper.ts"; import { SmeChatError } from "../Services/SmeChatService.ts"; import type { ProviderStartOptions } from "@okcode/contracts"; @@ -32,18 +31,11 @@ export function resolveAnthropicClientOptions( const env = input?.env ?? process.env; const explicitApiKey = nonEmptyTrimmed(env.ANTHROPIC_API_KEY); const explicitAuthToken = nonEmptyTrimmed(env.ANTHROPIC_AUTH_TOKEN); - const helperCommand = nonEmptyTrimmed(input?.providerOptions?.authTokenHelperCommand); - - let authToken = explicitAuthToken; - if (!authToken && helperCommand) { - authToken = readClaudeAuthTokenFromHelperCommand(helperCommand, { env }); - } - const baseURL = nonEmptyTrimmed(env.ANTHROPIC_BASE_URL ?? env.ANTHROPIC_API_BASE_URL); return { - apiKey: authToken ? null : (explicitApiKey ?? null), - authToken: authToken ?? null, + apiKey: explicitAuthToken ? null : (explicitApiKey ?? null), + authToken: explicitAuthToken ?? null, ...(baseURL ? { baseURL } : {}), }; } diff --git a/apps/web/src/appSettings.test.ts b/apps/web/src/appSettings.test.ts index 41c453d1..b65c8c1a 100644 --- a/apps/web/src/appSettings.test.ts +++ b/apps/web/src/appSettings.test.ts @@ -26,7 +26,6 @@ describe("AppSettingsSchema", () => { expect(settings.showNotificationDetails).toBe(false); expect(settings.includeDiagnosticsTipsInCopy).toBe(false); expect(settings.browserPreviewStartPageUrl).toBe(""); - expect(settings.claudeAuthTokenHelperCommand).toBe(""); }); it("defaults sidebar appearance controls", () => { @@ -64,11 +63,10 @@ describe("AppSettingsSchema", () => { }); describe("getProviderStartOptions", () => { - it("includes the Claude auth token helper command when configured", () => { + it("includes the Claude binary path when configured", () => { expect( getProviderStartOptions({ - claudeBinaryPath: "", - claudeAuthTokenHelperCommand: "op read op://shared/anthropic/token --no-newline", + claudeBinaryPath: "/usr/local/bin/claude", codexBinaryPath: "", codexHomePath: "", copilotBinaryPath: "", @@ -78,7 +76,7 @@ describe("getProviderStartOptions", () => { }), ).toEqual({ claudeAgent: { - authTokenHelperCommand: "op read op://shared/anthropic/token --no-newline", + binaryPath: "/usr/local/bin/claude", }, }); }); diff --git a/apps/web/src/appSettings.ts b/apps/web/src/appSettings.ts index 9580e6a7..23a2c50f 100644 --- a/apps/web/src/appSettings.ts +++ b/apps/web/src/appSettings.ts @@ -91,9 +91,6 @@ export const AppSettingsSchema = Schema.Struct({ claudeBinaryPath: Schema.String.check(Schema.isMaxLength(4096)).pipe(withDefaults(() => "")), copilotBinaryPath: Schema.String.check(Schema.isMaxLength(4096)).pipe(withDefaults(() => "")), copilotConfigDir: Schema.String.check(Schema.isMaxLength(4096)).pipe(withDefaults(() => "")), - claudeAuthTokenHelperCommand: Schema.String.check(Schema.isMaxLength(4096)).pipe( - withDefaults(() => ""), - ), codexBinaryPath: Schema.String.check(Schema.isMaxLength(4096)).pipe(withDefaults(() => "")), codexHomePath: Schema.String.check(Schema.isMaxLength(4096)).pipe(withDefaults(() => "")), backgroundImageUrl: Schema.String.check(Schema.isMaxLength(4096)).pipe(withDefaults(() => "")), @@ -265,7 +262,6 @@ function normalizeAppSettings(settings: AppSettings): AppSettings { ...settings, backgroundImageUrl: settings.backgroundImageUrl.trim(), browserPreviewStartPageUrl: settings.browserPreviewStartPageUrl.trim(), - claudeAuthTokenHelperCommand: settings.claudeAuthTokenHelperCommand.trim(), backgroundImageOpacity: clampBackgroundOpacity(settings.backgroundImageOpacity), sidebarOpacity: clampOpacity(settings.sidebarOpacity), sidebarProjectRowHeight: clampSidebarProjectRowHeight(settings.sidebarProjectRowHeight), @@ -389,7 +385,6 @@ export function getProviderStartOptions( | "claudeBinaryPath" | "copilotBinaryPath" | "copilotConfigDir" - | "claudeAuthTokenHelperCommand" | "codexBinaryPath" | "codexHomePath" | "openclawGatewayUrl" @@ -405,13 +400,10 @@ export function getProviderStartOptions( }, } : {}), - ...(settings.claudeBinaryPath || settings.claudeAuthTokenHelperCommand + ...(settings.claudeBinaryPath ? { claudeAgent: { - ...(settings.claudeBinaryPath ? { binaryPath: settings.claudeBinaryPath } : {}), - ...(settings.claudeAuthTokenHelperCommand - ? { authTokenHelperCommand: settings.claudeAuthTokenHelperCommand } - : {}), + binaryPath: settings.claudeBinaryPath, }, } : {}), diff --git a/apps/web/src/components/ChatView.tsx b/apps/web/src/components/ChatView.tsx index af2682c3..e9b30026 100644 --- a/apps/web/src/components/ChatView.tsx +++ b/apps/web/src/components/ChatView.tsx @@ -867,9 +867,8 @@ export default function ChatView({ threadId, onMinimize }: ChatViewProps) { getSelectableThreadProviders({ statuses: providerStatuses, openclawGatewayUrl: settings.openclawGatewayUrl, - claudeAuthTokenHelperCommand: settings.claudeAuthTokenHelperCommand, }), - [providerStatuses, settings.claudeAuthTokenHelperCommand, settings.openclawGatewayUrl], + [providerStatuses, settings.openclawGatewayUrl], ); const hasThreadStarted = Boolean( activeThread && diff --git a/apps/web/src/components/chat/ProviderSetupCard.tsx b/apps/web/src/components/chat/ProviderSetupCard.tsx index 811a0fa1..30c6e17f 100644 --- a/apps/web/src/components/chat/ProviderSetupCard.tsx +++ b/apps/web/src/components/chat/ProviderSetupCard.tsx @@ -27,9 +27,9 @@ const PROVIDER_CONFIG = { }, claudeAgent: { installCmd: "npm install -g @anthropic-ai/claude-code", - authCmd: "set ANTHROPIC_API_KEY or ANTHROPIC_AUTH_TOKEN", + authCmd: "claude auth login", verifyCmd: "claude auth status", - note: "You can also configure a Claude auth token helper command or one-click secret-manager preset in Settings.", + note: "Claude Code must be installed and signed in through the CLI before it can be used.", }, copilot: { installCmd: "npm install -g @github/copilot", diff --git a/apps/web/src/components/chat/threadError.test.ts b/apps/web/src/components/chat/threadError.test.ts index 1c0b71cf..ad1ae94b 100644 --- a/apps/web/src/components/chat/threadError.test.ts +++ b/apps/web/src/components/chat/threadError.test.ts @@ -48,7 +48,7 @@ describe("humanizeThreadError", () => { ).toBe(true); expect( isAuthenticationThreadError( - "Claude is not configured with a supported Anthropic credential. Set ANTHROPIC_API_KEY or ANTHROPIC_AUTH_TOKEN and try again.", + "Claude Code must be authenticated with `claude auth login` before starting a session. API key and auth token credentials are not supported.", ), ).toBe(true); }); @@ -81,11 +81,9 @@ describe("humanizeThreadError", () => { ).toContain("Troubleshooting:"); expect( buildThreadErrorDiagnosticsCopy( - "Claude Code is signed in with OAuth, which is not supported here. Set ANTHROPIC_API_KEY or ANTHROPIC_AUTH_TOKEN and try again.", + "Claude Code must be authenticated with `claude auth login` before starting a session. API key and auth token credentials are not supported.", { includeTips: true }, ), - ).toContain( - "Set `ANTHROPIC_API_KEY` or `ANTHROPIC_AUTH_TOKEN` in the runtime environment and retry the turn.", - ); + ).toContain("Run `claude auth login` and retry the turn."); }); }); diff --git a/apps/web/src/components/chat/threadError.ts b/apps/web/src/components/chat/threadError.ts index 27d71959..72e6398d 100644 --- a/apps/web/src/components/chat/threadError.ts +++ b/apps/web/src/components/chat/threadError.ts @@ -38,7 +38,7 @@ function extractWorktreeDetail(error: string): string | null { function getProviderLoginCommand(error: string): string | null { const lower = error.toLowerCase(); if (lower.includes("claude")) { - return "`ANTHROPIC_API_KEY` or `ANTHROPIC_AUTH_TOKEN`"; + return "`claude auth login`"; } if (lower.includes("codex")) { return "`codex login`"; diff --git a/apps/web/src/i18n/messages/en.json b/apps/web/src/i18n/messages/en.json index 389bd976..0a5aecc9 100644 --- a/apps/web/src/i18n/messages/en.json +++ b/apps/web/src/i18n/messages/en.json @@ -133,7 +133,7 @@ "settings.advanced.keybindings.opening": "Opening...", "settings.advanced.keybindings.resolvingPath": "Resolving keybindings path...", "settings.advanced.keybindings.title": "Keybindings", - "settings.advanced.providerInstalls.claude.binaryDescription": "Leave blank to use claude from your PATH. Claude Code needs ANTHROPIC_API_KEY or ANTHROPIC_AUTH_TOKEN in the runtime environment.", + "settings.advanced.providerInstalls.claude.binaryDescription": "Leave blank to use claude from your PATH. Authentication uses claude auth login.", "settings.advanced.providerInstalls.claude.binaryPathLabel": "Claude Code binary path", "settings.advanced.providerInstalls.claude.binaryPlaceholder": "Claude Code binary path", "settings.advanced.providerInstalls.codex.binaryDescription": "Leave blank to use codex from your PATH. Authentication normally uses codex login unless your Codex config points at a custom model provider.", diff --git a/apps/web/src/i18n/messages/es.json b/apps/web/src/i18n/messages/es.json index 794d8d74..52e9fea2 100644 --- a/apps/web/src/i18n/messages/es.json +++ b/apps/web/src/i18n/messages/es.json @@ -133,7 +133,7 @@ "settings.advanced.keybindings.opening": "Abriendo...", "settings.advanced.keybindings.resolvingPath": "Resolviendo la ruta de keybindings...", "settings.advanced.keybindings.title": "Atajos", - "settings.advanced.providerInstalls.claude.binaryDescription": "Déjalo vacío para usar claude desde tu PATH. Claude Code necesita ANTHROPIC_API_KEY o ANTHROPIC_AUTH_TOKEN en el entorno de ejecución.", + "settings.advanced.providerInstalls.claude.binaryDescription": "Déjalo vacío para usar claude desde tu PATH. La autenticación usa claude auth login.", "settings.advanced.providerInstalls.claude.binaryPathLabel": "Ruta del binario de Claude Code", "settings.advanced.providerInstalls.claude.binaryPlaceholder": "Ruta del binario de Claude Code", "settings.advanced.providerInstalls.codex.binaryDescription": "Déjalo vacío para usar codex desde tu PATH. La autenticación normalmente usa codex login, salvo que tu configuración de Codex apunte a un proveedor de modelos personalizado.", diff --git a/apps/web/src/i18n/messages/fr.json b/apps/web/src/i18n/messages/fr.json index 93d790ee..49e3a153 100644 --- a/apps/web/src/i18n/messages/fr.json +++ b/apps/web/src/i18n/messages/fr.json @@ -133,7 +133,7 @@ "settings.advanced.keybindings.opening": "Ouverture...", "settings.advanced.keybindings.resolvingPath": "Résolution du chemin de keybindings...", "settings.advanced.keybindings.title": "Raccourcis", - "settings.advanced.providerInstalls.claude.binaryDescription": "Laissez vide pour utiliser claude depuis votre PATH. Claude Code a besoin de ANTHROPIC_API_KEY ou ANTHROPIC_AUTH_TOKEN dans l'environnement d'exécution.", + "settings.advanced.providerInstalls.claude.binaryDescription": "Laissez vide pour utiliser claude depuis votre PATH. L'authentification utilise claude auth login.", "settings.advanced.providerInstalls.claude.binaryPathLabel": "Chemin du binaire Claude Code", "settings.advanced.providerInstalls.claude.binaryPlaceholder": "Chemin du binaire Claude Code", "settings.advanced.providerInstalls.codex.binaryDescription": "Laissez vide pour utiliser codex depuis votre PATH. L'authentification utilise normalement codex login, sauf si votre configuration Codex pointe vers un fournisseur de modèle personnalisé.", diff --git a/apps/web/src/i18n/messages/zh-CN.json b/apps/web/src/i18n/messages/zh-CN.json index c8d33010..dc2db436 100644 --- a/apps/web/src/i18n/messages/zh-CN.json +++ b/apps/web/src/i18n/messages/zh-CN.json @@ -133,7 +133,7 @@ "settings.advanced.keybindings.opening": "打开中...", "settings.advanced.keybindings.resolvingPath": "正在解析 keybindings 路径...", "settings.advanced.keybindings.title": "快捷键", - "settings.advanced.providerInstalls.claude.binaryDescription": "留空则使用 PATH 中的 claude。Claude Code 需要在运行环境中提供 ANTHROPIC_API_KEYANTHROPIC_AUTH_TOKEN。", + "settings.advanced.providerInstalls.claude.binaryDescription": "留空则使用 PATH 中的 claude。认证使用 claude auth login。", "settings.advanced.providerInstalls.claude.binaryPathLabel": "Claude Code 二进制路径", "settings.advanced.providerInstalls.claude.binaryPlaceholder": "Claude Code 二进制路径", "settings.advanced.providerInstalls.codex.binaryDescription": "留空则使用 PATH 中的 codex。认证通常使用 codex login,除非你的 Codex 配置指向了自定义模型提供方。", diff --git a/apps/web/src/lib/claudeAuthTokenHelperPresets.test.ts b/apps/web/src/lib/claudeAuthTokenHelperPresets.test.ts deleted file mode 100644 index c332685f..00000000 --- a/apps/web/src/lib/claudeAuthTokenHelperPresets.test.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { describe, expect, it } from "vitest"; - -import { CLAUDE_AUTH_TOKEN_HELPER_PRESETS } from "./claudeAuthTokenHelperPresets"; - -describe("CLAUDE_AUTH_TOKEN_HELPER_PRESETS", () => { - it("includes presets for common secret managers", () => { - expect(CLAUDE_AUTH_TOKEN_HELPER_PRESETS).toEqual([ - { - label: "1Password", - description: "Prefill an `op read` command for a 1Password secret.", - command: 'op read "op://Private/Anthropic/Claude Code/token" --no-newline', - }, - { - label: "pass", - description: "Prefill a `pass show` command for the `pass` password store.", - command: "pass show anthropic/claude-code", - }, - { - label: "Doppler", - description: "Prefill a `doppler secrets get` command for a linked project.", - command: "doppler secrets get ANTHROPIC_AUTH_TOKEN --plain", - }, - ]); - }); -}); diff --git a/apps/web/src/lib/claudeAuthTokenHelperPresets.ts b/apps/web/src/lib/claudeAuthTokenHelperPresets.ts deleted file mode 100644 index 97be2191..00000000 --- a/apps/web/src/lib/claudeAuthTokenHelperPresets.ts +++ /dev/null @@ -1,23 +0,0 @@ -export type ClaudeAuthTokenHelperPreset = { - readonly label: string; - readonly description: string; - readonly command: string; -}; - -export const CLAUDE_AUTH_TOKEN_HELPER_PRESETS: readonly ClaudeAuthTokenHelperPreset[] = [ - { - label: "1Password", - description: "Prefill an `op read` command for a 1Password secret.", - command: 'op read "op://Private/Anthropic/Claude Code/token" --no-newline', - }, - { - label: "pass", - description: "Prefill a `pass show` command for the `pass` password store.", - command: "pass show anthropic/claude-code", - }, - { - label: "Doppler", - description: "Prefill a `doppler secrets get` command for a linked project.", - command: "doppler secrets get ANTHROPIC_AUTH_TOKEN --plain", - }, -] as const; diff --git a/apps/web/src/lib/providerAvailability.test.ts b/apps/web/src/lib/providerAvailability.test.ts index af996aab..53c4fb68 100644 --- a/apps/web/src/lib/providerAvailability.test.ts +++ b/apps/web/src/lib/providerAvailability.test.ts @@ -49,16 +49,6 @@ describe("providerAvailability", () => { ).toBe(false); }); - it("allows Claude when a local auth token helper is configured", () => { - expect( - isProviderReadyForThreadSelection({ - provider: "claudeAgent", - statuses: [makeStatus("claudeAgent", { status: "error", authStatus: "unauthenticated" })], - claudeAuthTokenHelperCommand: "op read op://shared/anthropic/token --no-newline", - }), - ).toBe(true); - }); - it("treats configured OpenClaw as selectable even when server auth state is unknown", () => { expect( isProviderReadyForThreadSelection({ @@ -77,9 +67,8 @@ describe("providerAvailability", () => { makeStatus("codex"), makeStatus("claudeAgent", { status: "error", authStatus: "unauthenticated" }), ], - claudeAuthTokenHelperCommand: "op read op://shared/anthropic/token --no-newline", }), - ).toEqual(["codex", "claudeAgent", "openclaw"]); + ).toEqual(["codex", "openclaw"]); }); it("falls back to the first selectable provider when the preferred one is unavailable", () => { diff --git a/apps/web/src/lib/providerAvailability.ts b/apps/web/src/lib/providerAvailability.ts index c0d86da8..64017e8a 100644 --- a/apps/web/src/lib/providerAvailability.ts +++ b/apps/web/src/lib/providerAvailability.ts @@ -31,7 +31,6 @@ export function isProviderReadyForThreadSelection(input: { provider: ProviderKind; statuses: ReadonlyArray; openclawGatewayUrl?: string | null | undefined; - claudeAuthTokenHelperCommand?: string | null | undefined; }): boolean { const status = getProviderStatusByKind(input.statuses, input.provider); @@ -46,15 +45,6 @@ export function isProviderReadyForThreadSelection(input: { return false; } - if ( - input.provider === "claudeAgent" && - (input.claudeAuthTokenHelperCommand ?? "").trim().length > 0 && - status.available && - (status.authStatus ?? status.auth?.status) === "unauthenticated" - ) { - return true; - } - const authStatus = status.authStatus ?? status.auth?.status; return Boolean(status.available && status.status === "ready" && authStatus !== "unauthenticated"); } @@ -62,14 +52,12 @@ export function isProviderReadyForThreadSelection(input: { export function getSelectableThreadProviders(input: { statuses: ReadonlyArray; openclawGatewayUrl?: string | null | undefined; - claudeAuthTokenHelperCommand?: string | null | undefined; }): ProviderKind[] { return THREAD_PROVIDER_ORDER.filter((provider) => isProviderReadyForThreadSelection({ provider, statuses: input.statuses, openclawGatewayUrl: input.openclawGatewayUrl, - claudeAuthTokenHelperCommand: input.claudeAuthTokenHelperCommand, }), ); } diff --git a/apps/web/src/routes/_chat.settings.tsx b/apps/web/src/routes/_chat.settings.tsx index 5cc88014..85c3afc7 100644 --- a/apps/web/src/routes/_chat.settings.tsx +++ b/apps/web/src/routes/_chat.settings.tsx @@ -106,7 +106,6 @@ import { type CustomThemeData, } from "../lib/customTheme"; import { openUrlInAppBrowser } from "../lib/openUrlInAppBrowser"; -import { CLAUDE_AUTH_TOKEN_HELPER_PRESETS } from "../lib/claudeAuthTokenHelperPresets"; import { getSelectableThreadProviders, isProviderReadyForThreadSelection, @@ -361,9 +360,8 @@ const INSTALL_PROVIDER_SETTINGS: readonly InstallProviderSettings[] = [ binaryPlaceholder: "Claude Code binary path", binaryDescription: ( <> - Leave blank to use claude from your PATH. Claude Code sessions need an{" "} - ANTHROPIC_API_KEY or ANTHROPIC_AUTH_TOKEN in the runtime - environment. You can also source the token automatically with a helper command. + Leave blank to use claude from your PATH. Authentication uses{" "} + claude auth login. ), }, @@ -386,9 +384,9 @@ const PROVIDER_AUTH_GUIDES: Record< }, claudeAgent: { installCmd: "npm install -g @anthropic-ai/claude-code", - authCmd: "set ANTHROPIC_API_KEY or ANTHROPIC_AUTH_TOKEN", + authCmd: "claude auth login", verifyCmd: "claude auth status", - note: "Claude Code must be installed and configured with an Anthropic API key or auth token before it appears in the thread picker. Use Environment to add a Claude auth token in one click, or configure a helper command in the Claude install panel.", + note: "Claude Code must be installed and signed in through the CLI before it appears in the thread picker.", }, gemini: { installCmd: "npm install -g @google/gemini-cli", @@ -412,26 +410,15 @@ function getAuthenticationBadgeCopy(input: { status: ServerProviderStatus | null; provider: ProviderKind; openclawGatewayUrl: string; - hasClaudeAuthTokenHelper: boolean; }): { tone: "success" | "warning" | "error"; label: string; } { - if ( - input.provider === "claudeAgent" && - input.hasClaudeAuthTokenHelper && - input.status?.available === true && - input.status?.authStatus === "unauthenticated" - ) { - return { tone: "success", label: "Token helper configured" }; - } - if ( isProviderReadyForThreadSelection({ provider: input.provider, statuses: input.status ? [input.status] : [], openclawGatewayUrl: input.openclawGatewayUrl, - claudeAuthTokenHelperCommand: input.hasClaudeAuthTokenHelper ? "configured" : undefined, }) ) { return { tone: "success", label: "Available in thread picker" }; @@ -456,21 +443,16 @@ function AuthenticationStatusCard({ provider, status, openclawGatewayUrl, - claudeAuthTokenHelperCommand, }: { provider: ProviderKind; status: ServerProviderStatus | null; openclawGatewayUrl: string; - claudeAuthTokenHelperCommand: string; }) { const guide = PROVIDER_AUTH_GUIDES[provider]; - const hasClaudeAuthTokenHelper = - provider === "claudeAgent" && claudeAuthTokenHelperCommand.trim().length > 0; const badge = getAuthenticationBadgeCopy({ status, provider, openclawGatewayUrl, - hasClaudeAuthTokenHelper, }); const badgeClassName = badge.tone === "success" @@ -480,23 +462,13 @@ function AuthenticationStatusCard({ : "border-amber-500/25 bg-amber-500/10 text-amber-700 dark:text-amber-300"; const heading = status !== null - ? hasClaudeAuthTokenHelper && - status.provider === "claudeAgent" && - status.available && - status.authStatus === "unauthenticated" - ? "Claude Code will source its auth token automatically" - : getProviderStatusHeading(status) + ? getProviderStatusHeading(status) : provider === "openclaw" && openclawGatewayUrl.trim().length > 0 ? "OpenClaw gateway is configured locally" : `${getProviderStatusLabelName(provider)} needs configuration`; const description = status !== null - ? hasClaudeAuthTokenHelper && - status.provider === "claudeAgent" && - status.available && - status.authStatus === "unauthenticated" - ? "The configured helper command will run locally at session start and print ANTHROPIC_AUTH_TOKEN to stdout." - : getProviderStatusDescription(status) + ? getProviderStatusDescription(status) : provider === "openclaw" && openclawGatewayUrl.trim().length > 0 ? "OpenClaw is configured in local settings. Use Test Connection below to verify the gateway before starting a thread." : guide.note; @@ -832,7 +804,7 @@ function SettingsRouteView() { const [openKeybindingsError, setOpenKeybindingsError] = useState(null); const [openInstallProviders, setOpenInstallProviders] = useState>({ codex: Boolean(settings.codexBinaryPath || settings.codexHomePath), - claudeAgent: Boolean(settings.claudeBinaryPath || settings.claudeAuthTokenHelperCommand), + claudeAgent: Boolean(settings.claudeBinaryPath), gemini: false, openclaw: Boolean(settings.openclawGatewayUrl || settings.openclawPassword), copilot: Boolean(settings.copilotBinaryPath || settings.copilotConfigDir), @@ -912,11 +884,6 @@ function SettingsRouteView() { const codexBinaryPath = settings.codexBinaryPath; const codexHomePath = settings.codexHomePath; const claudeBinaryPath = settings.claudeBinaryPath; - const claudeAuthTokenHelperCommand = settings.claudeAuthTokenHelperCommand; - const selectedClaudeAuthTokenHelperPreset = - CLAUDE_AUTH_TOKEN_HELPER_PRESETS.find( - (preset) => preset.command === claudeAuthTokenHelperCommand, - )?.label ?? ""; const savedOpenclawGatewayUrl = openclawGatewayConfigQuery.data?.gatewayUrl ?? ""; const savedOpenclawHasSharedSecret = openclawGatewayConfigQuery.data?.hasSharedSecret ?? false; const effectiveOpenclawGatewayUrl = openclawGatewayDraft ?? savedOpenclawGatewayUrl; @@ -926,7 +893,6 @@ function SettingsRouteView() { const selectableProviders = getSelectableThreadProviders({ statuses: providerStatuses, openclawGatewayUrl: effectiveOpenclawGatewayUrl, - claudeAuthTokenHelperCommand: settings.claudeAuthTokenHelperCommand, }); const canImportLegacyOpenclawSettings = openclawGatewayConfigQuery.isSuccess && @@ -967,7 +933,6 @@ function SettingsRouteView() { : savedCustomModelRows.slice(0, 5); const isInstallSettingsDirty = settings.claudeBinaryPath !== defaults.claudeBinaryPath || - settings.claudeAuthTokenHelperCommand !== defaults.claudeAuthTokenHelperCommand || settings.codexBinaryPath !== defaults.codexBinaryPath || settings.codexHomePath !== defaults.codexHomePath; const isOpenClawSettingsDirty = @@ -2652,7 +2617,6 @@ function SettingsRouteView() { null } openclawGatewayUrl={effectiveOpenclawGatewayUrl} - claudeAuthTokenHelperCommand={settings.claudeAuthTokenHelperCommand} /> ))}
@@ -2669,7 +2633,6 @@ function SettingsRouteView() { onClick={() => { updateSettings({ claudeBinaryPath: defaults.claudeBinaryPath, - claudeAuthTokenHelperCommand: defaults.claudeAuthTokenHelperCommand, codexBinaryPath: defaults.codexBinaryPath, codexHomePath: defaults.codexHomePath, }); @@ -2693,9 +2656,7 @@ function SettingsRouteView() { providerSettings.provider === "codex" ? settings.codexBinaryPath !== defaults.codexBinaryPath || settings.codexHomePath !== defaults.codexHomePath - : settings.claudeBinaryPath !== defaults.claudeBinaryPath || - settings.claudeAuthTokenHelperCommand !== - defaults.claudeAuthTokenHelperCommand; + : settings.claudeBinaryPath !== defaults.claudeBinaryPath; const binaryPathValue = providerSettings.binaryPathKey === "claudeBinaryPath" ? claudeBinaryPath @@ -2769,85 +2730,6 @@ function SettingsRouteView() { {providerSettings.binaryDescription} - - {providerSettings.provider === "claudeAgent" ? ( - - ) : null} - {providerSettings.homePathKey ? (