diff --git a/src/cli/command-catalog.ts b/src/cli/command-catalog.ts index 89b78717f8e..3407ebf406c 100644 --- a/src/cli/command-catalog.ts +++ b/src/cli/command-catalog.ts @@ -1,6 +1,10 @@ import { hasFlag } from "./argv.js"; -export type CliCommandPluginLoadPolicy = "never" | "always" | "text-only"; +export type CliCommandPluginLoadPolicy = + | "never" + | "always" + | "text-only" + | ((ctx: { argv: string[]; commandPath: string[]; jsonOutputMode: boolean }) => boolean); export type CliRouteConfigGuardPolicy = "never" | "always" | "when-suppressed"; export type CliNetworkProxyPolicy = "default" | "bypass"; export type CliNetworkProxyPolicyResolver = @@ -48,7 +52,7 @@ export const cliCommandCatalog: readonly CliCommandCatalogEntry[] = [ { commandPath: ["agent"], policy: { - loadPlugins: "always", + loadPlugins: ({ argv, jsonOutputMode }) => hasFlag(argv, "--local") || !jsonOutputMode, networkProxy: ({ argv }) => (hasFlag(argv, "--local") ? "default" : "bypass"), }, }, diff --git a/src/cli/command-execution-startup.test.ts b/src/cli/command-execution-startup.test.ts index f50e98fcb34..263953cdb62 100644 --- a/src/cli/command-execution-startup.test.ts +++ b/src/cli/command-execution-startup.test.ts @@ -50,6 +50,37 @@ describe("command-execution-startup", () => { }); }); + it("skips local plugin bootstrap for JSON gateway agent calls", () => { + expect( + mod.resolveCliExecutionStartupContext({ + argv: ["node", "openclaw", "agent", "--agent", "main", "--message", "hi", "--json"], + jsonOutputMode: true, + }).startupPolicy.loadPlugins, + ).toBe(false); + expect( + mod.resolveCliExecutionStartupContext({ + argv: [ + "node", + "openclaw", + "agent", + "--agent", + "main", + "--message", + "hi", + "--json", + "--local", + ], + jsonOutputMode: true, + }).startupPolicy.loadPlugins, + ).toBe(true); + expect( + mod.resolveCliExecutionStartupContext({ + argv: ["node", "openclaw", "agent", "--agent", "main", "--message", "hi"], + jsonOutputMode: false, + }).startupPolicy.loadPlugins, + ).toBe(true); + }); + it("routes logs to stderr and emits banner only when allowed", async () => { await mod.applyCliExecutionStartupPresentation({ startupPolicy: { diff --git a/src/cli/command-execution-startup.ts b/src/cli/command-execution-startup.ts index 3498c9f46d9..ffe8107f11c 100644 --- a/src/cli/command-execution-startup.ts +++ b/src/cli/command-execution-startup.ts @@ -18,6 +18,7 @@ export function resolveCliExecutionStartupContext(params: { invocation, commandPath, startupPolicy: resolveCliStartupPolicy({ + argv: params.argv, commandPath, jsonOutputMode: params.jsonOutputMode, env: params.env, diff --git a/src/cli/command-startup-policy.ts b/src/cli/command-startup-policy.ts index 4c12e7889f5..634ef53b95f 100644 --- a/src/cli/command-startup-policy.ts +++ b/src/cli/command-startup-policy.ts @@ -17,10 +17,18 @@ export function shouldSkipRouteConfigGuardForCommandPath(params: { } export function shouldLoadPluginsForCommandPath(params: { + argv?: string[]; commandPath: string[]; jsonOutputMode: boolean; }): boolean { const loadPlugins = resolveCliCommandPathPolicy(params.commandPath).loadPlugins; + if (typeof loadPlugins === "function") { + return loadPlugins({ + argv: params.argv ?? [], + commandPath: params.commandPath, + jsonOutputMode: params.jsonOutputMode, + }); + } return loadPlugins === "always" || (loadPlugins === "text-only" && !params.jsonOutputMode); } @@ -39,6 +47,7 @@ export function shouldEnsureCliPathForCommandPath(commandPath: string[]): boolea } export function resolveCliStartupPolicy(params: { + argv?: string[]; commandPath: string[]; jsonOutputMode: boolean; env?: NodeJS.ProcessEnv; @@ -55,6 +64,7 @@ export function resolveCliStartupPolicy(params: { }) : false, loadPlugins: shouldLoadPluginsForCommandPath({ + argv: params.argv, commandPath: params.commandPath, jsonOutputMode: params.jsonOutputMode, }),