UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

198 lines (197 loc) 8.87 kB
import { D as resolveExpiresAtMsFromDurationMs } from "../../number-coercion-CLj0HTDM.js"; import { t as formatCliCommand } from "../../command-format-C7YfyMTd.js"; import { t as parseDurationMs } from "../../parse-duration-CuuCHKpt.js"; import { f as upsertAuthProfileWithLockOrThrow } from "../../profiles-DOTqXcYA.js"; import { n as listProfilesForProvider } from "../../profile-list-DyfWX-d2.js"; import { n as suggestOAuthProfileIdForLegacyDefault } from "../../repair-DXThsgJF.js"; import "../../provider-auth-BeZ7NZUU.js"; import { n as validateAnthropicSetupToken, t as buildTokenProfileId } from "../../provider-auth-token-BocDZcXC.js"; import { t as applyAuthProfileConfig } from "../../provider-auth-helpers-CaYTVMoC.js"; import "../../number-runtime-Cy4drVnh.js"; import "../../cli-runtime-DrESLPXg.js"; import "../../provider-auth-api-key-DSeBB_JQ.js"; import { t as buildAnthropicCliBackend } from "../../cli-backend-DnKWkDNh.js"; import { t as probeClaudeCliAuthStatus } from "../../cli-auth-seam-DnRSnbNO.js"; import { t as buildAnthropicCliMigrationResult } from "../../cli-migration-DgRXVL76.js"; //#region extensions/anthropic/auth.runtime.ts /** Auth execution stays deferred until a setup or doctor hook is invoked. */ const PROVIDER_ID = "anthropic"; const ANTHROPIC_SETUP_TOKEN_NOTE_LINES = [ "Anthropic setup-token auth is supported in OpenClaw.", "OpenClaw prefers the native Claude CLI runtime when it is available on the host.", "Anthropic staff told us this OpenClaw path is allowed again.", `If you want a direct API billing path instead, use ${formatCliCommand("openclaw models auth login --provider anthropic --method api-key --set-default")} or ${formatCliCommand("openclaw models auth login --provider anthropic --method cli --set-default")}.` ]; function normalizeAnthropicSetupTokenInput(value) { return value.replaceAll(/\s+/g, "").trim(); } function resolveAnthropicSetupTokenProfileId(rawProfileId) { if (typeof rawProfileId === "string") { const trimmed = rawProfileId.trim(); if (trimmed.length > 0) { if (trimmed.startsWith(`${PROVIDER_ID}:`)) return trimmed; return buildTokenProfileId({ provider: PROVIDER_ID, name: trimmed }); } } return `${PROVIDER_ID}:default`; } function resolveAnthropicSetupTokenExpiry(rawExpiresIn) { if (typeof rawExpiresIn !== "string" || rawExpiresIn.trim().length === 0) return; return resolveExpiresAtMsFromDurationMs(parseDurationMs(rawExpiresIn.trim(), { defaultUnit: "d" })); } async function runAnthropicSetupTokenAuth(ctx, defaultModel) { const token = (typeof ctx.opts?.token === "string" && ctx.opts.token.trim().length > 0 ? normalizeAnthropicSetupTokenInput(ctx.opts.token) : void 0) ?? normalizeAnthropicSetupTokenInput(await ctx.prompter.text({ message: "Paste Anthropic setup-token", validate: (value) => validateAnthropicSetupToken(normalizeAnthropicSetupTokenInput(value)) })); const tokenError = validateAnthropicSetupToken(token); if (tokenError) throw new Error(tokenError); const profileId = resolveAnthropicSetupTokenProfileId(ctx.opts?.tokenProfileId); const expires = resolveAnthropicSetupTokenExpiry(ctx.opts?.tokenExpiresIn); return { profiles: [{ profileId, credential: { type: "token", provider: PROVIDER_ID, token, ...expires ? { expires } : {} } }], defaultModel, notes: [...ANTHROPIC_SETUP_TOKEN_NOTE_LINES] }; } function validateAnthropicSetupTokenNonInteractive(ctx) { if (ctx.opts.secretInputMode === "ref") { ctx.runtime.error("Anthropic setup-token input cannot be stored with --secret-input-mode ref. Use --secret-input-mode plaintext."); ctx.runtime.exit(1); return null; } const rawToken = typeof ctx.opts.token === "string" ? normalizeAnthropicSetupTokenInput(ctx.opts.token) : ""; const tokenError = validateAnthropicSetupToken(rawToken); if (tokenError) { ctx.runtime.error(["Anthropic setup-token auth requires --token with a valid setup-token.", tokenError].join("\n")); ctx.runtime.exit(1); return null; } try { resolveAnthropicSetupTokenExpiry(ctx.opts.tokenExpiresIn); } catch (error) { ctx.runtime.error(`Invalid --token-expires-in: ${error instanceof Error ? error.message : String(error)}`); ctx.runtime.exit(1); return null; } return rawToken; } async function runAnthropicSetupTokenNonInteractive(ctx, defaultModel) { const rawToken = validateAnthropicSetupTokenNonInteractive(ctx); if (!rawToken) return null; const profileId = resolveAnthropicSetupTokenProfileId(ctx.opts.tokenProfileId); const expires = resolveAnthropicSetupTokenExpiry(ctx.opts.tokenExpiresIn); await upsertAuthProfileWithLockOrThrow({ profileId, credential: { type: "token", provider: PROVIDER_ID, token: rawToken, ...expires ? { expires } : {} }, agentDir: ctx.agentDir }); ctx.runtime.log(ANTHROPIC_SETUP_TOKEN_NOTE_LINES[0]); ctx.runtime.log(ANTHROPIC_SETUP_TOKEN_NOTE_LINES[1]); const withProfile = applyAuthProfileConfig(ctx.config, { profileId, provider: PROVIDER_ID, mode: "token" }); const existingModelConfig = withProfile.agents?.defaults?.model && typeof withProfile.agents.defaults.model === "object" ? withProfile.agents.defaults.model : {}; return { ...withProfile, agents: { ...withProfile.agents, defaults: { ...withProfile.agents?.defaults, model: { ...existingModelConfig, primary: defaultModel } } } }; } function buildAnthropicAuthDoctorHint(params) { const legacyProfileId = params.profileId ?? "anthropic:default"; const suggested = suggestOAuthProfileIdForLegacyDefault({ cfg: params.config, store: params.store, provider: PROVIDER_ID, legacyProfileId }); if (!suggested || suggested === legacyProfileId) return ""; const storeOauthProfiles = listProfilesForProvider(params.store, PROVIDER_ID).filter((id) => params.store.profiles[id]?.type === "oauth").join(", "); const cfgMode = params.config?.auth?.profiles?.[legacyProfileId]?.mode; const cfgProvider = params.config?.auth?.profiles?.[legacyProfileId]?.provider; return [ "Doctor hint (for GitHub issue):", `- provider: ${PROVIDER_ID}`, `- config: ${legacyProfileId}${cfgProvider || cfgMode ? ` (provider=${cfgProvider ?? "?"}, mode=${cfgMode ?? "?"})` : ""}`, `- auth store oauth profiles: ${storeOauthProfiles || "(none)"}`, `- suggested profile: ${suggested}`, `Fix: run "${formatCliCommand("openclaw doctor --yes")}"` ].join("\n"); } async function runAnthropicCliMigration(ctx) { if ((await probeClaudeCliAuthStatus(resolveAnthropicCliAuthProbe(ctx.env ?? process.env))).status !== "available") throw new Error(["Claude CLI is not authenticated on this host.", `Run ${formatCliCommand("claude auth login")} first, then re-run this setup.`].join("\n")); return buildAnthropicCliMigrationResult(ctx.config); } async function runAnthropicCliMigrationNonInteractive(ctx) { const authStatus = await probeClaudeCliAuthStatus(resolveAnthropicCliAuthProbe(process.env)); if (authStatus.status !== "available") { const error = authStatus.status === "unreadable" ? ["Auth choice \"anthropic-cli\" could not verify the installed Claude CLI login.", `Run ${formatCliCommand("claude auth status")}, then retry.`] : ["Auth choice \"anthropic-cli\" requires Claude CLI auth on this host.", `Run ${formatCliCommand("claude auth login")} first.`]; ctx.runtime.error(error.join("\n")); ctx.runtime.exit(1); return null; } const result = buildAnthropicCliMigrationResult(ctx.config); const currentDefaults = ctx.config.agents?.defaults; const currentModel = currentDefaults?.model; const currentFallbacks = currentModel && typeof currentModel === "object" && "fallbacks" in currentModel ? currentModel.fallbacks : void 0; const migratedModel = result.configPatch?.agents?.defaults?.model; const migratedFallbacks = migratedModel && typeof migratedModel === "object" && "fallbacks" in migratedModel ? migratedModel.fallbacks : void 0; const nextFallbacks = Array.isArray(migratedFallbacks) ? migratedFallbacks : currentFallbacks; return { ...ctx.config, ...result.configPatch, agents: { ...ctx.config.agents, ...result.configPatch?.agents, defaults: { ...currentDefaults, ...result.configPatch?.agents?.defaults, model: { ...Array.isArray(nextFallbacks) ? { fallbacks: nextFallbacks } : {}, primary: result.defaultModel } } } }; } function resolveAnthropicCliAuthProbe(env) { const backend = buildAnthropicCliBackend().config; const probeEnv = { ...env, ...backend.env }; for (const name of backend.clearEnv ?? []) delete probeEnv[name]; return { command: backend.command, env: probeEnv }; } //#endregion export { buildAnthropicAuthDoctorHint, runAnthropicCliMigration, runAnthropicCliMigrationNonInteractive, runAnthropicSetupTokenAuth, runAnthropicSetupTokenNonInteractive, validateAnthropicSetupTokenNonInteractive };