From c7ead7d8a98a2b96588e784a961cac168e8b33b2 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sat, 25 Apr 2026 23:23:01 -0700 Subject: [PATCH] fix(cli): lazy-load model auth runtime --- CHANGELOG.md | 1 + src/cli/capability-cli.test.ts | 7 +++++-- src/cli/capability-cli.ts | 3 ++- src/cli/model-auth-runtime-boundary.test.ts | 16 ++++++++++++++++ 4 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 src/cli/model-auth-runtime-boundary.test.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 52ea5fc88c5..4bf66995b17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,7 @@ Docs: https://docs.openclaw.ai - CLI/models: use OpenClaw Provider Index preview rows as the final cold fallback for installable providers, while keeping user config, installed manifests, and refreshed cache rows above provider-index metadata. Thanks @vincentkoc. - Providers/plugins: keep onboarding and auth-choice setup lists on cold manifest/install metadata and add Provider Index install metadata for not-yet-installed provider plugins. Thanks @vincentkoc. - Providers/plugins: keep provider setup guidance and configure auth imports on cold manifest metadata, with a regression guard against static provider-runtime imports on setup/configure list paths. Thanks @vincentkoc. +- CLI/capabilities: keep capability command registration from importing the models auth runtime until `model auth login` actually runs. Thanks @vincentkoc. - Plugins/chat commands: refresh the persisted plugin registry after `/plugins enable` and `/plugins disable`, matching the CLI mutation path. Thanks @vincentkoc. - Plugins/compat: mark `OPENCLAW_DISABLE_PERSISTED_PLUGIN_REGISTRY` as a deprecated break-glass switch and point operators at registry repair instead. Thanks @vincentkoc. - Plugins/registry: ignore stale persisted registry reads when plugin policy no longer matches current config, and stamp generated registry files with a do-not-edit warning. Thanks @vincentkoc. diff --git a/src/cli/capability-cli.test.ts b/src/cli/capability-cli.test.ts index be52ac652cc..5e2e1e5c33b 100644 --- a/src/cli/capability-cli.test.ts +++ b/src/cli/capability-cli.test.ts @@ -162,10 +162,13 @@ vi.mock("../agents/memory-search.js", () => ({ mocks.resolveMemorySearchConfig as typeof import("../agents/memory-search.js").resolveMemorySearchConfig, })); -vi.mock("../commands/models.js", () => ({ +vi.mock("../commands/models/auth.js", () => ({ modelsAuthLoginCommand: vi.fn(), +})); + +vi.mock("../commands/models/list.js", () => ({ modelsStatusCommand: - mocks.modelsStatusCommand as typeof import("../commands/models.js").modelsStatusCommand, + mocks.modelsStatusCommand as typeof import("../commands/models/list.js").modelsStatusCommand, })); vi.mock("../gateway/call.js", () => ({ diff --git a/src/cli/capability-cli.ts b/src/cli/capability-cli.ts index 3cc85555d42..8eb73b1d42c 100644 --- a/src/cli/capability-cli.ts +++ b/src/cli/capability-cli.ts @@ -13,7 +13,7 @@ import { import { updateAuthProfileStoreWithLock } from "../agents/auth-profiles/store.js"; import { resolveMemorySearchConfig } from "../agents/memory-search.js"; import { loadModelCatalog } from "../agents/model-catalog.js"; -import { modelsAuthLoginCommand, modelsStatusCommand } from "../commands/models.js"; +import { modelsStatusCommand } from "../commands/models/list.js"; import { loadConfig } from "../config/config.js"; import { resolveAgentModelPrimaryValue } from "../config/model-input.js"; import type { OpenClawConfig } from "../config/types.openclaw.js"; @@ -1522,6 +1522,7 @@ export function registerCapabilityCli(program: Command) { .requiredOption("--provider ", "Provider id") .action(async (opts) => { await runCommandWithRuntime(defaultRuntime, async () => { + const { modelsAuthLoginCommand } = await import("../commands/models/auth.js"); await modelsAuthLoginCommand({ provider: String(opts.provider) }, defaultRuntime); }); }); diff --git a/src/cli/model-auth-runtime-boundary.test.ts b/src/cli/model-auth-runtime-boundary.test.ts new file mode 100644 index 00000000000..dd3d9b53b93 --- /dev/null +++ b/src/cli/model-auth-runtime-boundary.test.ts @@ -0,0 +1,16 @@ +import fs from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import { describe, expect, it } from "vitest"; + +const repoRoot = fileURLToPath(new URL("../..", import.meta.url)); + +describe("model auth runtime boundary", () => { + it("keeps capability CLI command registration off the models auth runtime", () => { + const source = fs.readFileSync(path.join(repoRoot, "src/cli/capability-cli.ts"), "utf8"); + + expect(source).not.toMatch(/\bfrom\s+["'][^"']*commands\/models\.js["']/); + expect(source).not.toMatch(/\bfrom\s+["'][^"']*commands\/models\/auth\.js["']/); + expect(source).toMatch(/\bawait\s+import\(["'][^"']*commands\/models\/auth\.js["']\)/); + }); +});