From 4bc5e183ef76cff6e2783bf62864a50f95530357 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sun, 26 Apr 2026 10:40:58 +0100 Subject: [PATCH] fix: avoid CLI startup warmup leaks --- extensions/browser/openclaw.plugin.json | 1 + src/agents/context.lookup.test.ts | 7 +++++++ src/agents/context.ts | 18 ++++++++++++++++++ src/cli/program/register.subclis-core.ts | 5 +++-- src/cli/tui-cli.ts | 2 +- src/plugins/activation-planner.test.ts | 19 +++++++++++++++++++ 6 files changed, 49 insertions(+), 3 deletions(-) diff --git a/extensions/browser/openclaw.plugin.json b/extensions/browser/openclaw.plugin.json index 629f589b36d..63856a81a2c 100644 --- a/extensions/browser/openclaw.plugin.json +++ b/extensions/browser/openclaw.plugin.json @@ -1,6 +1,7 @@ { "id": "browser", "enabledByDefault": true, + "commandAliases": [{ "name": "browser" }], "skills": ["./skills"], "configSchema": { "type": "object", diff --git a/src/agents/context.lookup.test.ts b/src/agents/context.lookup.test.ts index 8402f074fc6..d6668378bcd 100644 --- a/src/agents/context.lookup.test.ts +++ b/src/agents/context.lookup.test.ts @@ -201,6 +201,10 @@ describe("lookupContextTokens", () => { const { shouldEagerWarmContextWindowCache } = await importContextModule(); expect(shouldEagerWarmContextWindowCache(["node", "openclaw", "chat"])).toBe(true); + expect(shouldEagerWarmContextWindowCache(["node", "openclaw", "chat", "--help"])).toBe(false); + expect( + shouldEagerWarmContextWindowCache(["node", "openclaw", "browser", "status", "--help"]), + ).toBe(false); expect( shouldEagerWarmContextWindowCache([ "node", @@ -215,6 +219,9 @@ describe("lookupContextTokens", () => { false, ); expect(shouldEagerWarmContextWindowCache(["node", "openclaw", "status", "--json"])).toBe(false); + expect(shouldEagerWarmContextWindowCache(["node", "openclaw", "sessions", "--json"])).toBe( + false, + ); expect( shouldEagerWarmContextWindowCache(["node", "scripts/test-built-plugin-singleton.mjs"]), ).toBe(false); diff --git a/src/agents/context.ts b/src/agents/context.ts index d7ce75d2cf2..7ffbf92b3f3 100644 --- a/src/agents/context.ts +++ b/src/agents/context.ts @@ -130,9 +130,22 @@ function getCommandPathFromArgv(argv: string[]): string[] { return tokens; } +function hasHelpOrVersionFlag(argv: string[]): boolean { + for (const arg of argv.slice(2)) { + if (arg === FLAG_TERMINATOR) { + return false; + } + if (arg === "-h" || arg === "--help" || arg === "-V" || arg === "--version") { + return true; + } + } + return false; +} + const SKIP_EAGER_WARMUP_PRIMARY_COMMANDS = new Set([ "agent", "backup", + "browser", "completion", "config", "directory", @@ -142,8 +155,10 @@ const SKIP_EAGER_WARMUP_PRIMARY_COMMANDS = new Set([ "hooks", "logs", "models", + "pairing", "plugins", "secrets", + "sessions", "status", "update", "webhooks", @@ -160,6 +175,9 @@ export function shouldEagerWarmContextWindowCache(argv: string[] = process.argv) if (!isLikelyOpenClawCliProcess(argv)) { return false; } + if (hasHelpOrVersionFlag(argv)) { + return false; + } const [primary] = getCommandPathFromArgv(argv); return Boolean(primary) && !SKIP_EAGER_WARMUP_PRIMARY_COMMANDS.has(primary); } diff --git a/src/cli/program/register.subclis-core.ts b/src/cli/program/register.subclis-core.ts index 09cfe7e85cb..066b0410c02 100644 --- a/src/cli/program/register.subclis-core.ts +++ b/src/cli/program/register.subclis-core.ts @@ -30,12 +30,13 @@ async function registerSubCliWithPluginCommands( registerSubCli: () => Promise, pluginCliPosition: "before" | "after", ) { + const isHelpOrVersion = resolveCliArgvInvocation(process.argv).hasHelpOrVersion; const { registerPluginCliCommandsFromValidatedConfig } = await import("../../plugins/cli.js"); - if (pluginCliPosition === "before") { + if (pluginCliPosition === "before" && !isHelpOrVersion) { await registerPluginCliCommandsFromValidatedConfig(program); } await registerSubCli(); - if (pluginCliPosition === "after") { + if (pluginCliPosition === "after" && !isHelpOrVersion) { await registerPluginCliCommandsFromValidatedConfig(program); } } diff --git a/src/cli/tui-cli.ts b/src/cli/tui-cli.ts index 2f082d6a95a..33603d7e39f 100644 --- a/src/cli/tui-cli.ts +++ b/src/cli/tui-cli.ts @@ -2,7 +2,6 @@ import type { Command } from "commander"; import { defaultRuntime } from "../runtime.js"; import { formatDocsLink } from "../terminal/links.js"; import { theme } from "../terminal/theme.js"; -import { runTui } from "../tui/tui.js"; import { parseTimeoutMs } from "./parse-timeout.js"; export function registerTuiCli(program: Command) { @@ -43,6 +42,7 @@ export function registerTuiCli(program: Command) { ); } const historyLimit = Number.parseInt(String(opts.historyLimit ?? "200"), 10); + const { runTui } = await import("../tui/tui.js"); await runTui({ local: isLocal, url: opts.url as string | undefined, diff --git a/src/plugins/activation-planner.test.ts b/src/plugins/activation-planner.test.ts index e7f75dcc869..ce72e58ce5c 100644 --- a/src/plugins/activation-planner.test.ts +++ b/src/plugins/activation-planner.test.ts @@ -42,6 +42,16 @@ describe("activation planner", () => { hooks: [], origin: "bundled", }, + { + id: "browser", + commandAliases: [{ name: "browser" }], + providers: [], + channels: [], + cliBackends: [], + skills: [], + hooks: [], + origin: "bundled", + }, { id: "openai", providers: ["openai"], @@ -88,6 +98,15 @@ describe("activation planner", () => { }), ).toEqual(["memory-core"]); + expect( + resolveManifestActivationPluginIds({ + trigger: { + kind: "command", + command: "browser", + }, + }), + ).toEqual(["browser"]); + expect( resolveManifestActivationPluginIds({ trigger: {