From 05a4e8f5a325a9c3954d6afb8a9d269fe319c788 Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Sat, 28 Mar 2026 10:47:53 +0700 Subject: [PATCH] fix(cli): resolve daemon executable path without wmic --- .../src/commands/daemon/runtime-toolchain.ts | 72 +++++++++++++++---- 1 file changed, 59 insertions(+), 13 deletions(-) diff --git a/packages/cli/src/commands/daemon/runtime-toolchain.ts b/packages/cli/src/commands/daemon/runtime-toolchain.ts index ca4df8a3d..6b4184761 100644 --- a/packages/cli/src/commands/daemon/runtime-toolchain.ts +++ b/packages/cli/src/commands/daemon/runtime-toolchain.ts @@ -35,29 +35,75 @@ function resolveNodePathFromPidUnix(pid: number): NodePathFromPidResult { return resolved ? { nodePath: resolved } : { nodePath: null, error: "ps returned an empty command path" }; } -function resolveNodePathFromPidWindows(pid: number): NodePathFromPidResult { - const result = spawnSync( - "wmic", - ["process", "where", `ProcessId=${pid}`, "get", "ExecutablePath", "/VALUE"], - { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }, - ); +function runProcessProbe(command: string, args: string[]): { + resolved: string | null; + error?: string; +} { + const result = spawnSync(command, args, { + encoding: "utf8", + stdio: ["ignore", "pipe", "pipe"], + }); if (result.error) { - return { nodePath: null, error: `wmic failed: ${normalizeError(result.error)}` }; + return { resolved: null, error: `${command} failed: ${normalizeError(result.error)}` }; } if ((result.status ?? 1) !== 0) { const details = result.stderr?.trim(); return { - nodePath: null, - error: details ? `wmic failed: ${details}` : `wmic exited with code ${result.status ?? 1}`, + resolved: null, + error: details ? `${command} failed: ${details}` : `${command} exited with code ${result.status ?? 1}`, }; } - // wmic output format: "ExecutablePath=C:\path\to\node.exe\r\n" - const match = result.stdout.match(/ExecutablePath=(.+)/); - const resolved = match?.[1]?.trim(); - return resolved ? { nodePath: resolved } : { nodePath: null, error: "wmic returned no executable path" }; + const resolved = result.stdout.trim(); + return resolved ? { resolved } : { resolved: null, error: `${command} returned no executable path` }; +} + +function resolveNodePathFromPidWindows(pid: number): NodePathFromPidResult { + const probes: Array<{ label: string; command: string; args: string[]; parseValue?: (stdout: string) => string | null }> = [ + { + label: "powershell-cim", + command: "powershell", + args: [ + "-NoProfile", + "-Command", + `(Get-CimInstance Win32_Process -Filter "ProcessId = ${pid}").ExecutablePath`, + ], + }, + { + label: "powershell-process", + command: "powershell", + args: ["-NoProfile", "-Command", `(Get-Process -Id ${pid}).Path`], + }, + { + label: "wmic", + command: "wmic", + args: ["process", "where", `ProcessId=${pid}`, "get", "ExecutablePath", "/VALUE"], + parseValue: (stdout) => { + const match = stdout.match(/ExecutablePath=(.+)/); + return match?.[1]?.trim() ?? null; + }, + }, + ]; + + const errors: string[] = []; + for (const probe of probes) { + const result = runProcessProbe(probe.command, probe.args); + if (result.resolved) { + const resolved = probe.parseValue ? probe.parseValue(result.resolved) : result.resolved; + if (resolved) { + return { nodePath: resolved }; + } + errors.push(`${probe.label} returned no executable path`); + continue; + } + if (result.error) { + errors.push(`${probe.label}: ${result.error}`); + } + } + + return { nodePath: null, error: errors.join("; ") || "could not resolve executable path from PID" }; } export function resolveNodePathFromPid(pid: number): NodePathFromPidResult {