@akagilnc/pi-workflow-roles 0.1.5382 → 0.1.5462
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 +4 -2
- package/README.zh-CN.md +4 -2
- package/dist/acp-host/production-host.js +8843 -9012
- package/dist/archivist-record-pointer.js +38 -0
- package/dist/compliance-transport.js +7 -5
- package/dist/doctor-auditor.js +1 -0
- package/dist/engine-detour-usage.js +9 -36
- package/dist/gatekeeper-role.js +4 -18
- package/dist/headless-host/description.js +0 -209
- package/dist/headless-host/production-host.js +7828 -8247
- package/dist/host-contracts.js +8 -0
- package/dist/judge-role.js +14 -1
- package/dist/migrate-book-topology.js +215 -96
- package/dist/navigator-attendance.js +10 -9
- package/dist/navigator-invocation-identity.js +18 -0
- package/dist/packaged-role-registry.js +1 -9
- package/dist/pi/role-turn-host.js +46 -19
- package/dist/public-cli/auto-resume.js +29 -66
- package/dist/public-cli/cli.js +1 -0
- package/dist/public-cli/countersign-run.js +4 -18
- package/dist/public-cli/instruction-seat-run.js +258 -69
- package/dist/public-cli/main.js +7488 -7758
- package/dist/public-cli/post-admission.js +451 -349
- package/dist/public-cli/process-cancel.js +8 -0
- package/dist/public-cli/run-lifecycle.js +24 -94
- package/dist/public-cli/settlement.js +624 -1471
- package/dist/public-cli/terminal.js +34 -53
- package/dist/public-cli/turn-request.js +3 -0
- package/dist/public-role-summons.js +3 -8
- package/dist/receipt-delivery-policy.js +162 -28
- package/dist/run-terminal-artifacts.js +19 -14
- package/dist/serialize-thrown-value.js +7 -1
- package/dist/submission-errors.js +11 -1
- package/dist/submission-gate.js +27 -4
- package/dist/submission-ledger.js +21 -89
- package/package.json +1 -1
- package/scripts/build-package.mjs +0 -2
- package/src/acp-host/role-turn-host.ts +168 -75
- package/src/archivist-record-pointer.ts +48 -0
- package/src/compliance-transport.ts +13 -8
- package/src/doctor-auditor.ts +3 -0
- package/src/engine-detour-usage.ts +10 -39
- package/src/external-host-turn-loop.ts +100 -43
- package/src/gatekeeper-role.ts +7 -22
- 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 +20 -10
- package/src/judge-role.ts +24 -5
- package/src/navigator-attendance.ts +17 -12
- package/src/navigator-invocation-identity.ts +31 -0
- package/src/navigator-public-session.ts +1 -1
- package/src/navigator-session-contracts.ts +1 -1
- package/src/packaged-role-registry.ts +2 -10
- package/src/pi/adapter.ts +33 -11
- package/src/pi/role-turn-host.ts +49 -28
- package/src/prepared-role-turn.ts +2 -0
- package/src/public-cli/auto-resume.ts +27 -66
- package/src/public-cli/cli.ts +1 -0
- package/src/public-cli/countersign-run.ts +4 -22
- package/src/public-cli/instruction-seat-run.ts +307 -74
- package/src/public-cli/post-admission.ts +615 -459
- package/src/public-cli/process-cancel.ts +9 -0
- package/src/public-cli/run-lifecycle.ts +25 -126
- package/src/public-cli/settlement.ts +801 -1859
- package/src/public-cli/terminal.ts +42 -70
- package/src/public-cli/turn-request.ts +10 -1
- package/src/public-role-summons.ts +3 -8
- package/src/receipt-delivery-policy.ts +219 -28
- package/src/role-envelope.ts +21 -10
- package/src/role-runtime-dependencies.ts +1 -0
- package/src/role-runtime.ts +79 -102
- package/src/run-terminal-artifacts.ts +21 -17
- package/src/serialize-thrown-value.ts +7 -1
- package/src/submission-correctable-error.ts +5 -2
- package/src/submission-errors.ts +12 -1
- package/src/submission-gate.ts +34 -4
- package/src/submission-ledger.ts +30 -116
- package/src/worker-role.ts +19 -7
- package/src/worker-submission-gates.ts +29 -7
- 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
|
@@ -31,7 +31,10 @@ import {
|
|
|
31
31
|
} from "./navigator-session-contracts.js";
|
|
32
32
|
import { sitianReport } from "./sitian-facade.js";
|
|
33
33
|
import { issueRoot, subjectPath } from "./work-subject-identity.js";
|
|
34
|
-
import {
|
|
34
|
+
import {
|
|
35
|
+
createReceiptDeliveryPolicy,
|
|
36
|
+
NO_RECEIPT_LIFECYCLE_ENTRY_TYPE
|
|
37
|
+
} from "./receipt-delivery-policy.js";
|
|
35
38
|
import { navigatorProseFromUnknown } from "./package-contracts/navigator-output.js";
|
|
36
39
|
import { persistNavigatorWorkBase } from "./navigator-work-base.js";
|
|
37
40
|
import { sha256Hex } from "./sha256.js";
|
|
@@ -250,8 +253,8 @@ function createNavigatorAttendance(options) {
|
|
|
250
253
|
try {
|
|
251
254
|
try {
|
|
252
255
|
if (disposed) throw navigatorUnavailableError("session", new Error("Navigator attendance was disposed"));
|
|
253
|
-
const delivery = createReceiptDeliveryPolicy();
|
|
254
|
-
const promptAllowingRejectedPrepare = async (text
|
|
256
|
+
const delivery = createReceiptDeliveryPolicy(options.deliveryRequestLimit);
|
|
257
|
+
const promptAllowingRejectedPrepare = async (text) => {
|
|
255
258
|
await persistNavigatorWorkBase(activeSession.recordPointer(), { subject, authority });
|
|
256
259
|
const entryStart = activeSession.entries().length;
|
|
257
260
|
prepareBatchRejected = false;
|
|
@@ -278,17 +281,15 @@ function createNavigatorAttendance(options) {
|
|
|
278
281
|
delivery.recordNestedNoReceipt(sessionNoReceipt);
|
|
279
282
|
return;
|
|
280
283
|
}
|
|
281
|
-
if (deliveryRequest && output === void 0) delivery.recordDeliveryRequest();
|
|
282
284
|
};
|
|
283
|
-
await promptAllowingRejectedPrepare(request
|
|
285
|
+
await promptAllowingRejectedPrepare(request);
|
|
284
286
|
if (boundSettlement !== void 0) {
|
|
285
287
|
while (output === void 0 && prepareBatchRejected && delivery.nextAction() === "request-delivery") {
|
|
286
|
-
|
|
288
|
+
delivery.recordDeliveryRequest();
|
|
289
|
+
await promptAllowingRejectedPrepare(JSON.stringify(delivery.deliveryState()));
|
|
287
290
|
}
|
|
288
291
|
if (output === void 0 && delivery.nextAction() === "request-delivery") {
|
|
289
|
-
|
|
290
|
-
delivery.recordDeliveryRequest();
|
|
291
|
-
}
|
|
292
|
+
delivery.closeBudget();
|
|
292
293
|
}
|
|
293
294
|
if (output === void 0 && delivery.nextAction() === "no-receipt" && activeSession.providerFailure?.() === void 0) {
|
|
294
295
|
const facts = delivery.facts({ runPointer: activeSession.recordPointer(), attemptPointer: invocationId });
|
|
@@ -86,6 +86,23 @@ function markerMatchesExpectedIdentity(marker, expected) {
|
|
|
86
86
|
}
|
|
87
87
|
return true;
|
|
88
88
|
}
|
|
89
|
+
function packagedRoleOutputRejectionReason(message) {
|
|
90
|
+
if (typeof message.toolName !== "string") return void 0;
|
|
91
|
+
if (!PACKAGED_ROLE_OUTPUT_TOOLS.has(message.toolName) && message.toolName !== "ak_submission_output") {
|
|
92
|
+
return void 0;
|
|
93
|
+
}
|
|
94
|
+
if (message.isError !== true) return void 0;
|
|
95
|
+
if (classifyPackagedRoleTerminalResult(message).kind !== "nonterminal") return void 0;
|
|
96
|
+
const content = message.content;
|
|
97
|
+
if (typeof content === "string") return content.trim();
|
|
98
|
+
if (!Array.isArray(content)) return "";
|
|
99
|
+
return content.map((part) => {
|
|
100
|
+
if (isRecord(part) && part.type === "text" && typeof part.text === "string") {
|
|
101
|
+
return part.text;
|
|
102
|
+
}
|
|
103
|
+
return "";
|
|
104
|
+
}).join("").trim();
|
|
105
|
+
}
|
|
89
106
|
function classifyPackagedRoleTerminalResult(message) {
|
|
90
107
|
if (typeof message.toolName !== "string") return { kind: "nonterminal" };
|
|
91
108
|
if (!PACKAGED_ROLE_OUTPUT_TOOLS.has(message.toolName) && message.toolName !== "ak_submission_output") return { kind: "nonterminal" };
|
|
@@ -181,6 +198,7 @@ export {
|
|
|
181
198
|
isNavigatorInfrastructureFailureFact,
|
|
182
199
|
markerMatchesExpectedIdentity,
|
|
183
200
|
mintNavigatorInvocationId,
|
|
201
|
+
packagedRoleOutputRejectionReason,
|
|
184
202
|
parseInvocationMarkerIdentity,
|
|
185
203
|
resolveLifecycleInvocationPrincipal
|
|
186
204
|
};
|
|
@@ -59,7 +59,6 @@ const PUBLIC_ROLE_RECORDS = [
|
|
|
59
59
|
outputTool: JUDGE_OUTPUT_TOOL_NAME,
|
|
60
60
|
auditTool: JUDGE_AUDIT_TOOL_NAME,
|
|
61
61
|
settlement: "sealed",
|
|
62
|
-
runnerFailure: "engine-detour-known-first",
|
|
63
62
|
/** Factory board: court until another station has started, then marshal. */
|
|
64
63
|
boardPlacement: "judge-history",
|
|
65
64
|
/** Navigator subject is the public admitted instruction when the run is bound. */
|
|
@@ -177,7 +176,6 @@ const PUBLIC_ROLE_RECORDS = [
|
|
|
177
176
|
},
|
|
178
177
|
/** Frozen base/lens/authority become the initial prompt; instruction follows. */
|
|
179
178
|
transportPrompt: "skill-args",
|
|
180
|
-
runnerFailure: "engine-detour-record-first",
|
|
181
179
|
boardPlacement: "marshal",
|
|
182
180
|
activationFlags: [
|
|
183
181
|
{ field: "baseRevision", flag: "ak-review-base" },
|
|
@@ -272,10 +270,7 @@ const PUBLIC_ROLE_RECORDS = [
|
|
|
272
270
|
/** Method-material load failure keeps the activation cause (not reviewer/fixer). */
|
|
273
271
|
phases: [null],
|
|
274
272
|
outputTool: MERGER_OUTPUT_TOOL_NAME,
|
|
275
|
-
settlement: "
|
|
276
|
-
/** #836: residual scan stays on the whole host session. */
|
|
277
|
-
residualScan: "session",
|
|
278
|
-
residualTool: MERGER_OUTPUT_TOOL_NAME,
|
|
273
|
+
settlement: "sealed",
|
|
279
274
|
artifactFace: {
|
|
280
275
|
evidenceRole: true,
|
|
281
276
|
leaves: [
|
|
@@ -452,7 +447,6 @@ const PUBLIC_ROLE_RECORDS = [
|
|
|
452
447
|
phases: [null],
|
|
453
448
|
outputTool: GATEKEEPER_OUTPUT_TOOL_NAME,
|
|
454
449
|
settlement: "accepted",
|
|
455
|
-
runnerFailure: "engine-detour-record-first",
|
|
456
450
|
activationStage: "load-and-install",
|
|
457
451
|
// Province materials; officers reuse their own public records below.
|
|
458
452
|
sessionMaterials: ["CLAUDE.md", "souls/gatekeeper.md", "souls/quality-law.md", "souls/gate-output-guide.md"]
|
|
@@ -467,7 +461,6 @@ const PUBLIC_ROLE_RECORDS = [
|
|
|
467
461
|
phases: [null],
|
|
468
462
|
outputTool: NAVIGATOR_OUTPUT_TOOL_NAME,
|
|
469
463
|
settlement: "accepted",
|
|
470
|
-
runnerFailure: "engine-detour-record-first",
|
|
471
464
|
activationStage: "load-and-install",
|
|
472
465
|
sessionMaterials: ["CLAUDE.md", "souls/navigator.md"]
|
|
473
466
|
},
|
|
@@ -490,7 +483,6 @@ const PUBLIC_ROLE_RECORDS = [
|
|
|
490
483
|
settlement: "accepted",
|
|
491
484
|
/** Court reask replaces the initial prompt. */
|
|
492
485
|
reaskPrompt: true,
|
|
493
|
-
runnerFailure: "engine-detour-record-first",
|
|
494
486
|
gateStageLabel: "\u5BA1\u5211\u9662",
|
|
495
487
|
/** Gate summon binds --subject judge and --source-run. */
|
|
496
488
|
gateSummon: "subject-source",
|
|
@@ -14,6 +14,9 @@ import { ExplicitInternalActivationError } from "../host-contracts.js";
|
|
|
14
14
|
import { applyEngineChildEnv, ENGINE_MODEL_FLAG_NAME, normalizeEngineName } from "../engine-detour.js";
|
|
15
15
|
import { projectActivationFlags } from "../role-activation-flags.js";
|
|
16
16
|
import { encodeUserDialogueStdin } from "../user-dialogue-stdin.js";
|
|
17
|
+
import { projectThrownFailureLeaf, retainPackageFault } from "../public-cli/settlement.js";
|
|
18
|
+
import { describeErrorIdentity } from "../public-cli/run-lifecycle.js";
|
|
19
|
+
import { RECEIPT_DELIVERY_LIMIT_ENV } from "../receipt-delivery-policy.js";
|
|
17
20
|
/** Package-relative Internal role entrypoint (ADR 0052; same path as public-cli registry). */
|
|
18
21
|
const INTERNAL_ROLE_ENTRYPOINT_RELATIVE = "extensions/role-runtime.ts";
|
|
19
22
|
export function resolveInternalRoleEntrypoint(packageRoot) {
|
|
@@ -190,7 +193,6 @@ export function createDefaultPiSpawnRunner(options) {
|
|
|
190
193
|
// fall back to rejecting on `error` if `close` never fires (e.g. spawn
|
|
191
194
|
// never succeeded so no `close` event will arrive).
|
|
192
195
|
let hasSpawned = false;
|
|
193
|
-
let executionError;
|
|
194
196
|
const armTimeoutAfterChildReady = () => {
|
|
195
197
|
if (spawnOptions.timeoutMs === undefined)
|
|
196
198
|
return;
|
|
@@ -206,6 +208,8 @@ export function createDefaultPiSpawnRunner(options) {
|
|
|
206
208
|
child.kill("SIGTERM");
|
|
207
209
|
};
|
|
208
210
|
parentSignal?.addEventListener("abort", terminateForParentAbort, { once: true });
|
|
211
|
+
const packageErrors = [];
|
|
212
|
+
let identityFailure;
|
|
209
213
|
let identityRecorded = Promise.resolve();
|
|
210
214
|
child.once("spawn", () => {
|
|
211
215
|
hasSpawned = true;
|
|
@@ -216,7 +220,10 @@ export function createDefaultPiSpawnRunner(options) {
|
|
|
216
220
|
if (typeof runDirectory === "string" &&
|
|
217
221
|
runDirectory !== "" &&
|
|
218
222
|
options.recordLaunchedPiIdentity !== undefined) {
|
|
219
|
-
identityRecorded = options.recordLaunchedPiIdentity(runDirectory, piIdentity)
|
|
223
|
+
identityRecorded = Promise.resolve().then(() => options.recordLaunchedPiIdentity(runDirectory, piIdentity)).catch((error) => {
|
|
224
|
+
packageErrors.push(error);
|
|
225
|
+
identityFailure = projectThrownFailureLeaf(error);
|
|
226
|
+
});
|
|
220
227
|
}
|
|
221
228
|
});
|
|
222
229
|
child.stderr.setEncoding("utf8").on("data", (chunk) => {
|
|
@@ -226,8 +233,10 @@ export function createDefaultPiSpawnRunner(options) {
|
|
|
226
233
|
// A pre-spawn error has no child lifecycle to close. After spawn,
|
|
227
234
|
// retain the execution error and let the mandatory close event own
|
|
228
235
|
// cleanup and the single settlement.
|
|
229
|
-
if (settled
|
|
230
|
-
|
|
236
|
+
if (settled)
|
|
237
|
+
return;
|
|
238
|
+
if (hasSpawned) {
|
|
239
|
+
packageErrors.push(error);
|
|
231
240
|
return;
|
|
232
241
|
}
|
|
233
242
|
if (timer !== undefined)
|
|
@@ -236,33 +245,43 @@ export function createDefaultPiSpawnRunner(options) {
|
|
|
236
245
|
settled = true;
|
|
237
246
|
reject(error);
|
|
238
247
|
});
|
|
239
|
-
|
|
248
|
+
// `close` carries (code, signal): a signal-killed child reports code null.
|
|
249
|
+
// Both travel out so a signal death is never read as a clean exit.
|
|
250
|
+
child.on("close", (code, closeSignal) => {
|
|
240
251
|
if (timer !== undefined)
|
|
241
252
|
clearTimeout(timer);
|
|
242
253
|
parentSignal?.removeEventListener("abort", terminateForParentAbort);
|
|
243
|
-
void
|
|
254
|
+
void (async () => {
|
|
244
255
|
if (settled)
|
|
245
256
|
return;
|
|
246
257
|
settled = true;
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
258
|
+
await identityRecorded;
|
|
259
|
+
if (stdinDeliveryError !== undefined)
|
|
260
|
+
packageErrors.push(stdinDeliveryError);
|
|
261
|
+
for (const error of packageErrors) {
|
|
262
|
+
const diagnostic = `Pi transport handling failed beside host terminal: ${describeErrorIdentity(error)}`;
|
|
263
|
+
const runDirectory = spawnOptions.env.AK_ROLE_RUN_DIR;
|
|
264
|
+
if (runDirectory !== undefined) {
|
|
265
|
+
await retainPackageFault({ runDirectory, diagnostic, error });
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
// Bare runner callers have no admitted artifact directory.
|
|
269
|
+
try {
|
|
270
|
+
process.stderr.write(`${diagnostic}\n`);
|
|
271
|
+
}
|
|
272
|
+
catch { /* Best-effort presentation beside the already closed child. */ }
|
|
273
|
+
}
|
|
254
274
|
}
|
|
255
275
|
resolveResult({
|
|
256
276
|
code,
|
|
257
277
|
stderr,
|
|
258
278
|
timedOut,
|
|
279
|
+
...(closeSignal === null ? {} : { signal: closeSignal }),
|
|
280
|
+
...(code === 0 && !timedOut && closeSignal === null && identityFailure !== undefined
|
|
281
|
+
? { knownFailure: identityFailure }
|
|
282
|
+
: {}),
|
|
259
283
|
});
|
|
260
|
-
}
|
|
261
|
-
if (settled)
|
|
262
|
-
return;
|
|
263
|
-
settled = true;
|
|
264
|
-
reject(error);
|
|
265
|
-
});
|
|
284
|
+
})();
|
|
266
285
|
});
|
|
267
286
|
});
|
|
268
287
|
};
|
|
@@ -307,6 +326,14 @@ export function createPiRoleTurnHost(config) {
|
|
|
307
326
|
delete env.AK_ROLE_HOST;
|
|
308
327
|
else
|
|
309
328
|
env.AK_ROLE_HOST = request.host.trim();
|
|
329
|
+
// #1132: the one effective delivery-request ceiling travels to the child
|
|
330
|
+
// on its own env so the in-child role runtime and the worker submission
|
|
331
|
+
// gate count with the same configured number the AK seam resolved. Omit
|
|
332
|
+
// must not inherit a parent value (same rule as the other AK_ROLE_ axes).
|
|
333
|
+
if (request.deliveryRequestLimit === undefined)
|
|
334
|
+
delete env[RECEIPT_DELIVERY_LIMIT_ENV];
|
|
335
|
+
else
|
|
336
|
+
env[RECEIPT_DELIVERY_LIMIT_ENV] = String(request.deliveryRequestLimit);
|
|
310
337
|
applyEngineChildEnv(env, request.engine);
|
|
311
338
|
// Nested auditor dossier tool binds the parent run pointer when published.
|
|
312
339
|
if (typeof process.env.AK_ROLE_AUDITOR_SOURCE_RUN === "string"
|
|
@@ -13,45 +13,46 @@
|
|
|
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
|
-
import {
|
|
19
|
-
import { AUTO_RESUME_LIMIT, describeErrorIdentity, acquireRunWriterLease, markRunResumable, markRunTerminal, RunWriterLeaseHeldError, } from "./run-lifecycle.js";
|
|
18
|
+
import { AUTO_RESUME_LIMIT, describeErrorIdentity, acquireRunWriterLease, markRunTerminal, RunWriterLeaseHeldError, } from "./run-lifecycle.js";
|
|
20
19
|
import { parseAutoResumeLimit } from "./config.js";
|
|
21
20
|
import { processCancelSignalName } from "./process-cancel.js";
|
|
22
21
|
import { isLawfulTypedTerminalOutcome, formatTerminalResult } from "./terminal.js";
|
|
23
|
-
import { attachRecordedSubmissions, presentFailureTerminal,
|
|
22
|
+
import { attachRecordedSubmissions, ensureRealArtifactsDirectory, presentFailureTerminal, retainPackageFault, } from "./settlement.js";
|
|
23
|
+
export { ensureRealArtifactsDirectory };
|
|
24
24
|
import { serializeThrownValue } from "../serialize-thrown-value.js";
|
|
25
|
-
import { errorText
|
|
25
|
+
import { errorText } from "../unknown-value.js";
|
|
26
26
|
const dummyIo = { stdout: () => { }, stderr: () => { } };
|
|
27
27
|
/**
|
|
28
28
|
* Persist run-state after a host-turn result, outside the retried dispatch try.
|
|
29
|
-
*
|
|
30
|
-
* win (#416 成功即停). 429 only marks resumable on the controlled-failure path.
|
|
31
|
-
* Write failure must escape the retried dispatch try instead of becoming a
|
|
32
|
-
* synthetic host-turn terminal.
|
|
29
|
+
* The host outcome already decided the terminal. This write only seals the run.
|
|
33
30
|
*/
|
|
34
|
-
export async function persistReturnedRunState(admitted
|
|
35
|
-
if (options?.lawful === true) {
|
|
36
|
-
await markRunTerminal(admitted.runDirectory);
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
const resumeObservation = await resolveControlledFailureResumeObservation({
|
|
40
|
-
runDirectory: admitted.runDirectory,
|
|
41
|
-
});
|
|
42
|
-
const typedHttp429 = resumeObservation.typedHttp429;
|
|
43
|
-
if (admitted.principal !== undefined && typedHttp429 !== undefined) {
|
|
44
|
-
await markRunResumable(admitted.runDirectory, typedHttp429);
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
31
|
+
export async function persistReturnedRunState(admitted) {
|
|
47
32
|
await markRunTerminal(admitted.runDirectory);
|
|
48
33
|
}
|
|
49
|
-
function presentTerminal(terminal, io) {
|
|
50
|
-
|
|
51
|
-
|
|
34
|
+
export async function presentTerminal(terminal, io, runDirectory, held) {
|
|
35
|
+
try {
|
|
36
|
+
if (held !== undefined) {
|
|
37
|
+
for (const value of held)
|
|
38
|
+
io.stdout(value);
|
|
39
|
+
}
|
|
40
|
+
else if (terminal.roleOutcome.kind === "failure" || terminal.roleOutcome.kind === "no_receipt") {
|
|
41
|
+
presentFailureTerminal(terminal, io);
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
io.stdout(formatTerminalResult(terminal));
|
|
45
|
+
}
|
|
52
46
|
}
|
|
53
|
-
|
|
54
|
-
|
|
47
|
+
catch (error) {
|
|
48
|
+
// Presentation consumes a settled report; it never reopens dispatch or
|
|
49
|
+
// replaces the host's cause, identity or open details.
|
|
50
|
+
await retainPackageFault({
|
|
51
|
+
runDirectory,
|
|
52
|
+
diagnostic: `terminal presentation failed beside host terminal: ${describeErrorIdentity(error)}`,
|
|
53
|
+
error,
|
|
54
|
+
stderr: (text) => io.stderr(text),
|
|
55
|
+
});
|
|
55
56
|
}
|
|
56
57
|
}
|
|
57
58
|
/**
|
|
@@ -89,39 +90,6 @@ export class TurnDispatchedFailure extends Error {
|
|
|
89
90
|
}
|
|
90
91
|
/** Session custom-entry type carrying the pointer to one dispatch error file. */
|
|
91
92
|
export const DISPATCH_ERROR_RETENTION_ENTRY_TYPE = "ak_run_dispatch_error_retention";
|
|
92
|
-
/**
|
|
93
|
-
* #182-A hardened path identity, mirrored from settlement.ts's
|
|
94
|
-
* ensureAuditEvidenceDirectory: a planted symlink at the run directory or the
|
|
95
|
-
* artifacts path must not receive a durable run artifact (O_NOFOLLOW only
|
|
96
|
-
* protects the final file name; recursive mkdir would accept a symlinked
|
|
97
|
-
* parent). Fails loudly with the true cause instead. Shared by every caller
|
|
98
|
-
* that needs a durable run-artifacts write independent of session/dossier
|
|
99
|
-
* health — dispatch-error retention here, and post-admission's best-effort
|
|
100
|
-
* cleanup diagnostic (#840 bounce class 2).
|
|
101
|
-
*/
|
|
102
|
-
export async function ensureRealArtifactsDirectory(runDirectory) {
|
|
103
|
-
const runStat = await lstat(runDirectory);
|
|
104
|
-
if (runStat.isSymbolicLink() || !runStat.isDirectory()) {
|
|
105
|
-
throw new Error("run artifact retention: run directory is not a real directory");
|
|
106
|
-
}
|
|
107
|
-
const artifactsDir = roleRunArtifactsDirectory(runDirectory);
|
|
108
|
-
try {
|
|
109
|
-
const existing = await lstat(artifactsDir);
|
|
110
|
-
if (existing.isSymbolicLink() || !existing.isDirectory()) {
|
|
111
|
-
throw new Error("run artifact retention: artifacts path is not a real directory");
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
catch (error) {
|
|
115
|
-
if (!isEnoent(error))
|
|
116
|
-
throw error;
|
|
117
|
-
await mkdir(artifactsDir, { recursive: true });
|
|
118
|
-
const created = await lstat(artifactsDir);
|
|
119
|
-
if (created.isSymbolicLink() || !created.isDirectory()) {
|
|
120
|
-
throw new Error("run artifact retention: artifacts directory is not a real directory");
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
return artifactsDir;
|
|
124
|
-
}
|
|
125
93
|
/** Cycle- and bigint-safe JSON replacer so serialization itself cannot drop data. */
|
|
126
94
|
function jsonSafeReplacer() {
|
|
127
95
|
const seen = new WeakSet();
|
|
@@ -406,12 +374,7 @@ export async function runWithAutoResumeLoop(options) {
|
|
|
406
374
|
} }
|
|
407
375
|
: terminal;
|
|
408
376
|
if (complete !== undefined) {
|
|
409
|
-
|
|
410
|
-
options.io.stdout(formatTerminalResult(complete));
|
|
411
|
-
}
|
|
412
|
-
else {
|
|
413
|
-
presentTerminal(complete, options.io);
|
|
414
|
-
}
|
|
377
|
+
await presentTerminal(complete, options.io, options.admitted.runDirectory);
|
|
415
378
|
}
|
|
416
379
|
return stoppedResult === undefined
|
|
417
380
|
? { exitCode: 1, terminal: complete }
|
package/dist/public-cli/cli.js
CHANGED
|
@@ -846,6 +846,7 @@ export async function runAkRole(argv, env) {
|
|
|
846
846
|
let current = result;
|
|
847
847
|
while (current.exitCode === 0 && current.admitted?.correlationId !== undefined
|
|
848
848
|
&& current.terminal?.roleOutcome.kind === "accepted"
|
|
849
|
+
&& current.terminal.roleOutcome.decisiveFacts?.directionUnsettled !== true
|
|
849
850
|
&& !latestPayloadEscalated(current.terminal.roleOutcome)) {
|
|
850
851
|
const parentRunId = current.admitted.correlationId;
|
|
851
852
|
resumeFailureContext = {
|
|
@@ -1,24 +1,11 @@
|
|
|
1
1
|
import { readableGateItem } from "../readable-gate-item.js";
|
|
2
|
+
import { currentReplyRows } from "./terminal.js";
|
|
2
3
|
import { isRecord } from "../unknown-value.js";
|
|
3
4
|
function isEscalatePayload(payload) {
|
|
4
5
|
if (!isRecord(payload))
|
|
5
6
|
return false;
|
|
6
7
|
return (payload.status === "escalate");
|
|
7
8
|
}
|
|
8
|
-
/**
|
|
9
|
-
* Rows a parent may read from a nested diarist terminal (#836 / #953).
|
|
10
|
-
* Accepted/audit use role result payloads; failure history is submissions only.
|
|
11
|
-
*/
|
|
12
|
-
function courtDiaristPayloadRows(roleOutcome, submissions) {
|
|
13
|
-
if (roleOutcome === undefined)
|
|
14
|
-
return submissions ?? [];
|
|
15
|
-
if (roleOutcome.kind === "accepted" || roleOutcome.kind === "audit_escalation") {
|
|
16
|
-
return roleOutcome.payloads ?? [];
|
|
17
|
-
}
|
|
18
|
-
if (roleOutcome.kind === "failure")
|
|
19
|
-
return submissions ?? [];
|
|
20
|
-
return [];
|
|
21
|
-
}
|
|
22
9
|
/**
|
|
23
10
|
* Parent diagnostic for court-diarist escalate (#953 / 失败诚实 / 传话).
|
|
24
11
|
* Relays diarist escalate payload(s) via readableGateItem — never invents
|
|
@@ -29,8 +16,8 @@ function courtDiaristPayloadRows(roleOutcome, submissions) {
|
|
|
29
16
|
* no courtAttempt sole-filter on diarist). Same law as secretariat parent face:
|
|
30
17
|
* every escalate receipt as-is, last = currentConclusion.
|
|
31
18
|
*/
|
|
32
|
-
function courtDiaristEscalateDiagnostic(
|
|
33
|
-
const payloads =
|
|
19
|
+
function courtDiaristEscalateDiagnostic(terminal) {
|
|
20
|
+
const payloads = currentReplyRows(terminal);
|
|
34
21
|
const escalatePayloads = [];
|
|
35
22
|
for (const payload of payloads) {
|
|
36
23
|
if (isEscalatePayload(payload))
|
|
@@ -100,14 +87,13 @@ export async function invokeCourtDiarist(input, env, io) {
|
|
|
100
87
|
: { hostAdapters: env.hostAdapters }),
|
|
101
88
|
});
|
|
102
89
|
const roleOutcome = result.terminal?.roleOutcome;
|
|
103
|
-
const submissions = result.terminal?.submissions;
|
|
104
90
|
// Escalate routing is a boolean over the preserved sequence (#881). Reasons and
|
|
105
91
|
// payload bodies stay on roleOutcome — never rewritten into a sole identity reason.
|
|
106
92
|
if (latestPayloadEscalated(roleOutcome)) {
|
|
107
93
|
return {
|
|
108
94
|
identity: {
|
|
109
95
|
kind: "escalate",
|
|
110
|
-
diagnostic: courtDiaristEscalateDiagnostic(
|
|
96
|
+
diagnostic: courtDiaristEscalateDiagnostic(result.terminal),
|
|
111
97
|
},
|
|
112
98
|
...(result.admitted === undefined ? {} : { admitted: result.admitted }),
|
|
113
99
|
...(result.terminal === undefined ? {} : { terminal: result.terminal }),
|