



























@@ -66,6 +66,15 @@ type SpawnTextParentSignalState = {
6666done: boolean;
6767signal: NodeJS.Signals | null;
6868};
69+type KillableChild = {
70+kill(signal: NodeJS.Signals): boolean;
71+pid?: number;
72+};
73+type RunTaskkill = (
74+command: string,
75+args: string[],
76+options: { stdio: "ignore" },
77+) => { error?: unknown; status?: number | null } | undefined;
69787079const activeSpawnTextParentSignals = new Set<SpawnTextParentSignalState>();
7180@@ -78,6 +87,65 @@ function maybeReraiseSpawnTextParentSignal(signal: NodeJS.Signals): void {
7887process.kill(process.pid, signal);
7988}
808990+function signalWindowsProcessTree(
91+pid: number,
92+signal: NodeJS.Signals,
93+runTaskkill: RunTaskkill = spawnSync,
94+): boolean {
95+const args = ["/PID", String(pid), "/T"];
96+if (signal === "SIGKILL") {
97+args.push("/F");
98+}
99+const result = runTaskkill("taskkill", args, { stdio: "ignore" });
100+return !result?.error && result?.status === 0;
101+}
102+103+function signalWindowsProcessTreeOrForce(
104+pid: number,
105+signal: NodeJS.Signals,
106+runTaskkill: RunTaskkill = spawnSync,
107+): boolean {
108+if (signalWindowsProcessTree(pid, signal, runTaskkill)) {
109+return true;
110+}
111+return signal !== "SIGKILL" && signalWindowsProcessTree(pid, "SIGKILL", runTaskkill);
112+}
113+114+function signalCliStartupMetadataProcessTree(
115+child: KillableChild,
116+signal: NodeJS.Signals,
117+{
118+ appendDiagnostic = () => {},
119+ platform = process.platform,
120+ runTaskkill = spawnSync,
121+ useProcessGroup = platform !== "win32",
122+}: {
123+appendDiagnostic?: (message: string) => void;
124+platform?: NodeJS.Platform;
125+runTaskkill?: RunTaskkill;
126+useProcessGroup?: boolean;
127+} = {},
128+): void {
129+if (useProcessGroup && typeof child.pid === "number") {
130+try {
131+process.kill(-child.pid, signal);
132+return;
133+} catch (error) {
134+if ((error as NodeJS.ErrnoException).code !== "ESRCH") {
135+appendDiagnostic(
136+`failed to send ${signal} to process group: ${error instanceof Error ? error.message : String(error)}\n`,
137+);
138+}
139+}
140+}
141+if (platform === "win32" && typeof child.pid === "number") {
142+if (signalWindowsProcessTreeOrForce(child.pid, signal, runTaskkill)) {
143+return;
144+}
145+}
146+child.kill(signal);
147+}
148+81149function resolveRootHelpBundleIdentity(
82150distDirOverride: string = distDir,
83151): { bundleName: string; signature: string } | null {
@@ -338,17 +406,12 @@ async function spawnText(
338406parentSignalHandlers.length = 0;
339407};
340408const signalChild = (signal: NodeJS.Signals) => {
341-if (useProcessGroup && typeof child.pid === "number") {
342-try {
343-process.kill(-child.pid, signal);
344-return;
345-} catch (error) {
346-if ((error as NodeJS.ErrnoException).code !== "ESRCH") {
347-stderr += `failed to send ${signal} to process group: ${error instanceof Error ? error.message : String(error)}\n`;
348-}
349-}
350-}
351-child.kill(signal);
409+signalCliStartupMetadataProcessTree(child, signal, {
410+appendDiagnostic: (message) => {
411+stderr += message;
412+},
413+ useProcessGroup,
414+});
352415};
353416const relayParentSignal = (signal: NodeJS.Signals) => {
354417const handler = () => {
@@ -843,6 +906,7 @@ function hasAllPrecomputedSubcommandHelpText(value: unknown): boolean {
843906844907export const testing = {
845908 mapWithConcurrency,
909+ signalCliStartupMetadataProcessTree,
846910 spawnText,
847911};
848912此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。