@akagilnc/pi-workflow-roles 0.1.5406 → 0.1.5475
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/CLAUDE.md +1 -1
- package/README.md +42 -55
- package/README.zh-CN.md +59 -73
- package/THIRD_PARTY_NOTICES.md +4 -7
- package/dist/acp-host/production-host.js +8261 -9073
- package/dist/collector-tool-schemas.js +1 -1
- package/dist/compliance-transport.js +2 -5
- package/dist/engine-detour-usage.js +3 -30
- package/dist/gatekeeper-role.js +4 -18
- package/dist/headless-host/description.js +0 -209
- package/dist/headless-host/production-host.js +6973 -8035
- package/dist/host-contracts.js +8 -0
- package/dist/migrate-book-topology.js +30 -27
- package/dist/packaged-role-registry.js +1 -9
- package/dist/pi/role-turn-host.js +37 -19
- package/dist/public-cli/auto-resume.js +29 -66
- package/dist/public-cli/countersign-run.js +4 -18
- package/dist/public-cli/instruction-seat-run.js +59 -76
- package/dist/public-cli/main.js +9844 -10720
- package/dist/public-cli/option-definitions.js +1 -1
- package/dist/public-cli/post-admission.js +204 -285
- package/dist/public-cli/process-cancel.js +8 -0
- package/dist/public-cli/run-lifecycle.js +24 -94
- package/dist/public-cli/settlement.js +614 -1524
- package/dist/public-cli/terminal.js +23 -53
- package/dist/public-role-summons.js +3 -8
- package/dist/receipt-delivery-policy.js +11 -12
- package/dist/run-terminal-artifacts.js +19 -14
- package/dist/serialize-thrown-value.js +7 -1
- package/dist/submission-ledger.js +21 -89
- package/package.json +1 -1
- package/packets/fixer-repair.md +3 -1
- package/packets/judge-apply.md +7 -16
- package/packets/judge-authority.md +7 -17
- package/packets/judge-plan.md +7 -18
- package/packets/judge-review.md +8 -22
- package/packets/judge-submission.md +4 -7
- package/resources/collector-bot-handbook.md +2 -2
- package/resources/diarist-collect.md +2 -2
- package/resources/engine-dispatch.md +2 -2
- package/resources/navigator-route-playbook.md +1 -1
- package/resources/secretariat-ticket-identity.md +1 -1
- package/scripts/build-package.mjs +0 -2
- package/souls/coder-output-guide.md +3 -3
- package/souls/coder.md +2 -3
- package/souls/doctor-auditor.md +0 -3
- package/souls/fixer-auditor.md +0 -2
- package/souls/fixer-output-guide.md +3 -3
- package/souls/fixer.md +2 -2
- package/souls/gate-output-guide.md +1 -1
- package/souls/quality-law.md +2 -0
- package/src/acp-host/role-turn-host.ts +168 -75
- package/src/collector-tool-schemas.ts +1 -1
- package/src/compliance-transport.ts +3 -6
- package/src/engine-detour-usage.ts +3 -33
- package/src/external-host-turn-loop.ts +81 -36
- package/src/gatekeeper-role.ts +5 -20
- package/src/headless-host/description.ts +4 -214
- package/src/headless-host/production-host.ts +2 -1
- package/src/headless-host/role-turn-host.ts +153 -186
- package/src/host-contracts.ts +13 -10
- package/src/navigator-public-session.ts +1 -1
- package/src/navigator-session-contracts.ts +1 -1
- package/src/package-contracts/gatekeeper-output.ts +1 -1
- package/src/package-contracts/navigator-output.ts +1 -1
- package/src/package-contracts/terminating-infrastructure.ts +1 -1
- package/src/packaged-role-registry.ts +2 -10
- package/src/pi/adapter.ts +0 -3
- package/src/pi/role-turn-host.ts +42 -28
- package/src/prepared-role-turn.ts +2 -0
- package/src/public-cli/auto-resume.ts +27 -66
- package/src/public-cli/countersign-run.ts +4 -22
- package/src/public-cli/instruction-seat-run.ts +79 -80
- package/src/public-cli/option-definitions.ts +1 -1
- package/src/public-cli/post-admission.ts +264 -340
- package/src/public-cli/process-cancel.ts +9 -0
- package/src/public-cli/run-lifecycle.ts +25 -126
- package/src/public-cli/settlement.ts +792 -1912
- package/src/public-cli/terminal.ts +29 -69
- package/src/public-role-summons.ts +3 -8
- package/src/receipt-delivery-policy.ts +11 -12
- package/src/role-envelope.ts +16 -9
- package/src/role-runtime.ts +14 -81
- package/src/run-terminal-artifacts.ts +21 -17
- package/src/serialize-thrown-value.ts +7 -1
- package/src/submission-ledger.ts +30 -116
- package/dist/audit-escalation.js +0 -7
- package/dist/pi/known-failure.js +0 -51
- package/dist/typed-provider-http.js +0 -57
- package/dist/upstream-error-testimony.js +0 -19
- package/src/pi/known-failure.ts +0 -76
- package/src/typed-provider-http.ts +0 -89
- package/src/upstream-error-testimony.ts +0 -45
|
@@ -96,7 +96,6 @@ export const PUBLIC_ROLE_RECORDS = [
|
|
|
96
96
|
outputTool: JUDGE_OUTPUT_TOOL_NAME,
|
|
97
97
|
auditTool: JUDGE_AUDIT_TOOL_NAME,
|
|
98
98
|
settlement: "sealed",
|
|
99
|
-
runnerFailure: "engine-detour-known-first",
|
|
100
99
|
/** Factory board: court until another station has started, then marshal. */
|
|
101
100
|
boardPlacement: "judge-history",
|
|
102
101
|
/** Navigator subject is the public admitted instruction when the run is bound. */
|
|
@@ -214,7 +213,6 @@ export const PUBLIC_ROLE_RECORDS = [
|
|
|
214
213
|
},
|
|
215
214
|
/** Frozen base/lens/authority become the initial prompt; instruction follows. */
|
|
216
215
|
transportPrompt: "skill-args",
|
|
217
|
-
runnerFailure: "engine-detour-record-first",
|
|
218
216
|
boardPlacement: "marshal",
|
|
219
217
|
activationFlags: [
|
|
220
218
|
{ field: "baseRevision", flag: "ak-review-base" },
|
|
@@ -309,10 +307,7 @@ export const PUBLIC_ROLE_RECORDS = [
|
|
|
309
307
|
/** Method-material load failure keeps the activation cause (not reviewer/fixer). */
|
|
310
308
|
phases: [null],
|
|
311
309
|
outputTool: MERGER_OUTPUT_TOOL_NAME,
|
|
312
|
-
settlement: "
|
|
313
|
-
/** #836: residual scan stays on the whole host session. */
|
|
314
|
-
residualScan: "session",
|
|
315
|
-
residualTool: MERGER_OUTPUT_TOOL_NAME,
|
|
310
|
+
settlement: "sealed",
|
|
316
311
|
artifactFace: {
|
|
317
312
|
evidenceRole: true,
|
|
318
313
|
leaves: [
|
|
@@ -489,7 +484,6 @@ export const PUBLIC_ROLE_RECORDS = [
|
|
|
489
484
|
phases: [null],
|
|
490
485
|
outputTool: GATEKEEPER_OUTPUT_TOOL_NAME,
|
|
491
486
|
settlement: "accepted",
|
|
492
|
-
runnerFailure: "engine-detour-record-first",
|
|
493
487
|
activationStage: "load-and-install",
|
|
494
488
|
// Province materials; officers reuse their own public records below.
|
|
495
489
|
sessionMaterials: ["CLAUDE.md", "souls/gatekeeper.md", "souls/quality-law.md", "souls/gate-output-guide.md"],
|
|
@@ -504,7 +498,6 @@ export const PUBLIC_ROLE_RECORDS = [
|
|
|
504
498
|
phases: [null],
|
|
505
499
|
outputTool: NAVIGATOR_OUTPUT_TOOL_NAME,
|
|
506
500
|
settlement: "accepted",
|
|
507
|
-
runnerFailure: "engine-detour-record-first",
|
|
508
501
|
activationStage: "load-and-install",
|
|
509
502
|
sessionMaterials: ["CLAUDE.md", "souls/navigator.md"],
|
|
510
503
|
},
|
|
@@ -527,7 +520,6 @@ export const PUBLIC_ROLE_RECORDS = [
|
|
|
527
520
|
settlement: "accepted",
|
|
528
521
|
/** Court reask replaces the initial prompt. */
|
|
529
522
|
reaskPrompt: true,
|
|
530
|
-
runnerFailure: "engine-detour-record-first",
|
|
531
523
|
gateStageLabel: "审刑院",
|
|
532
524
|
/** Gate summon binds --subject judge and --source-run. */
|
|
533
525
|
gateSummon: "subject-source",
|
|
@@ -630,7 +622,7 @@ export type PackagedActivationFlag = {
|
|
|
630
622
|
};
|
|
631
623
|
|
|
632
624
|
/**
|
|
633
|
-
* Output tool for seats whose settlement leaf is the
|
|
625
|
+
* Output tool for seats whose settlement leaf is the accepted ledger.
|
|
634
626
|
* Any other settlement leaf names that seat's own reader.
|
|
635
627
|
*/
|
|
636
628
|
export function packagedRoleAcceptedOutputTool(role: string): string | undefined {
|
package/src/pi/adapter.ts
CHANGED
|
@@ -194,9 +194,6 @@ export function createPiRoleHostAdapter(
|
|
|
194
194
|
} else if (registration[0] === "session_shutdown") {
|
|
195
195
|
const [, handler] = registration;
|
|
196
196
|
pi.on("session_shutdown", (_value, ctx) => handler({}, context(ctx)));
|
|
197
|
-
} else if (registration[0] === "after_provider_response") {
|
|
198
|
-
const [, handler] = registration;
|
|
199
|
-
pi.on("after_provider_response", (value, ctx) => handler({ status: value.status }, context(ctx)));
|
|
200
197
|
} else if (registration[0] === "agent_end") {
|
|
201
198
|
const [, handler] = registration;
|
|
202
199
|
pi.on("agent_end", (value, ctx) => handler({
|
package/src/pi/role-turn-host.ts
CHANGED
|
@@ -25,6 +25,8 @@ import { ExplicitInternalActivationError } from "../host-contracts.ts";
|
|
|
25
25
|
import { applyEngineChildEnv, ENGINE_MODEL_FLAG_NAME, normalizeEngineName } from "../engine-detour.ts";
|
|
26
26
|
import { projectActivationFlags } from "../role-activation-flags.ts";
|
|
27
27
|
import { encodeUserDialogueStdin } from "../user-dialogue-stdin.ts";
|
|
28
|
+
import { projectThrownFailureLeaf, retainPackageFault } from "../public-cli/settlement.ts";
|
|
29
|
+
import { describeErrorIdentity } from "../public-cli/run-lifecycle.ts";
|
|
28
30
|
import { RECEIPT_DELIVERY_LIMIT_ENV } from "../receipt-delivery-policy.ts";
|
|
29
31
|
|
|
30
32
|
/** Package-relative Internal role entrypoint (ADR 0052; same path as public-cli registry). */
|
|
@@ -156,6 +158,7 @@ export type PiSpawnRunner = (
|
|
|
156
158
|
code: number | null;
|
|
157
159
|
stderr: string;
|
|
158
160
|
timedOut: boolean;
|
|
161
|
+
signal?: string;
|
|
159
162
|
knownFailure?: RoleTurnKnownFailure;
|
|
160
163
|
}>;
|
|
161
164
|
|
|
@@ -287,7 +290,6 @@ export function createDefaultPiSpawnRunner(options: {
|
|
|
287
290
|
// fall back to rejecting on `error` if `close` never fires (e.g. spawn
|
|
288
291
|
// never succeeded so no `close` event will arrive).
|
|
289
292
|
let hasSpawned = false;
|
|
290
|
-
let executionError: Error | undefined;
|
|
291
293
|
const armTimeoutAfterChildReady = (): void => {
|
|
292
294
|
if (spawnOptions.timeoutMs === undefined) return;
|
|
293
295
|
timer = setTimeout(() => {
|
|
@@ -302,6 +304,8 @@ export function createDefaultPiSpawnRunner(options: {
|
|
|
302
304
|
child.kill("SIGTERM");
|
|
303
305
|
};
|
|
304
306
|
parentSignal?.addEventListener("abort", terminateForParentAbort, { once: true });
|
|
307
|
+
const packageErrors: unknown[] = [];
|
|
308
|
+
let identityFailure: RoleTurnKnownFailure | undefined;
|
|
305
309
|
let identityRecorded: Promise<void> = Promise.resolve();
|
|
306
310
|
child.once("spawn", () => {
|
|
307
311
|
hasSpawned = true;
|
|
@@ -313,7 +317,12 @@ export function createDefaultPiSpawnRunner(options: {
|
|
|
313
317
|
runDirectory !== "" &&
|
|
314
318
|
options.recordLaunchedPiIdentity !== undefined
|
|
315
319
|
) {
|
|
316
|
-
identityRecorded =
|
|
320
|
+
identityRecorded = Promise.resolve().then(() =>
|
|
321
|
+
options.recordLaunchedPiIdentity!(runDirectory, piIdentity),
|
|
322
|
+
).catch((error) => {
|
|
323
|
+
packageErrors.push(error);
|
|
324
|
+
identityFailure = projectThrownFailureLeaf(error);
|
|
325
|
+
});
|
|
317
326
|
}
|
|
318
327
|
});
|
|
319
328
|
child.stderr.setEncoding("utf8").on("data", (chunk) => {
|
|
@@ -323,8 +332,9 @@ export function createDefaultPiSpawnRunner(options: {
|
|
|
323
332
|
// A pre-spawn error has no child lifecycle to close. After spawn,
|
|
324
333
|
// retain the execution error and let the mandatory close event own
|
|
325
334
|
// cleanup and the single settlement.
|
|
326
|
-
if (settled
|
|
327
|
-
|
|
335
|
+
if (settled) return;
|
|
336
|
+
if (hasSpawned) {
|
|
337
|
+
packageErrors.push(error);
|
|
328
338
|
return;
|
|
329
339
|
}
|
|
330
340
|
if (timer !== undefined) clearTimeout(timer);
|
|
@@ -332,33 +342,37 @@ export function createDefaultPiSpawnRunner(options: {
|
|
|
332
342
|
settled = true;
|
|
333
343
|
reject(error);
|
|
334
344
|
});
|
|
335
|
-
|
|
345
|
+
// `close` carries (code, signal): a signal-killed child reports code null.
|
|
346
|
+
// Both travel out so a signal death is never read as a clean exit.
|
|
347
|
+
child.on("close", (code, closeSignal) => {
|
|
336
348
|
if (timer !== undefined) clearTimeout(timer);
|
|
337
349
|
parentSignal?.removeEventListener("abort", terminateForParentAbort);
|
|
338
|
-
void
|
|
339
|
-
()
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
350
|
+
void (async () => {
|
|
351
|
+
if (settled) return;
|
|
352
|
+
settled = true;
|
|
353
|
+
await identityRecorded;
|
|
354
|
+
if (stdinDeliveryError !== undefined) packageErrors.push(stdinDeliveryError);
|
|
355
|
+
for (const error of packageErrors) {
|
|
356
|
+
const diagnostic = `Pi transport handling failed beside host terminal: ${describeErrorIdentity(error)}`;
|
|
357
|
+
const runDirectory = spawnOptions.env.AK_ROLE_RUN_DIR;
|
|
358
|
+
if (runDirectory !== undefined) {
|
|
359
|
+
await retainPackageFault({ runDirectory, diagnostic, error });
|
|
360
|
+
} else {
|
|
361
|
+
// Bare runner callers have no admitted artifact directory.
|
|
362
|
+
try { process.stderr.write(`${diagnostic}\n`); }
|
|
363
|
+
catch { /* Best-effort presentation beside the already closed child. */ }
|
|
345
364
|
}
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
if (settled) return;
|
|
358
|
-
settled = true;
|
|
359
|
-
reject(error);
|
|
360
|
-
},
|
|
361
|
-
);
|
|
365
|
+
}
|
|
366
|
+
resolveResult({
|
|
367
|
+
code,
|
|
368
|
+
stderr,
|
|
369
|
+
timedOut,
|
|
370
|
+
...(closeSignal === null ? {} : { signal: closeSignal }),
|
|
371
|
+
...(code === 0 && !timedOut && closeSignal === null && identityFailure !== undefined
|
|
372
|
+
? { knownFailure: identityFailure }
|
|
373
|
+
: {}),
|
|
374
|
+
});
|
|
375
|
+
})();
|
|
362
376
|
});
|
|
363
377
|
});
|
|
364
378
|
};
|
|
@@ -37,6 +37,8 @@ export type PreparedRoleTurn = Readonly<{
|
|
|
37
37
|
}
|
|
38
38
|
| { readonly accepted: false; readonly failure: RoleTurnKnownFailure }
|
|
39
39
|
>;
|
|
40
|
+
/** Drain required shutdown work. Its failures throw; ordinary transport
|
|
41
|
+
* cleanup is reported by its owner without rejecting this drain. */
|
|
40
42
|
dispose?(): Promise<void>;
|
|
41
43
|
/**
|
|
42
44
|
* Headless CLI family (#645): role terminating-tool schema for host-native
|
|
@@ -13,10 +13,8 @@
|
|
|
13
13
|
*/
|
|
14
14
|
import { constants as fsConstants } from "node:fs";
|
|
15
15
|
import { randomUUID } from "node:crypto";
|
|
16
|
-
import {
|
|
16
|
+
import { open } from "node:fs/promises";
|
|
17
17
|
import { join } from "node:path";
|
|
18
|
-
|
|
19
|
-
import { roleRunArtifactsDirectory } from "../role-run-placement.ts";
|
|
20
18
|
import type {
|
|
21
19
|
DurablePrincipal,
|
|
22
20
|
DurablePrincipalAuthority,
|
|
@@ -26,7 +24,6 @@ import {
|
|
|
26
24
|
AUTO_RESUME_LIMIT,
|
|
27
25
|
describeErrorIdentity,
|
|
28
26
|
acquireRunWriterLease,
|
|
29
|
-
markRunResumable,
|
|
30
27
|
markRunTerminal,
|
|
31
28
|
RunWriterLeaseHeldError,
|
|
32
29
|
type RunWriterLease,
|
|
@@ -36,47 +33,47 @@ import { processCancelSignalName } from "./process-cancel.ts";
|
|
|
36
33
|
import { isLawfulTypedTerminalOutcome, formatTerminalResult, type TerminalArtifactRef, type TerminalResult, type TerminalRoleName } from "./terminal.ts";
|
|
37
34
|
import {
|
|
38
35
|
attachRecordedSubmissions,
|
|
36
|
+
ensureRealArtifactsDirectory,
|
|
39
37
|
presentFailureTerminal,
|
|
40
|
-
|
|
38
|
+
retainPackageFault,
|
|
41
39
|
} from "./settlement.ts";
|
|
40
|
+
|
|
41
|
+
export { ensureRealArtifactsDirectory };
|
|
42
42
|
import type { CliIo } from "./cli-io.ts";
|
|
43
43
|
import { serializeThrownValue } from "../serialize-thrown-value.ts";
|
|
44
44
|
|
|
45
|
-
import { errorText
|
|
45
|
+
import { errorText } from "../unknown-value.ts";
|
|
46
46
|
|
|
47
47
|
const dummyIo: CliIo = { stdout: () => {}, stderr: () => {} };
|
|
48
48
|
|
|
49
49
|
/**
|
|
50
50
|
* Persist run-state after a host-turn result, outside the retried dispatch try.
|
|
51
|
-
*
|
|
52
|
-
* win (#416 成功即停). 429 only marks resumable on the controlled-failure path.
|
|
53
|
-
* Write failure must escape the retried dispatch try instead of becoming a
|
|
54
|
-
* synthetic host-turn terminal.
|
|
51
|
+
* The host outcome already decided the terminal. This write only seals the run.
|
|
55
52
|
*/
|
|
56
53
|
export async function persistReturnedRunState(
|
|
57
|
-
admitted: { runDirectory: string
|
|
58
|
-
options?: { readonly lawful?: boolean },
|
|
54
|
+
admitted: { runDirectory: string },
|
|
59
55
|
): Promise<void> {
|
|
60
|
-
if (options?.lawful === true) {
|
|
61
|
-
await markRunTerminal(admitted.runDirectory);
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
const resumeObservation = await resolveControlledFailureResumeObservation({
|
|
65
|
-
runDirectory: admitted.runDirectory,
|
|
66
|
-
});
|
|
67
|
-
const typedHttp429 = resumeObservation.typedHttp429;
|
|
68
|
-
if (admitted.principal !== undefined && typedHttp429 !== undefined) {
|
|
69
|
-
await markRunResumable(admitted.runDirectory, typedHttp429);
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
56
|
await markRunTerminal(admitted.runDirectory);
|
|
73
57
|
}
|
|
74
58
|
|
|
75
|
-
function presentTerminal(terminal: TerminalResult, io: CliIo): void {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
59
|
+
export async function presentTerminal(terminal: TerminalResult, io: CliIo, runDirectory: string, held?: readonly string[]): Promise<void> {
|
|
60
|
+
try {
|
|
61
|
+
if (held !== undefined) {
|
|
62
|
+
for (const value of held) io.stdout(value);
|
|
63
|
+
} else if (terminal.roleOutcome.kind === "failure" || terminal.roleOutcome.kind === "no_receipt") {
|
|
64
|
+
presentFailureTerminal(terminal, io);
|
|
65
|
+
} else {
|
|
66
|
+
io.stdout(formatTerminalResult(terminal));
|
|
67
|
+
}
|
|
68
|
+
} catch (error) {
|
|
69
|
+
// Presentation consumes a settled report; it never reopens dispatch or
|
|
70
|
+
// replaces the host's cause, identity or open details.
|
|
71
|
+
await retainPackageFault({
|
|
72
|
+
runDirectory,
|
|
73
|
+
diagnostic: `terminal presentation failed beside host terminal: ${describeErrorIdentity(error)}`,
|
|
74
|
+
error,
|
|
75
|
+
stderr: (text) => io.stderr(text),
|
|
76
|
+
});
|
|
80
77
|
}
|
|
81
78
|
}
|
|
82
79
|
|
|
@@ -144,38 +141,6 @@ export class TurnDispatchedFailure extends Error {
|
|
|
144
141
|
/** Session custom-entry type carrying the pointer to one dispatch error file. */
|
|
145
142
|
export const DISPATCH_ERROR_RETENTION_ENTRY_TYPE = "ak_run_dispatch_error_retention" as const;
|
|
146
143
|
|
|
147
|
-
/**
|
|
148
|
-
* #182-A hardened path identity, mirrored from settlement.ts's
|
|
149
|
-
* ensureAuditEvidenceDirectory: a planted symlink at the run directory or the
|
|
150
|
-
* artifacts path must not receive a durable run artifact (O_NOFOLLOW only
|
|
151
|
-
* protects the final file name; recursive mkdir would accept a symlinked
|
|
152
|
-
* parent). Fails loudly with the true cause instead. Shared by every caller
|
|
153
|
-
* that needs a durable run-artifacts write independent of session/dossier
|
|
154
|
-
* health — dispatch-error retention here, and post-admission's best-effort
|
|
155
|
-
* cleanup diagnostic (#840 bounce class 2).
|
|
156
|
-
*/
|
|
157
|
-
export async function ensureRealArtifactsDirectory(runDirectory: string): Promise<string> {
|
|
158
|
-
const runStat = await lstat(runDirectory);
|
|
159
|
-
if (runStat.isSymbolicLink() || !runStat.isDirectory()) {
|
|
160
|
-
throw new Error("run artifact retention: run directory is not a real directory");
|
|
161
|
-
}
|
|
162
|
-
const artifactsDir = roleRunArtifactsDirectory(runDirectory);
|
|
163
|
-
try {
|
|
164
|
-
const existing = await lstat(artifactsDir);
|
|
165
|
-
if (existing.isSymbolicLink() || !existing.isDirectory()) {
|
|
166
|
-
throw new Error("run artifact retention: artifacts path is not a real directory");
|
|
167
|
-
}
|
|
168
|
-
} catch (error) {
|
|
169
|
-
if (!isEnoent(error)) throw error;
|
|
170
|
-
await mkdir(artifactsDir, { recursive: true });
|
|
171
|
-
const created = await lstat(artifactsDir);
|
|
172
|
-
if (created.isSymbolicLink() || !created.isDirectory()) {
|
|
173
|
-
throw new Error("run artifact retention: artifacts directory is not a real directory");
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
return artifactsDir;
|
|
177
|
-
}
|
|
178
|
-
|
|
179
144
|
/** Cycle- and bigint-safe JSON replacer so serialization itself cannot drop data. */
|
|
180
145
|
function jsonSafeReplacer(): (key: string, value: unknown) => unknown {
|
|
181
146
|
const seen = new WeakSet<object>();
|
|
@@ -563,11 +528,7 @@ export async function runWithAutoResumeLoop<
|
|
|
563
528
|
} } as TerminalResult
|
|
564
529
|
: terminal;
|
|
565
530
|
if (complete !== undefined) {
|
|
566
|
-
|
|
567
|
-
options.io.stdout(formatTerminalResult(complete));
|
|
568
|
-
} else {
|
|
569
|
-
presentTerminal(complete, options.io);
|
|
570
|
-
}
|
|
531
|
+
await presentTerminal(complete, options.io, options.admitted.runDirectory);
|
|
571
532
|
}
|
|
572
533
|
return stoppedResult === undefined
|
|
573
534
|
? { exitCode: 1, terminal: complete } as T
|
|
@@ -7,7 +7,7 @@ import { readableGateItem } from "../readable-gate-item.ts";
|
|
|
7
7
|
import type { AdmittedCountersignInvocation } from "./invocation.ts";
|
|
8
8
|
import type { PostAdmissionEnv } from "./post-admission.ts";
|
|
9
9
|
import type { CliIo } from "./cli-io.ts";
|
|
10
|
-
import type
|
|
10
|
+
import { currentReplyRows, type TerminalResult, type TerminalRoleOutcome } from "./terminal.ts";
|
|
11
11
|
|
|
12
12
|
import { isRecord } from "../unknown-value.ts";
|
|
13
13
|
|
|
@@ -60,22 +60,6 @@ function isEscalatePayload(payload: unknown): boolean {
|
|
|
60
60
|
);
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
/**
|
|
64
|
-
* Rows a parent may read from a nested diarist terminal (#836 / #953).
|
|
65
|
-
* Accepted/audit use role result payloads; failure history is submissions only.
|
|
66
|
-
*/
|
|
67
|
-
function courtDiaristPayloadRows(
|
|
68
|
-
roleOutcome: TerminalRoleOutcome | undefined,
|
|
69
|
-
submissions: readonly unknown[] | undefined,
|
|
70
|
-
): readonly unknown[] {
|
|
71
|
-
if (roleOutcome === undefined) return submissions ?? [];
|
|
72
|
-
if (roleOutcome.kind === "accepted" || roleOutcome.kind === "audit_escalation") {
|
|
73
|
-
return roleOutcome.payloads ?? [];
|
|
74
|
-
}
|
|
75
|
-
if (roleOutcome.kind === "failure") return submissions ?? [];
|
|
76
|
-
return [];
|
|
77
|
-
}
|
|
78
|
-
|
|
79
63
|
/**
|
|
80
64
|
* Parent diagnostic for court-diarist escalate (#953 / 失败诚实 / 传话).
|
|
81
65
|
* Relays diarist escalate payload(s) via readableGateItem — never invents
|
|
@@ -87,10 +71,9 @@ function courtDiaristPayloadRows(
|
|
|
87
71
|
* every escalate receipt as-is, last = currentConclusion.
|
|
88
72
|
*/
|
|
89
73
|
function courtDiaristEscalateDiagnostic(
|
|
90
|
-
|
|
91
|
-
submissions?: readonly unknown[],
|
|
74
|
+
terminal: TerminalResult | undefined,
|
|
92
75
|
): string {
|
|
93
|
-
const payloads =
|
|
76
|
+
const payloads = currentReplyRows(terminal);
|
|
94
77
|
const escalatePayloads: unknown[] = [];
|
|
95
78
|
for (const payload of payloads) {
|
|
96
79
|
if (isEscalatePayload(payload)) escalatePayloads.push(payload);
|
|
@@ -183,14 +166,13 @@ export async function invokeCourtDiarist(
|
|
|
183
166
|
});
|
|
184
167
|
|
|
185
168
|
const roleOutcome = result.terminal?.roleOutcome;
|
|
186
|
-
const submissions = result.terminal?.submissions;
|
|
187
169
|
// Escalate routing is a boolean over the preserved sequence (#881). Reasons and
|
|
188
170
|
// payload bodies stay on roleOutcome — never rewritten into a sole identity reason.
|
|
189
171
|
if (latestPayloadEscalated(roleOutcome)) {
|
|
190
172
|
return {
|
|
191
173
|
identity: {
|
|
192
174
|
kind: "escalate",
|
|
193
|
-
diagnostic: courtDiaristEscalateDiagnostic(
|
|
175
|
+
diagnostic: courtDiaristEscalateDiagnostic(result.terminal),
|
|
194
176
|
},
|
|
195
177
|
...(result.admitted === undefined ? {} : { admitted: result.admitted }),
|
|
196
178
|
...(result.terminal === undefined ? {} : { terminal: result.terminal }),
|