fix(cli): skip plugin preload for plugin updates

This commit is contained in:
Vincent Koc
2026-04-26 19:05:26 -07:00
parent a5f6603e61
commit ead76f61d8
2 changed files with 43 additions and 3 deletions

View File

@@ -1,5 +1,6 @@
import type { Command } from "commander";
import { resolveCliArgvInvocation } from "../argv-invocation.js";
import { resolveCliCommandPathPolicy } from "../command-path-policy.js";
import {
shouldEagerRegisterSubcommands,
shouldRegisterPrimarySubcommandOnly,
@@ -30,13 +31,17 @@ async function registerSubCliWithPluginCommands(
registerSubCli: () => Promise<void>,
pluginCliPosition: "before" | "after",
) {
const isHelpOrVersion = resolveCliArgvInvocation(process.argv).hasHelpOrVersion;
const invocation = resolveCliArgvInvocation(process.argv);
const shouldRegisterPluginCommands =
!invocation.hasHelpOrVersion &&
(invocation.commandPath.length <= 1 ||
resolveCliCommandPathPolicy(invocation.commandPath).loadPlugins !== "never");
const { registerPluginCliCommandsFromValidatedConfig } = await import("../../plugins/cli.js");
if (pluginCliPosition === "before" && !isHelpOrVersion) {
if (pluginCliPosition === "before" && shouldRegisterPluginCommands) {
await registerPluginCliCommandsFromValidatedConfig(program);
}
await registerSubCli();
if (pluginCliPosition === "after" && !isHelpOrVersion) {
if (pluginCliPosition === "after" && shouldRegisterPluginCommands) {
await registerPluginCliCommandsFromValidatedConfig(program);
}
}

View File

@@ -37,9 +37,22 @@ const { inferAction, registerCapabilityCli } = vi.hoisted(() => {
return { inferAction: action, registerCapabilityCli: register };
});
const { registerPluginsCli, registerPluginCliCommandsFromValidatedConfig } = vi.hoisted(() => ({
registerPluginsCli: vi.fn((program: Command) => {
const plugins = program.command("plugins");
plugins
.command("update")
.argument("[id]")
.action(() => undefined);
}),
registerPluginCliCommandsFromValidatedConfig: vi.fn(async () => null),
}));
vi.mock("../acp-cli.js", () => ({ registerAcpCli }));
vi.mock("../nodes-cli.js", () => ({ registerNodesCli }));
vi.mock("../capability-cli.js", () => ({ registerCapabilityCli }));
vi.mock("../plugins-cli.js", () => ({ registerPluginsCli }));
vi.mock("../../plugins/cli.js", () => ({ registerPluginCliCommandsFromValidatedConfig }));
vi.mock("./private-qa-cli.js", async () => {
const actual = await vi.importActual<typeof import("./private-qa-cli.js")>("./private-qa-cli.js");
return {
@@ -78,6 +91,8 @@ describe("registerSubCliCommands", () => {
loadPrivateQaCliModule.mockClear();
registerCapabilityCli.mockClear();
inferAction.mockClear();
registerPluginsCli.mockClear();
registerPluginCliCommandsFromValidatedConfig.mockClear();
});
afterEach(() => {
@@ -158,4 +173,24 @@ describe("registerSubCliCommands", () => {
expect(registerAcpCli).toHaveBeenCalledTimes(1);
expect(acpAction).toHaveBeenCalledTimes(1);
});
it("does not preload plugin CLI registrations for builtin plugins update", async () => {
process.argv = ["node", "openclaw", "plugins", "update", "lossless-claw"];
const program = new Command().name("openclaw");
await registerSubCliByName(program, "plugins");
expect(registerPluginsCli).toHaveBeenCalledTimes(1);
expect(registerPluginCliCommandsFromValidatedConfig).not.toHaveBeenCalled();
});
it("keeps plugin CLI registrations available for the plugins command root", async () => {
process.argv = ["node", "openclaw", "plugins"];
const program = new Command().name("openclaw");
await registerSubCliByName(program, "plugins");
expect(registerPluginsCli).toHaveBeenCalledTimes(1);
expect(registerPluginCliCommandsFromValidatedConfig).toHaveBeenCalledTimes(1);
});
});