Skip to content

Commit 9f4d01e

Browse files
Tao Liclaude
andcommitted
fix(gateway): fall back to PowerShell when wmic is unavailable on Windows
On modern Windows (11+), Microsoft has deprecated and removed wmic.exe. This causes resolveWindowsCommandLine() to silently fail, returning no command line for port listeners. The health check then only sees "node.exe" (the image name), which classifyPortListener() cannot identify as a gateway process — it requires "openclaw" in the command string. This results in ownsPort=false → healthy=false, and the restart health check loops for 60s before timing out, even though the gateway restarted successfully. Fix: when wmic fails (non-zero exit or no output), fall back to PowerShell Get-CimInstance Win32_Process to retrieve the full command line. This restores correct process classification on wmic-less systems. Related: #32620 (same class of bug on Linux when lsof is missing) Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
1 parent 43a1067 commit 9f4d01e

File tree

1 file changed

+29
-10
lines changed

1 file changed

+29
-10
lines changed

src/infra/ports-inspect.ts

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,24 @@ async function resolveWindowsImageName(pid: number): Promise<string | undefined>
248248
return undefined;
249249
}
250250

251+
async function resolveWindowsCommandLineViaPowerShell(
252+
pid: number,
253+
): Promise<string | undefined> {
254+
const res = await runCommandSafe([
255+
"powershell",
256+
"-NoProfile",
257+
"-Command",
258+
`(Get-CimInstance Win32_Process -Filter "ProcessId=${pid}").CommandLine`,
259+
]);
260+
if (res.code !== 0) {
261+
return undefined;
262+
}
263+
const value = res.stdout.trim();
264+
return value || undefined;
265+
}
266+
251267
async function resolveWindowsCommandLine(pid: number): Promise<string | undefined> {
268+
// Try wmic first (fast, but deprecated/removed on modern Windows 11+).
252269
const res = await runCommandSafe([
253270
"wmic",
254271
"process",
@@ -258,18 +275,20 @@ async function resolveWindowsCommandLine(pid: number): Promise<string | undefine
258275
"CommandLine",
259276
"/value",
260277
]);
261-
if (res.code !== 0) {
262-
return undefined;
263-
}
264-
for (const rawLine of res.stdout.split(/\r?\n/)) {
265-
const line = rawLine.trim();
266-
if (!line.toLowerCase().startsWith("commandline=")) {
267-
continue;
278+
if (res.code === 0) {
279+
for (const rawLine of res.stdout.split(/\r?\n/)) {
280+
const line = rawLine.trim();
281+
if (!line.toLowerCase().startsWith("commandline=")) {
282+
continue;
283+
}
284+
const value = line.slice("commandline=".length).trim();
285+
if (value) {
286+
return value;
287+
}
268288
}
269-
const value = line.slice("commandline=".length).trim();
270-
return value || undefined;
271289
}
272-
return undefined;
290+
// Fallback to PowerShell Get-CimInstance when wmic is unavailable.
291+
return resolveWindowsCommandLineViaPowerShell(pid);
273292
}
274293

275294
async function readWindowsListeners(

0 commit comments

Comments
 (0)