From c4facb2bb372e99037f497e2640ca7bdc5cbc5f6 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sun, 21 Jun 2026 12:22:18 +0200 Subject: [PATCH] fix(infra): resolve Windows port inspection tools --- src/infra/ports-inspect.ts | 21 ++++++++++++++++----- src/infra/ports.test.ts | 29 +++++++++++++++++------------ 2 files changed, 33 insertions(+), 17 deletions(-) diff --git a/src/infra/ports-inspect.ts b/src/infra/ports-inspect.ts index 7756ba271f25..d00e7cb2dfd4 100644 --- a/src/infra/ports-inspect.ts +++ b/src/infra/ports-inspect.ts @@ -15,6 +15,11 @@ import type { PortUsage, PortUsageStatus, } from "./ports-types.js"; +import { + getWindowsPowerShellExePath, + getWindowsSystem32ExePath, + getWindowsWmicExePath, +} from "./windows-install-roots.js"; type CommandResult = { stdout: string; @@ -495,7 +500,13 @@ function parseNetstatConnections(output: string, port: number): PortConnection[] } async function resolveWindowsImageName(pid: number): Promise { - const res = await runCommandSafe(["tasklist", "/FI", `PID eq ${pid}`, "/FO", "LIST"]); + const res = await runCommandSafe([ + getWindowsSystem32ExePath("tasklist.exe"), + "/FI", + `PID eq ${pid}`, + "/FO", + "LIST", + ]); if (res.code !== 0) { return undefined; } @@ -512,7 +523,7 @@ async function resolveWindowsImageName(pid: number): Promise async function resolveWindowsCommandLine(pid: number): Promise { const powershell = await runCommandSafe([ - "powershell", + getWindowsPowerShellExePath(), "-NoProfile", "-Command", `(Get-CimInstance Win32_Process -Filter "ProcessId = ${pid}" | Select-Object -ExpandProperty CommandLine)`, @@ -525,7 +536,7 @@ async function resolveWindowsCommandLine(pid: number): Promise { const errors: string[] = []; - const res = await runCommandSafe(["netstat", "-ano", "-p", "tcp"]); + const res = await runCommandSafe([getWindowsSystem32ExePath("netstat.exe"), "-ano", "-p", "tcp"]); if (res.code !== 0) { if (res.error) { errors.push(res.error); @@ -587,7 +598,7 @@ async function readWindowsEstablishedConnections( port: number, ): Promise<{ connections: PortConnection[]; detail?: string; errors: string[] }> { const errors: string[] = []; - const res = await runCommandSafe(["netstat", "-ano", "-p", "tcp"]); + const res = await runCommandSafe([getWindowsSystem32ExePath("netstat.exe"), "-ano", "-p", "tcp"]); if (res.code !== 0) { if (res.error) { errors.push(res.error); diff --git a/src/infra/ports.test.ts b/src/infra/ports.test.ts index aada7d16147a..dd3a1aade407 100644 --- a/src/infra/ports.test.ts +++ b/src/infra/ports.test.ts @@ -3,6 +3,11 @@ import net from "node:net"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { stripAnsi } from "../../packages/terminal-core/src/ansi.js"; import { mockProcessPlatform } from "../test-utils/vitest-spies.js"; +import { + getWindowsPowerShellExePath, + getWindowsSystem32ExePath, + getWindowsWmicExePath, +} from "./windows-install-roots.js"; const runCommandWithTimeoutMock = vi.hoisted(() => vi.fn()); @@ -422,7 +427,7 @@ describe("inspectPortUsage on Windows", () => { setPlatform("win32"); runCommandWithTimeoutMock.mockImplementation(async (argv: string[]) => { const [command] = argv; - if (command === "netstat") { + if (command === getWindowsSystem32ExePath("netstat.exe")) { return { stdout: " TCP 127.0.0.1:50123 127.0.0.1:18789 ESTABLISHED 4242\r\n" + @@ -431,10 +436,10 @@ describe("inspectPortUsage on Windows", () => { code: 0, }; } - if (command === "tasklist") { + if (command === getWindowsSystem32ExePath("tasklist.exe")) { return { stdout: "Image Name: node.exe\r\n", stderr: "", code: 0 }; } - if (command === "powershell") { + if (command === getWindowsPowerShellExePath()) { return { stdout: '"C:\\Program Files\\nodejs\\node.exe" C:\\Users\\me\\AppData\\Roaming\\npm\\node_modules\\openclaw\\dist\\index.js logs --follow\r\n', @@ -460,17 +465,17 @@ describe("inspectPortUsage on Windows", () => { setPlatform("win32"); runCommandWithTimeoutMock.mockImplementation(async (argv: string[]) => { const [command] = argv; - if (command === "netstat") { + if (command === getWindowsSystem32ExePath("netstat.exe")) { return { stdout: " TCP 127.0.0.1:18789 0.0.0.0:0 LISTENING 4242\r\n", stderr: "", code: 0, }; } - if (command === "tasklist") { + if (command === getWindowsSystem32ExePath("tasklist.exe")) { return { stdout: "Image Name: node.exe\r\n", stderr: "", code: 0 }; } - if (command === "powershell") { + if (command === getWindowsPowerShellExePath()) { return { stdout: '"C:\\Program Files\\nodejs\\node.exe" C:\\Users\\me\\AppData\\Roaming\\npm\\node_modules\\openclaw\\dist\\index.js gateway run\r\n', @@ -496,7 +501,7 @@ describe("inspectPortUsage on Windows", () => { setPlatform("win32"); runCommandWithTimeoutMock.mockImplementation(async (argv: string[]) => { const [command] = argv; - if (command === "netstat") { + if (command === getWindowsSystem32ExePath("netstat.exe")) { return { stdout: " TCP 127.0.0.1:187890 0.0.0.0:0 LISTENING 9000\r\n" + @@ -517,20 +522,20 @@ describe("inspectPortUsage on Windows", () => { setPlatform("win32"); runCommandWithTimeoutMock.mockImplementation(async (argv: string[]) => { const [command] = argv; - if (command === "netstat") { + if (command === getWindowsSystem32ExePath("netstat.exe")) { return { stdout: " TCP 127.0.0.1:18789 0.0.0.0:0 LISTENING 4242\r\n", stderr: "", code: 0, }; } - if (command === "tasklist") { + if (command === getWindowsSystem32ExePath("tasklist.exe")) { return { stdout: "Image Name: node.exe\r\n", stderr: "", code: 0 }; } - if (command === "powershell") { + if (command === getWindowsPowerShellExePath()) { return { stdout: "", stderr: "access denied", code: 1 }; } - if (command === "wmic") { + if (command === getWindowsWmicExePath()) { return { stdout: "CommandLine=node.exe C:\\openclaw\\dist\\index.js gateway run\r\n", stderr: "", @@ -544,6 +549,6 @@ describe("inspectPortUsage on Windows", () => { expect(result.listeners[0]?.commandLine).toContain("openclaw"); const commandNames = runCommandWithTimeoutMock.mock.calls.map(([argv]) => argv[0]); - expect(commandNames).toContain("wmic"); + expect(commandNames).toContain(getWindowsWmicExePath()); }); });