@nklisch/pi-enhanced 0.1.8 → 0.1.10
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/CHANGELOG.md +13 -0
- package/node_modules/@nklisch/pi-clearance/docs/ARCHITECTURE.md +4 -2
- package/node_modules/@nklisch/pi-clearance/docs/SPEC.md +1 -1
- package/node_modules/@nklisch/pi-clearance/native/clearance-core.win32-x64-msvc.node +0 -0
- package/node_modules/@nklisch/pi-clearance/package.json +2 -3
- package/node_modules/@nklisch/pi-plugins/README.md +4 -4
- package/node_modules/@nklisch/pi-plugins/dist/application/plugin-lifecycle-service.js +19 -2
- package/node_modules/@nklisch/pi-plugins/dist/application/plugin-lifecycle-service.js.map +1 -1
- package/node_modules/@nklisch/pi-plugins/dist/application/ports/lifecycle-transition-store.d.ts +12 -0
- package/node_modules/@nklisch/pi-plugins/dist/application/ports/lifecycle-transition-store.js.map +1 -1
- package/node_modules/@nklisch/pi-plugins/dist/infrastructure/recovery/create-node-recovery-adapters.js +2 -1
- package/node_modules/@nklisch/pi-plugins/dist/infrastructure/recovery/create-node-recovery-adapters.js.map +1 -1
- package/node_modules/@nklisch/pi-plugins/dist/infrastructure/recovery/sqlite-transition-journal.d.ts +4 -0
- package/node_modules/@nklisch/pi-plugins/dist/infrastructure/recovery/sqlite-transition-journal.js +28 -1
- package/node_modules/@nklisch/pi-plugins/dist/infrastructure/recovery/sqlite-transition-journal.js.map +1 -1
- package/node_modules/@nklisch/pi-plugins/dist/runtime/mcp/pi-mcp-adapter-package.js +1 -1
- package/node_modules/@nklisch/pi-plugins/dist/runtime/mcp/pi-mcp-adapter-runtime.js +1 -1
- package/node_modules/@nklisch/pi-plugins/dist/runtime/subagents/pi-subagents-package.js +7 -1
- package/node_modules/@nklisch/pi-plugins/dist/runtime/subagents/pi-subagents-package.js.map +1 -1
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/CHANGELOG.md +11 -0
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/dist/public.d.ts +3 -1
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/docs/FORK-MAINTENANCE.md +1 -1
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/docs/VISION.md +2 -1
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/docs/architecture/architecture.md +4 -4
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/docs/architecture/client-server-opportunities.md +4 -4
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/docs/comparison-with-upstream.md +1 -1
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/package.json +1 -1
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/index.ts +8 -8
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/create-subagent-session.ts +1 -0
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/parent-snapshot.ts +3 -0
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/subagent-manager.ts +16 -1
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/subagent-session.ts +12 -1
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/subagent.ts +18 -1
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/observation/composite-subagent-observer.ts +8 -0
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/observation/notification.ts +3 -0
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/observation/renderer.ts +2 -2
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/runtime.ts +1 -0
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/service/service-adapter.ts +11 -3
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/session/session-config.ts +7 -3
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/session/thinking-level.ts +42 -0
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/agent-tool.ts +3 -3
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/background-spawner.ts +7 -2
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/foreground-runner.ts +7 -5
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/get-result-report.ts +4 -1
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/get-result-tool.ts +1 -0
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/helpers.ts +1 -1
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/result-renderer.ts +7 -4
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/spawn-config.ts +15 -2
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/steer-tool.ts +3 -3
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/types.ts +6 -2
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/ui/agent-widget.ts +117 -62
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/ui/display.ts +8 -1
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/ui/session-navigation.ts +7 -3
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/ui/session-navigator.ts +2 -2
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/ui/widget-renderer.ts +6 -4
- package/node_modules/@nklisch/pi-plugins/package.json +3 -3
- package/package.json +3 -3
- package/test/verify-subagent-restart.mjs +186 -0
- package/node_modules/@nklisch/pi-clearance/native/clearance-core.win32-arm64-msvc.node +0 -0
|
@@ -9,9 +9,10 @@ import { truncateToWidth } from "@earendil-works/pi-tui";
|
|
|
9
9
|
import type { AgentConfigLookup } from "#src/config/agent-types";
|
|
10
10
|
import type { LifetimeUsage } from "#src/lifecycle/usage";
|
|
11
11
|
import { getLifetimeTotal } from "#src/lifecycle/usage";
|
|
12
|
-
import type { SubagentType } from "#src/types";
|
|
12
|
+
import type { SubagentType, ThinkingLevel } from "#src/types";
|
|
13
13
|
import {
|
|
14
14
|
describeActivity,
|
|
15
|
+
formatModelThinking,
|
|
15
16
|
formatMs,
|
|
16
17
|
formatSessionTokens,
|
|
17
18
|
formatTurns,
|
|
@@ -30,6 +31,7 @@ export interface WidgetAgent {
|
|
|
30
31
|
readonly status: string;
|
|
31
32
|
readonly description: string;
|
|
32
33
|
readonly modelLabel: string;
|
|
34
|
+
readonly thinkingLevel: ThinkingLevel;
|
|
33
35
|
readonly toolUses: number;
|
|
34
36
|
readonly startedAt: number;
|
|
35
37
|
readonly completedAt?: number;
|
|
@@ -78,7 +80,7 @@ export function renderFinishedLine(
|
|
|
78
80
|
statusText = theme.fg("warning", " aborted");
|
|
79
81
|
}
|
|
80
82
|
|
|
81
|
-
const parts: string[] = [agent.modelLabel];
|
|
83
|
+
const parts: string[] = [formatModelThinking(agent.modelLabel, agent.thinkingLevel)];
|
|
82
84
|
parts.push(formatTurns(agent.turnCount, agent.maxTurns));
|
|
83
85
|
if (agent.toolUses > 0) parts.push(`${agent.toolUses} tool use${agent.toolUses === 1 ? "" : "s"}`);
|
|
84
86
|
parts.push(duration);
|
|
@@ -102,7 +104,7 @@ export function renderRunningLines(
|
|
|
102
104
|
const tokens = getLifetimeTotal(agent.lifetimeUsage);
|
|
103
105
|
const tokenText = tokens > 0 ? formatSessionTokens(tokens, agent.contextPercent, theme, agent.compactionCount) : "";
|
|
104
106
|
|
|
105
|
-
const parts: string[] = [agent.modelLabel];
|
|
107
|
+
const parts: string[] = [formatModelThinking(agent.modelLabel, agent.thinkingLevel)];
|
|
106
108
|
parts.push(formatTurns(agent.turnCount, agent.maxTurns));
|
|
107
109
|
if (agent.toolUses > 0) parts.push(`${agent.toolUses} tool use${agent.toolUses === 1 ? "" : "s"}`);
|
|
108
110
|
if (tokenText) parts.push(tokenText);
|
|
@@ -176,7 +178,7 @@ function buildSections(
|
|
|
176
178
|
truncate(
|
|
177
179
|
theme.fg("dim", "\u251C\u2500")
|
|
178
180
|
+ ` ${theme.fg("muted", "\u25E6")} ${theme.fg("dim", getDisplayName(agent.type, registry))}`
|
|
179
|
-
+ ` ${theme.fg("dim", "·")} ${theme.fg("dim", agent.modelLabel)}`
|
|
181
|
+
+ ` ${theme.fg("dim", "·")} ${theme.fg("dim", formatModelThinking(agent.modelLabel, agent.thinkingLevel))}`
|
|
180
182
|
+ ` ${theme.fg("dim", "·")} ${theme.fg("dim", agent.description)}`
|
|
181
183
|
+ ` ${theme.fg("dim", "· queued")}`,
|
|
182
184
|
),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nklisch/pi-plugins",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.8",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Native marketplace and plugin lifecycle management for Pi, with Claude Code and Codex compatibility.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -67,8 +67,8 @@
|
|
|
67
67
|
"@nklisch/pi-subagents"
|
|
68
68
|
],
|
|
69
69
|
"dependencies": {
|
|
70
|
-
"@nklisch/pi-mcp-adapter": "2.20.1-nklisch.
|
|
71
|
-
"@nklisch/pi-subagents": "18.1.0-nklisch.
|
|
70
|
+
"@nklisch/pi-mcp-adapter": "2.20.1-nklisch.1",
|
|
71
|
+
"@nklisch/pi-subagents": "18.1.0-nklisch.1",
|
|
72
72
|
"jiti": "2.7.0",
|
|
73
73
|
"semver": "7.8.1",
|
|
74
74
|
"smol-toml": "^1.7.0",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nklisch/pi-enhanced",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.10",
|
|
4
4
|
"description": "Pi, enhanced — one install for nklisch's full harness: policy-gated command review, plugin marketplace, subagents, background tasks, research tools, search, model modes, and a curated UX set.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "nklisch"
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"@nklisch/pi-clearance": "^0",
|
|
68
68
|
"@nklisch/pi-conveniences": "^0",
|
|
69
69
|
"@nklisch/pi-fff-compat": "^0",
|
|
70
|
-
"@nklisch/pi-mcp-adapter": "2.20.1-nklisch.
|
|
70
|
+
"@nklisch/pi-mcp-adapter": "2.20.1-nklisch.1",
|
|
71
71
|
"@nklisch/pi-model-modes": "^0",
|
|
72
72
|
"@nklisch/pi-plugins": "^0",
|
|
73
73
|
"@sinclair/typebox": "^0.34.49",
|
|
@@ -101,6 +101,6 @@
|
|
|
101
101
|
"pi-web-access"
|
|
102
102
|
],
|
|
103
103
|
"scripts": {
|
|
104
|
-
"test": "node test/verify-bundle.mjs"
|
|
104
|
+
"test": "node test/verify-bundle.mjs && node test/verify-subagent-restart.mjs"
|
|
105
105
|
}
|
|
106
106
|
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { execFileSync } from "node:child_process";
|
|
3
|
+
import {
|
|
4
|
+
cpSync,
|
|
5
|
+
mkdtempSync,
|
|
6
|
+
mkdirSync,
|
|
7
|
+
readFileSync,
|
|
8
|
+
rmSync,
|
|
9
|
+
writeFileSync,
|
|
10
|
+
} from "node:fs";
|
|
11
|
+
import { tmpdir } from "node:os";
|
|
12
|
+
import { dirname, join, resolve } from "node:path";
|
|
13
|
+
import { fileURLToPath } from "node:url";
|
|
14
|
+
|
|
15
|
+
const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
16
|
+
const repoRoot = resolve(packageRoot, "../..");
|
|
17
|
+
const scratch = mkdtempSync(join(tmpdir(), "pi-enhanced-subagent-restart-"));
|
|
18
|
+
const packOut = join(scratch, "pack");
|
|
19
|
+
const extracted = join(scratch, "extracted");
|
|
20
|
+
const sessionDir = join(scratch, "sessions");
|
|
21
|
+
const inspector = join(scratch, "inspect-tools.mjs");
|
|
22
|
+
const sessionId = "019d9a5f-7b13-7000-8000-000000000001";
|
|
23
|
+
const requiredTools = ["subagent", "get_subagent_result", "steer_subagent"];
|
|
24
|
+
const liveChildren = new Set();
|
|
25
|
+
|
|
26
|
+
function stageRuntimeDependency(candidateRoot, name) {
|
|
27
|
+
const target = resolve(repoRoot, "node_modules", name);
|
|
28
|
+
const destination = join(candidateRoot, "node_modules", name);
|
|
29
|
+
mkdirSync(dirname(destination), { recursive: true });
|
|
30
|
+
cpSync(target, destination, { recursive: true });
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function startPi(extensionPath, extraArgs = []) {
|
|
34
|
+
const cli = resolve(repoRoot, "node_modules/@earendil-works/pi-coding-agent/dist/cli.js");
|
|
35
|
+
const child = spawn(process.execPath, [
|
|
36
|
+
cli,
|
|
37
|
+
"--offline",
|
|
38
|
+
"--approve",
|
|
39
|
+
"--no-extensions",
|
|
40
|
+
"--no-skills",
|
|
41
|
+
"--no-prompt-templates",
|
|
42
|
+
"--no-themes",
|
|
43
|
+
"--no-context-files",
|
|
44
|
+
"--extension", extensionPath,
|
|
45
|
+
"--extension", inspector,
|
|
46
|
+
"--mode", "rpc",
|
|
47
|
+
"--session-dir", sessionDir,
|
|
48
|
+
"--session-id", sessionId,
|
|
49
|
+
...extraArgs,
|
|
50
|
+
], {
|
|
51
|
+
cwd: repoRoot,
|
|
52
|
+
env: process.env,
|
|
53
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
liveChildren.add(child);
|
|
57
|
+
let stdout = "";
|
|
58
|
+
let stderr = "";
|
|
59
|
+
let sequence = 0;
|
|
60
|
+
const pending = new Map();
|
|
61
|
+
child.stderr.on("data", chunk => { stderr += chunk; });
|
|
62
|
+
child.stdout.on("data", chunk => {
|
|
63
|
+
stdout += chunk;
|
|
64
|
+
for (;;) {
|
|
65
|
+
const newline = stdout.indexOf("\n");
|
|
66
|
+
if (newline < 0) break;
|
|
67
|
+
const line = stdout.slice(0, newline);
|
|
68
|
+
stdout = stdout.slice(newline + 1);
|
|
69
|
+
if (!line) continue;
|
|
70
|
+
let event;
|
|
71
|
+
try { event = JSON.parse(line); }
|
|
72
|
+
catch { continue; }
|
|
73
|
+
if (event.type !== "response" || typeof event.id !== "string") continue;
|
|
74
|
+
const waiter = pending.get(event.id);
|
|
75
|
+
if (!waiter) continue;
|
|
76
|
+
pending.delete(event.id);
|
|
77
|
+
waiter.resolve(event);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
const exited = new Promise(resolvePromise => {
|
|
81
|
+
child.once("exit", (code, signal) => {
|
|
82
|
+
liveChildren.delete(child);
|
|
83
|
+
const error = new Error(`Pi exited before responding (${code ?? signal})\n${stderr}`);
|
|
84
|
+
for (const waiter of pending.values()) waiter.reject(error);
|
|
85
|
+
pending.clear();
|
|
86
|
+
resolvePromise({ code, signal });
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
async function request(command) {
|
|
91
|
+
const id = `restart-${++sequence}`;
|
|
92
|
+
const response = new Promise((resolvePromise, reject) => {
|
|
93
|
+
pending.set(id, { resolve: resolvePromise, reject });
|
|
94
|
+
});
|
|
95
|
+
child.stdin.write(`${JSON.stringify({ id, ...command })}\n`);
|
|
96
|
+
const timer = setTimeout(() => {
|
|
97
|
+
const waiter = pending.get(id);
|
|
98
|
+
if (!waiter) return;
|
|
99
|
+
pending.delete(id);
|
|
100
|
+
waiter.reject(new Error(`Pi RPC timed out for ${command.type}\n${stderr}`));
|
|
101
|
+
}, 20_000);
|
|
102
|
+
timer.unref?.();
|
|
103
|
+
try {
|
|
104
|
+
const result = await response;
|
|
105
|
+
if (!result.success) throw new Error(`Pi RPC ${command.type} failed: ${result.error ?? "unknown error"}\n${stderr}`);
|
|
106
|
+
return result;
|
|
107
|
+
} finally {
|
|
108
|
+
clearTimeout(timer);
|
|
109
|
+
pending.delete(id);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return { child, exited, request, stderr: () => stderr };
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async function inspect(runtime) {
|
|
117
|
+
await runtime.request({ type: "get_commands" });
|
|
118
|
+
await runtime.request({ type: "prompt", message: "/inspect-tools" });
|
|
119
|
+
const entries = await runtime.request({ type: "get_entries" });
|
|
120
|
+
const report = entries.data.entries.findLast(
|
|
121
|
+
entry => entry.type === "custom" && entry.customType === "subagent-tool-regression",
|
|
122
|
+
)?.data;
|
|
123
|
+
if (!report) throw new Error(`Inspector produced no report\n${runtime.stderr()}`);
|
|
124
|
+
for (const name of requiredTools) {
|
|
125
|
+
if (!report.registered.includes(name) || !report.active.includes(name)) {
|
|
126
|
+
throw new Error(`Missing active subagent tool ${name}: ${JSON.stringify(report)}\n${runtime.stderr()}`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
try {
|
|
132
|
+
mkdirSync(packOut, { recursive: true });
|
|
133
|
+
mkdirSync(extracted, { recursive: true });
|
|
134
|
+
mkdirSync(sessionDir, { recursive: true });
|
|
135
|
+
const raw = execFileSync(
|
|
136
|
+
process.execPath,
|
|
137
|
+
[resolve(repoRoot, "scripts/pack-package.mjs"), packageRoot, "--out", packOut],
|
|
138
|
+
{ encoding: "utf8" },
|
|
139
|
+
);
|
|
140
|
+
const report = JSON.parse(raw);
|
|
141
|
+
const tarball = join(packOut, report[0].filename);
|
|
142
|
+
execFileSync("tar", ["-xzf", tarball, "-C", extracted]);
|
|
143
|
+
const candidate = join(extracted, "package");
|
|
144
|
+
|
|
145
|
+
// A normal npm installation provides these ordinary dependencies beside the
|
|
146
|
+
// bundled packages. Keep Pi's peer packages absent from this tree: the test
|
|
147
|
+
// specifically exercises the bridge from an externally installed Pi host.
|
|
148
|
+
stageRuntimeDependency(candidate, "jiti");
|
|
149
|
+
stageRuntimeDependency(candidate, "@sinclair/typebox");
|
|
150
|
+
|
|
151
|
+
writeFileSync(inspector, `
|
|
152
|
+
export default function (pi) {
|
|
153
|
+
pi.registerCommand("inspect-tools", {
|
|
154
|
+
description: "Inspect subagent tool registration",
|
|
155
|
+
handler: async () => {
|
|
156
|
+
pi.appendEntry("subagent-tool-regression", {
|
|
157
|
+
registered: pi.getAllTools().map(tool => tool.name),
|
|
158
|
+
active: pi.getActiveTools(),
|
|
159
|
+
});
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
`);
|
|
164
|
+
|
|
165
|
+
const manifest = JSON.parse(readFileSync(join(candidate, "package.json"), "utf8"));
|
|
166
|
+
const extensionPath = resolve(candidate, manifest.pi.extensions.find(path => path.includes("production-subagents-extension")));
|
|
167
|
+
|
|
168
|
+
const first = startPi(extensionPath);
|
|
169
|
+
await inspect(first);
|
|
170
|
+
first.child.kill("SIGKILL");
|
|
171
|
+
await first.exited;
|
|
172
|
+
|
|
173
|
+
const resumed = startPi(extensionPath);
|
|
174
|
+
await inspect(resumed);
|
|
175
|
+
resumed.child.stdin.end();
|
|
176
|
+
const exit = await resumed.exited;
|
|
177
|
+
if (exit.code !== 0) throw new Error(`Resumed Pi exited unsuccessfully: ${JSON.stringify(exit)}\n${resumed.stderr()}`);
|
|
178
|
+
|
|
179
|
+
console.log("Subagent tools remain registered and active after abrupt Pi process replacement.");
|
|
180
|
+
} finally {
|
|
181
|
+
const children = [...liveChildren];
|
|
182
|
+
const exits = children.map(child => new Promise(resolvePromise => child.once("exit", resolvePromise)));
|
|
183
|
+
for (const child of children) child.kill("SIGKILL");
|
|
184
|
+
await Promise.allSettled(exits);
|
|
185
|
+
rmSync(scratch, { recursive: true, force: true });
|
|
186
|
+
}
|