@mystilleef/pi-subagent 0.3.0 → 0.4.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.
- package/README.md +169 -11
- package/package.json +32 -14
- package/src/cancel-command.ts +3 -1
- package/src/index.ts +5 -0
- package/src/instance-name.ts +164 -0
- package/src/jobs-command.ts +41 -0
- package/src/progress-state.ts +80 -0
- package/src/progress.ts +100 -111
- package/src/run-registry.ts +1 -0
- package/src/subagent-orchestrator.ts +74 -16
- package/src/termination.ts +7 -6
- package/src/types.ts +1 -0
- package/src/ui.ts +198 -15
package/src/progress.ts
CHANGED
|
@@ -16,36 +16,19 @@
|
|
|
16
16
|
* @module progress
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
import type { ThemeColor } from "@earendil-works/pi-coding-agent";
|
|
20
19
|
import type { Component } from "@earendil-works/pi-tui";
|
|
21
|
-
import { Text } from "@earendil-works/pi-tui";
|
|
20
|
+
import { Box, Text } from "@earendil-works/pi-tui";
|
|
22
21
|
import {
|
|
22
|
+
formatHeaderStats,
|
|
23
23
|
getProgressState,
|
|
24
24
|
type ProgressStatus,
|
|
25
|
+
STATUS_BG,
|
|
26
|
+
STATUS_COLOR,
|
|
27
|
+
STATUS_ICON,
|
|
25
28
|
type SubagentProgressState,
|
|
29
|
+
type ThemeBg,
|
|
26
30
|
} from "./progress-state.js";
|
|
27
|
-
import
|
|
28
|
-
|
|
29
|
-
const STATUS_COLOR: Record<ProgressStatus, ThemeColor> = {
|
|
30
|
-
success: "success",
|
|
31
|
-
error: "error",
|
|
32
|
-
cancelled: "error",
|
|
33
|
-
running: "accent",
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
const STATUS_ICON: Record<ProgressStatus, string> = {
|
|
37
|
-
success: "✓",
|
|
38
|
-
error: "✗",
|
|
39
|
-
cancelled: "⊘",
|
|
40
|
-
running: "⟳",
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
const STATUS_BG: Record<ProgressStatus, ThemeBg> = {
|
|
44
|
-
success: "toolSuccessBg",
|
|
45
|
-
error: "toolErrorBg",
|
|
46
|
-
cancelled: "toolErrorBg",
|
|
47
|
-
running: "toolPendingBg",
|
|
48
|
-
};
|
|
31
|
+
import { formatSubagentTitle, type SubagentTheme } from "./ui.js";
|
|
49
32
|
|
|
50
33
|
export { makeToolPreview } from "./normalize.js";
|
|
51
34
|
export {
|
|
@@ -55,64 +38,21 @@ export {
|
|
|
55
38
|
extractProgressFromDetails,
|
|
56
39
|
failProgressState,
|
|
57
40
|
finalizeProgressState,
|
|
41
|
+
formatContextPercent,
|
|
42
|
+
formatElapsed,
|
|
43
|
+
formatHeaderStats,
|
|
44
|
+
formatTokenCount,
|
|
58
45
|
getProgressState,
|
|
59
46
|
makeTaskPreview,
|
|
60
47
|
type ProgressStatus,
|
|
61
48
|
patchProgressState,
|
|
62
49
|
resetProgressStore,
|
|
50
|
+
STATUS_COLOR,
|
|
51
|
+
STATUS_ICON,
|
|
63
52
|
type SubagentProgressState,
|
|
53
|
+
type ThemeBg,
|
|
64
54
|
} from "./progress-state.js";
|
|
65
55
|
|
|
66
|
-
/**
|
|
67
|
-
* Format a millisecond duration for compact display.
|
|
68
|
-
* Renders sub-minute durations as decimal seconds (`45.2s`),
|
|
69
|
-
* longer durations as minutes and whole seconds (`2m 15s`).
|
|
70
|
-
*/
|
|
71
|
-
export function formatElapsed(ms: number): string {
|
|
72
|
-
if (ms < 60000) return `${(ms / 1000).toFixed(1)}s`;
|
|
73
|
-
const mins = Math.floor(ms / 60000);
|
|
74
|
-
const secs = Math.floor((ms % 60000) / 1000);
|
|
75
|
-
return `${mins}m ${secs}s`;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Format a raw token count for compact inline display.
|
|
80
|
-
* Values below 1000 rendered as-is. Larger counts use `k`
|
|
81
|
-
* or `M` suffixes with one decimal place, stripping trailing `.0`.
|
|
82
|
-
*/
|
|
83
|
-
export function formatTokenCount(count: number): string {
|
|
84
|
-
if (count < 1000) return String(count);
|
|
85
|
-
const unit = count >= 1_000_000 ? "M" : "k";
|
|
86
|
-
const divisor = count >= 1_000_000 ? 1_000_000 : 1000;
|
|
87
|
-
return `${trimTrailingZero((count / divisor).toFixed(1))}${unit}`;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Format the one-line statistics header for a subagent progress display.
|
|
92
|
-
* Includes tool count, context window usage, and elapsed time.
|
|
93
|
-
* When the subagent is still running (`durationMs` unset), elapsed is
|
|
94
|
-
* computed live from `startTime`.
|
|
95
|
-
*
|
|
96
|
-
* @returns Single line ending in `\n`, e.g. `"3 tools · 45% ctx · 12.3s\n"`
|
|
97
|
-
*/
|
|
98
|
-
export function formatHeaderStats(state: SubagentProgressState): string {
|
|
99
|
-
const elapsedMs = state.durationMs ?? Date.now() - state.startTime;
|
|
100
|
-
const toolLabel = state.toolCount === 1 ? "tool" : "tools";
|
|
101
|
-
return `${state.toolCount} ${toolLabel} · ${formatContextPercent(state)} ctx · ${formatElapsed(elapsedMs)}\n`;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
function formatContextPercent(state: SubagentProgressState): string {
|
|
105
|
-
const d = state.contextWindowTokens;
|
|
106
|
-
if (!d || d <= 0 || !Number.isFinite(d)) return "--%";
|
|
107
|
-
const n = state.contextTokens;
|
|
108
|
-
if (!n || n <= 0 || !Number.isFinite(n)) return "0%";
|
|
109
|
-
return `${Math.round((n / d) * 100)}%`;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
function trimTrailingZero(value: string): string {
|
|
113
|
-
return value.endsWith(".0") ? value.slice(0, -2) : value;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
56
|
/**
|
|
117
57
|
* Create a live-updating TUI progress component from a pi message.
|
|
118
58
|
*
|
|
@@ -156,11 +96,7 @@ class DynamicSubagentProgressText implements Component {
|
|
|
156
96
|
render(width: number): string[] {
|
|
157
97
|
const state = getProgressState(this.requestId);
|
|
158
98
|
if (!state) return [];
|
|
159
|
-
|
|
160
|
-
const bg = getProgressBackground(state.status);
|
|
161
|
-
return text
|
|
162
|
-
? new Text(text, 1, 1, (line) => this.theme.bg(bg, line)).render(width)
|
|
163
|
-
: [];
|
|
99
|
+
return renderProgressBox(state, this.options, this.theme).render(width);
|
|
164
100
|
}
|
|
165
101
|
}
|
|
166
102
|
|
|
@@ -168,44 +104,97 @@ function getProgressBackground(status: ProgressStatus): ThemeBg {
|
|
|
168
104
|
return STATUS_BG[status];
|
|
169
105
|
}
|
|
170
106
|
|
|
171
|
-
function
|
|
172
|
-
|
|
107
|
+
function renderProgressBox(
|
|
108
|
+
state: SubagentProgressState,
|
|
173
109
|
options: { expanded: boolean },
|
|
174
110
|
theme: SubagentTheme,
|
|
175
|
-
):
|
|
176
|
-
const state = getProgressState(requestId);
|
|
177
|
-
if (!state) return undefined;
|
|
111
|
+
): Box {
|
|
178
112
|
const status = state.status;
|
|
179
|
-
const
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
113
|
+
const title = formatSubagentTitle(state.agent, state.instanceName, theme);
|
|
114
|
+
const header = `${theme.fg(STATUS_COLOR[status], STATUS_ICON[status])} ${title} ${theme.fg("dim", `[${status}]`)} ${theme.fg("muted", formatHeaderStats(state))}`;
|
|
115
|
+
const box = new Box(1, 1, (line) =>
|
|
116
|
+
theme.bg(getProgressBackground(status), line),
|
|
117
|
+
);
|
|
118
|
+
box.addChild(new Text(header, 0, 0));
|
|
119
|
+
addProgressBody(box, state, options, theme);
|
|
120
|
+
return box;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function addProgressBody(
|
|
124
|
+
box: Box,
|
|
125
|
+
state: SubagentProgressState,
|
|
126
|
+
options: { expanded: boolean },
|
|
127
|
+
theme: SubagentTheme,
|
|
128
|
+
): void {
|
|
129
|
+
const body = makeProgressBody(state, options, theme);
|
|
130
|
+
if (body.length === 0) return;
|
|
131
|
+
for (const line of body) box.addChild(line);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function makeProgressBody(
|
|
135
|
+
state: SubagentProgressState,
|
|
136
|
+
options: { expanded: boolean },
|
|
137
|
+
theme: SubagentTheme,
|
|
138
|
+
): Text[] {
|
|
139
|
+
if (state.status === "running")
|
|
140
|
+
return makeRunningProgressBody(state, options, theme);
|
|
141
|
+
if (state.status === "error" || state.status === "cancelled") {
|
|
142
|
+
return makeStoppedProgressBody(state, options, theme);
|
|
188
143
|
}
|
|
189
|
-
if (status === "
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
144
|
+
if (state.status === "success")
|
|
145
|
+
return makeSuccessProgressBody(state, options, theme);
|
|
146
|
+
return [];
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function makeRunningProgressBody(
|
|
150
|
+
state: SubagentProgressState,
|
|
151
|
+
options: { expanded: boolean },
|
|
152
|
+
theme: SubagentTheme,
|
|
153
|
+
): Text[] {
|
|
154
|
+
const body: Text[] = [];
|
|
155
|
+
if (state.lastToolPreview) {
|
|
156
|
+
body.push(
|
|
157
|
+
new Text(formatRunningToolPreview(state.lastToolPreview, theme), 2, 0),
|
|
158
|
+
);
|
|
197
159
|
}
|
|
198
|
-
if (
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
160
|
+
if (options.expanded)
|
|
161
|
+
body.push(new Text(theme.fg("dim", state.taskPreview), 2, 0));
|
|
162
|
+
return body;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function makeStoppedProgressBody(
|
|
166
|
+
state: SubagentProgressState,
|
|
167
|
+
options: { expanded: boolean },
|
|
168
|
+
theme: SubagentTheme,
|
|
169
|
+
): Text[] {
|
|
170
|
+
const body: Text[] = [];
|
|
171
|
+
if (state.errorText)
|
|
172
|
+
body.push(new Text(theme.fg("error", state.errorText), 2, 0));
|
|
173
|
+
if (options.expanded)
|
|
174
|
+
body.push(new Text(theme.fg("dim", state.taskPreview), 2, 0));
|
|
175
|
+
return body;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function makeSuccessProgressBody(
|
|
179
|
+
state: SubagentProgressState,
|
|
180
|
+
options: { expanded: boolean },
|
|
181
|
+
theme: SubagentTheme,
|
|
182
|
+
): Text[] {
|
|
183
|
+
const output = state.finalOutput?.trim().split("\n")[0] ?? "";
|
|
184
|
+
if (!options.expanded) {
|
|
185
|
+
return output ? [new Text(theme.fg("toolOutput", output), 2, 0)] : [];
|
|
207
186
|
}
|
|
208
|
-
|
|
187
|
+
const body = [new Text(theme.fg("dim", state.taskPreview), 2, 0)];
|
|
188
|
+
body.push(
|
|
189
|
+
output
|
|
190
|
+
? new Text(
|
|
191
|
+
`${theme.fg("muted", "─── Output ───")}\n${theme.fg("toolOutput", output)}`,
|
|
192
|
+
0,
|
|
193
|
+
0,
|
|
194
|
+
)
|
|
195
|
+
: new Text(theme.fg("muted", "(no output)"), 0, 0),
|
|
196
|
+
);
|
|
197
|
+
return body;
|
|
209
198
|
}
|
|
210
199
|
|
|
211
200
|
function formatRunningToolPreview(
|
package/src/run-registry.ts
CHANGED
|
@@ -11,12 +11,15 @@ import {
|
|
|
11
11
|
discoverAgents,
|
|
12
12
|
type ThinkingLevel,
|
|
13
13
|
} from "./agents.js";
|
|
14
|
+
import { generateSubagentInstanceName } from "./instance-name.js";
|
|
14
15
|
import { runSingleAgent } from "./process.js";
|
|
15
16
|
import {
|
|
16
17
|
cancelProgressState,
|
|
17
18
|
createProgressState,
|
|
18
19
|
failProgressState,
|
|
19
20
|
finalizeProgressState,
|
|
21
|
+
formatElapsed,
|
|
22
|
+
getProgressState,
|
|
20
23
|
} from "./progress.js";
|
|
21
24
|
import {
|
|
22
25
|
createSubagentError,
|
|
@@ -26,7 +29,12 @@ import {
|
|
|
26
29
|
patchProgressFromDetails,
|
|
27
30
|
sanitizeDetailsForDisplay,
|
|
28
31
|
} from "./result-details.js";
|
|
29
|
-
import {
|
|
32
|
+
import {
|
|
33
|
+
listRunJobs,
|
|
34
|
+
type RunJob,
|
|
35
|
+
registerRunJob,
|
|
36
|
+
removeRunJob,
|
|
37
|
+
} from "./run-registry.js";
|
|
30
38
|
import { formatSubagentResultForParent } from "./summary.js";
|
|
31
39
|
import type {
|
|
32
40
|
OnUpdateCallback,
|
|
@@ -167,6 +175,32 @@ function sendSubagentResultMessage(
|
|
|
167
175
|
});
|
|
168
176
|
}
|
|
169
177
|
|
|
178
|
+
export function emitCompletionNotification(
|
|
179
|
+
ctx: ExtensionContext,
|
|
180
|
+
state: ReturnType<typeof getProgressState>,
|
|
181
|
+
): void {
|
|
182
|
+
if (!state) return;
|
|
183
|
+
if (state.status === "cancelled") return;
|
|
184
|
+
if (!ctx.ui?.notify) return;
|
|
185
|
+
const tty = (process.stdout as { isTTY?: boolean }).isTTY;
|
|
186
|
+
if (!tty) return;
|
|
187
|
+
const icon = state.status === "error" ? "✗" : "✓";
|
|
188
|
+
const severity =
|
|
189
|
+
state.status === "error" ? ("error" as const) : ("info" as const);
|
|
190
|
+
const elapsed = formatElapsed(
|
|
191
|
+
state.durationMs ?? Date.now() - state.startTime,
|
|
192
|
+
);
|
|
193
|
+
const raw = state.errorText ?? state.finalOutput ?? "";
|
|
194
|
+
const preview = raw.trim().slice(0, 80);
|
|
195
|
+
const namePart = state.instanceName
|
|
196
|
+
? `${state.agent} ${state.instanceName}`
|
|
197
|
+
: state.agent;
|
|
198
|
+
const toast = `${namePart} ${icon} ${elapsed} — "${preview}"`;
|
|
199
|
+
// Terminal bell to draw attention when all jobs complete
|
|
200
|
+
process.stdout.write("\x07");
|
|
201
|
+
ctx.ui.notify(toast, severity);
|
|
202
|
+
}
|
|
203
|
+
|
|
170
204
|
async function runSubagentWorker(
|
|
171
205
|
pi: ExtensionAPI,
|
|
172
206
|
ctx: ExtensionContext,
|
|
@@ -252,11 +286,22 @@ async function runSubagentWorker(
|
|
|
252
286
|
} finally {
|
|
253
287
|
requestProgressRender();
|
|
254
288
|
removeRunJob(requestId);
|
|
289
|
+
if (listRunJobs().length === 0) {
|
|
290
|
+
const state = getProgressState(requestId);
|
|
291
|
+
if (state) {
|
|
292
|
+
emitCompletionNotification(ctx, state);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
255
295
|
}
|
|
256
296
|
}
|
|
257
297
|
|
|
258
298
|
export type StartJobResult =
|
|
259
|
-
| {
|
|
299
|
+
| {
|
|
300
|
+
kind: "started";
|
|
301
|
+
requestId: string;
|
|
302
|
+
instanceName: string;
|
|
303
|
+
makeDetails: DetailsBuilder;
|
|
304
|
+
}
|
|
260
305
|
| { kind: "cancelled"; makeDetails: DetailsBuilder }
|
|
261
306
|
| { kind: "not_found"; makeDetails: DetailsBuilder };
|
|
262
307
|
|
|
@@ -266,7 +311,7 @@ export function formatStartJobStatus(
|
|
|
266
311
|
): string {
|
|
267
312
|
if (result.kind === "not_found") return `Unknown agent: "${agentName}"`;
|
|
268
313
|
if (result.kind === "cancelled") return "Canceled";
|
|
269
|
-
return `Subagent ${agentName} started (job: ${result.requestId})`;
|
|
314
|
+
return `Subagent ${agentName} ${result.instanceName} started (job: ${result.requestId})`;
|
|
270
315
|
}
|
|
271
316
|
|
|
272
317
|
function needsProjectAgentConfirmation(
|
|
@@ -305,6 +350,16 @@ export async function startSubagentJob(
|
|
|
305
350
|
);
|
|
306
351
|
const requested = agents.find((a) => a.name === params.agent);
|
|
307
352
|
if (!requested) return { kind: "not_found", makeDetails };
|
|
353
|
+
if (hostSignal?.aborted) return { kind: "cancelled", makeDetails };
|
|
354
|
+
const task = params.task?.trim() ?? "";
|
|
355
|
+
if (needsProjectAgentConfirmation(ctx, requested)) {
|
|
356
|
+
const confirmed = await confirmProjectAgentRun(
|
|
357
|
+
ctx,
|
|
358
|
+
requested,
|
|
359
|
+
discovery.projectAgentsDir,
|
|
360
|
+
);
|
|
361
|
+
if (!confirmed) return { kind: "cancelled", makeDetails };
|
|
362
|
+
}
|
|
308
363
|
if (requested.source === "project") {
|
|
309
364
|
const userAgents = discoverAgents(ctx.cwd, "user");
|
|
310
365
|
const hasUserCollision = userAgents.agents.some(
|
|
@@ -319,36 +374,34 @@ export async function startSubagentJob(
|
|
|
319
374
|
});
|
|
320
375
|
}
|
|
321
376
|
}
|
|
322
|
-
const task = params.task?.trim() ?? "";
|
|
323
|
-
if (needsProjectAgentConfirmation(ctx, requested)) {
|
|
324
|
-
const confirmed = await confirmProjectAgentRun(
|
|
325
|
-
ctx,
|
|
326
|
-
requested,
|
|
327
|
-
discovery.projectAgentsDir,
|
|
328
|
-
);
|
|
329
|
-
if (!confirmed) return { kind: "cancelled", makeDetails };
|
|
330
|
-
}
|
|
331
377
|
const parentModel = ctx.model
|
|
332
378
|
? { provider: ctx.model.provider, id: ctx.model.id }
|
|
333
379
|
: undefined;
|
|
334
380
|
const parentThinking = pi.getThinkingLevel() as ThinkingLevel;
|
|
335
381
|
const requestId = crypto.randomUUID();
|
|
382
|
+
const instanceName = generateSubagentInstanceName();
|
|
336
383
|
const controller = new AbortController();
|
|
337
384
|
const job: RunJob = registerRunJob({
|
|
338
385
|
requestId,
|
|
339
386
|
agentName: params.agent,
|
|
387
|
+
instanceName,
|
|
340
388
|
controller,
|
|
341
389
|
startedAt: Date.now(),
|
|
342
390
|
});
|
|
343
391
|
const mergedSignal = hostSignal
|
|
344
392
|
? AbortSignal.any([hostSignal, job.controller.signal])
|
|
345
393
|
: job.controller.signal;
|
|
346
|
-
|
|
394
|
+
const makeStartedDetails: DetailsBuilder = (results, options) =>
|
|
395
|
+
makeDetails(
|
|
396
|
+
results.map((result) => ({ ...result, instanceName })),
|
|
397
|
+
options,
|
|
398
|
+
);
|
|
399
|
+
createProgressState(requestId, params.agent, task, instanceName);
|
|
347
400
|
pi.sendMessage({
|
|
348
401
|
customType: "subagent-progress",
|
|
349
402
|
content: "",
|
|
350
403
|
display: true,
|
|
351
|
-
details: { requestId },
|
|
404
|
+
details: { agent: params.agent, instanceName, requestId },
|
|
352
405
|
});
|
|
353
406
|
const requestProgressRender = createProgressRenderRequester(ctx, requestId);
|
|
354
407
|
setImmediate(() => {
|
|
@@ -366,12 +419,17 @@ export async function startSubagentJob(
|
|
|
366
419
|
debug,
|
|
367
420
|
parentModel,
|
|
368
421
|
parentThinking,
|
|
369
|
-
|
|
422
|
+
makeStartedDetails,
|
|
370
423
|
requestId,
|
|
371
424
|
job,
|
|
372
425
|
mergedSignal,
|
|
373
426
|
);
|
|
374
427
|
});
|
|
375
428
|
if (mergedSignal.aborted) return { kind: "cancelled", makeDetails };
|
|
376
|
-
return {
|
|
429
|
+
return {
|
|
430
|
+
kind: "started",
|
|
431
|
+
requestId,
|
|
432
|
+
instanceName,
|
|
433
|
+
makeDetails: makeStartedDetails,
|
|
434
|
+
};
|
|
377
435
|
}
|
package/src/termination.ts
CHANGED
|
@@ -124,10 +124,13 @@ function sendTreeSignal(
|
|
|
124
124
|
sendDirectSignal(proc, signal, state, options);
|
|
125
125
|
return;
|
|
126
126
|
}
|
|
127
|
-
|
|
128
|
-
options.killProcessTree(proc, signal, platform);
|
|
127
|
+
const markTreeKilled = () => {
|
|
129
128
|
state.metadata.target = "tree";
|
|
130
129
|
state.metadata.processTreeKilled = true;
|
|
130
|
+
};
|
|
131
|
+
if (options.killProcessTree) {
|
|
132
|
+
options.killProcessTree(proc, signal, platform);
|
|
133
|
+
markTreeKilled();
|
|
131
134
|
return;
|
|
132
135
|
}
|
|
133
136
|
if (platform !== "win32") {
|
|
@@ -137,8 +140,7 @@ function sendTreeSignal(
|
|
|
137
140
|
options.killProcessGroup ??
|
|
138
141
|
((pid, nextSignal) => process.kill(pid, nextSignal))
|
|
139
142
|
)(-pid, signal);
|
|
140
|
-
|
|
141
|
-
state.metadata.processTreeKilled = true;
|
|
143
|
+
markTreeKilled();
|
|
142
144
|
return;
|
|
143
145
|
}
|
|
144
146
|
if (signal === "SIGKILL") {
|
|
@@ -148,8 +150,7 @@ function sendTreeSignal(
|
|
|
148
150
|
"/t",
|
|
149
151
|
"/f",
|
|
150
152
|
]);
|
|
151
|
-
|
|
152
|
-
state.metadata.processTreeKilled = true;
|
|
153
|
+
markTreeKilled();
|
|
153
154
|
return;
|
|
154
155
|
}
|
|
155
156
|
throw new Error("unsupported tree termination platform");
|