From e93a1d8138288fb610d751ae86e78acb8b669268 Mon Sep 17 00:00:00 2001 From: ddyo Date: Sat, 17 Jan 2026 11:46:37 +0200 Subject: [PATCH] feat: add kimi code provider onboarding --- docs/cli/index.md | 3 +- docs/providers/moonshot.md | 62 +++++++++++++++-- src/agents/model-auth.ts | 1 + src/agents/models-config.providers.ts | 37 +++++++++- src/cli/program.smoke.test.ts | 23 +++++++ src/cli/program/register.onboard.ts | 4 +- src/commands/auth-choice-options.test.ts | 1 + src/commands/auth-choice-options.ts | 5 +- .../auth-choice.apply.api-providers.ts | 53 ++++++++++++++ .../auth-choice.preferred-provider.ts | 1 + src/commands/onboard-auth.config-core.ts | 69 +++++++++++++++++++ src/commands/onboard-auth.credentials.ts | 13 ++++ src/commands/onboard-auth.models.ts | 27 ++++++++ src/commands/onboard-auth.ts | 7 ++ .../local/auth-choice.ts | 21 ++++++ src/commands/onboard-types.ts | 2 + 16 files changed, 318 insertions(+), 11 deletions(-) diff --git a/docs/cli/index.md b/docs/cli/index.md index 4d4c6d261..d07bb3407 100644 --- a/docs/cli/index.md +++ b/docs/cli/index.md @@ -292,7 +292,7 @@ Options: - `--non-interactive` - `--mode ` - `--flow ` -- `--auth-choice ` +- `--auth-choice ` - `--token-provider ` (non-interactive; used with `--auth-choice token`) - `--token ` (non-interactive; used with `--auth-choice token`) - `--token-profile-id ` (non-interactive; default: `:manual`) @@ -302,6 +302,7 @@ Options: - `--openrouter-api-key ` - `--ai-gateway-api-key ` - `--moonshot-api-key ` +- `--kimi-code-api-key ` - `--gemini-api-key ` - `--zai-api-key ` - `--minimax-api-key ` diff --git a/docs/providers/moonshot.md b/docs/providers/moonshot.md index 7de182e01..0fcaae77d 100644 --- a/docs/providers/moonshot.md +++ b/docs/providers/moonshot.md @@ -1,13 +1,16 @@ --- -summary: "Use Moonshot AI (Kimi K2) with Clawdbot" +summary: "Configure Moonshot K2 vs Kimi Code (separate providers + keys)" read_when: - - You want to use Moonshot/Kimi models in Clawdbot - - You need the Moonshot auth + config example + - You want Moonshot K2 (Moonshot Open Platform) vs Kimi Code setup + - You need to understand separate endpoints, keys, and model refs + - You want copy/paste config for either provider --- + # Moonshot AI (Kimi) Moonshot provides the Kimi API with OpenAI-compatible endpoints. Configure the -provider and set the default model to `moonshot/kimi-k2-0905-preview`. +provider and set the default model to `moonshot/kimi-k2-0905-preview`, or use +Kimi Code with `kimi-code/kimi-for-coding`. Current Kimi K2 model IDs: {/* moonshot-kimi-k2-ids:start */} @@ -21,7 +24,15 @@ Current Kimi K2 model IDs: clawdbot onboard --auth-choice moonshot-api-key ``` -## Config snippet +Kimi Code: + +```bash +clawdbot onboard --auth-choice kimi-code-api-key +``` + +Note: Moonshot and Kimi Code are separate providers. Keys are not interchangeable, endpoints differ, and model refs differ (Moonshot uses `moonshot/...`, Kimi Code uses `kimi-code/...`). + +## Config snippet (Moonshot API) ```json5 { @@ -92,9 +103,48 @@ clawdbot onboard --auth-choice moonshot-api-key } ``` +## Kimi Code + +```json5 +{ + env: { KIMICODE_API_KEY: "sk-..." }, + agents: { + defaults: { + model: { primary: "kimi-code/kimi-for-coding" }, + models: { + "kimi-code/kimi-for-coding": { alias: "Kimi Code" } + } + } + }, + models: { + mode: "merge", + providers: { + "kimi-code": { + baseUrl: "https://api.kimi.com/coding/v1", + apiKey: "${KIMICODE_API_KEY}", + api: "openai-completions", + models: [ + { + id: "kimi-for-coding", + name: "Kimi For Coding", + reasoning: true, + input: ["text"], + cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, + contextWindow: 262144, + maxTokens: 32768, + headers: { "User-Agent": "KimiCLI/0.77" }, + compat: { supportsDeveloperRole: false } + } + ] + } + } + } +} +``` + ## Notes -- Model refs use `moonshot/`. +- Moonshot model refs use `moonshot/`. Kimi Code model refs use `kimi-code/`. - Override pricing and context metadata in `models.providers` if needed. - If Moonshot publishes different context limits for a model, adjust `contextWindow` accordingly. diff --git a/src/agents/model-auth.ts b/src/agents/model-auth.ts index 32257de9a..87ae20fbd 100644 --- a/src/agents/model-auth.ts +++ b/src/agents/model-auth.ts @@ -157,6 +157,7 @@ export function resolveEnvApiKey(provider: string): EnvApiKeyResult | null { openrouter: "OPENROUTER_API_KEY", "vercel-ai-gateway": "AI_GATEWAY_API_KEY", moonshot: "MOONSHOT_API_KEY", + "kimi-code": "KIMICODE_API_KEY", minimax: "MINIMAX_API_KEY", synthetic: "SYNTHETIC_API_KEY", mistral: "MISTRAL_API_KEY", diff --git a/src/agents/models-config.providers.ts b/src/agents/models-config.providers.ts index 9b02a2396..633bf5579 100644 --- a/src/agents/models-config.providers.ts +++ b/src/agents/models-config.providers.ts @@ -37,6 +37,12 @@ const MOONSHOT_DEFAULT_COST = { cacheRead: 0, cacheWrite: 0, }; +const KIMI_CODE_BASE_URL = "https://api.kimi.com/coding/v1"; +const KIMI_CODE_MODEL_ID = "kimi-for-coding"; +const KIMI_CODE_CONTEXT_WINDOW = 262144; +const KIMI_CODE_MAX_TOKENS = 32768; +const KIMI_CODE_HEADERS = { "User-Agent": "KimiCLI/0.77" } as const; +const KIMI_CODE_COMPAT = { supportsDeveloperRole: false } as const; function normalizeApiKeyConfig(value: string): string { const trimmed = value.trim(); @@ -184,6 +190,26 @@ function buildMoonshotProvider(): ProviderConfig { }; } +function buildKimiCodeProvider(): ProviderConfig { + return { + baseUrl: KIMI_CODE_BASE_URL, + api: "openai-completions", + models: [ + { + id: KIMI_CODE_MODEL_ID, + name: "Kimi For Coding", + reasoning: true, + input: ["text"], + cost: MOONSHOT_DEFAULT_COST, + contextWindow: KIMI_CODE_CONTEXT_WINDOW, + maxTokens: KIMI_CODE_MAX_TOKENS, + headers: KIMI_CODE_HEADERS, + compat: KIMI_CODE_COMPAT + } + ] + }; +} + function buildSyntheticProvider(): ProviderConfig { return { baseUrl: SYNTHETIC_BASE_URL, @@ -192,7 +218,9 @@ function buildSyntheticProvider(): ProviderConfig { }; } -export function resolveImplicitProviders(params: { agentDir: string }): ModelsConfig["providers"] { +export function resolveImplicitProviders(params: { + agentDir: string; +}): ModelsConfig["providers"] { const providers: Record = {}; const authStore = ensureAuthProfileStore(params.agentDir, { allowKeychainPrompt: false, @@ -212,6 +240,13 @@ export function resolveImplicitProviders(params: { agentDir: string }): ModelsCo providers.moonshot = { ...buildMoonshotProvider(), apiKey: moonshotKey }; } + const kimiCodeKey = + resolveEnvApiKeyVarName("kimi-code") ?? + resolveApiKeyFromProfiles({ provider: "kimi-code", store: authStore }); + if (kimiCodeKey) { + providers["kimi-code"] = { ...buildKimiCodeProvider(), apiKey: kimiCodeKey }; + } + const syntheticKey = resolveEnvApiKeyVarName("synthetic") ?? resolveApiKeyFromProfiles({ provider: "synthetic", store: authStore }); diff --git a/src/cli/program.smoke.test.ts b/src/cli/program.smoke.test.ts index 875510265..5745fe2dd 100644 --- a/src/cli/program.smoke.test.ts +++ b/src/cli/program.smoke.test.ts @@ -180,6 +180,29 @@ describe("cli program (smoke)", () => { ); }); + it("passes kimi code api key to onboard", async () => { + const program = buildProgram(); + await program.parseAsync( + [ + "onboard", + "--non-interactive", + "--auth-choice", + "kimi-code-api-key", + "--kimi-code-api-key", + "sk-kimi-code-test" + ], + { from: "user" }, + ); + expect(onboardCommand).toHaveBeenCalledWith( + expect.objectContaining({ + nonInteractive: true, + authChoice: "kimi-code-api-key", + kimiCodeApiKey: "sk-kimi-code-test" + }), + runtime, + ); + }); + it("passes synthetic api key to onboard", async () => { const program = buildProgram(); await program.parseAsync( diff --git a/src/cli/program/register.onboard.ts b/src/cli/program/register.onboard.ts index 9294e152f..08d610182 100644 --- a/src/cli/program/register.onboard.ts +++ b/src/cli/program/register.onboard.ts @@ -51,7 +51,7 @@ export function registerOnboardCommand(program: Command) { .option("--mode ", "Wizard mode: local|remote") .option( "--auth-choice ", - "Auth: setup-token|claude-cli|token|chutes|openai-codex|openai-api-key|openrouter-api-key|ai-gateway-api-key|moonshot-api-key|synthetic-api-key|codex-cli|gemini-api-key|zai-api-key|apiKey|minimax-api|minimax-api-lightning|opencode-zen|skip", + "Auth: setup-token|claude-cli|token|chutes|openai-codex|openai-api-key|openrouter-api-key|ai-gateway-api-key|moonshot-api-key|kimi-code-api-key|synthetic-api-key|codex-cli|gemini-api-key|zai-api-key|apiKey|minimax-api|minimax-api-lightning|opencode-zen|skip", ) .option( "--token-provider ", @@ -68,6 +68,7 @@ export function registerOnboardCommand(program: Command) { .option("--openrouter-api-key ", "OpenRouter API key") .option("--ai-gateway-api-key ", "Vercel AI Gateway API key") .option("--moonshot-api-key ", "Moonshot API key") + .option("--kimi-code-api-key ", "Kimi Code API key") .option("--gemini-api-key ", "Gemini API key") .option("--zai-api-key ", "Z.AI API key") .option("--minimax-api-key ", "MiniMax API key") @@ -116,6 +117,7 @@ export function registerOnboardCommand(program: Command) { openrouterApiKey: opts.openrouterApiKey as string | undefined, aiGatewayApiKey: opts.aiGatewayApiKey as string | undefined, moonshotApiKey: opts.moonshotApiKey as string | undefined, + kimiCodeApiKey: opts.kimiCodeApiKey as string | undefined, geminiApiKey: opts.geminiApiKey as string | undefined, zaiApiKey: opts.zaiApiKey as string | undefined, minimaxApiKey: opts.minimaxApiKey as string | undefined, diff --git a/src/commands/auth-choice-options.test.ts b/src/commands/auth-choice-options.test.ts index 2dd654a62..da31b77e5 100644 --- a/src/commands/auth-choice-options.test.ts +++ b/src/commands/auth-choice-options.test.ts @@ -100,6 +100,7 @@ describe("buildAuthChoiceOptions", () => { }); expect(options.some((opt) => opt.value === "moonshot-api-key")).toBe(true); + expect(options.some((opt) => opt.value === "kimi-code-api-key")).toBe(true); }); it("includes Vercel AI Gateway auth choice", () => { diff --git a/src/commands/auth-choice-options.ts b/src/commands/auth-choice-options.ts index 40cb1a110..16c156980 100644 --- a/src/commands/auth-choice-options.ts +++ b/src/commands/auth-choice-options.ts @@ -79,8 +79,8 @@ const AUTH_CHOICE_GROUP_DEFS: { { value: "moonshot", label: "Moonshot AI", - hint: "Kimi K2 preview", - choices: ["moonshot-api-key"], + hint: "Kimi K2 + Kimi Code", + choices: ["moonshot-api-key", "kimi-code-api-key"], }, { value: "zai", @@ -180,6 +180,7 @@ export function buildAuthChoiceOptions(params: { label: "Vercel AI Gateway API key", }); options.push({ value: "moonshot-api-key", label: "Moonshot AI API key" }); + options.push({ value: "kimi-code-api-key", label: "Kimi Code API key" }); options.push({ value: "synthetic-api-key", label: "Synthetic API key" }); options.push({ value: "github-copilot", diff --git a/src/commands/auth-choice.apply.api-providers.ts b/src/commands/auth-choice.apply.api-providers.ts index addc7ab29..a9fd3383d 100644 --- a/src/commands/auth-choice.apply.api-providers.ts +++ b/src/commands/auth-choice.apply.api-providers.ts @@ -13,6 +13,8 @@ import { } from "./google-gemini-model-default.js"; import { applyAuthProfileConfig, + applyKimiCodeConfig, + applyKimiCodeProviderConfig, applyMoonshotConfig, applyMoonshotProviderConfig, applyOpencodeZenConfig, @@ -24,11 +26,13 @@ import { applyVercelAiGatewayConfig, applyVercelAiGatewayProviderConfig, applyZaiConfig, + KIMI_CODE_MODEL_REF, MOONSHOT_DEFAULT_MODEL_REF, OPENROUTER_DEFAULT_MODEL_REF, SYNTHETIC_DEFAULT_MODEL_REF, VERCEL_AI_GATEWAY_DEFAULT_MODEL_REF, setGeminiApiKey, + setKimiCodeApiKey, setMoonshotApiKey, setOpencodeZenApiKey, setOpenrouterApiKey, @@ -208,6 +212,55 @@ export async function applyAuthChoiceApiProviders( return { config: nextConfig, agentModelOverride }; } + if (params.authChoice === "kimi-code-api-key") { + await params.prompter.note( + [ + "Kimi Code uses a dedicated endpoint and API key.", + "Get your API key at: https://www.kimi.com/code/en" + ].join("\n"), + "Kimi Code", + ); + let hasCredential = false; + const envKey = resolveEnvApiKey("kimi-code"); + if (envKey) { + const useExisting = await params.prompter.confirm({ + message: `Use existing KIMICODE_API_KEY (${envKey.source}, ${formatApiKeyPreview(envKey.apiKey)})?`, + initialValue: true, + }); + if (useExisting) { + await setKimiCodeApiKey(envKey.apiKey, params.agentDir); + hasCredential = true; + } + } + if (!hasCredential) { + const key = await params.prompter.text({ + message: "Enter Kimi Code API key", + validate: validateApiKeyInput, + }); + await setKimiCodeApiKey(normalizeApiKeyInput(String(key)), params.agentDir); + } + nextConfig = applyAuthProfileConfig(nextConfig, { + profileId: "kimi-code:default", + provider: "kimi-code", + mode: "api_key" + }); + { + const applied = await applyDefaultModelChoice({ + config: nextConfig, + setDefaultModel: params.setDefaultModel, + defaultModel: KIMI_CODE_MODEL_REF, + applyDefaultConfig: applyKimiCodeConfig, + applyProviderConfig: applyKimiCodeProviderConfig, + noteDefault: KIMI_CODE_MODEL_REF, + noteAgentModel, + prompter: params.prompter + }); + nextConfig = applied.config; + agentModelOverride = applied.agentModelOverride ?? agentModelOverride; + } + return { config: nextConfig, agentModelOverride }; + } + if (params.authChoice === "gemini-api-key") { let hasCredential = false; const envKey = resolveEnvApiKey("google"); diff --git a/src/commands/auth-choice.preferred-provider.ts b/src/commands/auth-choice.preferred-provider.ts index 9d2d8e273..b8df8cd7f 100644 --- a/src/commands/auth-choice.preferred-provider.ts +++ b/src/commands/auth-choice.preferred-provider.ts @@ -13,6 +13,7 @@ const PREFERRED_PROVIDER_BY_AUTH_CHOICE: Partial> = { "openrouter-api-key": "openrouter", "ai-gateway-api-key": "vercel-ai-gateway", "moonshot-api-key": "moonshot", + "kimi-code-api-key": "kimi-code", "gemini-api-key": "google", "zai-api-key": "zai", "synthetic-api-key": "synthetic", diff --git a/src/commands/onboard-auth.config-core.ts b/src/commands/onboard-auth.config-core.ts index f36064f3e..995392f57 100644 --- a/src/commands/onboard-auth.config-core.ts +++ b/src/commands/onboard-auth.config-core.ts @@ -11,7 +11,11 @@ import { ZAI_DEFAULT_MODEL_REF, } from "./onboard-auth.credentials.js"; import { + buildKimiCodeModelDefinition, buildMoonshotModelDefinition, + KIMI_CODE_BASE_URL, + KIMI_CODE_MODEL_ID, + KIMI_CODE_MODEL_REF, MOONSHOT_BASE_URL, MOONSHOT_DEFAULT_MODEL_ID, MOONSHOT_DEFAULT_MODEL_REF, @@ -192,6 +196,71 @@ export function applyMoonshotConfig(cfg: ClawdbotConfig): ClawdbotConfig { }; } +export function applyKimiCodeProviderConfig(cfg: ClawdbotConfig): ClawdbotConfig { + const models = { ...cfg.agents?.defaults?.models }; + models[KIMI_CODE_MODEL_REF] = { + ...models[KIMI_CODE_MODEL_REF], + alias: models[KIMI_CODE_MODEL_REF]?.alias ?? "Kimi Code" + }; + + const providers = { ...cfg.models?.providers }; + const existingProvider = providers["kimi-code"]; + const existingModels = Array.isArray(existingProvider?.models) ? existingProvider.models : []; + const defaultModel = buildKimiCodeModelDefinition(); + const hasDefaultModel = existingModels.some((model) => model.id === KIMI_CODE_MODEL_ID); + const mergedModels = hasDefaultModel ? existingModels : [...existingModels, defaultModel]; + const { apiKey: existingApiKey, ...existingProviderRest } = (existingProvider ?? {}) as Record< + string, + unknown + > as { apiKey?: string }; + const resolvedApiKey = typeof existingApiKey === "string" ? existingApiKey : undefined; + const normalizedApiKey = resolvedApiKey?.trim(); + providers["kimi-code"] = { + ...existingProviderRest, + baseUrl: KIMI_CODE_BASE_URL, + api: "openai-completions", + ...(normalizedApiKey ? { apiKey: normalizedApiKey } : {}), + models: mergedModels.length > 0 ? mergedModels : [defaultModel] + }; + + return { + ...cfg, + agents: { + ...cfg.agents, + defaults: { + ...cfg.agents?.defaults, + models, + }, + }, + models: { + mode: cfg.models?.mode ?? "merge", + providers, + }, + }; +} + +export function applyKimiCodeConfig(cfg: ClawdbotConfig): ClawdbotConfig { + const next = applyKimiCodeProviderConfig(cfg); + const existingModel = next.agents?.defaults?.model; + return { + ...next, + agents: { + ...next.agents, + defaults: { + ...next.agents?.defaults, + model: { + ...(existingModel && "fallbacks" in (existingModel as Record) + ? { + fallbacks: (existingModel as { fallbacks?: string[] }).fallbacks, + } + : undefined), + primary: KIMI_CODE_MODEL_REF + }, + }, + }, + }; +} + export function applySyntheticProviderConfig(cfg: ClawdbotConfig): ClawdbotConfig { const models = { ...cfg.agents?.defaults?.models }; models[SYNTHETIC_DEFAULT_MODEL_REF] = { diff --git a/src/commands/onboard-auth.credentials.ts b/src/commands/onboard-auth.credentials.ts index 711a2ddd8..4af0671cd 100644 --- a/src/commands/onboard-auth.credentials.ts +++ b/src/commands/onboard-auth.credentials.ts @@ -73,6 +73,19 @@ export async function setMoonshotApiKey(key: string, agentDir?: string) { }); } +export async function setKimiCodeApiKey(key: string, agentDir?: string) { + // Write to resolved agent dir so gateway finds credentials on startup. + upsertAuthProfile({ + profileId: "kimi-code:default", + credential: { + type: "api_key", + provider: "kimi-code", + key + }, + agentDir: resolveAuthAgentDir(agentDir), + }); +} + export async function setSyntheticApiKey(key: string, agentDir?: string) { // Write to resolved agent dir so gateway finds credentials on startup. upsertAuthProfile({ diff --git a/src/commands/onboard-auth.models.ts b/src/commands/onboard-auth.models.ts index 780403627..01c62383b 100644 --- a/src/commands/onboard-auth.models.ts +++ b/src/commands/onboard-auth.models.ts @@ -12,6 +12,13 @@ export const MOONSHOT_DEFAULT_MODEL_ID = "kimi-k2-0905-preview"; export const MOONSHOT_DEFAULT_MODEL_REF = `moonshot/${MOONSHOT_DEFAULT_MODEL_ID}`; export const MOONSHOT_DEFAULT_CONTEXT_WINDOW = 256000; export const MOONSHOT_DEFAULT_MAX_TOKENS = 8192; +export const KIMI_CODE_BASE_URL = "https://api.kimi.com/coding/v1"; +export const KIMI_CODE_MODEL_ID = "kimi-for-coding"; +export const KIMI_CODE_MODEL_REF = `kimi-code/${KIMI_CODE_MODEL_ID}`; +export const KIMI_CODE_CONTEXT_WINDOW = 262144; +export const KIMI_CODE_MAX_TOKENS = 32768; +export const KIMI_CODE_HEADERS = { "User-Agent": "KimiCLI/0.77" } as const; +export const KIMI_CODE_COMPAT = { supportsDeveloperRole: false } as const; // Pricing: MiniMax doesn't publish public rates. Override in models.json for accurate costs. export const MINIMAX_API_COST = { @@ -38,6 +45,12 @@ export const MOONSHOT_DEFAULT_COST = { cacheRead: 0, cacheWrite: 0, }; +export const KIMI_CODE_DEFAULT_COST = { + input: 0, + output: 0, + cacheRead: 0, + cacheWrite: 0 +}; const MINIMAX_MODEL_CATALOG = { "MiniMax-M2.1": { name: "MiniMax M2.1", reasoning: false }, @@ -89,3 +102,17 @@ export function buildMoonshotModelDefinition(): ModelDefinitionConfig { maxTokens: MOONSHOT_DEFAULT_MAX_TOKENS, }; } + +export function buildKimiCodeModelDefinition(): ModelDefinitionConfig { + return { + id: KIMI_CODE_MODEL_ID, + name: "Kimi For Coding", + reasoning: true, + input: ["text"], + cost: KIMI_CODE_DEFAULT_COST, + contextWindow: KIMI_CODE_CONTEXT_WINDOW, + maxTokens: KIMI_CODE_MAX_TOKENS, + headers: KIMI_CODE_HEADERS, + compat: KIMI_CODE_COMPAT + }; +} diff --git a/src/commands/onboard-auth.ts b/src/commands/onboard-auth.ts index 13fe0555e..93d68339c 100644 --- a/src/commands/onboard-auth.ts +++ b/src/commands/onboard-auth.ts @@ -4,6 +4,8 @@ export { } from "../agents/synthetic-models.js"; export { applyAuthProfileConfig, + applyKimiCodeConfig, + applyKimiCodeProviderConfig, applyMoonshotConfig, applyMoonshotProviderConfig, applyOpenrouterConfig, @@ -31,6 +33,7 @@ export { OPENROUTER_DEFAULT_MODEL_REF, setAnthropicApiKey, setGeminiApiKey, + setKimiCodeApiKey, setMinimaxApiKey, setMoonshotApiKey, setOpencodeZenApiKey, @@ -43,10 +46,14 @@ export { ZAI_DEFAULT_MODEL_REF, } from "./onboard-auth.credentials.js"; export { + buildKimiCodeModelDefinition, buildMinimaxApiModelDefinition, buildMinimaxModelDefinition, buildMoonshotModelDefinition, DEFAULT_MINIMAX_BASE_URL, + KIMI_CODE_BASE_URL, + KIMI_CODE_MODEL_ID, + KIMI_CODE_MODEL_REF, MINIMAX_API_BASE_URL, MINIMAX_HOSTED_MODEL_ID, MINIMAX_HOSTED_MODEL_REF, diff --git a/src/commands/onboard-non-interactive/local/auth-choice.ts b/src/commands/onboard-non-interactive/local/auth-choice.ts index 15151d690..64034e1fd 100644 --- a/src/commands/onboard-non-interactive/local/auth-choice.ts +++ b/src/commands/onboard-non-interactive/local/auth-choice.ts @@ -13,6 +13,7 @@ import { buildTokenProfileId, validateAnthropicSetupToken } from "../../auth-tok import { applyGoogleGeminiModelDefault } from "../../google-gemini-model-default.js"; import { applyAuthProfileConfig, + applyKimiCodeConfig, applyMinimaxApiConfig, applyMinimaxConfig, applyMoonshotConfig, @@ -23,6 +24,7 @@ import { applyZaiConfig, setAnthropicApiKey, setGeminiApiKey, + setKimiCodeApiKey, setMinimaxApiKey, setMoonshotApiKey, setOpencodeZenApiKey, @@ -231,6 +233,25 @@ export async function applyNonInteractiveAuthChoice(params: { return applyMoonshotConfig(nextConfig); } + if (authChoice === "kimi-code-api-key") { + const resolved = await resolveNonInteractiveApiKey({ + provider: "kimi-code", + cfg: baseConfig, + flagValue: opts.kimiCodeApiKey, + flagName: "--kimi-code-api-key", + envVar: "KIMICODE_API_KEY", + runtime + }); + if (!resolved) return null; + if (resolved.source !== "profile") await setKimiCodeApiKey(resolved.key); + nextConfig = applyAuthProfileConfig(nextConfig, { + profileId: "kimi-code:default", + provider: "kimi-code", + mode: "api_key" + }); + return applyKimiCodeConfig(nextConfig); + } + if (authChoice === "synthetic-api-key") { const resolved = await resolveNonInteractiveApiKey({ provider: "synthetic", diff --git a/src/commands/onboard-types.ts b/src/commands/onboard-types.ts index 5dd610777..a60c764b4 100644 --- a/src/commands/onboard-types.ts +++ b/src/commands/onboard-types.ts @@ -14,6 +14,7 @@ export type AuthChoice = | "openrouter-api-key" | "ai-gateway-api-key" | "moonshot-api-key" + | "kimi-code-api-key" | "synthetic-api-key" | "codex-cli" | "apiKey" @@ -57,6 +58,7 @@ export type OnboardOptions = { openrouterApiKey?: string; aiGatewayApiKey?: string; moonshotApiKey?: string; + kimiCodeApiKey?: string; geminiApiKey?: string; zaiApiKey?: string; minimaxApiKey?: string;