diff --git a/src/cli/channels-cli.test.ts b/src/cli/channels-cli.test.ts index 96f233c16117..8bf108499f9d 100644 --- a/src/cli/channels-cli.test.ts +++ b/src/cli/channels-cli.test.ts @@ -528,8 +528,8 @@ describe("registerChannelsCli", () => { mockProcessPlatform("win32"); process.argv = [ "C:\\Program Files\\nodejs\\node.exe", - "C:\\repo\\openclaw.js", "C:\\Program Files\\nodejs\\node.exe", + "C:\\repo\\openclaw.js", "channels", "add", "--channel", diff --git a/src/cli/windows-argv.test.ts b/src/cli/windows-argv.test.ts index f0659aa75ccc..055f1d6fafd1 100644 --- a/src/cli/windows-argv.test.ts +++ b/src/cli/windows-argv.test.ts @@ -83,4 +83,52 @@ describe("normalizeWindowsArgv", () => { platform.mockRestore(); } }); + + it("preserves node.exe as the first user argument after the script entry", () => { + const platform = mockProcessPlatform("win32"); + try { + expect( + normalizeWindowsArgv([ + "C:\\Program Files\\nodejs\\node.exe", + "C:\\pkg\\openclaw.mjs", + "node.exe", + "--help", + ]), + ).toEqual([ + "C:\\Program Files\\nodejs\\node.exe", + "C:\\pkg\\openclaw.mjs", + "node.exe", + "--help", + ]); + } finally { + platform.mockRestore(); + } + }); + + it("preserves a post-script node.exe argument after normalizing a duplicated prefix", () => { + const platform = mockProcessPlatform("win32"); + try { + expect( + normalizeWindowsArgv([ + "C:\\Program Files\\nodejs\\node.exe", + "C:\\Program Files\\nodejs\\node.exe", + "C:\\pkg\\openclaw.mjs", + "node.exe", + "--help", + ]), + ).toEqual([ + "C:\\Program Files\\nodejs\\node.exe", + "C:\\pkg\\openclaw.mjs", + "node.exe", + "--help", + ]); + } finally { + platform.mockRestore(); + } + }); + + it("does not normalize POSIX argv", () => { + const argv = ["/usr/bin/node", "/opt/openclaw/openclaw.mjs", "node.exe", "--help"]; + expect(normalizeWindowsArgv(argv, { platform: "linux" })).toBe(argv); + }); }); diff --git a/src/cli/windows-argv.ts b/src/cli/windows-argv.ts index 22de646d02f6..6dcbaecf0896 100644 --- a/src/cli/windows-argv.ts +++ b/src/cli/windows-argv.ts @@ -58,31 +58,13 @@ export function normalizeWindowsArgv( ); }; - const argv0IsExecPath = isExecPath(argv[0]); const next = [...argv]; - let removedLauncherPrefix = false; for (const i = 1; i < next.length;) { if (isExecPath(next[i])) { next.splice(i, 1); - removedLauncherPrefix = true; continue; } break; } - if (next.length < 3 || (!argv0IsExecPath && !removedLauncherPrefix)) { - return next; - } - const cleaned = [...next]; - for (const i = 2; i < cleaned.length;) { - const arg = cleaned[i]; - if (!arg || arg.startsWith("-")) { - break; - } - if (isExecPath(arg)) { - cleaned.splice(i, 1); - continue; - } - break; - } - return cleaned; + return next; } diff --git a/src/entry.respawn.test.ts b/src/entry.respawn.test.ts index 7e0fc4685e36..5ce8c718fa93 100644 --- a/src/entry.respawn.test.ts +++ b/src/entry.respawn.test.ts @@ -216,7 +216,7 @@ describe("buildCliRespawnPlan", () => { expect(respawnPlan.detachForProcessTree).toBe(false); }); - it("normalizes duplicated Windows node.exe argv before respawning", () => { + it("normalizes a duplicated Windows node.exe launcher prefix before respawning", () => { const scriptPath = "C:\\Users\\alice\\AppData\\Roaming\\npm\\node_modules\\openclaw\\openclaw.mjs"; const plan = buildCliRespawnPlan({ @@ -224,7 +224,6 @@ describe("buildCliRespawnPlan", () => { "C:\\Program Files\\nodejs\\node.exe", "C:\\Program Files\\nodejs\\node.exe", scriptPath, - "node.exe", "dashboard", "--no-open", ], @@ -238,6 +237,27 @@ describe("buildCliRespawnPlan", () => { expect(respawnPlan.argv).toEqual(["--stack-size=8192", scriptPath, "dashboard", "--no-open"]); }); + it("preserves post-script node.exe arguments after normalizing the launcher prefix", () => { + const scriptPath = + "C:\\Users\\alice\\AppData\\Roaming\\npm\\node_modules\\openclaw\\openclaw.mjs"; + const plan = buildCliRespawnPlan({ + argv: [ + "C:\\Program Files\\nodejs\\node.exe", + "C:\\Program Files\\nodejs\\node.exe", + scriptPath, + "node.exe", + "status", + ], + env: {}, + execArgv: [], + execPath: "C:\\Program Files\\nodejs\\node.exe", + platform: "win32", + }); + + const respawnPlan = expectCliRespawnPlan(plan); + expect(respawnPlan.argv).toEqual(["--stack-size=8192", scriptPath, "node.exe", "status"]); + }); + it("does not respawn on Windows when stack size is already configured", () => { expect( buildCliRespawnPlan({