pi-background-tasks 2.5.0 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (203) hide show
  1. package/BACKGROUND-TASKS-INSTRUCTIONS.md +1 -1
  2. package/README.md +70 -25
  3. package/TESTING.md +42 -2
  4. package/TEST_PLAN.md +7 -4
  5. package/dist/extensions/anthropic-attribution-child.js +4 -0
  6. package/dist/extensions/anthropic-attribution-child.js.map +1 -0
  7. package/dist/extensions/anthropic-attribution.js +107 -0
  8. package/dist/extensions/anthropic-attribution.js.map +1 -0
  9. package/dist/extensions/background-tasks.js +2 -0
  10. package/dist/extensions/background-tasks.js.map +1 -0
  11. package/dist/extensions/delegate-child.js +2 -0
  12. package/dist/extensions/delegate-child.js.map +1 -0
  13. package/dist/extensions/fusion-child.js +2 -0
  14. package/dist/extensions/fusion-child.js.map +1 -0
  15. package/dist/package.json +5 -0
  16. package/dist/src/core/anthropic-attribution-path.js +24 -0
  17. package/dist/src/core/anthropic-attribution-path.js.map +1 -0
  18. package/dist/src/core/anthropic-attribution.js +2247 -0
  19. package/dist/src/core/anthropic-attribution.js.map +1 -0
  20. package/dist/src/core/attested-pi-contract.js +5 -0
  21. package/dist/src/core/attested-pi-contract.js.map +1 -0
  22. package/dist/src/core/attested-pi-run.js +749 -0
  23. package/dist/src/core/attested-pi-run.js.map +1 -0
  24. package/dist/src/core/canonical-json.js +19 -0
  25. package/dist/src/core/canonical-json.js.map +1 -0
  26. package/dist/src/core/common.js +787 -0
  27. package/dist/src/core/common.js.map +1 -0
  28. package/dist/src/core/config.js +78 -0
  29. package/dist/src/core/config.js.map +1 -0
  30. package/dist/src/core/context/parent-snapshot.js +75 -0
  31. package/dist/src/core/context/parent-snapshot.js.map +1 -0
  32. package/dist/src/core/context/token-budget.js +631 -0
  33. package/dist/src/core/context/token-budget.js.map +1 -0
  34. package/dist/src/core/context/visible-conversation-v2.js +390 -0
  35. package/dist/src/core/context/visible-conversation-v2.js.map +1 -0
  36. package/dist/src/core/delegate/artifacts.js +357 -0
  37. package/dist/src/core/delegate/artifacts.js.map +1 -0
  38. package/dist/src/core/delegate/budget.js +266 -0
  39. package/dist/src/core/delegate/budget.js.map +1 -0
  40. package/dist/src/core/delegate/facade-contract.js +7 -0
  41. package/dist/src/core/delegate/facade-contract.js.map +1 -0
  42. package/dist/src/core/delegate/hook-contract-evidence.json +18 -0
  43. package/dist/src/core/delegate/hook-contract.js +124 -0
  44. package/dist/src/core/delegate/hook-contract.js.map +1 -0
  45. package/dist/src/core/delegate/launch.js +366 -0
  46. package/dist/src/core/delegate/launch.js.map +1 -0
  47. package/dist/src/core/delegate/result-package.js +293 -0
  48. package/dist/src/core/delegate/result-package.js.map +1 -0
  49. package/dist/src/core/delegate/runner.js +398 -0
  50. package/dist/src/core/delegate/runner.js.map +1 -0
  51. package/dist/src/core/delegate/seed.js +334 -0
  52. package/dist/src/core/delegate/seed.js.map +1 -0
  53. package/dist/src/core/delegate/types.js +103 -0
  54. package/dist/src/core/delegate/types.js.map +1 -0
  55. package/dist/src/core/durable-fs.js +372 -0
  56. package/dist/src/core/durable-fs.js.map +1 -0
  57. package/dist/src/core/extension-api.js +382 -0
  58. package/dist/src/core/extension-api.js.map +1 -0
  59. package/dist/src/core/fusion/artifacts.js +654 -0
  60. package/dist/src/core/fusion/artifacts.js.map +1 -0
  61. package/dist/src/core/fusion/budget.js +949 -0
  62. package/dist/src/core/fusion/budget.js.map +1 -0
  63. package/dist/src/core/fusion/child-protocol.js +176 -0
  64. package/dist/src/core/fusion/child-protocol.js.map +1 -0
  65. package/dist/src/core/fusion/claude-cache.js +156 -0
  66. package/dist/src/core/fusion/claude-cache.js.map +1 -0
  67. package/dist/src/core/fusion/clean-context.js +64 -0
  68. package/dist/src/core/fusion/clean-context.js.map +1 -0
  69. package/dist/src/core/fusion/config.js +349 -0
  70. package/dist/src/core/fusion/config.js.map +1 -0
  71. package/dist/src/core/fusion/context.js +184 -0
  72. package/dist/src/core/fusion/context.js.map +1 -0
  73. package/dist/src/core/fusion/evaluation.js +696 -0
  74. package/dist/src/core/fusion/evaluation.js.map +1 -0
  75. package/dist/src/core/fusion/facade-contract.js +3 -0
  76. package/dist/src/core/fusion/facade-contract.js.map +1 -0
  77. package/dist/src/core/fusion/orchestrator.js +867 -0
  78. package/dist/src/core/fusion/orchestrator.js.map +1 -0
  79. package/dist/src/core/fusion/output-contract.js +27 -0
  80. package/dist/src/core/fusion/output-contract.js.map +1 -0
  81. package/dist/src/core/fusion/pi-child.js +1741 -0
  82. package/dist/src/core/fusion/pi-child.js.map +1 -0
  83. package/dist/src/core/fusion/prompts.js +260 -0
  84. package/dist/src/core/fusion/prompts.js.map +1 -0
  85. package/dist/src/core/fusion/result-package.js +857 -0
  86. package/dist/src/core/fusion/result-package.js.map +1 -0
  87. package/dist/src/core/fusion/source-policy.js +259 -0
  88. package/dist/src/core/fusion/source-policy.js.map +1 -0
  89. package/dist/src/core/fusion/types.js +207 -0
  90. package/dist/src/core/fusion/types.js.map +1 -0
  91. package/dist/src/core/fusion/web-fetch.js +777 -0
  92. package/dist/src/core/fusion/web-fetch.js.map +1 -0
  93. package/dist/src/core/fusion/workflows.js +126 -0
  94. package/dist/src/core/fusion/workflows.js.map +1 -0
  95. package/dist/src/core/lazy-module.js +181 -0
  96. package/dist/src/core/lazy-module.js.map +1 -0
  97. package/dist/src/core/pi-launch.js +431 -0
  98. package/dist/src/core/pi-launch.js.map +1 -0
  99. package/dist/src/core/registry.js +3331 -0
  100. package/dist/src/core/registry.js.map +1 -0
  101. package/dist/src/core/reload-shell-owner.js +1396 -0
  102. package/dist/src/core/reload-shell-owner.js.map +1 -0
  103. package/dist/src/core/shell-policy.js +80 -0
  104. package/dist/src/core/shell-policy.js.map +1 -0
  105. package/dist/src/core/task-durable.js +51 -0
  106. package/dist/src/core/task-durable.js.map +1 -0
  107. package/dist/src/core/update-check.js +92 -0
  108. package/dist/src/core/update-check.js.map +1 -0
  109. package/dist/src/core/windows-taskkill.js +185 -0
  110. package/dist/src/core/windows-taskkill.js.map +1 -0
  111. package/dist/src/delegate-child-extension.js +776 -0
  112. package/dist/src/delegate-child-extension.js.map +1 -0
  113. package/dist/src/delegate-extension.js +746 -0
  114. package/dist/src/delegate-extension.js.map +1 -0
  115. package/dist/src/extension.js +953 -0
  116. package/dist/src/extension.js.map +1 -0
  117. package/dist/src/fusion-child-extension.js +760 -0
  118. package/dist/src/fusion-child-extension.js.map +1 -0
  119. package/dist/src/fusion-extension.js +1030 -0
  120. package/dist/src/fusion-extension.js.map +1 -0
  121. package/dist/src/ui/background-tasks-manager.js +689 -0
  122. package/dist/src/ui/background-tasks-manager.js.map +1 -0
  123. package/dist/src/ui/fusion-model-selector.js +277 -0
  124. package/dist/src/ui/fusion-model-selector.js.map +1 -0
  125. package/docs/INDEX.md +35 -33
  126. package/docs/api/eventbus-v1.md +21 -5
  127. package/docs/choose-a-workflow.md +2 -0
  128. package/docs/commands/bg-clear.md +3 -3
  129. package/docs/commands/bg-update.md +3 -3
  130. package/docs/commands/bg.md +18 -6
  131. package/docs/commands/claude-cache.md +4 -4
  132. package/docs/commands/fusion-models.md +49 -4
  133. package/docs/commands/fusion.md +3 -3
  134. package/docs/commands/jobs.md +3 -3
  135. package/docs/commands/kill.md +3 -3
  136. package/docs/commands/logs.md +3 -3
  137. package/docs/commands/task-manager.md +5 -5
  138. package/docs/concepts/completion-delivery.md +6 -2
  139. package/docs/getting-started.md +7 -1
  140. package/docs/manifest.json +228 -42
  141. package/docs/operations/configuration.md +58 -5
  142. package/docs/operations/releasing.md +4 -2
  143. package/docs/operations/testing.md +22 -0
  144. package/docs/operations/troubleshooting.md +6 -2
  145. package/docs/read-before-edit.md +44 -31
  146. package/docs/reference/runtime-contracts.md +87 -51
  147. package/docs/reference/shortcuts-and-dock.md +28 -14
  148. package/docs/subsystems/anthropic-attribution.md +23 -11
  149. package/docs/subsystems/attested-pi-runs.md +12 -7
  150. package/docs/subsystems/background-task-runtime.md +53 -11
  151. package/docs/subsystems/child-launch-durability-and-safety.md +28 -9
  152. package/docs/subsystems/delegation.md +16 -3
  153. package/docs/subsystems/docs-freshness-gate.md +14 -7
  154. package/docs/subsystems/fusion.md +36 -11
  155. package/docs/subsystems/host-ui-and-telemetry.md +22 -9
  156. package/docs/tools/bg_delegate.md +3 -1
  157. package/docs/tools/bg_kill.md +3 -1
  158. package/docs/tools/bg_logs.md +3 -1
  159. package/docs/tools/bg_result.md +5 -3
  160. package/docs/tools/bg_run.md +31 -5
  161. package/docs/tools/bg_run_pi_attested.md +3 -1
  162. package/docs/tools/bg_status.md +3 -1
  163. package/docs/tools/fusion_investigate.md +3 -1
  164. package/docs/tools/fusion_reason.md +3 -1
  165. package/docs/tools/fusion_research.md +3 -1
  166. package/docs/tools/fusion_validate.md +3 -1
  167. package/extensions/anthropic-attribution-child.ts +3 -0
  168. package/extensions/anthropic-attribution.ts +166 -1
  169. package/package.json +12 -10
  170. package/src/core/anthropic-attribution-path.ts +5 -4
  171. package/src/core/anthropic-attribution.ts +293 -113
  172. package/src/core/attested-pi-contract.ts +4 -0
  173. package/src/core/attested-pi-run.ts +468 -81
  174. package/src/core/canonical-json.ts +21 -0
  175. package/src/core/common.ts +450 -40
  176. package/src/core/config.ts +121 -0
  177. package/src/core/context/visible-conversation-v2.ts +3 -6
  178. package/src/core/delegate/artifacts.ts +13 -9
  179. package/src/core/delegate/budget.ts +13 -6
  180. package/src/core/delegate/facade-contract.ts +6 -0
  181. package/src/core/delegate/result-package.ts +32 -14
  182. package/src/core/delegate/runner.ts +129 -58
  183. package/src/core/delegate/seed.ts +5 -7
  184. package/src/core/durable-fs.ts +178 -30
  185. package/src/core/extension-api.ts +36 -8
  186. package/src/core/fusion/artifacts.ts +17 -16
  187. package/src/core/fusion/clean-context.ts +8 -5
  188. package/src/core/fusion/config.ts +2 -1
  189. package/src/core/fusion/context.ts +2 -6
  190. package/src/core/fusion/facade-contract.ts +2 -0
  191. package/src/core/fusion/orchestrator.ts +3 -3
  192. package/src/core/fusion/prompts.ts +1 -1
  193. package/src/core/fusion/result-package.ts +259 -72
  194. package/src/core/fusion/source-policy.ts +43 -17
  195. package/src/core/lazy-module.ts +215 -0
  196. package/src/core/pi-launch.ts +390 -65
  197. package/src/core/registry.ts +2010 -381
  198. package/src/core/reload-shell-owner.ts +1662 -0
  199. package/src/core/shell-policy.ts +134 -0
  200. package/src/core/task-durable.ts +67 -0
  201. package/src/delegate-extension.ts +404 -144
  202. package/src/extension.ts +387 -114
  203. package/src/fusion-extension.ts +202 -96
