






















@@ -223,31 +223,66 @@ function runCommand(command, args, options = {}) {
223223return new Promise((resolve, reject) => {
224224const child = childProcess.spawn(command, args, {
225225cwd: options.cwd ?? process.cwd(),
226+detached: options.detached ?? process.platform !== "win32",
226227env: options.env ?? process.env,
227228shell: options.shell,
228229stdio: options.stdio ?? ["pipe", "pipe", "pipe"],
229230windowsVerbatimArguments: options.windowsVerbatimArguments,
230231});
231232const stdout = createOutputCapture("stdout");
232233const stderr = createOutputCapture("stderr");
234+let timedOut = false;
235+let killTimer;
233236const timer = setTimeout(() => {
234-child.kill("SIGTERM");
235-setTimeout(() => child.kill("SIGKILL"), 1000).unref();
236-reject(new Error(scrub(`command timed out: ${command} ${args.join(" ")}`)));
237+timedOut = true;
238+terminateProcessTree(child, "SIGTERM");
239+killTimer = setTimeout(() => terminateProcessTree(child, "SIGKILL"), 1000);
240+killTimer.unref();
237241}, timeoutMs);
238-child.stdout.on("data", (chunk) => {
242+child.stdout?.on("data", (chunk) => {
239243stdout.append(chunk);
240244});
241-child.stderr.on("data", (chunk) => {
245+child.stderr?.on("data", (chunk) => {
242246stderr.append(chunk);
243247});
248+const parentSignalHandlers = new Map();
249+const removeParentSignalHandlers = () => {
250+for (const [signal, handler] of parentSignalHandlers) {
251+process.off(signal, handler);
252+}
253+parentSignalHandlers.clear();
254+};
255+if (process.platform !== "win32" && child.pid) {
256+for (const signal of ["SIGHUP", "SIGINT", "SIGTERM"]) {
257+const handler = () => {
258+terminateProcessTree(child, signal);
259+removeParentSignalHandlers();
260+process.kill(process.pid, signal);
261+};
262+parentSignalHandlers.set(signal, handler);
263+process.once(signal, handler);
264+}
265+}
244266child.on("error", (error) => {
245267clearTimeout(timer);
268+if (killTimer) {
269+clearTimeout(killTimer);
270+}
271+removeParentSignalHandlers();
246272reject(error instanceof Error ? error : new Error(formatErrorMessage(error)));
247273});
248274child.on("close", (code, signal) => {
249275clearTimeout(timer);
276+if (killTimer) {
277+clearTimeout(killTimer);
278+}
279+removeParentSignalHandlers();
250280const result = { code: code ?? 0, signal, stdout: stdout.text(), stderr: stderr.text() };
281+if (timedOut) {
282+terminateProcessTree(child, "SIGKILL");
283+reject(new Error(scrub(`command timed out: ${command} ${args.join(" ")}`)));
284+return;
285+}
251286if (result.code !== 0 && options.allowFailure !== true) {
252287reject(
253288new Error(
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。