From 7e6837bc07bb278c226203f29d36d91c0000488c Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Tue, 26 May 2026 18:08:51 +0100 Subject: [PATCH] fix: respect root options in startup guards (#86927) --- scripts/check-cli-startup-memory.mjs | 39 ++++++++++------- src/cli/argv.test.ts | 2 + src/cli/argv.ts | 2 +- test/scripts/check-cli-startup-memory.test.ts | 42 +++++++++++++++++++ 4 files changed, 69 insertions(+), 16 deletions(-) create mode 100644 test/scripts/check-cli-startup-memory.test.ts diff --git a/scripts/check-cli-startup-memory.mjs b/scripts/check-cli-startup-memory.mjs index a59aa287a8d..2b8c2cb7e40 100644 --- a/scripts/check-cli-startup-memory.mjs +++ b/scripts/check-cli-startup-memory.mjs @@ -14,10 +14,10 @@ if (!isLinux && !isMac) { } const repoRoot = process.cwd(); -const tmpHome = mkdtempSync(path.join(os.tmpdir(), "openclaw-startup-memory-")); const tmpDir = process.env.TMPDIR || process.env.TEMP || process.env.TMP || os.tmpdir(); -const rssHookPath = path.join(tmpHome, "measure-rss.mjs"); const MAX_RSS_MARKER = "__OPENCLAW_MAX_RSS_KB__="; +let tmpHome = null; +let rssHookPath = null; function parseArgs(argv) { const options = { @@ -59,18 +59,6 @@ function parseArgs(argv) { return options; } -writeFileSync( - rssHookPath, - [ - "process.on('exit', () => {", - " const usage = typeof process.resourceUsage === 'function' ? process.resourceUsage() : null;", - ` if (usage && typeof usage.maxRSS === 'number') console.error('${MAX_RSS_MARKER}' + String(usage.maxRSS));`, - "});", - "", - ].join("\n"), - "utf8", -); - const DEFAULT_LIMITS_MB = { help: 100, statusJson: 400, @@ -146,6 +134,9 @@ function formatCaseCommand(testCase) { } function buildBenchEnv() { + if (!tmpHome) { + throw new Error("temporary home is not initialized"); + } const env = { HOME: tmpHome, USERPROFILE: tmpHome, @@ -181,6 +172,9 @@ function buildBenchEnv() { } function runCase(testCase) { + if (!rssHookPath) { + throw new Error("RSS hook path is not initialized"); + } const env = buildBenchEnv(); const result = spawnSync(process.execPath, ["--import", rssHookPath, ...testCase.args], { cwd: repoRoot, @@ -278,6 +272,19 @@ function writeReport(options, results) { } const options = parseArgs(process.argv.slice(2)); +tmpHome = mkdtempSync(path.join(os.tmpdir(), "openclaw-startup-memory-")); +rssHookPath = path.join(tmpHome, "measure-rss.mjs"); +writeFileSync( + rssHookPath, + [ + "process.on('exit', () => {", + " const usage = typeof process.resourceUsage === 'function' ? process.resourceUsage() : null;", + ` if (usage && typeof usage.maxRSS === 'number') console.error('${MAX_RSS_MARKER}' + String(usage.maxRSS));`, + "});", + "", + ].join("\n"), + "utf8", +); const results = []; try { for (const testCase of cases) { @@ -285,7 +292,9 @@ try { } } finally { writeReport(options, results); - rmSync(tmpHome, { recursive: true, force: true }); + if (tmpHome) { + rmSync(tmpHome, { recursive: true, force: true }); + } } const failure = results.find((result) => result.status !== "pass"); diff --git a/src/cli/argv.test.ts b/src/cli/argv.test.ts index 909596f62ee..e37d9e3003b 100644 --- a/src/cli/argv.test.ts +++ b/src/cli/argv.test.ts @@ -468,6 +468,8 @@ describe("argv helpers", () => { { argv: ["node", "openclaw", "status"], expected: false }, { argv: ["node", "openclaw", "health"], expected: false }, { argv: ["node", "openclaw", "sessions"], expected: false }, + { argv: ["node", "openclaw", "--profile", "work", "status"], expected: false }, + { argv: ["node", "openclaw", "--log-level=debug", "models", "list"], expected: false }, { argv: ["node", "openclaw", "config", "get", "update"], expected: false }, { argv: ["node", "openclaw", "config", "unset", "update"], expected: false }, { argv: ["node", "openclaw", "models", "list"], expected: false }, diff --git a/src/cli/argv.ts b/src/cli/argv.ts index 903200e1a5d..a73b2dfcbe0 100644 --- a/src/cli/argv.ts +++ b/src/cli/argv.ts @@ -384,5 +384,5 @@ export function shouldMigrateStateFromPath(path: string[]): boolean { } export function shouldMigrateState(argv: string[]): boolean { - return shouldMigrateStateFromPath(getCommandPath(argv, 2)); + return shouldMigrateStateFromPath(getCommandPathWithRootOptions(argv, 2)); } diff --git a/test/scripts/check-cli-startup-memory.test.ts b/test/scripts/check-cli-startup-memory.test.ts new file mode 100644 index 00000000000..e099c167097 --- /dev/null +++ b/test/scripts/check-cli-startup-memory.test.ts @@ -0,0 +1,42 @@ +import { spawnSync } from "node:child_process"; +import { readdirSync, mkdtempSync, rmSync } from "node:fs"; +import { tmpdir } from "node:os"; +import path from "node:path"; +import { afterEach, describe, expect, it } from "vitest"; + +const tempRoots: string[] = []; + +function makeTempRoot(): string { + const root = mkdtempSync(path.join(tmpdir(), "openclaw-startup-memory-test-")); + tempRoots.push(root); + return root; +} + +afterEach(() => { + for (const root of tempRoots.splice(0)) { + rmSync(root, { recursive: true, force: true }); + } +}); + +describe("check-cli-startup-memory", () => { + it("does not create a temp home before argument validation succeeds", () => { + if (process.platform !== "darwin" && process.platform !== "linux") { + return; + } + + const tempRoot = makeTempRoot(); + const result = spawnSync(process.execPath, ["scripts/check-cli-startup-memory.mjs", "--json"], { + cwd: path.resolve(__dirname, "..", ".."), + encoding: "utf8", + env: { + ...process.env, + TMPDIR: tempRoot, + TEMP: tempRoot, + TMP: tempRoot, + }, + }); + + expect(result.status).not.toBe(0); + expect(readdirSync(tempRoot)).toEqual([]); + }); +});