fix(windows): resolve taskkill in core spawns

This commit is contained in:
Vincent Koc
2026-06-21 10:57:35 +02:00
parent 7975ec0b11
commit a192b2ea52
3 changed files with 23 additions and 11 deletions

View File

@@ -100,6 +100,7 @@ import {
type PreUpdateConfigRestoreInput,
} from "../../infra/update-post-core-context.js";
import { runGatewayUpdate, type UpdateRunResult } from "../../infra/update-runner.js";
import { getWindowsSystem32ExePath } from "../../infra/windows-install-roots.js";
import { normalizePluginsConfig, resolveEffectiveEnableState } from "../../plugins/config-state.js";
import {
loadInstalledPluginIndexInstallRecords,
@@ -2877,10 +2878,14 @@ async function readPostCorePluginUpdateResultFile(
function stopPostCoreUpdateChild(child: ChildProcess): void {
if (process.platform === "win32" && child.pid) {
try {
const killer = spawn("taskkill", ["/PID", String(child.pid), "/T", "/F"], {
stdio: "ignore",
windowsHide: true,
});
const killer = spawn(
getWindowsSystem32ExePath("taskkill.exe"),
["/PID", String(child.pid), "/T", "/F"],
{
stdio: "ignore",
windowsHide: true,
},
);
killer.once("error", () => {
child.kill();
});

View File

@@ -11,6 +11,7 @@ import {
decodeWindowsOutputBuffer,
resolveWindowsConsoleEncoding,
} from "../infra/windows-encoding.js";
import { getWindowsSystem32ExePath } from "../infra/windows-install-roots.js";
import { logDebug, logError } from "../logger.js";
import { killProcessTree as terminateProcessTree } from "./kill-tree.js";
import { resolveCommandStdio } from "./spawn-utils.js";
@@ -430,8 +431,9 @@ export async function runCommandWithTimeout(
}
if (killProcessTree && typeof child.pid === "number" && child.pid > 0) {
if (process.platform === "win32") {
const taskkillPath = getWindowsSystem32ExePath("taskkill.exe");
try {
spawn("taskkill", ["/PID", String(child.pid), "/T"], {
spawn(taskkillPath, ["/PID", String(child.pid), "/T"], {
stdio: "ignore",
windowsHide: true,
});
@@ -447,7 +449,7 @@ export async function runCommandWithTimeout(
return;
}
try {
spawn("taskkill", ["/PID", String(child.pid), "/T", "/F"], {
spawn(taskkillPath, ["/PID", String(child.pid), "/T", "/F"], {
stdio: "ignore",
windowsHide: true,
});
@@ -467,10 +469,14 @@ export async function runCommandWithTimeout(
}
if (process.platform === "win32" && typeof child.pid === "number" && child.pid > 0) {
try {
spawn("taskkill", ["/PID", String(child.pid), "/T", "/F"], {
stdio: "ignore",
windowsHide: true,
});
spawn(
getWindowsSystem32ExePath("taskkill.exe"),
["/PID", String(child.pid), "/T", "/F"],
{
stdio: "ignore",
windowsHide: true,
},
);
return;
} catch {
// Fall through to Node's direct child kill as a last resort.

View File

@@ -7,6 +7,7 @@ import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vite
import {
resetWindowsInstallRootsForTests,
getWindowsInstallRoots,
getWindowsSystem32ExePath,
} from "../infra/windows-install-roots.js";
import { withMockedWindowsPlatform, withRestoredMocks } from "../test-utils/vitest-spies.js";
@@ -496,7 +497,7 @@ describe("windows command wrapper behavior", () => {
expect(child.kill).not.toHaveBeenCalled();
expect(spawnMock).toHaveBeenCalledTimes(2);
const taskkillCall = requireSpawnCall(1);
expect(taskkillCall[0]).toBe("taskkill");
expect(taskkillCall[0]).toBe(getWindowsSystem32ExePath("taskkill.exe"));
expect(taskkillCall[1]).toEqual(["/PID", "1234", "/T", "/F"]);
expect(taskkillCall[2]).toEqual({
stdio: "ignore",