mirror of https://github.com/openclaw/openclaw.git
refactor: move legacy auth choice aliases into plugin manifests
This commit is contained in:
parent
e25f634d50
commit
2d26f2d876
|
|
@ -11,6 +11,7 @@
|
|||
"provider": "anthropic",
|
||||
"method": "cli",
|
||||
"choiceId": "anthropic-cli",
|
||||
"deprecatedChoiceIds": ["claude-cli"],
|
||||
"choiceLabel": "Anthropic Claude CLI",
|
||||
"choiceHint": "Reuse a local Claude CLI login on this host",
|
||||
"groupId": "anthropic",
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
"provider": "openai-codex",
|
||||
"method": "oauth",
|
||||
"choiceId": "openai-codex",
|
||||
"deprecatedChoiceIds": ["codex-cli"],
|
||||
"choiceLabel": "OpenAI Codex (ChatGPT OAuth)",
|
||||
"choiceHint": "Browser sign-in",
|
||||
"groupId": "openai",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
resolveLegacyAuthChoiceAliasesForCli,
|
||||
formatDeprecatedNonInteractiveAuthChoiceError,
|
||||
normalizeLegacyOnboardAuthChoice,
|
||||
resolveDeprecatedAuthChoiceReplacement,
|
||||
|
|
@ -16,4 +17,13 @@ describe("auth choice legacy aliases", () => {
|
|||
'Auth choice "claude-cli" is deprecated.\nUse "--auth-choice anthropic-cli".',
|
||||
);
|
||||
});
|
||||
|
||||
it("sources deprecated cli aliases from plugin manifests", () => {
|
||||
expect(resolveLegacyAuthChoiceAliasesForCli()).toEqual([
|
||||
"setup-token",
|
||||
"oauth",
|
||||
"claude-cli",
|
||||
"codex-cli",
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,53 +1,114 @@
|
|||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import {
|
||||
resolveManifestDeprecatedProviderAuthChoice,
|
||||
resolveManifestProviderAuthChoices,
|
||||
} from "../plugins/provider-auth-choices.js";
|
||||
import type { AuthChoice } from "./onboard-types.js";
|
||||
|
||||
export const AUTH_CHOICE_LEGACY_ALIASES_FOR_CLI: ReadonlyArray<AuthChoice> = [
|
||||
"setup-token",
|
||||
"oauth",
|
||||
"claude-cli",
|
||||
"codex-cli",
|
||||
];
|
||||
function resolveLegacyCliBackendChoice(
|
||||
choice: string,
|
||||
params?: {
|
||||
config?: OpenClawConfig;
|
||||
workspaceDir?: string;
|
||||
env?: NodeJS.ProcessEnv;
|
||||
},
|
||||
) {
|
||||
if (!choice.endsWith("-cli")) {
|
||||
return undefined;
|
||||
}
|
||||
return resolveManifestDeprecatedProviderAuthChoice(choice, params);
|
||||
}
|
||||
|
||||
function resolveReplacementLabel(choiceLabel: string): string {
|
||||
return choiceLabel.trim() || "the replacement auth choice";
|
||||
}
|
||||
|
||||
export function resolveLegacyAuthChoiceAliasesForCli(params?: {
|
||||
config?: OpenClawConfig;
|
||||
workspaceDir?: string;
|
||||
env?: NodeJS.ProcessEnv;
|
||||
}): ReadonlyArray<AuthChoice> {
|
||||
const manifestCliAliases = resolveManifestProviderAuthChoices(params)
|
||||
.flatMap((choice) => choice.deprecatedChoiceIds ?? [])
|
||||
.filter((choice): choice is AuthChoice => choice.endsWith("-cli"))
|
||||
.toSorted((left, right) => left.localeCompare(right));
|
||||
return ["setup-token", "oauth", ...manifestCliAliases];
|
||||
}
|
||||
|
||||
export function normalizeLegacyOnboardAuthChoice(
|
||||
authChoice: AuthChoice | undefined,
|
||||
params?: {
|
||||
config?: OpenClawConfig;
|
||||
workspaceDir?: string;
|
||||
env?: NodeJS.ProcessEnv;
|
||||
},
|
||||
): AuthChoice | undefined {
|
||||
if (authChoice === "oauth") {
|
||||
return "setup-token";
|
||||
}
|
||||
if (authChoice === "claude-cli") {
|
||||
return "anthropic-cli";
|
||||
}
|
||||
if (authChoice === "codex-cli") {
|
||||
return "openai-codex";
|
||||
if (typeof authChoice === "string") {
|
||||
const deprecatedChoice = resolveLegacyCliBackendChoice(authChoice, params);
|
||||
if (deprecatedChoice) {
|
||||
return deprecatedChoice.choiceId as AuthChoice;
|
||||
}
|
||||
}
|
||||
return authChoice;
|
||||
}
|
||||
|
||||
export function isDeprecatedAuthChoice(
|
||||
authChoice: AuthChoice | undefined,
|
||||
): authChoice is "claude-cli" | "codex-cli" {
|
||||
return authChoice === "claude-cli" || authChoice === "codex-cli";
|
||||
params?: {
|
||||
config?: OpenClawConfig;
|
||||
workspaceDir?: string;
|
||||
env?: NodeJS.ProcessEnv;
|
||||
},
|
||||
): authChoice is AuthChoice {
|
||||
return (
|
||||
typeof authChoice === "string" && Boolean(resolveLegacyCliBackendChoice(authChoice, params))
|
||||
);
|
||||
}
|
||||
|
||||
export function resolveDeprecatedAuthChoiceReplacement(authChoice: "claude-cli" | "codex-cli"): {
|
||||
normalized: AuthChoice;
|
||||
message: string;
|
||||
} {
|
||||
if (authChoice === "claude-cli") {
|
||||
return {
|
||||
normalized: "anthropic-cli",
|
||||
message: 'Auth choice "claude-cli" is deprecated; using Anthropic Claude CLI setup instead.',
|
||||
};
|
||||
export function resolveDeprecatedAuthChoiceReplacement(
|
||||
authChoice: AuthChoice,
|
||||
params?: {
|
||||
config?: OpenClawConfig;
|
||||
workspaceDir?: string;
|
||||
env?: NodeJS.ProcessEnv;
|
||||
},
|
||||
):
|
||||
| {
|
||||
normalized: AuthChoice;
|
||||
message: string;
|
||||
}
|
||||
| undefined {
|
||||
if (typeof authChoice !== "string") {
|
||||
return undefined;
|
||||
}
|
||||
const deprecatedChoice = resolveLegacyCliBackendChoice(authChoice, params);
|
||||
if (!deprecatedChoice) {
|
||||
return undefined;
|
||||
}
|
||||
const replacementLabel = resolveReplacementLabel(deprecatedChoice.choiceLabel);
|
||||
return {
|
||||
normalized: "openai-codex",
|
||||
message: 'Auth choice "codex-cli" is deprecated; using OpenAI Codex OAuth instead.',
|
||||
normalized: deprecatedChoice.choiceId as AuthChoice,
|
||||
message: `Auth choice "${authChoice}" is deprecated; using ${replacementLabel} setup instead.`,
|
||||
};
|
||||
}
|
||||
|
||||
export function formatDeprecatedNonInteractiveAuthChoiceError(
|
||||
authChoice: "claude-cli" | "codex-cli",
|
||||
): string {
|
||||
const replacement =
|
||||
authChoice === "claude-cli" ? '"--auth-choice anthropic-cli"' : '"--auth-choice openai-codex"';
|
||||
return [`Auth choice "${authChoice}" is deprecated.`, `Use ${replacement}.`].join("\n");
|
||||
authChoice: AuthChoice,
|
||||
params?: {
|
||||
config?: OpenClawConfig;
|
||||
workspaceDir?: string;
|
||||
env?: NodeJS.ProcessEnv;
|
||||
},
|
||||
): string | undefined {
|
||||
const replacement = resolveDeprecatedAuthChoiceReplacement(authChoice, params);
|
||||
if (!replacement) {
|
||||
return undefined;
|
||||
}
|
||||
return [
|
||||
`Auth choice "${authChoice}" is deprecated.`,
|
||||
`Use "--auth-choice ${replacement.normalized}".`,
|
||||
].join("\n");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { AUTH_CHOICE_LEGACY_ALIASES_FOR_CLI } from "./auth-choice-legacy.js";
|
||||
import { resolveLegacyAuthChoiceAliasesForCli } from "./auth-choice-legacy.js";
|
||||
import type { AuthChoice, AuthChoiceGroupId } from "./onboard-types.js";
|
||||
|
||||
export type { AuthChoiceGroupId };
|
||||
|
|
@ -33,6 +33,9 @@ export const CORE_AUTH_CHOICE_OPTIONS: ReadonlyArray<AuthChoiceOption> = [
|
|||
export function formatStaticAuthChoiceChoicesForCli(params?: {
|
||||
includeSkip?: boolean;
|
||||
includeLegacyAliases?: boolean;
|
||||
config?: import("../config/config.js").OpenClawConfig;
|
||||
workspaceDir?: string;
|
||||
env?: NodeJS.ProcessEnv;
|
||||
}): string {
|
||||
const includeSkip = params?.includeSkip ?? true;
|
||||
const includeLegacyAliases = params?.includeLegacyAliases ?? false;
|
||||
|
|
@ -42,7 +45,7 @@ export function formatStaticAuthChoiceChoicesForCli(params?: {
|
|||
values.push("skip");
|
||||
}
|
||||
if (includeLegacyAliases) {
|
||||
values.push(...AUTH_CHOICE_LEGACY_ALIASES_FOR_CLI);
|
||||
values.push(...resolveLegacyAuthChoiceAliasesForCli(params));
|
||||
}
|
||||
|
||||
return values.join("|");
|
||||
|
|
|
|||
|
|
@ -271,6 +271,25 @@ describe("buildAuthChoiceOptions", () => {
|
|||
});
|
||||
|
||||
it("can include legacy aliases in cli help choices", () => {
|
||||
resolveManifestProviderAuthChoices.mockReturnValue([
|
||||
{
|
||||
pluginId: "anthropic",
|
||||
providerId: "anthropic",
|
||||
methodId: "cli",
|
||||
choiceId: "anthropic-cli",
|
||||
choiceLabel: "Anthropic Claude CLI",
|
||||
deprecatedChoiceIds: ["claude-cli"],
|
||||
},
|
||||
{
|
||||
pluginId: "openai",
|
||||
providerId: "openai-codex",
|
||||
methodId: "oauth",
|
||||
choiceId: "openai-codex",
|
||||
choiceLabel: "OpenAI Codex (ChatGPT OAuth)",
|
||||
deprecatedChoiceIds: ["codex-cli"],
|
||||
},
|
||||
]);
|
||||
|
||||
const cliChoices = formatAuthChoiceChoicesForCli({
|
||||
includeLegacyAliases: true,
|
||||
includeSkip: true,
|
||||
|
|
|
|||
|
|
@ -28,7 +28,10 @@ export async function applyAuthChoice(
|
|||
params: ApplyAuthChoiceParams,
|
||||
): Promise<ApplyAuthChoiceResult> {
|
||||
const normalizedAuthChoice =
|
||||
normalizeLegacyOnboardAuthChoice(params.authChoice) ?? params.authChoice;
|
||||
normalizeLegacyOnboardAuthChoice(params.authChoice, {
|
||||
config: params.config,
|
||||
env: process.env,
|
||||
}) ?? params.authChoice;
|
||||
const normalizedProviderAuthChoice = normalizeApiKeyTokenProviderAuthChoice({
|
||||
authChoice: normalizedAuthChoice,
|
||||
tokenProvider: params.opts?.tokenProvider,
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const resolveManifestProviderAuthChoice = vi.hoisted(() => vi.fn());
|
||||
const resolveManifestDeprecatedProviderAuthChoice = vi.hoisted(() => vi.fn());
|
||||
const resolveManifestProviderAuthChoices = vi.hoisted(() => vi.fn(() => []));
|
||||
const resolveProviderPluginChoice = vi.hoisted(() => vi.fn());
|
||||
const resolvePluginProviders = vi.hoisted(() => vi.fn(() => []));
|
||||
|
||||
vi.mock("../plugins/provider-auth-choices.js", () => ({
|
||||
resolveManifestProviderAuthChoice,
|
||||
resolveManifestDeprecatedProviderAuthChoice,
|
||||
resolveManifestProviderAuthChoices,
|
||||
}));
|
||||
|
||||
vi.mock("../plugins/provider-wizard.js", () => ({
|
||||
|
|
@ -22,6 +26,8 @@ describe("resolvePreferredProviderForAuthChoice", () => {
|
|||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
resolveManifestProviderAuthChoice.mockReturnValue(undefined);
|
||||
resolveManifestDeprecatedProviderAuthChoice.mockReturnValue(undefined);
|
||||
resolveManifestProviderAuthChoices.mockReturnValue([]);
|
||||
resolvePluginProviders.mockReturnValue([]);
|
||||
resolveProviderPluginChoice.mockReturnValue(null);
|
||||
});
|
||||
|
|
@ -42,25 +48,23 @@ describe("resolvePreferredProviderForAuthChoice", () => {
|
|||
});
|
||||
|
||||
it("normalizes legacy auth choices before plugin lookup", async () => {
|
||||
resolveProviderPluginChoice.mockReturnValue({
|
||||
provider: { id: "anthropic", label: "Anthropic", auth: [] },
|
||||
method: { id: "setup-token", label: "setup-token", kind: "token" },
|
||||
resolveManifestDeprecatedProviderAuthChoice.mockReturnValue({
|
||||
choiceId: "anthropic-cli",
|
||||
choiceLabel: "Anthropic Claude CLI",
|
||||
});
|
||||
resolveManifestProviderAuthChoice.mockReturnValue({
|
||||
pluginId: "anthropic",
|
||||
providerId: "anthropic",
|
||||
methodId: "cli",
|
||||
choiceId: "anthropic-cli",
|
||||
choiceLabel: "Anthropic Claude CLI",
|
||||
});
|
||||
|
||||
await expect(resolvePreferredProviderForAuthChoice({ choice: "claude-cli" })).resolves.toBe(
|
||||
"anthropic",
|
||||
);
|
||||
expect(resolveProviderPluginChoice).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
choice: "setup-token",
|
||||
}),
|
||||
);
|
||||
expect(resolvePluginProviders).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
bundledProviderAllowlistCompat: true,
|
||||
bundledProviderVitestCompat: true,
|
||||
}),
|
||||
);
|
||||
expect(resolveProviderPluginChoice).not.toHaveBeenCalled();
|
||||
expect(resolvePluginProviders).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("falls back to static core choices when no provider plugin claims the choice", async () => {
|
||||
|
|
|
|||
|
|
@ -13,8 +13,10 @@ vi.mock("../api-keys.js", () => ({
|
|||
}));
|
||||
|
||||
const resolveManifestDeprecatedProviderAuthChoice = vi.hoisted(() => vi.fn(() => undefined));
|
||||
const resolveManifestProviderAuthChoices = vi.hoisted(() => vi.fn(() => []));
|
||||
vi.mock("../../../plugins/provider-auth-choices.js", () => ({
|
||||
resolveManifestDeprecatedProviderAuthChoice,
|
||||
resolveManifestProviderAuthChoices,
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
|
|
|
|||
|
|
@ -116,8 +116,13 @@ export async function applyNonInteractiveAuthChoice(params: {
|
|||
...(params.metadata ? { metadata: params.metadata } : {}),
|
||||
};
|
||||
};
|
||||
if (isDeprecatedAuthChoice(authChoice)) {
|
||||
runtime.error(formatDeprecatedNonInteractiveAuthChoiceError(authChoice));
|
||||
if (isDeprecatedAuthChoice(authChoice, { config: nextConfig, env: process.env })) {
|
||||
runtime.error(
|
||||
formatDeprecatedNonInteractiveAuthChoiceError(authChoice, {
|
||||
config: nextConfig,
|
||||
env: process.env,
|
||||
})!,
|
||||
);
|
||||
runtime.exit(1);
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ export type BuiltInAuthChoice =
|
|||
// Legacy alias for `setup-token` (kept for backwards CLI compatibility).
|
||||
| "oauth"
|
||||
| "setup-token"
|
||||
| "claude-cli"
|
||||
| "token"
|
||||
| "chutes"
|
||||
| "deepseek-api-key"
|
||||
|
|
@ -25,7 +24,6 @@ export type BuiltInAuthChoice =
|
|||
| "venice-api-key"
|
||||
| "together-api-key"
|
||||
| "huggingface-api-key"
|
||||
| "codex-cli"
|
||||
| "apiKey"
|
||||
| "gemini-api-key"
|
||||
| "google-gemini-cli"
|
||||
|
|
|
|||
|
|
@ -23,14 +23,22 @@ export async function setupWizardCommand(
|
|||
) {
|
||||
assertSupportedRuntime(runtime);
|
||||
const originalAuthChoice = opts.authChoice;
|
||||
const normalizedAuthChoice = normalizeLegacyOnboardAuthChoice(originalAuthChoice);
|
||||
if (opts.nonInteractive && isDeprecatedAuthChoice(originalAuthChoice)) {
|
||||
runtime.error(formatDeprecatedNonInteractiveAuthChoiceError(originalAuthChoice));
|
||||
const normalizedAuthChoice = normalizeLegacyOnboardAuthChoice(originalAuthChoice, {
|
||||
env: process.env,
|
||||
});
|
||||
if (opts.nonInteractive && isDeprecatedAuthChoice(originalAuthChoice, { env: process.env })) {
|
||||
runtime.error(
|
||||
formatDeprecatedNonInteractiveAuthChoiceError(originalAuthChoice, {
|
||||
env: process.env,
|
||||
})!,
|
||||
);
|
||||
runtime.exit(1);
|
||||
return;
|
||||
}
|
||||
if (isDeprecatedAuthChoice(originalAuthChoice)) {
|
||||
runtime.log(resolveDeprecatedAuthChoiceReplacement(originalAuthChoice).message);
|
||||
if (isDeprecatedAuthChoice(originalAuthChoice, { env: process.env })) {
|
||||
runtime.log(
|
||||
resolveDeprecatedAuthChoiceReplacement(originalAuthChoice, { env: process.env })!.message,
|
||||
);
|
||||
}
|
||||
const flow = opts.flow === "manual" ? ("advanced" as const) : opts.flow;
|
||||
const normalizedOpts =
|
||||
|
|
|
|||
|
|
@ -192,6 +192,7 @@ export const GENERATED_BUNDLED_PLUGIN_METADATA = [
|
|||
provider: "anthropic",
|
||||
method: "cli",
|
||||
choiceId: "anthropic-cli",
|
||||
deprecatedChoiceIds: ["claude-cli"],
|
||||
choiceLabel: "Anthropic Claude CLI",
|
||||
choiceHint: "Reuse a local Claude CLI login on this host",
|
||||
groupId: "anthropic",
|
||||
|
|
@ -11374,6 +11375,7 @@ export const GENERATED_BUNDLED_PLUGIN_METADATA = [
|
|||
provider: "openai-codex",
|
||||
method: "oauth",
|
||||
choiceId: "openai-codex",
|
||||
deprecatedChoiceIds: ["codex-cli"],
|
||||
choiceLabel: "OpenAI Codex (ChatGPT OAuth)",
|
||||
choiceHint: "Browser sign-in",
|
||||
groupId: "openai",
|
||||
|
|
|
|||
|
|
@ -3,11 +3,12 @@ import type { OpenClawConfig } from "../config/config.js";
|
|||
import { resolveManifestProviderAuthChoice } from "./provider-auth-choices.js";
|
||||
|
||||
const PREFERRED_PROVIDER_BY_AUTH_CHOICE: Partial<Record<string, string>> = {
|
||||
chutes: "chutes",
|
||||
"custom-api-key": "custom",
|
||||
};
|
||||
|
||||
function normalizeLegacyAuthChoice(choice: string): string {
|
||||
return normalizeLegacyOnboardAuthChoice(choice) ?? choice;
|
||||
return normalizeLegacyOnboardAuthChoice(choice, { env: process.env }) ?? choice;
|
||||
}
|
||||
|
||||
export async function resolvePreferredProviderForAuthChoice(params: {
|
||||
|
|
|
|||
Loading…
Reference in New Issue