@@ -0,0 +1,185 @@
1
+ import { spawn as nodeSpawn } from 'node:child_process';
2
+ import { win32 } from 'node:path';
3
+ const DEFAULT_TIMEOUT_MS = 5000;
4
+ const DEFAULT_MAX_CAPTURE_BYTES = 8 * 1024;
5
+ class BoundedCapture {
6
+ maxBytes;
7
+ chunks = [];
8
+ capturedBytes = 0;
9
+ truncated = false;
10
+ constructor(maxBytes) {
11
+ this.maxBytes = maxBytes;
12
+ }
13
+ append(data) {
14
+ const buffer = Buffer.isBuffer(data) ? data : Buffer.from(data, 'utf8');
15
+ if (buffer.length === 0)
16
+ return;
17
+ const remaining = this.maxBytes - this.capturedBytes;
18
+ if (remaining > 0) {
19
+ const kept = buffer.length <= remaining ? buffer : buffer.subarray(0, remaining);
20
+ this.chunks.push(kept);
21
+ this.capturedBytes += kept.length;
22
+ }
23
+ if (buffer.length > Math.max(0, remaining))
24
+ this.truncated = true;
25
+ }
26
+ text() {
27
+ return Buffer.concat(this.chunks, this.capturedBytes).toString('utf8');
28
+ }
29
+ isTruncated() {
30
+ return this.truncated;
31
+ }
32
+ }
33
+ function lookupEnv(env, name) {
34
+ const direct = env[name];
35
+ if (direct !== undefined)
36
+ return direct;
37
+ const lowerName = name.toLowerCase();
38
+ for (const key of Object.keys(env)) {
39
+ if (key.toLowerCase() === lowerName)
40
+ return env[key];
41
+ }
42
+ return undefined;
43
+ }
44
+ function validateWindowsRoot(raw, label) {
45
+ const value = raw.trim();
46
+ if (value.length === 0)
47
+ throw new Error(`${label} is empty; cannot resolve taskkill.exe`);
48
+ if (value.includes('\0'))
49
+ throw new Error(`${label} contains a NUL byte; cannot resolve taskkill.exe`);
50
+ if (!win32.isAbsolute(value)) {
51
+ throw new Error(`${label} must be an absolute Windows path; cannot resolve taskkill.exe`);
52
+ }
53
+ return value;
54
+ }
55
+ export function resolveTaskkillPath(env = process.env) {
56
+ const systemRoot = lookupEnv(env, 'SystemRoot');
57
+ if (systemRoot !== undefined) {
58
+ return win32.join(validateWindowsRoot(systemRoot, 'SystemRoot'), 'System32', 'taskkill.exe');
59
+ }
60
+ const windir = lookupEnv(env, 'WINDIR');
61
+ if (windir !== undefined) {
62
+ return win32.join(validateWindowsRoot(windir, 'WINDIR'), 'System32', 'taskkill.exe');
63
+ }
64
+ throw new Error('Cannot resolve taskkill.exe: SystemRoot is missing and WINDIR fallback is missing');
65
+ }
66
+ function validatePid(pid) {
67
+ if (!Number.isSafeInteger(pid) || pid <= 0) {
68
+ throw new Error(`Invalid Windows taskkill pid ${String(pid)}; expected a positive safe integer`);
69
+ }
70
+ }
71
+ function validatePhase(phase) {
72
+ if (phase !== 'terminate' && phase !== 'force') {
73
+ throw new Error(`Invalid Windows taskkill phase ${String(phase)}`);
74
+ }
75
+ }
76
+ function positiveFiniteInteger(value, fallback, label) {
77
+ const candidate = value ?? fallback;
78
+ if (!Number.isFinite(candidate) || candidate <= 0) {
79
+ throw new Error(`${label} must be a positive finite number`);
80
+ }
81
+ return Math.max(1, Math.floor(candidate));
82
+ }
83
+ function outcome(exitCode, signal, stdout, stderr) {
84
+ return {
85
+ exitCode,
86
+ signal,
87
+ stdout: stdout.text(),
88
+ stderr: stderr.text(),
89
+ stdoutTruncated: stdout.isTruncated(),
90
+ stderrTruncated: stderr.isTruncated(),
91
+ };
92
+ }
93
+ function defaultSpawn(command, args, options) {
94
+ return nodeSpawn(command, args, options);
95
+ }
96
+ export function runWindowsTaskkill(pid, phase, options = {}) {
97
+ validatePid(pid);
98
+ validatePhase(phase);
99
+ const env = options.env ?? process.env;
100
+ const taskkill = resolveTaskkillPath(env);
101
+ const timeoutMs = positiveFiniteInteger(options.timeoutMs, DEFAULT_TIMEOUT_MS, 'timeoutMs');
102
+ const maxCaptureBytes = positiveFiniteInteger(options.maxCaptureBytes, DEFAULT_MAX_CAPTURE_BYTES, 'maxCaptureBytes');
103
+ const spawn = options.spawn ?? defaultSpawn;
104
+ const abortSignal = options.signal;
105
+ const args = ['/PID', String(pid), '/T'];
106
+ if (phase === 'force')
107
+ args.push('/F');
108
+ if (abortSignal?.aborted) {
109
+ const stdout = new BoundedCapture(maxCaptureBytes);
110
+ const stderr = new BoundedCapture(maxCaptureBytes);
111
+ stderr.append('Windows taskkill was aborted before launch');
112
+ return Promise.resolve(outcome(null, null, stdout, stderr));
113
+ }
114
+ return new Promise((resolve) => {
115
+ const stdout = new BoundedCapture(maxCaptureBytes);
116
+ const stderr = new BoundedCapture(maxCaptureBytes);
117
+ let settled = false;
118
+ let timeout;
119
+ let child;
120
+ let abortListener;
121
+ const settle = (result) => {
122
+ if (settled)
123
+ return;
124
+ settled = true;
125
+ if (timeout !== undefined)
126
+ clearTimeout(timeout);
127
+ if (abortSignal !== undefined && abortListener !== undefined) {
128
+ abortSignal.removeEventListener('abort', abortListener);
129
+ }
130
+ resolve(result);
131
+ };
132
+ const stopHelper = (reason) => {
133
+ stderr.append(reason);
134
+ if (child !== undefined) {
135
+ try {
136
+ child.kill('SIGKILL');
137
+ }
138
+ catch (error) {
139
+ stderr.append(`; helper kill failed: ${error instanceof Error ? error.message : String(error)}`);
140
+ }
141
+ }
142
+ settle(outcome(null, null, stdout, stderr));
143
+ };
144
+ const spawnOptions = {
145
+ env,
146
+ shell: false,
147
+ windowsVerbatimArguments: false,
148
+ windowsHide: true,
149
+ stdio: ['ignore', 'pipe', 'pipe'],
150
+ };
151
+ try {
152
+ child = spawn(taskkill, args, spawnOptions);
153
+ }
154
+ catch (error) {
155
+ stderr.append(`Windows taskkill spawn failed: ${error instanceof Error ? error.message : String(error)}`);
156
+ settle(outcome(null, null, stdout, stderr));
157
+ return;
158
+ }
159
+ child.stdout?.on('data', (data) => {
160
+ stdout.append(data);
161
+ });
162
+ child.stderr?.on('data', (data) => {
163
+ stderr.append(data);
164
+ });
165
+ child.on('error', (error) => {
166
+ stderr.append(`Windows taskkill spawn error: ${error.message}`);
167
+ settle(outcome(null, null, stdout, stderr));
168
+ });
169
+ child.on('close', (code, signal) => {
170
+ settle(outcome(code, signal, stdout, stderr));
171
+ });
172
+ abortListener = () => {
173
+ stopHelper('Windows taskkill was aborted');
174
+ };
175
+ abortSignal?.addEventListener('abort', abortListener, { once: true });
176
+ // This timeout is the settlement guarantee for a taskkill helper that never
177
+ // exits. It must keep the event loop alive: an unref'd timer lets the loop
178
+ // drain first and leaves this promise pending forever. `settle()` always
179
+ // clears it, so keeping it referenced cannot leak.
180
+ timeout = setTimeout(() => {
181
+ stopHelper(`Windows taskkill timed out after ${String(timeoutMs)}ms`);
182
+ }, timeoutMs);
183
+ });
184
+ }
185
+ //# sourceMappingURL=windows-taskkill.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"windows-taskkill.js","sourceRoot":"","sources":["../../../src/core/windows-taskkill.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn as nodeSpawn, type SpawnOptions } from 'node:child_process';\nimport { win32 } from 'node:path';\n\nexport type WindowsKillPhase = 'terminate' | 'force';\n\nexport interface TaskkillOutcome {\n readonly exitCode: number | null;\n readonly signal: NodeJS.Signals | null;\n readonly stdout: string;\n readonly stderr: string;\n readonly stdoutTruncated: boolean;\n readonly stderrTruncated: boolean;\n}\n\ninterface TaskkillOutputStream {\n on(event: 'data', listener: (data: Buffer | string) => void): unknown;\n}\n\ninterface WindowsTaskkillChildProcess {\n readonly stdout?: TaskkillOutputStream | null | undefined;\n readonly stderr?: TaskkillOutputStream | null | undefined;\n kill(signal?: NodeJS.Signals): boolean;\n on(event: 'error', listener: (error: Error) => void): unknown;\n on(\n event: 'close',\n listener: (code: number | null, signal: NodeJS.Signals | null) => void,\n ): unknown;\n}\n\ntype WindowsTaskkillSpawn = (\n command: string,\n args: string[],\n options: SpawnOptions,\n) => WindowsTaskkillChildProcess;\n\nexport interface WindowsTaskkillOptions {\n readonly spawn?: WindowsTaskkillSpawn;\n readonly env?: NodeJS.ProcessEnv;\n readonly timeoutMs?: number;\n readonly signal?: AbortSignal;\n readonly maxCaptureBytes?: number;\n}\n\nconst DEFAULT_TIMEOUT_MS = 5000;\nconst DEFAULT_MAX_CAPTURE_BYTES = 8 * 1024;\n\nclass BoundedCapture {\n private readonly chunks: Buffer[] = [];\n private capturedBytes = 0;\n private truncated = false;\n\n constructor(private readonly maxBytes: number) {}\n\n append(data: Buffer | string): void {\n const buffer = Buffer.isBuffer(data) ? data : Buffer.from(data, 'utf8');\n if (buffer.length === 0) return;\n const remaining = this.maxBytes - this.capturedBytes;\n if (remaining > 0) {\n const kept = buffer.length <= remaining ? buffer : buffer.subarray(0, remaining);\n this.chunks.push(kept);\n this.capturedBytes += kept.length;\n }\n if (buffer.length > Math.max(0, remaining)) this.truncated = true;\n }\n\n text(): string {\n return Buffer.concat(this.chunks, this.capturedBytes).toString('utf8');\n }\n\n isTruncated(): boolean {\n return this.truncated;\n }\n}\n\nfunction lookupEnv(env: NodeJS.ProcessEnv, name: string): string | undefined {\n const direct = env[name];\n if (direct !== undefined) return direct;\n const lowerName = name.toLowerCase();\n for (const key of Object.keys(env)) {\n if (key.toLowerCase() === lowerName) return env[key];\n }\n return undefined;\n}\n\nfunction validateWindowsRoot(raw: string, label: string): string {\n const value = raw.trim();\n if (value.length === 0) throw new Error(`${label} is empty; cannot resolve taskkill.exe`);\n if (value.includes('\\0')) throw new Error(`${label} contains a NUL byte; cannot resolve taskkill.exe`);\n if (!win32.isAbsolute(value)) {\n throw new Error(`${label} must be an absolute Windows path; cannot resolve taskkill.exe`);\n }\n return value;\n}\n\nexport function resolveTaskkillPath(env: NodeJS.ProcessEnv = process.env): string {\n const systemRoot = lookupEnv(env, 'SystemRoot');\n if (systemRoot !== undefined) {\n return win32.join(validateWindowsRoot(systemRoot, 'SystemRoot'), 'System32', 'taskkill.exe');\n }\n\n const windir = lookupEnv(env, 'WINDIR');\n if (windir !== undefined) {\n return win32.join(validateWindowsRoot(windir, 'WINDIR'), 'System32', 'taskkill.exe');\n }\n\n throw new Error('Cannot resolve taskkill.exe: SystemRoot is missing and WINDIR fallback is missing');\n}\n\nfunction validatePid(pid: number): void {\n if (!Number.isSafeInteger(pid) || pid <= 0) {\n throw new Error(`Invalid Windows taskkill pid ${String(pid)}; expected a positive safe integer`);\n }\n}\n\nfunction validatePhase(phase: WindowsKillPhase): void {\n if (phase !== 'terminate' && phase !== 'force') {\n throw new Error(`Invalid Windows taskkill phase ${String(phase)}`);\n }\n}\n\nfunction positiveFiniteInteger(value: number | undefined, fallback: number, label: string): number {\n const candidate = value ?? fallback;\n if (!Number.isFinite(candidate) || candidate <= 0) {\n throw new Error(`${label} must be a positive finite number`);\n }\n return Math.max(1, Math.floor(candidate));\n}\n\nfunction outcome(\n exitCode: number | null,\n signal: NodeJS.Signals | null,\n stdout: BoundedCapture,\n stderr: BoundedCapture,\n): TaskkillOutcome {\n return {\n exitCode,\n signal,\n stdout: stdout.text(),\n stderr: stderr.text(),\n stdoutTruncated: stdout.isTruncated(),\n stderrTruncated: stderr.isTruncated(),\n };\n}\n\nfunction defaultSpawn(command: string, args: string[], options: SpawnOptions): WindowsTaskkillChildProcess {\n return nodeSpawn(command, args, options);\n}\n\nexport function runWindowsTaskkill(\n pid: number,\n phase: WindowsKillPhase,\n options: WindowsTaskkillOptions = {},\n): Promise<TaskkillOutcome> {\n validatePid(pid);\n validatePhase(phase);\n const env = options.env ?? process.env;\n const taskkill = resolveTaskkillPath(env);\n const timeoutMs = positiveFiniteInteger(options.timeoutMs, DEFAULT_TIMEOUT_MS, 'timeoutMs');\n const maxCaptureBytes = positiveFiniteInteger(\n options.maxCaptureBytes,\n DEFAULT_MAX_CAPTURE_BYTES,\n 'maxCaptureBytes',\n );\n const spawn = options.spawn ?? defaultSpawn;\n const abortSignal = options.signal;\n\n const args = ['/PID', String(pid), '/T'];\n if (phase === 'force') args.push('/F');\n\n if (abortSignal?.aborted) {\n const stdout = new BoundedCapture(maxCaptureBytes);\n const stderr = new BoundedCapture(maxCaptureBytes);\n stderr.append('Windows taskkill was aborted before launch');\n return Promise.resolve(outcome(null, null, stdout, stderr));\n }\n\n return new Promise<TaskkillOutcome>((resolve) => {\n const stdout = new BoundedCapture(maxCaptureBytes);\n const stderr = new BoundedCapture(maxCaptureBytes);\n let settled = false;\n let timeout: NodeJS.Timeout | undefined;\n let child: WindowsTaskkillChildProcess | undefined;\n let abortListener: (() => void) | undefined;\n\n const settle = (result: TaskkillOutcome): void => {\n if (settled) return;\n settled = true;\n if (timeout !== undefined) clearTimeout(timeout);\n if (abortSignal !== undefined && abortListener !== undefined) {\n abortSignal.removeEventListener('abort', abortListener);\n }\n resolve(result);\n };\n\n const stopHelper = (reason: string): void => {\n stderr.append(reason);\n if (child !== undefined) {\n try {\n child.kill('SIGKILL');\n } catch (error) {\n stderr.append(`; helper kill failed: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n settle(outcome(null, null, stdout, stderr));\n };\n\n const spawnOptions: SpawnOptions = {\n env,\n shell: false,\n windowsVerbatimArguments: false,\n windowsHide: true,\n stdio: ['ignore', 'pipe', 'pipe'],\n };\n\n try {\n child = spawn(taskkill, args, spawnOptions);\n } catch (error) {\n stderr.append(`Windows taskkill spawn failed: ${error instanceof Error ? error.message : String(error)}`);\n settle(outcome(null, null, stdout, stderr));\n return;\n }\n\n child.stdout?.on('data', (data) => {\n stdout.append(data);\n });\n child.stderr?.on('data', (data) => {\n stderr.append(data);\n });\n child.on('error', (error) => {\n stderr.append(`Windows taskkill spawn error: ${error.message}`);\n settle(outcome(null, null, stdout, stderr));\n });\n child.on('close', (code, signal) => {\n settle(outcome(code, signal, stdout, stderr));\n });\n\n abortListener = () => {\n stopHelper('Windows taskkill was aborted');\n };\n abortSignal?.addEventListener('abort', abortListener, { once: true });\n\n // This timeout is the settlement guarantee for a taskkill helper that never\n // exits. It must keep the event loop alive: an unref'd timer lets the loop\n // drain first and leaves this promise pending forever. `settle()` always\n // clears it, so keeping it referenced cannot leak.\n timeout = setTimeout(() => {\n stopHelper(`Windows taskkill timed out after ${String(timeoutMs)}ms`);\n }, timeoutMs);\n });\n}\n"]}