diff --git a/CHANGELOG.md b/CHANGELOG.md index e5a96fcf0..30f1c74f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,9 @@ - Onboarding/CLI: group model/auth choice by provider and label Z.AI as GLM 4.7. - Onboarding/Docs: add Moonshot AI (Kimi K2) auth choice + config example. - CLI/Onboarding: prompt to reuse detected API keys for Moonshot/MiniMax/Z.AI/Gemini/Anthropic/OpenCode. +- CLI/Onboarding: move MiniMax to the top of the provider list. +- CLI/Onboarding: add MiniMax M2.1 Lightning auth choice. +- CLI/Onboarding: show key previews when reusing detected API keys. - Auto-reply: add compact `/model` picker (models + available providers) and show provider endpoints in `/model status`. - Control UI: add Config tab model presets (MiniMax M2.1, GLM 4.7, Kimi) for one-click setup. - Plugins: add extension loader (tools/RPC/CLI/services), discovery paths, and config schema + Control UI labels (uiHints). @@ -73,6 +76,7 @@ - Auto-reply: allow inline `/status` for allowlisted senders (stripped before the model); unauthorized senders see it as plain text. - Auto-reply: include config-only allowlisted models in `/model` even when the catalog is partial. - Auto-reply: ignore inline `/status` directives unless the message is directive-only. +- CLI/Configure: enter the selected section immediately, then return to the section picker. - Auto-reply: align `/think` default display with model reasoning defaults. (#751) — thanks @gabriel-trigo. - Auto-reply: flush block reply buffers on tool boundaries. (#750) — thanks @sebslight. - Auto-reply: allow sender fallback for command authorization when `SenderId` is empty (WhatsApp self-chat). (#755) — thanks @juanpablodlc. diff --git a/src/cli/program.ts b/src/cli/program.ts index 14ca640d8..dd65c81e8 100644 --- a/src/cli/program.ts +++ b/src/cli/program.ts @@ -262,7 +262,7 @@ export function buildProgram() { .option("--mode ", "Wizard mode: local|remote") .option( "--auth-choice ", - "Auth: setup-token|claude-cli|token|openai-codex|openai-api-key|openrouter-api-key|moonshot-api-key|codex-cli|antigravity|gemini-api-key|zai-api-key|apiKey|minimax-api|opencode-zen|skip", + "Auth: setup-token|claude-cli|token|openai-codex|openai-api-key|openrouter-api-key|moonshot-api-key|codex-cli|antigravity|gemini-api-key|zai-api-key|apiKey|minimax-api|minimax-api-lightning|opencode-zen|skip", ) .option( "--token-provider ", @@ -339,6 +339,7 @@ export function buildProgram() { | "apiKey" | "minimax-cloud" | "minimax-api" + | "minimax-api-lightning" | "minimax" | "opencode-zen" | "skip" diff --git a/src/commands/auth-choice-options.test.ts b/src/commands/auth-choice-options.test.ts index 035cb0f88..3071904da 100644 --- a/src/commands/auth-choice-options.test.ts +++ b/src/commands/auth-choice-options.test.ts @@ -79,6 +79,9 @@ describe("buildAuthChoiceOptions", () => { }); expect(options.some((opt) => opt.value === "minimax-api")).toBe(true); + expect(options.some((opt) => opt.value === "minimax-api-lightning")).toBe( + true, + ); }); it("includes Moonshot auth choice", () => { diff --git a/src/commands/auth-choice-options.ts b/src/commands/auth-choice-options.ts index 812b848dd..a9d01e023 100644 --- a/src/commands/auth-choice-options.ts +++ b/src/commands/auth-choice-options.ts @@ -47,6 +47,12 @@ const AUTH_CHOICE_GROUP_DEFS: { hint: "Claude CLI + API key", choices: ["claude-cli", "setup-token", "token", "apiKey"], }, + { + value: "minimax", + label: "MiniMax", + hint: "M2.1 (recommended)", + choices: ["minimax-api", "minimax-api-lightning"], + }, { value: "google", label: "Google", @@ -77,12 +83,6 @@ const AUTH_CHOICE_GROUP_DEFS: { hint: "API key", choices: ["opencode-zen"], }, - { - value: "minimax", - label: "MiniMax", - hint: "M2.1 (recommended)", - choices: ["minimax-api"], - }, ]; function formatOAuthHint( @@ -181,6 +181,11 @@ export function buildAuthChoiceOptions(params: { 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, lower cost", + }); if (params.includeSkip) { options.push({ value: "skip", label: "Skip for now" }); } diff --git a/src/commands/auth-choice.ts b/src/commands/auth-choice.ts index 56407ccaa..f0f18f1e7 100644 --- a/src/commands/auth-choice.ts +++ b/src/commands/auth-choice.ts @@ -68,6 +68,27 @@ import { } from "./openai-codex-model-default.js"; import { OPENCODE_ZEN_DEFAULT_MODEL } from "./opencode-zen-model-default.js"; +const DEFAULT_KEY_PREVIEW = { head: 4, tail: 4 }; + +function formatApiKeyPreview( + raw: string, + opts: { head?: number; tail?: number } = {}, +): string { + 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)}`; +} + export async function warnIfModelConfigLooksOff( config: ClawdbotConfig, prompter: WizardPrompter, @@ -339,7 +360,7 @@ export async function applyAuthChoice(params: { const envKey = resolveEnvApiKey("openai"); if (envKey) { const useExisting = await params.prompter.confirm({ - message: `Use existing OPENAI_API_KEY (${envKey.source})?`, + message: `Use existing OPENAI_API_KEY (${envKey.source}, ${formatApiKeyPreview(envKey.apiKey)})?`, initialValue: true, }); if (useExisting) { @@ -406,7 +427,7 @@ export async function applyAuthChoice(params: { const envKey = resolveEnvApiKey("openrouter"); if (envKey) { const useExisting = await params.prompter.confirm({ - message: `Use existing OPENROUTER_API_KEY (${envKey.source})?`, + message: `Use existing OPENROUTER_API_KEY (${envKey.source}, ${formatApiKeyPreview(envKey.apiKey)})?`, initialValue: true, }); if (useExisting) { @@ -448,7 +469,7 @@ export async function applyAuthChoice(params: { const envKey = resolveEnvApiKey("moonshot"); if (envKey) { const useExisting = await params.prompter.confirm({ - message: `Use existing MOONSHOT_API_KEY (${envKey.source})?`, + message: `Use existing MOONSHOT_API_KEY (${envKey.source}, ${formatApiKeyPreview(envKey.apiKey)})?`, initialValue: true, }); if (useExisting) { @@ -691,7 +712,7 @@ export async function applyAuthChoice(params: { const envKey = resolveEnvApiKey("google"); if (envKey) { const useExisting = await params.prompter.confirm({ - message: `Use existing GEMINI_API_KEY (${envKey.source})?`, + message: `Use existing GEMINI_API_KEY (${envKey.source}, ${formatApiKeyPreview(envKey.apiKey)})?`, initialValue: true, }); if (useExisting) { @@ -729,7 +750,7 @@ export async function applyAuthChoice(params: { const envKey = resolveEnvApiKey("zai"); if (envKey) { const useExisting = await params.prompter.confirm({ - message: `Use existing ZAI_API_KEY (${envKey.source})?`, + message: `Use existing ZAI_API_KEY (${envKey.source}, ${formatApiKeyPreview(envKey.apiKey)})?`, initialValue: true, }); if (useExisting) { @@ -782,7 +803,7 @@ export async function applyAuthChoice(params: { const envKey = process.env.ANTHROPIC_API_KEY?.trim(); if (envKey) { const useExisting = await params.prompter.confirm({ - message: "Use existing ANTHROPIC_API_KEY (env)?", + message: `Use existing ANTHROPIC_API_KEY (env, ${formatApiKeyPreview(envKey)})?`, initialValue: true, }); if (useExisting) { @@ -804,14 +825,18 @@ export async function applyAuthChoice(params: { }); } else if ( params.authChoice === "minimax-cloud" || - params.authChoice === "minimax-api" + params.authChoice === "minimax-api" || + params.authChoice === "minimax-api-lightning" ) { - const modelId = "MiniMax-M2.1"; + const modelId = + params.authChoice === "minimax-api-lightning" + ? "MiniMax-M2.1-lightning" + : "MiniMax-M2.1"; let hasCredential = false; const envKey = resolveEnvApiKey("minimax"); if (envKey) { const useExisting = await params.prompter.confirm({ - message: `Use existing MINIMAX_API_KEY (${envKey.source})?`, + message: `Use existing MINIMAX_API_KEY (${envKey.source}, ${formatApiKeyPreview(envKey.apiKey)})?`, initialValue: true, }); if (useExisting) { @@ -860,7 +885,7 @@ export async function applyAuthChoice(params: { const envKey = resolveEnvApiKey("opencode"); if (envKey) { const useExisting = await params.prompter.confirm({ - message: `Use existing OPENCODE_API_KEY (${envKey.source})?`, + message: `Use existing OPENCODE_API_KEY (${envKey.source}, ${formatApiKeyPreview(envKey.apiKey)})?`, initialValue: true, }); if (useExisting) { @@ -923,6 +948,7 @@ export function resolvePreferredProviderForAuthChoice( return "google-antigravity"; case "minimax-cloud": case "minimax-api": + case "minimax-api-lightning": return "minimax"; case "minimax": return "lmstudio"; diff --git a/src/commands/onboard-non-interactive.ts b/src/commands/onboard-non-interactive.ts index 0197b2d03..c197a8560 100644 --- a/src/commands/onboard-non-interactive.ts +++ b/src/commands/onboard-non-interactive.ts @@ -305,7 +305,11 @@ export async function runNonInteractiveOnboarding( mode: "api_key", }); nextConfig = applyMoonshotConfig(nextConfig); - } else if (authChoice === "minimax-cloud" || authChoice === "minimax-api") { + } else if ( + authChoice === "minimax-cloud" || + authChoice === "minimax-api" || + authChoice === "minimax-api-lightning" + ) { const resolved = await resolveNonInteractiveApiKey({ provider: "minimax", cfg: baseConfig, @@ -323,7 +327,10 @@ export async function runNonInteractiveOnboarding( provider: "minimax", mode: "api_key", }); - const modelId = "MiniMax-M2.1"; + const modelId = + authChoice === "minimax-api-lightning" + ? "MiniMax-M2.1-lightning" + : "MiniMax-M2.1"; nextConfig = applyMinimaxApiConfig(nextConfig, modelId); } else if (authChoice === "claude-cli") { const store = ensureAuthProfileStore(undefined, { diff --git a/src/commands/onboard-types.ts b/src/commands/onboard-types.ts index 074d6970c..e28a271c5 100644 --- a/src/commands/onboard-types.ts +++ b/src/commands/onboard-types.ts @@ -20,6 +20,7 @@ export type AuthChoice = | "minimax-cloud" | "minimax" | "minimax-api" + | "minimax-api-lightning" | "opencode-zen" | "skip"; export type GatewayAuthChoice = "off" | "token" | "password";