From 45f3074ee68794f7d5ca1143846146b728add4b6 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Wed, 29 Apr 2026 01:17:33 +0100 Subject: [PATCH] fix(cli): skip plugin preload for json agent runs --- src/cli/command-catalog.ts | 2 +- src/cli/command-path-policy.test.ts | 9 +++++++++ src/cli/program/preaction.test.ts | 28 +++++++++++++++++++++++----- 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/src/cli/command-catalog.ts b/src/cli/command-catalog.ts index 3407ebf406c..eacfc9fe3c7 100644 --- a/src/cli/command-catalog.ts +++ b/src/cli/command-catalog.ts @@ -52,7 +52,7 @@ export const cliCommandCatalog: readonly CliCommandCatalogEntry[] = [ { commandPath: ["agent"], policy: { - loadPlugins: ({ argv, jsonOutputMode }) => hasFlag(argv, "--local") || !jsonOutputMode, + loadPlugins: "text-only", networkProxy: ({ argv }) => (hasFlag(argv, "--local") ? "default" : "bypass"), }, }, diff --git a/src/cli/command-path-policy.test.ts b/src/cli/command-path-policy.test.ts index 89a2da50ab9..009550b1478 100644 --- a/src/cli/command-path-policy.test.ts +++ b/src/cli/command-path-policy.test.ts @@ -67,6 +67,15 @@ describe("command-path-policy", () => { }); it("keeps config-only agent commands on config-only startup", () => { + expect(resolveCliCommandPathPolicy(["agent"])).toEqual({ + bypassConfigGuard: false, + routeConfigGuard: "never", + loadPlugins: "text-only", + hideBanner: false, + ensureCliPath: true, + networkProxy: expect.any(Function), + }); + for (const commandPath of [ ["agents", "bind"], ["agents", "bindings"], diff --git a/src/cli/program/preaction.test.ts b/src/cli/program/preaction.test.ts index 6be6d9c4840..c398db532e0 100644 --- a/src/cli/program/preaction.test.ts +++ b/src/cli/program/preaction.test.ts @@ -145,6 +145,10 @@ describe("registerPreActionHooks", () => { program.command("onboard").action(() => {}); const channels = program.command("channels"); channels.command("add").action(() => {}); + channels + .command("send") + .option("--json") + .action(() => {}); program .command("plugins") .command("install") @@ -229,7 +233,7 @@ describe("registerPreActionHooks", () => { processTitleSetSpy.mockRestore(); }); - it("loads plugins for local agent runs", async () => { + it("loads plugins for text local agent runs", async () => { await runPreAction({ parseArgv: ["agent"], processArgv: ["node", "openclaw", "agent", "--local", "--message", "hi"], @@ -242,6 +246,20 @@ describe("registerPreActionHooks", () => { expect(ensurePluginRegistryLoadedMock).toHaveBeenCalledWith({ scope: "all" }); }); + it("skips broad plugin preload for json local agent runs", async () => { + await runPreAction({ + parseArgv: ["agent"], + processArgv: ["node", "openclaw", "agent", "--local", "--message", "hi", "--json"], + }); + + expect(ensureConfigReadyMock).toHaveBeenCalledWith({ + runtime: runtimeMock, + commandPath: ["agent", "hi"], + suppressDoctorStdout: true, + }); + expect(ensurePluginRegistryLoadedMock).not.toHaveBeenCalled(); + }); + it("keeps setup alias and channels add manifest-first", async () => { await runPreAction({ parseArgv: ["onboard"], @@ -394,8 +412,8 @@ describe("registerPreActionHooks", () => { it("routes logs to stderr in --json mode so stdout stays clean", async () => { await runPreAction({ - parseArgv: ["agent"], - processArgv: ["node", "openclaw", "agent", "--message", "hi", "--json"], + parseArgv: ["channels", "send"], + processArgv: ["node", "openclaw", "channels", "send", "--json"], }); expect(routeLogsToStderrMock).toHaveBeenCalledOnce(); @@ -484,8 +502,8 @@ describe("registerPreActionHooks", () => { }); await runPreAction({ - parseArgv: ["agent"], - processArgv: ["node", "openclaw", "agent", "--local", "--message", "hi", "--json"], + parseArgv: ["channels", "send"], + processArgv: ["node", "openclaw", "channels", "send", "--json"], }); expect(ensurePluginRegistryLoadedMock).toHaveBeenCalled();