perf(cli): route plugin list json directly

This commit is contained in:
Vincent Koc
2026-05-14 16:28:51 +08:00
parent 641ad418c9
commit 94f3ecae9a
7 changed files with 84 additions and 2 deletions

View File

@@ -272,6 +272,24 @@ export function parseChannelsStatusRouteArgs(argv: string[]) {
};
}
export function parsePluginsListRouteArgs(argv: string[]) {
if (!hasFlag(argv, "--json")) {
return null;
}
const positionals = getCommandPositionalsWithRootOptions(argv, {
commandPath: ["plugins", "list"],
booleanFlags: ["--json", "--enabled", "--verbose"],
});
if (!positionals || positionals.length !== 0) {
return null;
}
return {
json: true as const,
enabled: hasFlag(argv, "--enabled"),
verbose: hasFlag(argv, "--verbose"),
};
}
function parseTasksListRouteArgsForCommandPath(argv: string[], commandPath: string[]) {
if (!hasFlag(argv, "--json")) {
return null;

View File

@@ -10,6 +10,7 @@ import {
parseHealthRouteArgs,
parseModelsListRouteArgs,
parseModelsStatusRouteArgs,
parsePluginsListRouteArgs,
parseSessionsRouteArgs,
parseStatusRouteArgs,
parseTasksAuditRouteArgs,
@@ -164,4 +165,11 @@ export const routedCommandDefinitions = {
await channelsStatusCommand(args, defaultRuntime);
},
}),
"plugins-list": defineRoutedCommand({
parseArgs: parsePluginsListRouteArgs,
runParsedArgs: async (args) => {
const { runPluginsListCommand } = await import("../plugins-list-command.js");
await runPluginsListCommand(args, defaultRuntime);
},
}),
};

View File

@@ -13,6 +13,8 @@ const tasksAuditJsonCommandMock = vi.hoisted(() => vi.fn(async () => {}));
const channelsListCommandMock = vi.hoisted(() => vi.fn(async () => {}));
const channelsStatusCommandMock = vi.hoisted(() => vi.fn(async () => {}));
const agentsListCommandMock = vi.hoisted(() => vi.fn(async () => {}));
const runPluginsListCommandMock = vi.hoisted(() => vi.fn(async () => {}));
const pluginsCliLoadedMock = vi.hoisted(() => vi.fn());
vi.mock("../config-cli.js", () => ({
runConfigGet: runConfigGetMock,
@@ -55,6 +57,17 @@ vi.mock("../../commands/agents.js", () => ({
agentsListCommand: agentsListCommandMock,
}));
vi.mock("../plugins-list-command.js", () => ({
runPluginsListCommand: runPluginsListCommandMock,
}));
vi.mock("../plugins-cli.js", () => {
pluginsCliLoadedMock();
return {
registerPluginsCli: vi.fn(),
};
});
describe("program routes", () => {
beforeEach(() => {
vi.clearAllMocks();
@@ -150,6 +163,29 @@ describe("program routes", () => {
);
});
it("routes plugins list JSON without importing the full plugins CLI", async () => {
const route = expectRoute(["plugins", "list"]);
expect(route.loadPlugins).toBeUndefined();
expect(route.canRun?.(["node", "openclaw", "plugins", "list"])).toBe(false);
await expect(
route.run(["node", "openclaw", "plugins", "list", "--json", "--enabled", "--verbose"]),
).resolves.toBe(true);
expect(runPluginsListCommandMock).toHaveBeenCalledWith(
{ json: true, enabled: true, verbose: true },
defaultRuntime,
);
expect(pluginsCliLoadedMock).not.toHaveBeenCalled();
});
it("returns false for plugins list JSON route with unsupported arguments", async () => {
await expectRunFalse(
["plugins", "list"],
["node", "openclaw", "plugins", "list", "--json", "--wat"],
);
});
it("matches gateway status route without plugin preload", () => {
const route = expectRoute(["gateway", "status"]);
expect(route.loadPlugins).toBeUndefined();