gentle-pi 2.2.0 → 2.3.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 +51 -80
- package/assets/agents/review-readability.md +0 -2
- package/assets/agents/review-reliability.md +0 -2
- package/assets/agents/review-resilience.md +0 -2
- package/assets/agents/review-risk.md +0 -2
- package/assets/agents/sdd-apply.md +5 -3
- package/assets/agents/sdd-proposal.md +2 -0
- package/assets/agents/sdd-research.md +54 -0
- package/assets/agents/sdd-status.md +4 -4
- package/assets/agents/sdd-tasks.md +2 -3
- package/assets/agents/sdd-verify.md +21 -1
- package/assets/chains/sdd-full.chain.md +1 -1
- package/assets/chains/sdd-verify.chain.md +1 -1
- package/assets/orchestrator-delegation.md +54 -248
- package/assets/orchestrator-memory.md +2 -0
- package/assets/orchestrator.md +22 -38
- package/assets/sdd-orchestrator-workflow.md +30 -37
- package/assets/support/sdd-status-contract.md +7 -7
- package/contracts/review-integration/v1/schemas/transition-execution.schema.json +42 -0
- package/contracts/review-integration/v2/schemas/last-event-closure.schema.json +66 -0
- package/contracts/review-integration/v2/schemas/opencode-provider-role.schema.json +14 -0
- package/docs/native-authority-architecture.md +9 -11
- package/docs/review-integration.md +27 -373
- package/extensions/ask-user-choice.ts +151 -0
- package/extensions/gentle-ai.ts +1778 -3673
- package/extensions/quiet-tools.ts +515 -32
- package/extensions/sdd-init.ts +4 -8
- package/lib/gentle-ai-renderer.ts +70 -0
- package/lib/model-routing-authority.ts +133 -0
- package/lib/native-review-cli.ts +372 -940
- package/lib/opaque-pi-reviewer-adapter.ts +284 -0
- package/lib/review-candidate-view.ts +341 -132
- package/lib/review-host-relay.ts +210 -68
- package/lib/review-integration-v2.ts +839 -307
- package/lib/review-last-event-controller.ts +35 -0
- package/lib/sdd-preflight.ts +177 -66
- package/lib/sdd-status.ts +66 -111
- package/lib/terminal-theme.ts +1 -1
- package/package.json +83 -82
- package/runtime/gentle-ai-binary.mjs +1 -1
- package/runtime/native-review-cli.mjs +322 -890
- package/runtime/review-integration-v2.mjs +789 -257
- package/runtime/review-relay-contract.mjs +1 -1
- package/scripts/{build-git-commit-transaction-runner.mjs → build-runtime-modules.mjs} +4 -5
- package/scripts/gentle-ai-installer.mjs +75 -22
- package/scripts/maintainer/provider-relay-matrix.mjs +195 -11
- package/scripts/test-packed-runner.mjs +4 -7
- package/scripts/verify-package-files.mjs +12 -13
- package/skills/_shared/review-ledger-contract.md +8 -14
- package/skills/chained-pr/SKILL.md +3 -0
- package/skills/cognitive-doc-design/SKILL.md +1 -1
- package/skills/comment-writer/SKILL.md +1 -1
- package/skills/gentle-ai/SKILL.md +7 -74
- package/skills/judgment-day/SKILL.md +5 -7
- package/skills/rdd-defect-workflow/SKILL.md +3 -3
- package/skills/release/SKILL.md +3 -3
- package/skills/skill-registry/SKILL.md +1 -1
- package/skills/work-unit-commits/SKILL.md +3 -1
- package/tests/artifact-language.test.ts +24 -11
- package/tests/ask-user-choice.test.ts +264 -0
- package/tests/codegraph-tools.test.ts +3 -3
- package/tests/crosslane/cross-lane.mjs +15 -1168
- package/tests/delegated-key-learnings-contract.test.ts +8 -6
- package/tests/devbinary/native-review-parity.devtest.ts +167 -250
- package/tests/devbinary/pi-host-relay.devtest.ts +867 -0
- package/tests/fixtures/devbinary/last-event-capture-correction-plan.captured.json +10 -0
- package/tests/fixtures/devbinary/last-event-capture-refuter-approved.captured.json +20 -0
- package/tests/fixtures/devbinary/last-event-capture-refuter-correction-required.captured.json +26 -0
- package/tests/fixtures/devbinary/last-event-capture-result-approved.captured.json +8 -0
- package/tests/fixtures/devbinary/last-event-capture-result-correction-required.captured.json +26 -0
- package/tests/fixtures/devbinary/last-event-capture-validation-approved.captured.json +8 -0
- package/tests/fixtures/devbinary/last-event-closure.provenance.md +13 -0
- package/tests/fixtures/devbinary/review-acknowledged-v1.captured.json +9 -0
- package/tests/fixtures/devbinary/review-acknowledged.provenance.md +31 -0
- package/tests/fixtures/devbinary/start-v3-zero-lens-closed.captured.json +21 -0
- package/tests/fixtures/native-review-cli/v2.5.0-rc.1/PROVENANCE.txt +15 -0
- package/tests/gentle-ai-binary.test.ts +83 -13
- package/tests/gentle-ai-dev-binary.test.ts +51 -228
- package/tests/gentle-ai-installer.test.ts +137 -47
- package/tests/gentle-ai.test.ts +820 -131
- package/tests/gentle-theme.test.ts +133 -0
- package/tests/maintainer/provider-relay.maintest.ts +340 -4
- package/tests/model-routing-authority.test.ts +257 -0
- package/tests/native-review-capability-contract.test.ts +28 -1
- package/tests/native-review-cli.test.ts +586 -962
- package/tests/native-review-consent.test.ts +150 -66
- package/tests/native-review-parity-runtime.test.ts +80 -359
- package/tests/native-review-parity.test.ts +674 -925
- package/tests/opaque-pi-reviewer-adapter.test.ts +266 -0
- package/tests/orchestrator-budget.test.ts +132 -88
- package/tests/orchestrator-rdd-ownership.test.ts +103 -0
- package/tests/package-manifest.test.ts +37 -35
- package/tests/provider-defect-handoff.test.ts +15 -118
- package/tests/quiet-tool-rendering.test.ts +1055 -28
- package/tests/review-authority-recovery-docs.test.ts +1 -2
- package/tests/review-candidate-view.test.ts +409 -3
- package/tests/review-compact-contract.test.ts +4 -30
- package/tests/review-controller-lock-status.test.ts +2 -2
- package/tests/review-controller-native-recovery.test.ts +363 -1450
- package/tests/review-controller-native-routing.test.ts +1251 -5642
- package/tests/review-controller-retired-ops.test.ts +1 -1
- package/tests/review-controller-workspace-root.test.ts +222 -71
- package/tests/review-controller.test.ts +26 -816
- package/tests/review-corrected-finalize-binding.test.ts +112 -153
- package/tests/review-dispatch-hydration-gap.test.ts +1 -53
- package/tests/review-gate.test.ts +0 -45
- package/tests/review-host-relay-restart-parity.test.ts +360 -0
- package/tests/review-host-relay-routing.test.ts +117 -82
- package/tests/review-host-relay.test.ts +242 -8
- package/tests/review-integration-v2-forward.test.ts +576 -553
- package/tests/review-integration-v2.test.ts +239 -165
- package/tests/review-last-event-closure.test.ts +408 -0
- package/tests/review-ledger-contract.test.ts +97 -35
- package/tests/review-recovered-lineage-routing.test.ts +0 -47
- package/tests/review-relay-transport-agent.test.ts +119 -46
- package/tests/review-snapshot.test.ts +3 -2
- package/tests/runtime-harness.mjs +361 -196
- package/tests/sdd-agent-tools.test.ts +36 -0
- package/tests/sdd-preflight.test.ts +81 -15
- package/tests/sdd-status.test.ts +109 -110
- package/tests/skill-collision-prefixes.test.ts +5 -8
- package/tests/writer-edit-surface-scope.test.ts +230 -0
- package/themes/Gentleman-Cute.json +94 -0
- package/themes/Gentleman-Sexy.json +92 -0
- package/lib/git-commit-transaction.ts +0 -861
- package/runtime/git-commit-transaction.mjs +0 -862
- package/scripts/run-git-commit-transaction.mjs +0 -35
- package/tests/fixtures/native-review-cli/v2.1.3/sdd-status-engram.json +0 -139
- package/tests/fixtures/native-review-cli/v2.1.3/sdd-status.json +0 -200
- package/tests/git-commit-transaction.test.ts +0 -530
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { chmod, mkdtemp, rm } from "node:fs/promises";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join, posix, win32 } from "node:path";
|
|
5
|
+
|
|
6
|
+
export const OPAQUE_PI_REVIEWER_ARGV = Object.freeze([
|
|
7
|
+
"--print",
|
|
8
|
+
"--mode", "text",
|
|
9
|
+
"--no-session",
|
|
10
|
+
"--no-tools",
|
|
11
|
+
"--no-extensions",
|
|
12
|
+
"--no-skills",
|
|
13
|
+
"--no-prompt-templates",
|
|
14
|
+
"--no-themes",
|
|
15
|
+
"--no-context-files",
|
|
16
|
+
"--no-approve",
|
|
17
|
+
] as const);
|
|
18
|
+
|
|
19
|
+
export const OPAQUE_PI_REVIEWER_TRANSPORT_FAILURE = {
|
|
20
|
+
SCRATCH_FAILED: "scratch-failed",
|
|
21
|
+
LAUNCH_FAILED: "launch-failed",
|
|
22
|
+
CANCELLED: "cancelled",
|
|
23
|
+
TIMED_OUT: "timed-out",
|
|
24
|
+
NONZERO_EXIT: "nonzero-exit",
|
|
25
|
+
EMPTY_OUTPUT: "empty-output",
|
|
26
|
+
CLEANUP_FAILED: "cleanup-failed",
|
|
27
|
+
} as const;
|
|
28
|
+
export type OpaquePiReviewerTransportFailureKind = (typeof OPAQUE_PI_REVIEWER_TRANSPORT_FAILURE)[keyof typeof OPAQUE_PI_REVIEWER_TRANSPORT_FAILURE];
|
|
29
|
+
|
|
30
|
+
export interface OpaquePiReviewerOptions {
|
|
31
|
+
readonly piExecutable?: string;
|
|
32
|
+
readonly environment?: NodeJS.ProcessEnv;
|
|
33
|
+
readonly timeoutMs?: number;
|
|
34
|
+
readonly signal?: AbortSignal;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface OpaquePiReviewerResult {
|
|
38
|
+
readonly stdout: Buffer;
|
|
39
|
+
readonly promptByteLength: number;
|
|
40
|
+
readonly stdoutByteLength: number;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface OpaquePiReviewerTransportDetails {
|
|
44
|
+
readonly exitCode?: number | null;
|
|
45
|
+
readonly stderr?: Buffer;
|
|
46
|
+
readonly timedOut?: boolean;
|
|
47
|
+
readonly cancelled?: boolean;
|
|
48
|
+
/** Wall time for a launched Pi process; absent when no process was launched. */
|
|
49
|
+
readonly elapsedMs?: number;
|
|
50
|
+
/** The bound applied to a launched Pi process; absent when no process was launched. */
|
|
51
|
+
readonly timeoutMs?: number;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export class OpaquePiReviewerTransportError extends Error {
|
|
55
|
+
readonly kind: OpaquePiReviewerTransportFailureKind;
|
|
56
|
+
readonly exitCode: number | null;
|
|
57
|
+
readonly stderr: Buffer;
|
|
58
|
+
readonly timedOut: boolean;
|
|
59
|
+
readonly cancelled: boolean;
|
|
60
|
+
readonly elapsedMs: number | null;
|
|
61
|
+
readonly timeoutMs: number | null;
|
|
62
|
+
|
|
63
|
+
constructor(kind: OpaquePiReviewerTransportFailureKind, message: string, details: OpaquePiReviewerTransportDetails = {}) {
|
|
64
|
+
super(message);
|
|
65
|
+
this.name = "OpaquePiReviewerTransportError";
|
|
66
|
+
this.kind = kind;
|
|
67
|
+
this.exitCode = details.exitCode ?? null;
|
|
68
|
+
this.stderr = details.stderr ?? Buffer.alloc(0);
|
|
69
|
+
this.timedOut = details.timedOut ?? false;
|
|
70
|
+
this.cancelled = details.cancelled ?? false;
|
|
71
|
+
this.elapsedMs = details.elapsedMs ?? null;
|
|
72
|
+
this.timeoutMs = details.timeoutMs ?? null;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
interface OpaquePiProcessResult {
|
|
77
|
+
readonly stdout: Buffer;
|
|
78
|
+
readonly stderr: Buffer;
|
|
79
|
+
readonly exitCode: number | null;
|
|
80
|
+
readonly timedOut: boolean;
|
|
81
|
+
readonly cancelled: boolean;
|
|
82
|
+
readonly elapsedMs: number;
|
|
83
|
+
readonly timeoutMs: number;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const DEFAULT_OPAQUE_PI_TIMEOUT_MS = 600_000;
|
|
87
|
+
|
|
88
|
+
export interface PiLaunch {
|
|
89
|
+
readonly file: string;
|
|
90
|
+
readonly arguments: readonly string[];
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
interface PiHostProcess {
|
|
94
|
+
readonly execPath: string;
|
|
95
|
+
readonly entry: string | undefined;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* The exact spawn shape for the fresh Pi process. A bare `pi` on Windows
|
|
100
|
+
* resolves to pi.cmd, pi.ps1, or a POSIX shim, none of which Node can spawn
|
|
101
|
+
* with shell:false (EINVAL or ENOENT). This adapter already runs inside Pi, so
|
|
102
|
+
* on win32 the host's own JavaScript entry is spawned through the host's
|
|
103
|
+
* process.execPath instead; a shell is never enabled. Every other platform,
|
|
104
|
+
* and every explicit launcher, keeps the exact shape it always had.
|
|
105
|
+
*/
|
|
106
|
+
export function resolvePiLaunch(
|
|
107
|
+
piExecutable: string | undefined,
|
|
108
|
+
platform: NodeJS.Platform = process.platform,
|
|
109
|
+
host: PiHostProcess = { execPath: process.execPath, entry: process.argv[1] },
|
|
110
|
+
): PiLaunch {
|
|
111
|
+
if (piExecutable !== undefined) return { file: piExecutable, arguments: [...OPAQUE_PI_REVIEWER_ARGV] };
|
|
112
|
+
if (platform !== "win32") return { file: "pi", arguments: [...OPAQUE_PI_REVIEWER_ARGV] };
|
|
113
|
+
if (typeof host.entry !== "string" || host.entry.length === 0 || !(platform === "win32" ? win32 : posix).isAbsolute(host.entry)) {
|
|
114
|
+
throw new Error(`Pi host entry could not be resolved from the running process (received ${JSON.stringify(host.entry ?? null)}); a bare pi launcher cannot be spawned on Windows without a shell`);
|
|
115
|
+
}
|
|
116
|
+
return { file: host.execPath, arguments: [host.entry, ...OPAQUE_PI_REVIEWER_ARGV] };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function errorMessage(error: unknown): string {
|
|
120
|
+
return error instanceof Error ? error.message : String(error);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function runPiProcess(prompt: Buffer, scratchDirectory: string, options: OpaquePiReviewerOptions): Promise<OpaquePiProcessResult> {
|
|
124
|
+
return new Promise((resolve, reject) => {
|
|
125
|
+
const startedAt = Date.now();
|
|
126
|
+
let launch: PiLaunch;
|
|
127
|
+
try {
|
|
128
|
+
launch = resolvePiLaunch(options.piExecutable);
|
|
129
|
+
} catch (error) {
|
|
130
|
+
reject(error);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
const child = spawn(launch.file, [...launch.arguments], {
|
|
134
|
+
cwd: scratchDirectory,
|
|
135
|
+
env: options.environment ?? process.env,
|
|
136
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
137
|
+
shell: false,
|
|
138
|
+
windowsHide: true,
|
|
139
|
+
});
|
|
140
|
+
const stdout: Buffer[] = [];
|
|
141
|
+
const stderr: Buffer[] = [];
|
|
142
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_OPAQUE_PI_TIMEOUT_MS;
|
|
143
|
+
let timedOut = false;
|
|
144
|
+
let cancelled = false;
|
|
145
|
+
let settled = false;
|
|
146
|
+
const timer = timeoutMs > 0
|
|
147
|
+
? setTimeout(() => {
|
|
148
|
+
timedOut = true;
|
|
149
|
+
child.kill("SIGKILL");
|
|
150
|
+
}, timeoutMs)
|
|
151
|
+
: undefined;
|
|
152
|
+
timer?.unref();
|
|
153
|
+
const cancel = () => {
|
|
154
|
+
cancelled = true;
|
|
155
|
+
child.kill("SIGKILL");
|
|
156
|
+
};
|
|
157
|
+
const clear = () => {
|
|
158
|
+
if (timer !== undefined) clearTimeout(timer);
|
|
159
|
+
options.signal?.removeEventListener("abort", cancel);
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
child.stdout.on("data", (chunk: Buffer) => stdout.push(chunk));
|
|
163
|
+
child.stderr.on("data", (chunk: Buffer) => stderr.push(chunk));
|
|
164
|
+
child.on("error", (error) => {
|
|
165
|
+
if (settled) return;
|
|
166
|
+
settled = true;
|
|
167
|
+
clear();
|
|
168
|
+
reject(error);
|
|
169
|
+
});
|
|
170
|
+
child.on("close", (code) => {
|
|
171
|
+
if (settled) return;
|
|
172
|
+
settled = true;
|
|
173
|
+
clear();
|
|
174
|
+
resolve({
|
|
175
|
+
stdout: Buffer.concat(stdout),
|
|
176
|
+
stderr: Buffer.concat(stderr),
|
|
177
|
+
exitCode: code,
|
|
178
|
+
timedOut,
|
|
179
|
+
cancelled,
|
|
180
|
+
elapsedMs: Date.now() - startedAt,
|
|
181
|
+
timeoutMs,
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
if (options.signal?.aborted) cancel();
|
|
185
|
+
else options.signal?.addEventListener("abort", cancel, { once: true });
|
|
186
|
+
child.stdin.on("error", () => undefined);
|
|
187
|
+
child.stdin.end(prompt);
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/** Runs raw prompt bytes through one fixed, isolated Pi process. */
|
|
192
|
+
export async function runOpaquePiReviewer(prompt: Buffer, options: OpaquePiReviewerOptions = {}): Promise<OpaquePiReviewerResult> {
|
|
193
|
+
if (options.signal?.aborted) {
|
|
194
|
+
throw new OpaquePiReviewerTransportError(
|
|
195
|
+
OPAQUE_PI_REVIEWER_TRANSPORT_FAILURE.CANCELLED,
|
|
196
|
+
"Pi process was cancelled before launch",
|
|
197
|
+
{ cancelled: true },
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
let scratchDirectory: string | undefined;
|
|
202
|
+
let primaryFailure = false;
|
|
203
|
+
try {
|
|
204
|
+
try {
|
|
205
|
+
scratchDirectory = await mkdtemp(join(tmpdir(), "gentle-pi-opaque-reviewer-"));
|
|
206
|
+
await chmod(scratchDirectory, 0o700);
|
|
207
|
+
} catch (error) {
|
|
208
|
+
throw new OpaquePiReviewerTransportError(
|
|
209
|
+
OPAQUE_PI_REVIEWER_TRANSPORT_FAILURE.SCRATCH_FAILED,
|
|
210
|
+
`Pi scratch directory could not be prepared: ${errorMessage(error)}`,
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
let processResult: OpaquePiProcessResult;
|
|
215
|
+
try {
|
|
216
|
+
processResult = await runPiProcess(prompt, scratchDirectory, options);
|
|
217
|
+
} catch (error) {
|
|
218
|
+
if (options.signal?.aborted) {
|
|
219
|
+
throw new OpaquePiReviewerTransportError(
|
|
220
|
+
OPAQUE_PI_REVIEWER_TRANSPORT_FAILURE.CANCELLED,
|
|
221
|
+
"Pi process was cancelled",
|
|
222
|
+
{ cancelled: true },
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
throw new OpaquePiReviewerTransportError(
|
|
226
|
+
OPAQUE_PI_REVIEWER_TRANSPORT_FAILURE.LAUNCH_FAILED,
|
|
227
|
+
`Pi process could not start: ${errorMessage(error)}`,
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
const timing = {
|
|
231
|
+
elapsedMs: processResult.elapsedMs,
|
|
232
|
+
timeoutMs: processResult.timeoutMs,
|
|
233
|
+
};
|
|
234
|
+
if (processResult.timedOut) {
|
|
235
|
+
throw new OpaquePiReviewerTransportError(
|
|
236
|
+
OPAQUE_PI_REVIEWER_TRANSPORT_FAILURE.TIMED_OUT,
|
|
237
|
+
"Pi process timed out",
|
|
238
|
+
{ exitCode: processResult.exitCode, stderr: processResult.stderr, timedOut: true, ...timing },
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
if (processResult.cancelled) {
|
|
242
|
+
throw new OpaquePiReviewerTransportError(
|
|
243
|
+
OPAQUE_PI_REVIEWER_TRANSPORT_FAILURE.CANCELLED,
|
|
244
|
+
"Pi process was cancelled",
|
|
245
|
+
{ exitCode: processResult.exitCode, stderr: processResult.stderr, cancelled: true, ...timing },
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
if (processResult.exitCode !== 0) {
|
|
249
|
+
throw new OpaquePiReviewerTransportError(
|
|
250
|
+
OPAQUE_PI_REVIEWER_TRANSPORT_FAILURE.NONZERO_EXIT,
|
|
251
|
+
"Pi process failed",
|
|
252
|
+
{ exitCode: processResult.exitCode, stderr: processResult.stderr, ...timing },
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
if (processResult.stdout.length === 0) {
|
|
256
|
+
throw new OpaquePiReviewerTransportError(
|
|
257
|
+
OPAQUE_PI_REVIEWER_TRANSPORT_FAILURE.EMPTY_OUTPUT,
|
|
258
|
+
"Pi process produced no output bytes",
|
|
259
|
+
{ exitCode: 0, stderr: processResult.stderr, ...timing },
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
return {
|
|
263
|
+
stdout: processResult.stdout,
|
|
264
|
+
promptByteLength: prompt.length,
|
|
265
|
+
stdoutByteLength: processResult.stdout.length,
|
|
266
|
+
};
|
|
267
|
+
} catch (error) {
|
|
268
|
+
primaryFailure = true;
|
|
269
|
+
throw error;
|
|
270
|
+
} finally {
|
|
271
|
+
if (scratchDirectory !== undefined) {
|
|
272
|
+
try {
|
|
273
|
+
await rm(scratchDirectory, { recursive: true, force: true });
|
|
274
|
+
} catch (error) {
|
|
275
|
+
if (!primaryFailure) {
|
|
276
|
+
throw new OpaquePiReviewerTransportError(
|
|
277
|
+
OPAQUE_PI_REVIEWER_TRANSPORT_FAILURE.CLEANUP_FAILED,
|
|
278
|
+
`Pi scratch directory cleanup failed: ${errorMessage(error)}`,
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|