From 6a4b5fa4b5e10a82588dcdc497416e9bddf47b45 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Mon, 19 Jan 2026 01:11:39 +0000 Subject: [PATCH] fix: harden windows cli launch --- src/agents/shell-utils.ts | 19 ++++++++++++++++++- src/entry.ts | 19 +++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/agents/shell-utils.ts b/src/agents/shell-utils.ts index 27ac5bf21..b4a703861 100644 --- a/src/agents/shell-utils.ts +++ b/src/agents/shell-utils.ts @@ -1,5 +1,22 @@ +import fs from "node:fs"; +import path from "node:path"; import { spawn } from "node:child_process"; +function resolvePowerShellPath(): string { + const systemRoot = process.env.SystemRoot || process.env.WINDIR; + if (systemRoot) { + const candidate = path.join( + systemRoot, + "System32", + "WindowsPowerShell", + "v1.0", + "powershell.exe", + ); + if (fs.existsSync(candidate)) return candidate; + } + return "powershell.exe"; +} + export function getShellConfig(): { shell: string; args: string[] } { if (process.platform === "win32") { // Use PowerShell instead of cmd.exe on Windows. @@ -8,7 +25,7 @@ export function getShellConfig(): { shell: string; args: string[] } { // When Node.js spawns cmd.exe with piped stdio, these utilities produce no output. // PowerShell properly captures and redirects their output to stdout. return { - shell: "powershell.exe", + shell: resolvePowerShellPath(), args: ["-NoProfile", "-NonInteractive", "-Command"], }; } diff --git a/src/entry.ts b/src/entry.ts index c53251da4..61f69953e 100644 --- a/src/entry.ts +++ b/src/entry.ts @@ -1,5 +1,6 @@ #!/usr/bin/env node import { spawn } from "node:child_process"; +import path from "node:path"; import process from "node:process"; import { applyCliProfileEnv, parseCliProfileArgs } from "./cli/profile.js"; @@ -56,6 +57,24 @@ function ensureExperimentalWarningSuppressed(): boolean { return true; } +function normalizeWindowsArgv(argv: string[]): string[] { + if (process.platform !== "win32") return argv; + if (argv.length < 3) return argv; + const execBase = path.basename(process.execPath).toLowerCase(); + const arg1 = path.basename(argv[1] ?? "").toLowerCase(); + const arg2 = path.basename(argv[2] ?? "").toLowerCase(); + const looksLikeEntry = arg1 === "entry.ts" || arg1 === "entry.js"; + if (arg1 === execBase) { + return [argv[0], ...argv.slice(2)]; + } + if (looksLikeEntry && arg2 === execBase) { + return [argv[0], argv[1], ...argv.slice(3)]; + } + return argv; +} + +process.argv = normalizeWindowsArgv(process.argv); + if (!ensureExperimentalWarningSuppressed()) { const parsed = parseCliProfileArgs(process.argv); if (!parsed.ok) {