UNPKG

@gguf/claw

Version:

WhatsApp gateway CLI (Baileys web) with Pi RPC agent

1,444 lines (1,434 loc) 115 kB
import { C as buildAllowedModelSet, K as VENICE_DEFAULT_MODEL_REF, M as resolveAllowlistModelKey, N as resolveConfiguredModelRef, O as modelKey, S as resolveOpenClawAgentDir, T as buildModelAliasIndex, X as SYNTHETIC_DEFAULT_MODEL_REF, _ as ensureAuthProfileStore, _t as DEFAULT_PROVIDER, c as CHUTES_AUTHORIZE_ENDPOINT, d as parseOAuthCallbackInput, et as getCustomProviderApiKey, ft as CLOUDFLARE_AI_GATEWAY_DEFAULT_MODEL_REF, g as upsertAuthProfile, gt as DEFAULT_MODEL, it as resolveEnvApiKey, k as normalizeProviderId, l as exchangeChutesCodeForTokens, n as resolveAuthProfileOrder, p as listProfilesForProvider, u as generateChutesPkce } from "./auth-profiles-CYBuGiBb.js"; import { t as formatCliCommand } from "./command-format-ayFsmwwz.js"; import { d as resolveConfigDir, m as resolveUserPath, o as ensureDir, t as CONFIG_DIR } from "./utils-DX85MiPR.js"; import { t as runCommandWithTimeout } from "./exec-B8JKbXKW.js"; import { a as resolveAgentModelPrimary, c as resolveDefaultAgentId, r as resolveAgentDir, s as resolveAgentWorkspaceDir, w as resolveDefaultAgentWorkspaceDir } from "./agent-scope-C9VjJXEK.js"; import { t as resolveBrewExecutable } from "./brew-CcZV0dSS.js"; import { Kt as loadModelCatalog, m as openUrl, o as detectBinary, y as resolveNodeManagerOptions } from "./loader-_Pj-TZS2.js"; import { a as enablePluginInConfig } from "./onboard-channels-D-ZQTy5V.js"; import { t as scanDirectoryWithSummary } from "./skill-scanner-Bp1D9gra.js"; import { R as fetchWithSsrFGuard } from "./deliver-Cau4HL7W.js"; import { _ as resolveSkillKey, d as hasBinary, i as loadWorkspaceSkillEntries, t as resolveSkillsInstallPreferences } from "./skills-CmU0Q92f.js"; import { n as resolveWideAreaDiscoveryDomain } from "./widearea-dns-CsSylzXH.js"; import { $ as setVeniceApiKey, A as applySyntheticProviderConfig, B as OPENROUTER_DEFAULT_MODEL_REF, C as applyMoonshotConfig, D as applyOpenrouterConfig, E as applyMoonshotProviderConfigCn, F as applyXaiConfig, G as setCloudflareAiGatewayConfig, H as XIAOMI_DEFAULT_MODEL_REF, I as applyXaiProviderConfig, J as setMinimaxApiKey, K as setGeminiApiKey, L as applyXiaomiConfig, M as applyVeniceProviderConfig, N as applyVercelAiGatewayConfig, O as applyOpenrouterProviderConfig, P as applyVercelAiGatewayProviderConfig, Q as setSyntheticApiKey, R as applyXiaomiProviderConfig, S as applyKimiCodeProviderConfig, T as applyMoonshotProviderConfig, U as ZAI_DEFAULT_MODEL_REF, V as VERCEL_AI_GATEWAY_DEFAULT_MODEL_REF, W as setAnthropicApiKey, X as setOpencodeZenApiKey, Y as setMoonshotApiKey, Z as setOpenrouterApiKey, _ as applyMinimaxProviderConfig, at as KIMI_CODING_MODEL_REF, b as applyCloudflareAiGatewayProviderConfig, ct as buildTokenProfileId, d as resolvePluginProviders, et as setVercelAiGatewayApiKey, f as applyOpencodeZenConfig, g as applyMinimaxConfig, h as applyMinimaxApiProviderConfig, i as formatTokenK, it as writeOAuthCredentials, j as applyVeniceConfig, k as applySyntheticConfig, l as createVpsAwareOAuthHandlers, lt as validateAnthropicSetupToken, m as applyMinimaxApiConfig, nt as setXiaomiApiKey, ot as MOONSHOT_DEFAULT_MODEL_REF, p as applyOpencodeZenProviderConfig, q as setKimiCodingApiKey, rt as setZaiApiKey, st as XAI_DEFAULT_MODEL_REF, t as githubCopilotLoginCommand, tt as setXaiApiKey, u as isRemoteEnvironment, v as applyAuthProfileConfig, w as applyMoonshotConfigCn, x as applyKimiCodeConfig, y as applyCloudflareAiGatewayConfig, z as applyZaiConfig } from "./github-copilot-auth-B_lK1g__.js"; import { t as buildWorkspaceSkillStatus } from "./skills-status-DtXrj3fy.js"; import path from "node:path"; import fs from "node:fs"; import { loginOpenAICodex } from "@mariozechner/pi-ai"; import { randomBytes } from "node:crypto"; import { createServer } from "node:http"; import { Readable } from "node:stream"; import { pipeline } from "node:stream/promises"; //#region src/infra/bonjour-discovery.ts const DEFAULT_TIMEOUT_MS = 2e3; const GATEWAY_SERVICE_TYPE = "_openclaw-gw._tcp"; function decodeDnsSdEscapes(value) { let decoded = false; const bytes = []; let pending = ""; const flush = () => { if (!pending) return; bytes.push(...Buffer.from(pending, "utf8")); pending = ""; }; for (let i = 0; i < value.length; i += 1) { const ch = value[i] ?? ""; if (ch === "\\" && i + 3 < value.length) { const escaped = value.slice(i + 1, i + 4); if (/^[0-9]{3}$/.test(escaped)) { const byte = Number.parseInt(escaped, 10); if (!Number.isFinite(byte) || byte < 0 || byte > 255) { pending += ch; continue; } flush(); bytes.push(byte); decoded = true; i += 3; continue; } } pending += ch; } if (!decoded) return value; flush(); return Buffer.from(bytes).toString("utf8"); } function isTailnetIPv4(address) { const parts = address.split("."); if (parts.length !== 4) return false; const octets = parts.map((p) => Number.parseInt(p, 10)); if (octets.some((n) => !Number.isFinite(n) || n < 0 || n > 255)) return false; const [a, b] = octets; return a === 100 && b >= 64 && b <= 127; } function parseDigShortLines(stdout) { return stdout.split("\n").map((l) => l.trim()).filter(Boolean); } function parseDigTxt(stdout) { const tokens = []; for (const raw of stdout.split("\n")) { const line = raw.trim(); if (!line) continue; const matches = Array.from(line.matchAll(/"([^"]*)"/g), (m) => m[1] ?? ""); for (const m of matches) { const unescaped = m.replaceAll("\\\\", "\\").replaceAll("\\\"", "\"").replaceAll("\\n", "\n"); tokens.push(unescaped); } } return tokens; } function parseDigSrv(stdout) { const line = stdout.split("\n").map((l) => l.trim()).find(Boolean); if (!line) return null; const parts = line.split(/\s+/).filter(Boolean); if (parts.length < 4) return null; const port = Number.parseInt(parts[2] ?? "", 10); const hostRaw = parts[3] ?? ""; if (!Number.isFinite(port) || port <= 0) return null; const host = hostRaw.replace(/\.$/, ""); if (!host) return null; return { host, port }; } function parseTailscaleStatusIPv4s(stdout) { const parsed = stdout ? JSON.parse(stdout) : {}; const out = []; const addIps = (value) => { if (!value || typeof value !== "object") return; const ips = value.TailscaleIPs; if (!Array.isArray(ips)) return; for (const ip of ips) { if (typeof ip !== "string") continue; const trimmed = ip.trim(); if (trimmed && isTailnetIPv4(trimmed)) out.push(trimmed); } }; addIps(parsed.Self); const peerObj = parsed.Peer; if (peerObj && typeof peerObj === "object") for (const peer of Object.values(peerObj)) addIps(peer); return [...new Set(out)]; } function parseIntOrNull(value) { if (!value) return; const parsed = Number.parseInt(value, 10); return Number.isFinite(parsed) ? parsed : void 0; } function parseTxtTokens(tokens) { const txt = {}; for (const token of tokens) { const idx = token.indexOf("="); if (idx <= 0) continue; const key = token.slice(0, idx).trim(); const value = decodeDnsSdEscapes(token.slice(idx + 1).trim()); if (!key) continue; txt[key] = value; } return txt; } function parseDnsSdBrowse(stdout) { const instances = /* @__PURE__ */ new Set(); for (const raw of stdout.split("\n")) { const line = raw.trim(); if (!line || !line.includes(GATEWAY_SERVICE_TYPE)) continue; if (!line.includes("Add")) continue; const match = line.match(/_openclaw-gw\._tcp\.?\s+(.+)$/); if (match?.[1]) instances.add(decodeDnsSdEscapes(match[1].trim())); } return Array.from(instances.values()); } function parseDnsSdResolve(stdout, instanceName) { const decodedInstanceName = decodeDnsSdEscapes(instanceName); const beacon = { instanceName: decodedInstanceName }; let txt = {}; for (const raw of stdout.split("\n")) { const line = raw.trim(); if (!line) continue; if (line.includes("can be reached at")) { const match = line.match(/can be reached at\s+([^\s:]+):(\d+)/i); if (match?.[1]) beacon.host = match[1].replace(/\.$/, ""); if (match?.[2]) beacon.port = parseIntOrNull(match[2]); continue; } if (line.startsWith("txt") || line.includes("txtvers=")) txt = parseTxtTokens(line.split(/\s+/).filter(Boolean)); } beacon.txt = Object.keys(txt).length ? txt : void 0; if (txt.displayName) beacon.displayName = decodeDnsSdEscapes(txt.displayName); if (txt.lanHost) beacon.lanHost = txt.lanHost; if (txt.tailnetDns) beacon.tailnetDns = txt.tailnetDns; if (txt.cliPath) beacon.cliPath = txt.cliPath; beacon.gatewayPort = parseIntOrNull(txt.gatewayPort); beacon.sshPort = parseIntOrNull(txt.sshPort); if (txt.gatewayTls) { const raw = txt.gatewayTls.trim().toLowerCase(); beacon.gatewayTls = raw === "1" || raw === "true" || raw === "yes"; } if (txt.gatewayTlsSha256) beacon.gatewayTlsFingerprintSha256 = txt.gatewayTlsSha256; if (txt.role) beacon.role = txt.role; if (txt.transport) beacon.transport = txt.transport; if (!beacon.displayName) beacon.displayName = decodedInstanceName; return beacon; } async function discoverViaDnsSd(domain, timeoutMs, run) { const instances = parseDnsSdBrowse((await run([ "dns-sd", "-B", GATEWAY_SERVICE_TYPE, domain ], { timeoutMs })).stdout); const results = []; for (const instance of instances) { const parsed = parseDnsSdResolve((await run([ "dns-sd", "-L", instance, GATEWAY_SERVICE_TYPE, domain ], { timeoutMs })).stdout, instance); if (parsed) results.push({ ...parsed, domain }); } return results; } async function discoverWideAreaViaTailnetDns(domain, timeoutMs, run) { if (!domain || domain === "local.") return []; const startedAt = Date.now(); const remainingMs = () => timeoutMs - (Date.now() - startedAt); const tailscaleCandidates = ["tailscale", "/Applications/Tailscale.app/Contents/MacOS/Tailscale"]; let ips = []; for (const candidate of tailscaleCandidates) try { ips = parseTailscaleStatusIPv4s((await run([ candidate, "status", "--json" ], { timeoutMs: Math.max(1, Math.min(700, remainingMs())) })).stdout); if (ips.length > 0) break; } catch {} if (ips.length === 0) return []; if (remainingMs() <= 0) return []; ips = ips.slice(0, 40); const probeName = `${GATEWAY_SERVICE_TYPE}.${domain.replace(/\.$/, "")}`; const concurrency = 6; let nextIndex = 0; let nameserver = null; let ptrs = []; const worker = async () => { while (nameserver === null) { const budget = remainingMs(); if (budget <= 0) return; const i = nextIndex; nextIndex += 1; if (i >= ips.length) return; const ip = ips[i] ?? ""; if (!ip) continue; try { const lines = parseDigShortLines((await run([ "dig", "+short", "+time=1", "+tries=1", `@${ip}`, probeName, "PTR" ], { timeoutMs: Math.max(1, Math.min(250, budget)) })).stdout); if (lines.length === 0) continue; nameserver = ip; ptrs = lines; return; } catch {} } }; await Promise.all(Array.from({ length: Math.min(concurrency, ips.length) }, () => worker())); if (!nameserver || ptrs.length === 0) return []; if (remainingMs() <= 0) return []; const nameserverArg = `@${String(nameserver)}`; const results = []; for (const ptr of ptrs) { const budget = remainingMs(); if (budget <= 0) break; const ptrName = ptr.trim().replace(/\.$/, ""); if (!ptrName) continue; const instanceName = ptrName.replace(/\.?_openclaw-gw\._tcp\..*$/, ""); const srv = await run([ "dig", "+short", "+time=1", "+tries=1", nameserverArg, ptrName, "SRV" ], { timeoutMs: Math.max(1, Math.min(350, budget)) }).catch(() => null); const srvParsed = srv ? parseDigSrv(srv.stdout) : null; if (!srvParsed) continue; const txtBudget = remainingMs(); if (txtBudget <= 0) { results.push({ instanceName: instanceName || ptrName, displayName: instanceName || ptrName, domain, host: srvParsed.host, port: srvParsed.port }); continue; } const txt = await run([ "dig", "+short", "+time=1", "+tries=1", nameserverArg, ptrName, "TXT" ], { timeoutMs: Math.max(1, Math.min(350, txtBudget)) }).catch(() => null); const txtTokens = txt ? parseDigTxt(txt.stdout) : []; const txtMap = txtTokens.length > 0 ? parseTxtTokens(txtTokens) : {}; const beacon = { instanceName: instanceName || ptrName, displayName: txtMap.displayName || instanceName || ptrName, domain, host: srvParsed.host, port: srvParsed.port, txt: Object.keys(txtMap).length ? txtMap : void 0, gatewayPort: parseIntOrNull(txtMap.gatewayPort), sshPort: parseIntOrNull(txtMap.sshPort), tailnetDns: txtMap.tailnetDns || void 0, cliPath: txtMap.cliPath || void 0 }; if (txtMap.gatewayTls) { const raw = txtMap.gatewayTls.trim().toLowerCase(); beacon.gatewayTls = raw === "1" || raw === "true" || raw === "yes"; } if (txtMap.gatewayTlsSha256) beacon.gatewayTlsFingerprintSha256 = txtMap.gatewayTlsSha256; if (txtMap.role) beacon.role = txtMap.role; if (txtMap.transport) beacon.transport = txtMap.transport; results.push(beacon); } return results; } function parseAvahiBrowse(stdout) { const results = []; let current = null; for (const raw of stdout.split("\n")) { const line = raw.trimEnd(); if (!line) continue; if (line.startsWith("=") && line.includes(GATEWAY_SERVICE_TYPE)) { if (current) results.push(current); const marker = ` ${GATEWAY_SERVICE_TYPE}`; const idx = line.indexOf(marker); const left = idx >= 0 ? line.slice(0, idx).trim() : line; const parts = left.split(/\s+/); const instanceName = parts.length > 3 ? parts.slice(3).join(" ") : left; current = { instanceName, displayName: instanceName }; continue; } if (!current) continue; const trimmed = line.trim(); if (trimmed.startsWith("hostname =")) { const match = trimmed.match(/hostname\s*=\s*\[([^\]]+)\]/); if (match?.[1]) current.host = match[1]; continue; } if (trimmed.startsWith("port =")) { const match = trimmed.match(/port\s*=\s*\[(\d+)\]/); if (match?.[1]) current.port = parseIntOrNull(match[1]); continue; } if (trimmed.startsWith("txt =")) { const txt = parseTxtTokens(Array.from(trimmed.matchAll(/"([^"]*)"/g), (m) => m[1])); current.txt = Object.keys(txt).length ? txt : void 0; if (txt.displayName) current.displayName = txt.displayName; if (txt.lanHost) current.lanHost = txt.lanHost; if (txt.tailnetDns) current.tailnetDns = txt.tailnetDns; if (txt.cliPath) current.cliPath = txt.cliPath; current.gatewayPort = parseIntOrNull(txt.gatewayPort); current.sshPort = parseIntOrNull(txt.sshPort); if (txt.gatewayTls) { const raw = txt.gatewayTls.trim().toLowerCase(); current.gatewayTls = raw === "1" || raw === "true" || raw === "yes"; } if (txt.gatewayTlsSha256) current.gatewayTlsFingerprintSha256 = txt.gatewayTlsSha256; if (txt.role) current.role = txt.role; if (txt.transport) current.transport = txt.transport; } } if (current) results.push(current); return results; } async function discoverViaAvahi(domain, timeoutMs, run) { const args = [ "avahi-browse", "-rt", GATEWAY_SERVICE_TYPE ]; if (domain && domain !== "local.") args.push("-d", domain.replace(/\.$/, "")); return parseAvahiBrowse((await run(args, { timeoutMs })).stdout).map((beacon) => ({ ...beacon, domain })); } async function discoverGatewayBeacons(opts = {}) { const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS; const platform = opts.platform ?? process.platform; const run = opts.run ?? runCommandWithTimeout; const wideAreaDomain = resolveWideAreaDiscoveryDomain({ configDomain: opts.wideAreaDomain }); const domainsRaw = Array.isArray(opts.domains) ? opts.domains : []; const defaultDomains = ["local.", ...wideAreaDomain ? [wideAreaDomain] : []]; const domains = (domainsRaw.length > 0 ? domainsRaw : defaultDomains).map((d) => String(d).trim()).filter(Boolean).map((d) => d.endsWith(".") ? d : `${d}.`); try { if (platform === "darwin") { const discovered = (await Promise.allSettled(domains.map(async (domain) => await discoverViaDnsSd(domain, timeoutMs, run)))).flatMap((r) => r.status === "fulfilled" ? r.value : []); const wantsWideArea = wideAreaDomain ? domains.includes(wideAreaDomain) : false; const hasWideArea = wideAreaDomain ? discovered.some((b) => b.domain === wideAreaDomain) : false; if (wantsWideArea && !hasWideArea && wideAreaDomain) { const fallback = await discoverWideAreaViaTailnetDns(wideAreaDomain, timeoutMs, run).catch(() => []); return [...discovered, ...fallback]; } return discovered; } if (platform === "linux") return (await Promise.allSettled(domains.map(async (domain) => await discoverViaAvahi(domain, timeoutMs, run)))).flatMap((r) => r.status === "fulfilled" ? r.value : []); } catch { return []; } return []; } //#endregion //#region src/commands/auth-choice-options.ts const AUTH_CHOICE_GROUP_DEFS = [ { value: "xai", label: "xAI (Grok)", hint: "API key", choices: ["xai-api-key"] }, { value: "openai", label: "OpenAI", hint: "Codex OAuth + API key", choices: ["openai-codex", "openai-api-key"] }, { value: "anthropic", label: "Anthropic", hint: "setup-token + API key", choices: ["token", "apiKey"] }, { value: "minimax", label: "MiniMax", hint: "M2.1 (recommended)", choices: [ "minimax-portal", "minimax-api", "minimax-api-lightning" ] }, { value: "moonshot", label: "Moonshot AI (Kimi K2.5)", hint: "Kimi K2.5 + Kimi Coding", choices: [ "moonshot-api-key", "moonshot-api-key-cn", "kimi-code-api-key" ] }, { value: "google", label: "Google", hint: "Gemini API key + OAuth", choices: [ "gemini-api-key", "google-antigravity", "google-gemini-cli" ] }, { value: "openrouter", label: "OpenRouter", hint: "API key", choices: ["openrouter-api-key"] }, { value: "qwen", label: "Qwen", hint: "OAuth", choices: ["qwen-portal"] }, { value: "zai", label: "Z.AI (GLM 4.7)", hint: "API key", choices: ["zai-api-key"] }, { value: "copilot", label: "Copilot", hint: "GitHub + local proxy", choices: ["github-copilot", "copilot-proxy"] }, { value: "ai-gateway", label: "Vercel AI Gateway", hint: "API key", choices: ["ai-gateway-api-key"] }, { value: "opencode-zen", label: "OpenCode Zen", hint: "API key", choices: ["opencode-zen"] }, { value: "xiaomi", label: "Xiaomi", hint: "API key", choices: ["xiaomi-api-key"] }, { value: "synthetic", label: "Synthetic", hint: "Anthropic-compatible (multi-model)", choices: ["synthetic-api-key"] }, { value: "venice", label: "Venice AI", hint: "Privacy-focused (uncensored models)", choices: ["venice-api-key"] }, { value: "cloudflare-ai-gateway", label: "Cloudflare AI Gateway", hint: "Account ID + Gateway ID + API key", choices: ["cloudflare-ai-gateway-api-key"] } ]; function buildAuthChoiceOptions(params) { params.store; const options = []; options.push({ value: "token", label: "Anthropic token (paste setup-token)", hint: "run `claude setup-token` elsewhere, then paste the token here" }); options.push({ value: "openai-codex", label: "OpenAI Codex (ChatGPT OAuth)" }); options.push({ value: "chutes", label: "Chutes (OAuth)" }); options.push({ value: "openai-api-key", label: "OpenAI API key" }); options.push({ value: "openrouter-api-key", label: "OpenRouter API key" }); options.push({ value: "xai-api-key", label: "xAI (Grok) API key" }); options.push({ value: "ai-gateway-api-key", label: "Vercel AI Gateway API key" }); options.push({ value: "cloudflare-ai-gateway-api-key", label: "Cloudflare AI Gateway", hint: "Account ID + Gateway ID + API key" }); options.push({ value: "moonshot-api-key", label: "Kimi API key (.ai)" }); options.push({ value: "moonshot-api-key-cn", label: "Kimi API key (.cn)" }); options.push({ value: "kimi-code-api-key", label: "Kimi Code API key (subscription)" }); options.push({ value: "synthetic-api-key", label: "Synthetic API key" }); options.push({ value: "venice-api-key", label: "Venice AI API key", hint: "Privacy-focused inference (uncensored models)" }); options.push({ value: "github-copilot", label: "GitHub Copilot (GitHub device login)", hint: "Uses GitHub device flow" }); options.push({ value: "gemini-api-key", label: "Google Gemini API key" }); options.push({ value: "google-antigravity", label: "Google Antigravity OAuth", hint: "Uses the bundled Antigravity auth plugin" }); options.push({ value: "google-gemini-cli", label: "Google Gemini CLI OAuth", hint: "Uses the bundled Gemini CLI auth plugin" }); options.push({ value: "zai-api-key", label: "Z.AI (GLM 4.7) API key" }); options.push({ value: "xiaomi-api-key", label: "Xiaomi API key" }); options.push({ value: "minimax-portal", label: "MiniMax OAuth", hint: "Oauth plugin for MiniMax" }); options.push({ value: "qwen-portal", label: "Qwen OAuth" }); options.push({ value: "copilot-proxy", label: "Copilot Proxy (local)", hint: "Local proxy for VS Code Copilot models" }); options.push({ value: "apiKey", label: "Anthropic API key" }); options.push({ value: "opencode-zen", label: "OpenCode Zen (multi-model proxy)", hint: "Claude, GPT, Gemini via opencode.ai/zen" }); options.push({ value: "minimax-api", label: "MiniMax M2.1" }); options.push({ value: "minimax-api-lightning", label: "MiniMax M2.1 Lightning", hint: "Faster, higher output cost" }); if (params.includeSkip) options.push({ value: "skip", label: "Skip for now" }); return options; } function buildAuthChoiceGroups(params) { const options = buildAuthChoiceOptions({ ...params, includeSkip: false }); const optionByValue = new Map(options.map((opt) => [opt.value, opt])); return { groups: AUTH_CHOICE_GROUP_DEFS.map((group) => ({ ...group, options: group.choices.map((choice) => optionByValue.get(choice)).filter((opt) => Boolean(opt)) })), skipOption: params.includeSkip ? { value: "skip", label: "Skip for now" } : void 0 }; } //#endregion //#region src/commands/auth-choice-prompt.ts const BACK_VALUE = "__back"; async function promptAuthChoiceGrouped(params) { const { groups, skipOption } = buildAuthChoiceGroups(params); const availableGroups = groups.filter((group) => group.options.length > 0); while (true) { const providerOptions = [...availableGroups.map((group) => ({ value: group.value, label: group.label, hint: group.hint })), ...skipOption ? [skipOption] : []]; const providerSelection = await params.prompter.select({ message: "Model/auth provider", options: providerOptions }); if (providerSelection === "skip") return "skip"; const group = availableGroups.find((candidate) => candidate.value === providerSelection); if (!group || group.options.length === 0) { await params.prompter.note("No auth methods available for that provider.", "Model/auth choice"); continue; } const methodSelection = await params.prompter.select({ message: `${group.label} auth method`, options: [...group.options, { value: BACK_VALUE, label: "Back" }] }); if (methodSelection === BACK_VALUE) continue; return methodSelection; } } //#endregion //#region src/commands/auth-choice.api-key.ts const DEFAULT_KEY_PREVIEW = { head: 4, tail: 4 }; function normalizeApiKeyInput(raw) { const trimmed = String(raw ?? "").trim(); if (!trimmed) return ""; const assignmentMatch = trimmed.match(/^(?:export\s+)?[A-Za-z_][A-Za-z0-9_]*\s*=\s*(.+)$/); const valuePart = assignmentMatch ? assignmentMatch[1].trim() : trimmed; const unquoted = valuePart.length >= 2 && (valuePart.startsWith("\"") && valuePart.endsWith("\"") || valuePart.startsWith("'") && valuePart.endsWith("'") || valuePart.startsWith("`") && valuePart.endsWith("`")) ? valuePart.slice(1, -1) : valuePart; return (unquoted.endsWith(";") ? unquoted.slice(0, -1) : unquoted).trim(); } const validateApiKeyInput = (value) => normalizeApiKeyInput(value).length > 0 ? void 0 : "Required"; function formatApiKeyPreview(raw, opts = {}) { const trimmed = raw.trim(); if (!trimmed) return "…"; const head = opts.head ?? DEFAULT_KEY_PREVIEW.head; const tail = opts.tail ?? DEFAULT_KEY_PREVIEW.tail; if (trimmed.length <= head + tail) { const shortHead = Math.min(2, trimmed.length); const shortTail = Math.min(2, trimmed.length - shortHead); if (shortTail <= 0) return `${trimmed.slice(0, shortHead)}…`; return `${trimmed.slice(0, shortHead)}…${trimmed.slice(-shortTail)}`; } return `${trimmed.slice(0, head)}…${trimmed.slice(-tail)}`; } //#endregion //#region src/commands/auth-choice.apply.anthropic.ts async function applyAuthChoiceAnthropic(params) { if (params.authChoice === "setup-token" || params.authChoice === "oauth" || params.authChoice === "token") { let nextConfig = params.config; await params.prompter.note(["Run `claude setup-token` in your terminal.", "Then paste the generated token below."].join("\n"), "Anthropic setup-token"); const tokenRaw = await params.prompter.text({ message: "Paste Anthropic setup-token", validate: (value) => validateAnthropicSetupToken(String(value ?? "")) }); const token = String(tokenRaw).trim(); const profileNameRaw = await params.prompter.text({ message: "Token name (blank = default)", placeholder: "default" }); const provider = "anthropic"; const namedProfileId = buildTokenProfileId({ provider, name: String(profileNameRaw ?? "") }); upsertAuthProfile({ profileId: namedProfileId, agentDir: params.agentDir, credential: { type: "token", provider, token } }); nextConfig = applyAuthProfileConfig(nextConfig, { profileId: namedProfileId, provider, mode: "token" }); return { config: nextConfig }; } if (params.authChoice === "apiKey") { if (params.opts?.tokenProvider && params.opts.tokenProvider !== "anthropic") return null; let nextConfig = params.config; let hasCredential = false; const envKey = process.env.ANTHROPIC_API_KEY?.trim(); if (params.opts?.token) { await setAnthropicApiKey(normalizeApiKeyInput(params.opts.token), params.agentDir); hasCredential = true; } if (!hasCredential && envKey) { if (await params.prompter.confirm({ message: `Use existing ANTHROPIC_API_KEY (env, ${formatApiKeyPreview(envKey)})?`, initialValue: true })) { await setAnthropicApiKey(envKey, params.agentDir); hasCredential = true; } } if (!hasCredential) { const key = await params.prompter.text({ message: "Enter Anthropic API key", validate: validateApiKeyInput }); await setAnthropicApiKey(normalizeApiKeyInput(String(key)), params.agentDir); } nextConfig = applyAuthProfileConfig(nextConfig, { profileId: "anthropic:default", provider: "anthropic", mode: "api_key" }); return { config: nextConfig }; } return null; } //#endregion //#region src/commands/model-allowlist.ts function ensureModelAllowlistEntry(params) { const rawModelRef = params.modelRef.trim(); if (!rawModelRef) return params.cfg; const models = { ...params.cfg.agents?.defaults?.models }; const keySet = new Set([rawModelRef]); const canonicalKey = resolveAllowlistModelKey(rawModelRef, params.defaultProvider ?? DEFAULT_PROVIDER); if (canonicalKey) keySet.add(canonicalKey); for (const key of keySet) models[key] = { ...models[key] }; return { ...params.cfg, agents: { ...params.cfg.agents, defaults: { ...params.cfg.agents?.defaults, models } } }; } //#endregion //#region src/commands/auth-choice.default-model.ts async function applyDefaultModelChoice(params) { if (params.setDefaultModel) { const next = params.applyDefaultConfig(params.config); if (params.noteDefault) await params.prompter.note(`Default model set to ${params.noteDefault}`, "Model configured"); return { config: next }; } const nextWithModel = ensureModelAllowlistEntry({ cfg: params.applyProviderConfig(params.config), modelRef: params.defaultModel }); await params.noteAgentModel(params.defaultModel); return { config: nextWithModel, agentModelOverride: params.defaultModel }; } //#endregion //#region src/commands/google-gemini-model-default.ts const GOOGLE_GEMINI_DEFAULT_MODEL = "google/gemini-3-pro-preview"; function resolvePrimaryModel$1(model) { if (typeof model === "string") return model; if (model && typeof model === "object" && typeof model.primary === "string") return model.primary; } function applyGoogleGeminiModelDefault(cfg) { if (resolvePrimaryModel$1(cfg.agents?.defaults?.model)?.trim() === GOOGLE_GEMINI_DEFAULT_MODEL) return { next: cfg, changed: false }; return { next: { ...cfg, agents: { ...cfg.agents, defaults: { ...cfg.agents?.defaults, model: cfg.agents?.defaults?.model && typeof cfg.agents.defaults.model === "object" ? { ...cfg.agents.defaults.model, primary: GOOGLE_GEMINI_DEFAULT_MODEL } : { primary: GOOGLE_GEMINI_DEFAULT_MODEL } } } }, changed: true }; } //#endregion //#region src/commands/opencode-zen-model-default.ts const OPENCODE_ZEN_DEFAULT_MODEL = "opencode/claude-opus-4-6"; //#endregion //#region src/commands/auth-choice.apply.api-providers.ts async function applyAuthChoiceApiProviders(params) { let nextConfig = params.config; let agentModelOverride; const noteAgentModel = async (model) => { if (!params.agentId) return; await params.prompter.note(`Default model set to ${model} for agent "${params.agentId}".`, "Model configured"); }; let authChoice = params.authChoice; if (authChoice === "apiKey" && params.opts?.tokenProvider && params.opts.tokenProvider !== "anthropic" && params.opts.tokenProvider !== "openai") { if (params.opts.tokenProvider === "openrouter") authChoice = "openrouter-api-key"; else if (params.opts.tokenProvider === "vercel-ai-gateway") authChoice = "ai-gateway-api-key"; else if (params.opts.tokenProvider === "cloudflare-ai-gateway") authChoice = "cloudflare-ai-gateway-api-key"; else if (params.opts.tokenProvider === "moonshot") authChoice = "moonshot-api-key"; else if (params.opts.tokenProvider === "kimi-code" || params.opts.tokenProvider === "kimi-coding") authChoice = "kimi-code-api-key"; else if (params.opts.tokenProvider === "google") authChoice = "gemini-api-key"; else if (params.opts.tokenProvider === "zai") authChoice = "zai-api-key"; else if (params.opts.tokenProvider === "xiaomi") authChoice = "xiaomi-api-key"; else if (params.opts.tokenProvider === "synthetic") authChoice = "synthetic-api-key"; else if (params.opts.tokenProvider === "venice") authChoice = "venice-api-key"; else if (params.opts.tokenProvider === "opencode") authChoice = "opencode-zen"; } if (authChoice === "openrouter-api-key") { const store = ensureAuthProfileStore(params.agentDir, { allowKeychainPrompt: false }); const existingProfileId = resolveAuthProfileOrder({ cfg: nextConfig, store, provider: "openrouter" }).find((profileId) => Boolean(store.profiles[profileId])); const existingCred = existingProfileId ? store.profiles[existingProfileId] : void 0; let profileId = "openrouter:default"; let mode = "api_key"; let hasCredential = false; if (existingProfileId && existingCred?.type) { profileId = existingProfileId; mode = existingCred.type === "oauth" ? "oauth" : existingCred.type === "token" ? "token" : "api_key"; hasCredential = true; } if (!hasCredential && params.opts?.token && params.opts?.tokenProvider === "openrouter") { await setOpenrouterApiKey(normalizeApiKeyInput(params.opts.token), params.agentDir); hasCredential = true; } if (!hasCredential) { const envKey = resolveEnvApiKey("openrouter"); if (envKey) { if (await params.prompter.confirm({ message: `Use existing OPENROUTER_API_KEY (${envKey.source}, ${formatApiKeyPreview(envKey.apiKey)})?`, initialValue: true })) { await setOpenrouterApiKey(envKey.apiKey, params.agentDir); hasCredential = true; } } } if (!hasCredential) { const key = await params.prompter.text({ message: "Enter OpenRouter API key", validate: validateApiKeyInput }); await setOpenrouterApiKey(normalizeApiKeyInput(String(key)), params.agentDir); hasCredential = true; } if (hasCredential) nextConfig = applyAuthProfileConfig(nextConfig, { profileId, provider: "openrouter", mode }); { const applied = await applyDefaultModelChoice({ config: nextConfig, setDefaultModel: params.setDefaultModel, defaultModel: OPENROUTER_DEFAULT_MODEL_REF, applyDefaultConfig: applyOpenrouterConfig, applyProviderConfig: applyOpenrouterProviderConfig, noteDefault: OPENROUTER_DEFAULT_MODEL_REF, noteAgentModel, prompter: params.prompter }); nextConfig = applied.config; agentModelOverride = applied.agentModelOverride ?? agentModelOverride; } return { config: nextConfig, agentModelOverride }; } if (authChoice === "ai-gateway-api-key") { let hasCredential = false; if (!hasCredential && params.opts?.token && params.opts?.tokenProvider === "vercel-ai-gateway") { await setVercelAiGatewayApiKey(normalizeApiKeyInput(params.opts.token), params.agentDir); hasCredential = true; } const envKey = resolveEnvApiKey("vercel-ai-gateway"); if (envKey) { if (await params.prompter.confirm({ message: `Use existing AI_GATEWAY_API_KEY (${envKey.source}, ${formatApiKeyPreview(envKey.apiKey)})?`, initialValue: true })) { await setVercelAiGatewayApiKey(envKey.apiKey, params.agentDir); hasCredential = true; } } if (!hasCredential) { const key = await params.prompter.text({ message: "Enter Vercel AI Gateway API key", validate: validateApiKeyInput }); await setVercelAiGatewayApiKey(normalizeApiKeyInput(String(key)), params.agentDir); } nextConfig = applyAuthProfileConfig(nextConfig, { profileId: "vercel-ai-gateway:default", provider: "vercel-ai-gateway", mode: "api_key" }); { const applied = await applyDefaultModelChoice({ config: nextConfig, setDefaultModel: params.setDefaultModel, defaultModel: VERCEL_AI_GATEWAY_DEFAULT_MODEL_REF, applyDefaultConfig: applyVercelAiGatewayConfig, applyProviderConfig: applyVercelAiGatewayProviderConfig, noteDefault: VERCEL_AI_GATEWAY_DEFAULT_MODEL_REF, noteAgentModel, prompter: params.prompter }); nextConfig = applied.config; agentModelOverride = applied.agentModelOverride ?? agentModelOverride; } return { config: nextConfig, agentModelOverride }; } if (authChoice === "cloudflare-ai-gateway-api-key") { let hasCredential = false; let accountId = params.opts?.cloudflareAiGatewayAccountId?.trim() ?? ""; let gatewayId = params.opts?.cloudflareAiGatewayGatewayId?.trim() ?? ""; const ensureAccountGateway = async () => { if (!accountId) { const value = await params.prompter.text({ message: "Enter Cloudflare Account ID", validate: (val) => String(val).trim() ? void 0 : "Account ID is required" }); accountId = String(value).trim(); } if (!gatewayId) { const value = await params.prompter.text({ message: "Enter Cloudflare AI Gateway ID", validate: (val) => String(val).trim() ? void 0 : "Gateway ID is required" }); gatewayId = String(value).trim(); } }; const optsApiKey = normalizeApiKeyInput(params.opts?.cloudflareAiGatewayApiKey ?? ""); if (!hasCredential && accountId && gatewayId && optsApiKey) { await setCloudflareAiGatewayConfig(accountId, gatewayId, optsApiKey, params.agentDir); hasCredential = true; } const envKey = resolveEnvApiKey("cloudflare-ai-gateway"); if (!hasCredential && envKey) { if (await params.prompter.confirm({ message: `Use existing CLOUDFLARE_AI_GATEWAY_API_KEY (${envKey.source}, ${formatApiKeyPreview(envKey.apiKey)})?`, initialValue: true })) { await ensureAccountGateway(); await setCloudflareAiGatewayConfig(accountId, gatewayId, normalizeApiKeyInput(envKey.apiKey), params.agentDir); hasCredential = true; } } if (!hasCredential && optsApiKey) { await ensureAccountGateway(); await setCloudflareAiGatewayConfig(accountId, gatewayId, optsApiKey, params.agentDir); hasCredential = true; } if (!hasCredential) { await ensureAccountGateway(); const key = await params.prompter.text({ message: "Enter Cloudflare AI Gateway API key", validate: validateApiKeyInput }); await setCloudflareAiGatewayConfig(accountId, gatewayId, normalizeApiKeyInput(String(key)), params.agentDir); hasCredential = true; } if (hasCredential) nextConfig = applyAuthProfileConfig(nextConfig, { profileId: "cloudflare-ai-gateway:default", provider: "cloudflare-ai-gateway", mode: "api_key" }); { const applied = await applyDefaultModelChoice({ config: nextConfig, setDefaultModel: params.setDefaultModel, defaultModel: CLOUDFLARE_AI_GATEWAY_DEFAULT_MODEL_REF, applyDefaultConfig: (cfg) => applyCloudflareAiGatewayConfig(cfg, { accountId: accountId || params.opts?.cloudflareAiGatewayAccountId, gatewayId: gatewayId || params.opts?.cloudflareAiGatewayGatewayId }), applyProviderConfig: (cfg) => applyCloudflareAiGatewayProviderConfig(cfg, { accountId: accountId || params.opts?.cloudflareAiGatewayAccountId, gatewayId: gatewayId || params.opts?.cloudflareAiGatewayGatewayId }), noteDefault: CLOUDFLARE_AI_GATEWAY_DEFAULT_MODEL_REF, noteAgentModel, prompter: params.prompter }); nextConfig = applied.config; agentModelOverride = applied.agentModelOverride ?? agentModelOverride; } return { config: nextConfig, agentModelOverride }; } if (authChoice === "moonshot-api-key") { let hasCredential = false; if (!hasCredential && params.opts?.token && params.opts?.tokenProvider === "moonshot") { await setMoonshotApiKey(normalizeApiKeyInput(params.opts.token), params.agentDir); hasCredential = true; } const envKey = resolveEnvApiKey("moonshot"); if (envKey) { if (await params.prompter.confirm({ message: `Use existing MOONSHOT_API_KEY (${envKey.source}, ${formatApiKeyPreview(envKey.apiKey)})?`, initialValue: true })) { await setMoonshotApiKey(envKey.apiKey, params.agentDir); hasCredential = true; } } if (!hasCredential) { const key = await params.prompter.text({ message: "Enter Moonshot API key", validate: validateApiKeyInput }); await setMoonshotApiKey(normalizeApiKeyInput(String(key)), params.agentDir); } nextConfig = applyAuthProfileConfig(nextConfig, { profileId: "moonshot:default", provider: "moonshot", mode: "api_key" }); { const applied = await applyDefaultModelChoice({ config: nextConfig, setDefaultModel: params.setDefaultModel, defaultModel: MOONSHOT_DEFAULT_MODEL_REF, applyDefaultConfig: applyMoonshotConfig, applyProviderConfig: applyMoonshotProviderConfig, noteAgentModel, prompter: params.prompter }); nextConfig = applied.config; agentModelOverride = applied.agentModelOverride ?? agentModelOverride; } return { config: nextConfig, agentModelOverride }; } if (authChoice === "moonshot-api-key-cn") { let hasCredential = false; if (!hasCredential && params.opts?.token && params.opts?.tokenProvider === "moonshot") { await setMoonshotApiKey(normalizeApiKeyInput(params.opts.token), params.agentDir); hasCredential = true; } const envKey = resolveEnvApiKey("moonshot"); if (envKey) { if (await params.prompter.confirm({ message: `Use existing MOONSHOT_API_KEY (${envKey.source}, ${formatApiKeyPreview(envKey.apiKey)})?`, initialValue: true })) { await setMoonshotApiKey(envKey.apiKey, params.agentDir); hasCredential = true; } } if (!hasCredential) { const key = await params.prompter.text({ message: "Enter Moonshot API key (.cn)", validate: validateApiKeyInput }); await setMoonshotApiKey(normalizeApiKeyInput(String(key)), params.agentDir); } nextConfig = applyAuthProfileConfig(nextConfig, { profileId: "moonshot:default", provider: "moonshot", mode: "api_key" }); { const applied = await applyDefaultModelChoice({ config: nextConfig, setDefaultModel: params.setDefaultModel, defaultModel: MOONSHOT_DEFAULT_MODEL_REF, applyDefaultConfig: applyMoonshotConfigCn, applyProviderConfig: applyMoonshotProviderConfigCn, noteAgentModel, prompter: params.prompter }); nextConfig = applied.config; agentModelOverride = applied.agentModelOverride ?? agentModelOverride; } return { config: nextConfig, agentModelOverride }; } if (authChoice === "kimi-code-api-key") { let hasCredential = false; const tokenProvider = params.opts?.tokenProvider?.trim().toLowerCase(); if (!hasCredential && params.opts?.token && (tokenProvider === "kimi-code" || tokenProvider === "kimi-coding")) { await setKimiCodingApiKey(normalizeApiKeyInput(params.opts.token), params.agentDir); hasCredential = true; } if (!hasCredential) await params.prompter.note(["Kimi Coding uses a dedicated endpoint and API key.", "Get your API key at: https://www.kimi.com/code/en"].join("\n"), "Kimi Coding"); const envKey = resolveEnvApiKey("kimi-coding"); if (envKey) { if (await params.prompter.confirm({ message: `Use existing KIMI_API_KEY (${envKey.source}, ${formatApiKeyPreview(envKey.apiKey)})?`, initialValue: true })) { await setKimiCodingApiKey(envKey.apiKey, params.agentDir); hasCredential = true; } } if (!hasCredential) { const key = await params.prompter.text({ message: "Enter Kimi Coding API key", validate: validateApiKeyInput }); await setKimiCodingApiKey(normalizeApiKeyInput(String(key)), params.agentDir); } nextConfig = applyAuthProfileConfig(nextConfig, { profileId: "kimi-coding:default", provider: "kimi-coding", mode: "api_key" }); { const applied = await applyDefaultModelChoice({ config: nextConfig, setDefaultModel: params.setDefaultModel, defaultModel: KIMI_CODING_MODEL_REF, applyDefaultConfig: applyKimiCodeConfig, applyProviderConfig: applyKimiCodeProviderConfig, noteDefault: KIMI_CODING_MODEL_REF, noteAgentModel, prompter: params.prompter }); nextConfig = applied.config; agentModelOverride = applied.agentModelOverride ?? agentModelOverride; } return { config: nextConfig, agentModelOverride }; } if (authChoice === "gemini-api-key") { let hasCredential = false; if (!hasCredential && params.opts?.token && params.opts?.tokenProvider === "google") { await setGeminiApiKey(normalizeApiKeyInput(params.opts.token), params.agentDir); hasCredential = true; } const envKey = resolveEnvApiKey("google"); if (envKey) { if (await params.prompter.confirm({ message: `Use existing GEMINI_API_KEY (${envKey.source}, ${formatApiKeyPreview(envKey.apiKey)})?`, initialValue: true })) { await setGeminiApiKey(envKey.apiKey, params.agentDir); hasCredential = true; } } if (!hasCredential) { const key = await params.prompter.text({ message: "Enter Gemini API key", validate: validateApiKeyInput }); await setGeminiApiKey(normalizeApiKeyInput(String(key)), params.agentDir); } nextConfig = applyAuthProfileConfig(nextConfig, { profileId: "google:default", provider: "google", mode: "api_key" }); if (params.setDefaultModel) { const applied = applyGoogleGeminiModelDefault(nextConfig); nextConfig = applied.next; if (applied.changed) await params.prompter.note(`Default model set to ${GOOGLE_GEMINI_DEFAULT_MODEL}`, "Model configured"); } else { agentModelOverride = GOOGLE_GEMINI_DEFAULT_MODEL; await noteAgentModel(GOOGLE_GEMINI_DEFAULT_MODEL); } return { config: nextConfig, agentModelOverride }; } if (authChoice === "zai-api-key") { let hasCredential = false; if (!hasCredential && params.opts?.token && params.opts?.tokenProvider === "zai") { await setZaiApiKey(normalizeApiKeyInput(params.opts.token), params.agentDir); hasCredential = true; } const envKey = resolveEnvApiKey("zai"); if (envKey) { if (await params.prompter.confirm({ message: `Use existing ZAI_API_KEY (${envKey.source}, ${formatApiKeyPreview(envKey.apiKey)})?`, initialValue: true })) { await setZaiApiKey(envKey.apiKey, params.agentDir); hasCredential = true; } } if (!hasCredential) { const key = await params.prompter.text({ message: "Enter Z.AI API key", validate: validateApiKeyInput }); await setZaiApiKey(normalizeApiKeyInput(String(key)), params.agentDir); } nextConfig = applyAuthProfileConfig(nextConfig, { profileId: "zai:default", provider: "zai", mode: "api_key" }); { const applied = await applyDefaultModelChoice({ config: nextConfig, setDefaultModel: params.setDefaultModel, defaultModel: ZAI_DEFAULT_MODEL_REF, applyDefaultConfig: applyZaiConfig, applyProviderConfig: (config) => ({ ...config, agents: { ...config.agents, defaults: { ...config.agents?.defaults, models: { ...config.agents?.defaults?.models, [ZAI_DEFAULT_MODEL_REF]: { ...config.agents?.defaults?.models?.[ZAI_DEFAULT_MODEL_REF], alias: config.agents?.defaults?.models?.[ZAI_DEFAULT_MODEL_REF]?.alias ?? "GLM" } } } } }), noteDefault: ZAI_DEFAULT_MODEL_REF, noteAgentModel, prompter: params.prompter }); nextConfig = applied.config; agentModelOverride = applied.agentModelOverride ?? agentModelOverride; } return { config: nextConfig, agentModelOverride }; } if (authChoice === "xiaomi-api-key") { let hasCredential = false; if (!hasCredential && params.opts?.token && params.opts?.tokenProvider === "xiaomi") { await setXiaomiApiKey(normalizeApiKeyInput(params.opts.token), params.agentDir); hasCredential = true; } const envKey = resolveEnvApiKey("xiaomi"); if (envKey) { if (await params.prompter.confirm({ message: `Use existing XIAOMI_API_KEY (${envKey.source}, ${formatApiKeyPreview(envKey.apiKey)})?`, initialValue: true })) { await setXiaomiApiKey(envKey.apiKey, params.agentDir); hasCredential = true; } } if (!hasCredential) { const key = await params.prompter.text({ message: "Enter Xiaomi API key", validate: validateApiKeyInput }); await setXiaomiApiKey(normalizeApiKeyInput(String(key)), params.agentDir); } nextConfig = applyAuthProfileConfig(nextConfig, { profileId: "xiaomi:default", provider: "xiaomi", mode: "api_key" }); { const applied = await applyDefaultModelChoice({ config: nextConfig, setDefaultModel: params.setDefaultModel, defaultModel: XIAOMI_DEFAULT_MODEL_REF, applyDefaultConfig: applyXiaomiConfig, applyProviderConfig: applyXiaomiProviderConfig, noteDefault: XIAOMI_DEFAULT_MODEL_REF, noteAgentModel, prompter: params.prompter }); nextConfig = applied.config; agentModelOverride = applied.agentModelOverride ?? agentModelOverride; } return { config: nextConfig, agentModelOverride }; } if (authChoice === "synthetic-api-key") { if (params.opts?.token && params.opts?.tokenProvider === "synthetic") await setSyntheticApiKey(String(params.opts.token).trim(), params.agentDir); else { const key = await params.prompter.text({ message: "Enter Synthetic API key", validate: (value) => value?.trim() ? void 0 : "Required" }); await setSyntheticApiKey(String(key).trim(), params.agentDir); } nextConfig = applyAuthProfileConfig(nextConfig, { profileId: "synthetic:default", provider: "synthetic", mode: "api_key" }); { const applied = await applyDefaultModelChoice({ config: nextConfig, setDefaultModel: params.setDefaultModel, defaultModel: SYNTHETIC_DEFAULT_MODEL_REF, applyDefaultConfig: applySyntheticConfig, applyProviderConfig: applySyntheticProviderConfig, noteDefault: SYNTHETIC_DEFAULT_MODEL_REF, noteAgentModel, prompter: params.prompter }); nextConfig = applied.config; agentModelOverride = applied.agentModelOverride ?? agentModelOverride; } return { config: nextConfig, agentModelOverride }; } if (authChoice === "venice-api-key") { let hasCredential = false; if (!hasCredential && params.opts?.token && params.opts?.tokenProvider === "venice") { await setVeniceApiKey(normalizeApiKeyInput(params.opts.token), params.agentDir); hasCredential = true; } if (!hasCredential) await params.prompter.note([ "Venice AI provides privacy-focused inference with uncensored models.", "Get your API key at: https://venice.ai/settings/api", "Supports 'private' (fully private) and 'anonymized' (proxy) modes." ].join("\n"), "Venice AI"); const envKey = resolveEnvApiKey("venice"); if (envKey) { if (await params.prompter.confirm({ message: `Use existing VENICE_API_KEY (${envKey.source}, ${formatApiKeyPreview(envKey.apiKey)})?`, initialValue: true })) { await setVeniceApiKey(envKey.apiKey, params.agentDir); hasCredential = true; } } if (!hasCredential) { const key = await params.prompter.text({ message: "Enter Venice AI API key", validate: validateApiKeyInput }); await setVeniceApiKey(normalizeApiKeyInput(String(key)), params.agentDir); } nextConfig = applyAuthProfileConfig(nextConfig, { profileId: "venice:default", provider: "venice", mode: "api_key" }); { const applied = await applyDefaultModelChoice({ config: nextConfig, setDefaultModel: params.setDefaultModel, defaultModel: VENICE_DEFAULT_MODEL_REF, applyDefaultConfig: applyVeniceConfig, applyProviderConfig: applyVeniceProviderConfig, noteDefault: VENICE_DEFAULT_MODEL_REF, noteAgentM