refactor: centralize auth choice inference flags (#8484) (thanks @f-trycua)

This commit is contained in:
Gustavo Madeira Santana
2026-02-04 20:14:14 -05:00
parent 55acd021c6
commit fa22b155e0
2 changed files with 82 additions and 53 deletions

View File

@@ -1,6 +1,6 @@
import type { OpenClawConfig } from "../../config/config.js";
import type { RuntimeEnv } from "../../runtime.js";
import type { AuthChoice, OnboardOptions } from "../onboard-types.js";
import type { OnboardOptions } from "../onboard-types.js";
import { formatCliCommand } from "../../cli/command-format.js";
import { resolveGatewayPort, writeConfigFile } from "../../config/config.js";
import { logConfigUpdated } from "../../config/logging.js";
@@ -13,6 +13,7 @@ import {
resolveControlUiLinks,
waitForGatewayReachable,
} from "../onboard-helpers.js";
import { inferAuthChoiceFromFlags } from "./local/auth-choice-inference.js";
import { applyNonInteractiveAuthChoice } from "./local/auth-choice.js";
import { installGatewayDaemonNonInteractive } from "./local/daemon-install.js";
import { applyNonInteractiveGatewayConfig } from "./local/gateway-config.js";
@@ -20,57 +21,6 @@ import { logNonInteractiveOnboardingJson } from "./local/output.js";
import { applyNonInteractiveSkillsConfig } from "./local/skills-config.js";
import { resolveNonInteractiveWorkspaceDir } from "./local/workspace.js";
/**
* Infer --auth-choice from provider-specific API key flags when --auth-choice
* is not explicitly provided. This avoids silently skipping credential storage
* when the user passes e.g. `--anthropic-api-key` without `--auth-choice apiKey`.
*/
function inferAuthChoiceFromFlags(opts: OnboardOptions): AuthChoice | undefined {
if (opts.anthropicApiKey) {
return "apiKey";
}
if (opts.geminiApiKey) {
return "gemini-api-key";
}
if (opts.openaiApiKey) {
return "openai-api-key";
}
if (opts.openrouterApiKey) {
return "openrouter-api-key";
}
if (opts.aiGatewayApiKey) {
return "ai-gateway-api-key";
}
if (opts.cloudflareAiGatewayApiKey) {
return "cloudflare-ai-gateway-api-key";
}
if (opts.moonshotApiKey) {
return "moonshot-api-key";
}
if (opts.kimiCodeApiKey) {
return "kimi-code-api-key";
}
if (opts.syntheticApiKey) {
return "synthetic-api-key";
}
if (opts.veniceApiKey) {
return "venice-api-key";
}
if (opts.zaiApiKey) {
return "zai-api-key";
}
if (opts.xiaomiApiKey) {
return "xiaomi-api-key";
}
if (opts.minimaxApiKey) {
return "minimax-api";
}
if (opts.opencodeZenApiKey) {
return "opencode-zen";
}
return undefined;
}
export async function runNonInteractiveOnboardingLocal(params: {
opts: OnboardOptions;
runtime: RuntimeEnv;
@@ -100,7 +50,19 @@ export async function runNonInteractiveOnboardingLocal(params: {
},
};
const authChoice = opts.authChoice ?? inferAuthChoiceFromFlags(opts) ?? "skip";
const inferredAuthChoice = inferAuthChoiceFromFlags(opts);
if (!opts.authChoice && inferredAuthChoice.matches.length > 1) {
runtime.error(
[
"Multiple API key flags were provided for non-interactive onboarding.",
"Use a single provider flag or pass --auth-choice explicitly.",
`Flags: ${inferredAuthChoice.matches.map((match) => match.label).join(", ")}`,
].join("\n"),
);
runtime.exit(1);
return;
}
const authChoice = opts.authChoice ?? inferredAuthChoice.choice ?? "skip";
const nextConfigAfterAuth = await applyNonInteractiveAuthChoice({
nextConfig,
authChoice,

View File

@@ -0,0 +1,67 @@
import type { AuthChoice, OnboardOptions } from "../../onboard-types.js";
type AuthChoiceFlag = {
flag: keyof AuthChoiceFlagOptions;
authChoice: AuthChoice;
label: string;
};
type AuthChoiceFlagOptions = Pick<
OnboardOptions,
| "anthropicApiKey"
| "geminiApiKey"
| "openaiApiKey"
| "openrouterApiKey"
| "aiGatewayApiKey"
| "cloudflareAiGatewayApiKey"
| "moonshotApiKey"
| "kimiCodeApiKey"
| "syntheticApiKey"
| "veniceApiKey"
| "zaiApiKey"
| "xiaomiApiKey"
| "minimaxApiKey"
| "opencodeZenApiKey"
>;
const AUTH_CHOICE_FLAG_MAP = [
{ flag: "anthropicApiKey", authChoice: "apiKey", label: "--anthropic-api-key" },
{ flag: "geminiApiKey", authChoice: "gemini-api-key", label: "--gemini-api-key" },
{ flag: "openaiApiKey", authChoice: "openai-api-key", label: "--openai-api-key" },
{ flag: "openrouterApiKey", authChoice: "openrouter-api-key", label: "--openrouter-api-key" },
{ flag: "aiGatewayApiKey", authChoice: "ai-gateway-api-key", label: "--ai-gateway-api-key" },
{
flag: "cloudflareAiGatewayApiKey",
authChoice: "cloudflare-ai-gateway-api-key",
label: "--cloudflare-ai-gateway-api-key",
},
{ flag: "moonshotApiKey", authChoice: "moonshot-api-key", label: "--moonshot-api-key" },
{ flag: "kimiCodeApiKey", authChoice: "kimi-code-api-key", label: "--kimi-code-api-key" },
{ flag: "syntheticApiKey", authChoice: "synthetic-api-key", label: "--synthetic-api-key" },
{ flag: "veniceApiKey", authChoice: "venice-api-key", label: "--venice-api-key" },
{ flag: "zaiApiKey", authChoice: "zai-api-key", label: "--zai-api-key" },
{ flag: "xiaomiApiKey", authChoice: "xiaomi-api-key", label: "--xiaomi-api-key" },
{ flag: "minimaxApiKey", authChoice: "minimax-api", label: "--minimax-api-key" },
{ flag: "opencodeZenApiKey", authChoice: "opencode-zen", label: "--opencode-zen-api-key" },
] satisfies ReadonlyArray<AuthChoiceFlag>;
export type AuthChoiceInference = {
choice?: AuthChoice;
matches: AuthChoiceFlag[];
};
// Infer auth choice from explicit provider API key flags.
export function inferAuthChoiceFromFlags(opts: OnboardOptions): AuthChoiceInference {
const matches = AUTH_CHOICE_FLAG_MAP.filter(({ flag }) => {
const value = opts[flag];
if (typeof value === "string") {
return value.trim().length > 0;
}
return Boolean(value);
});
return {
choice: matches[0]?.authChoice,
matches,
};
}