diff --git a/CHANGELOG.md b/CHANGELOG.md index c6e378b7996..21d63c78025 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ Docs: https://docs.openclaw.ai ### Fixes +- CLI/plugins: stop treating the non-plugin `auth` command root as a bundled plugin id, so restrictive `plugins.allow` configs no longer tell users to add stale `auth` plugin entries. - Plugins/externalization: repair missing configured plugin installs from npm by default, reserve ClawHub downloads for explicit `clawhubSpec` metadata, and cover agent-runtime/env-selected plugin repair. Thanks @vincentkoc. - Upgrade/config: validate configured web-search providers and statically suppressed model/provider pairs against the active plugin set at config load, so stale plugin state fails loud before runtime fallback. - Status/update: resolve beta update-channel checks from the installed version when config still says `stable`, and let `status --deep` reuse live gateway channel credential state instead of warning on command-path-only token misses. diff --git a/src/cli/command-registration-policy.test.ts b/src/cli/command-registration-policy.test.ts index 23992545d8d..11bc7db54a0 100644 --- a/src/cli/command-registration-policy.test.ts +++ b/src/cli/command-registration-policy.test.ts @@ -50,6 +50,13 @@ describe("command-registration-policy", () => { hasBuiltinPrimary: false, }), ).toBe(false); + expect( + shouldSkipPluginCommandRegistration({ + argv: ["node", "openclaw", "auth", "login"], + primary: "auth", + hasBuiltinPrimary: false, + }), + ).toBe(true); expect( shouldSkipPluginCommandRegistration({ argv: ["node", "openclaw", "tool", "image_generate"], diff --git a/src/cli/command-registration-policy.ts b/src/cli/command-registration-policy.ts index 673f59c2d28..aea4d3605d6 100644 --- a/src/cli/command-registration-policy.ts +++ b/src/cli/command-registration-policy.ts @@ -1,7 +1,7 @@ import { isTruthyEnvValue } from "../infra/env.js"; import { resolveCliArgvInvocation } from "./argv-invocation.js"; -const RESERVED_NON_PLUGIN_COMMAND_ROOTS = new Set(["tool", "tools"]); +const RESERVED_NON_PLUGIN_COMMAND_ROOTS = new Set(["auth", "tool", "tools"]); export function isReservedNonPluginCommandRoot(primary: string | null | undefined): boolean { return typeof primary === "string" && RESERVED_NON_PLUGIN_COMMAND_ROOTS.has(primary); diff --git a/src/cli/run-main.exit.test.ts b/src/cli/run-main.exit.test.ts index 1be30a2a709..a219272e88a 100644 --- a/src/cli/run-main.exit.test.ts +++ b/src/cli/run-main.exit.test.ts @@ -400,6 +400,7 @@ describe("runCli exit behavior", () => { }); it.each([ + ["auth", ["node", "openclaw", "auth", "--help"]], ["tool", ["node", "openclaw", "tool", "image_generate"]], ["tools", ["node", "openclaw", "tools", "effective"]], ])("keeps reserved %s command roots out of plugin command discovery", async (_name, argv) => { diff --git a/src/cli/run-main.test.ts b/src/cli/run-main.test.ts index 1a319478ffc..92592bc8097 100644 --- a/src/cli/run-main.test.ts +++ b/src/cli/run-main.test.ts @@ -214,12 +214,14 @@ describe("resolveMissingPluginCommandMessage", () => { }); it("does not classify reserved non-plugin command roots as plugin allowlist misses", () => { - const message = resolveMissingPluginCommandMessage("tool", { - plugins: { - allow: ["browser"], - }, - }); - expect(message).toBeNull(); + for (const root of ["auth", "tool"]) { + const message = resolveMissingPluginCommandMessage(root, { + plugins: { + allow: ["browser"], + }, + }); + expect(message).toBeNull(); + } }); it("explains that dreaming is a runtime slash command, not a CLI command", () => {