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

View File

@@ -37,9 +37,22 @@ const { inferAction, registerCapabilityCli } = vi.hoisted(() => {
return { inferAction: action, registerCapabilityCli: register }; 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("../acp-cli.js", () => ({ registerAcpCli }));
vi.mock("../nodes-cli.js", () => ({ registerNodesCli })); vi.mock("../nodes-cli.js", () => ({ registerNodesCli }));
vi.mock("../capability-cli.js", () => ({ registerCapabilityCli })); 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 () => { vi.mock("./private-qa-cli.js", async () => {
const actual = await vi.importActual<typeof import("./private-qa-cli.js")>("./private-qa-cli.js"); const actual = await vi.importActual<typeof import("./private-qa-cli.js")>("./private-qa-cli.js");
return { return {
@@ -78,6 +91,8 @@ describe("registerSubCliCommands", () => {
loadPrivateQaCliModule.mockClear(); loadPrivateQaCliModule.mockClear();
registerCapabilityCli.mockClear(); registerCapabilityCli.mockClear();
inferAction.mockClear(); inferAction.mockClear();
registerPluginsCli.mockClear();
registerPluginCliCommandsFromValidatedConfig.mockClear();
}); });
afterEach(() => { afterEach(() => {
@@ -158,4 +173,24 @@ describe("registerSubCliCommands", () => {
expect(registerAcpCli).toHaveBeenCalledTimes(1); expect(registerAcpCli).toHaveBeenCalledTimes(1);
expect(acpAction).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);
});
}); });