@akagilnc/pi-workflow-roles 0.1.3280 → 0.1.3353

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.
Files changed (41) hide show
  1. package/README.md +5 -5
  2. package/README.zh-CN.md +5 -5
  3. package/dist/audit-escalation.js +31 -4
  4. package/dist/gatekeeper-role.js +25 -4
  5. package/dist/grok/production-host.js +1167 -862
  6. package/dist/inspector-contracts.js +5 -2
  7. package/dist/notary-contracts.js +16 -5
  8. package/dist/packaged-role-registry.js +0 -7
  9. package/dist/public-cli/main.js +867 -757
  10. package/package.json +1 -1
  11. package/src/audit-escalation.ts +52 -8
  12. package/src/collector-ledger.ts +309 -74
  13. package/src/collector-receipt.ts +0 -1
  14. package/src/collector-role.ts +21 -14
  15. package/src/diarist-mechanical.ts +16 -5
  16. package/src/gatekeeper-role.ts +33 -4
  17. package/src/grok/role-envelope.ts +68 -52
  18. package/src/inspector-contracts.ts +6 -3
  19. package/src/inspector-role.ts +5 -2
  20. package/src/notary-contracts.ts +20 -5
  21. package/src/notary-role.ts +2 -2
  22. package/src/packaged-role-registry.ts +0 -12
  23. package/src/public-cli/cli.ts +50 -125
  24. package/src/public-cli/coder-run.ts +5 -19
  25. package/src/public-cli/collector-run.ts +65 -21
  26. package/src/public-cli/countersign-run.ts +14 -40
  27. package/src/public-cli/doctor-run.ts +50 -6
  28. package/src/public-cli/fixer-run.ts +5 -19
  29. package/src/public-cli/gleaner-left-run.ts +14 -40
  30. package/src/public-cli/inspector-run.ts +51 -7
  31. package/src/public-cli/instruction-seat-run.ts +27 -0
  32. package/src/public-cli/judge-run.ts +11 -36
  33. package/src/public-cli/merger-run.ts +5 -19
  34. package/src/public-cli/notary-run.ts +54 -5
  35. package/src/public-cli/option-definitions.ts +3 -3
  36. package/src/public-cli/post-admission.ts +76 -0
  37. package/src/public-cli/reviewer-run.ts +5 -19
  38. package/src/public-cli/run-lifecycle.ts +342 -107
  39. package/src/public-cli/settlement.ts +134 -71
  40. package/src/role-runtime.ts +18 -1
  41. package/src/submission-ledger.ts +55 -5
@@ -2697,11 +2697,14 @@ var notaryOutputSchema = withInfrastructureFailureDeclaration(
2697
2697
  openToolObject(
2698
2698
  Type10.Object({
2699
2699
  status: Type10.Unknown({
2700
- description: "pass | bounce \u2014 \u5F62\u72B6\u6307\u5F15\uFF0C\u975E schema \u95F8"
2700
+ description: "pass | bounce | escalate \u2014 \u5F62\u72B6\u6307\u5F15\uFF0C\u975E schema \u95F8"
2701
2701
  }),
2702
2702
  findings: Type10.Unknown({
2703
- description: "string[] findings\uFF0C\u968F pass \u6216 bounce \u7559\u5B58"
2704
- })
2703
+ description: "string[] findings\uFF0C\u968F pass\u3001bounce \u6216 escalate \u7559\u5B58"
2704
+ }),
2705
+ reason: Type10.Optional(Type10.Unknown({
2706
+ description: "status \u4E3A escalate \u65F6\u7684\u4E0A\u5448\u7406\u7531"
2707
+ }))
2705
2708
  })
2706
2709
  )
2707
2710
  );
@@ -2726,6 +2729,9 @@ function projectLawfulNotaryOutput(value) {
2726
2729
  if (!Array.isArray(clone.findings)) clone.findings = asStringArray2(clone.findings);
2727
2730
  return clone;
2728
2731
  }
2732
+ if (status === "escalate") {
2733
+ return structuredClone(value);
2734
+ }
2729
2735
  return void 0;
2730
2736
  }
2731
2737
  function retainNotarySubmission(value) {
@@ -2805,7 +2811,7 @@ function validateRecordedInspectorOutput(value) {
2805
2811
  } catch {
2806
2812
  throw new Error("Inspector output has no execution discriminator");
2807
2813
  }
2808
- if (status === "pass" || status === "bounce") {
2814
+ if (status === "pass" || status === "bounce" || status === "escalate") {
2809
2815
  return value;
2810
2816
  }
2811
2817
  throw new Error("Inspector output has no execution discriminator");
@@ -4982,9 +4988,23 @@ function buildAuditEscalationResult(decision, deliveredOutput) {
4982
4988
  if (Object.hasOwn(decision, "decisionGate")) {
4983
4989
  auditOwned.auditDecisionGate = decision.decisionGate;
4984
4990
  }
4991
+ if (Object.hasOwn(decision, "reason") && decision.reason !== void 0) {
4992
+ auditOwned.reason = decision.reason;
4993
+ }
4994
+ if (Object.hasOwn(decision, "officer") && decision.officer !== void 0) {
4995
+ auditOwned.officer = decision.officer;
4996
+ }
4997
+ if (Object.hasOwn(decision, "findings") && decision.findings !== void 0) {
4998
+ auditOwned.findings = decision.findings;
4999
+ }
4985
5000
  const deliveredFields = deliveredOutput !== void 0 && deliveredOutput !== null && typeof deliveredOutput === "object" && !Array.isArray(deliveredOutput) ? { ...deliveredOutput } : {};
4986
5001
  delete deliveredFields.conflicts;
4987
5002
  delete deliveredFields.auditDecisionGate;
5003
+ if (Object.hasOwn(decision, "officer")) {
5004
+ delete deliveredFields.reason;
5005
+ delete deliveredFields.officer;
5006
+ delete deliveredFields.findings;
5007
+ }
4988
5008
  const result2 = {
4989
5009
  ...deliveredFields,
4990
5010
  ...auditOwned
@@ -4996,11 +5016,20 @@ function isAuditEscalationProjection(value) {
4996
5016
  if (!isAuditEscalationResult(value)) return false;
4997
5017
  return AUDIT_ESCALATION_LIVE_REGISTRY.has(value);
4998
5018
  }
4999
- function humanDecisionText(result2) {
5000
- const lines = ["Human decision required: compliance audit escalation."];
5019
+ function humanDecisionText(decision, result2) {
5020
+ const officer = Object.hasOwn(decision, "officer") ? decision.officer : void 0;
5021
+ const lines = [
5022
+ officer === void 0 ? "Human decision required: compliance audit escalation." : `Human decision required: ${officer} escalation.`
5023
+ ];
5024
+ if (officer !== void 0 && typeof result2.reason === "string") {
5025
+ lines.push(`Reason: ${result2.reason}`);
5026
+ }
5001
5027
  if (Array.isArray(result2.conflicts)) {
5002
5028
  lines.push("Conflicts:", ...result2.conflicts.map((conflict) => `- ${conflict}`));
5003
5029
  }
5030
+ if (officer !== void 0 && Array.isArray(result2.findings) && result2.findings.length > 0) {
5031
+ lines.push("Findings:", ...result2.findings.map((finding2) => `- ${finding2}`));
5032
+ }
5004
5033
  const gate = result2.auditDecisionGate;
5005
5034
  if (gate !== null && typeof gate === "object" && !Array.isArray(gate)) {
5006
5035
  const record4 = gate;
@@ -5014,7 +5043,7 @@ function humanDecisionText(result2) {
5014
5043
  function projectAuditEscalation(decision, deliveredOutput) {
5015
5044
  const details = buildAuditEscalationResult(decision, deliveredOutput);
5016
5045
  return {
5017
- content: [{ type: "text", text: humanDecisionText(details) }],
5046
+ content: [{ type: "text", text: humanDecisionText(decision, details) }],
5018
5047
  details,
5019
5048
  terminate: true,
5020
5049
  ...decision.usage === void 0 ? {} : { usage: decision.usage }
@@ -6370,18 +6399,6 @@ init_activation_ledger_topology();
6370
6399
  import { chmod, open, readdir as readdir2, readFile as readFile10, unlink as unlink2, writeFile as writeFile6 } from "node:fs/promises";
6371
6400
  import { join as join15 } from "node:path";
6372
6401
 
6373
- // src/public-cli/invocation.ts
6374
- init_activation_ledger_topology();
6375
- init_activation_ledger_git();
6376
- import {
6377
- lstat,
6378
- mkdir as mkdir2,
6379
- readFile as readFile9,
6380
- realpath as realpath3,
6381
- writeFile as writeFile5
6382
- } from "node:fs/promises";
6383
- import { basename as basename4, isAbsolute as isAbsolute3, join as join14, resolve as resolve11, sep as sep3 } from "node:path";
6384
-
6385
6402
  // src/collector-config.ts
6386
6403
  import { createHash as createHash6 } from "node:crypto";
6387
6404
  import { readFile as readFile8 } from "node:fs/promises";
@@ -6456,6 +6473,18 @@ async function loadCollectorManifest(path) {
6456
6473
  return { requests, canonicalJson: canonicalJson2, digest: createHash6("sha256").update(canonicalJson2).digest("hex"), sourcePath: path };
6457
6474
  }
6458
6475
 
6476
+ // src/public-cli/invocation.ts
6477
+ init_activation_ledger_topology();
6478
+ init_activation_ledger_git();
6479
+ import {
6480
+ lstat,
6481
+ mkdir as mkdir2,
6482
+ readFile as readFile9,
6483
+ realpath as realpath3,
6484
+ writeFile as writeFile5
6485
+ } from "node:fs/promises";
6486
+ import { basename as basename4, isAbsolute as isAbsolute3, join as join14, resolve as resolve11, sep as sep3 } from "node:path";
6487
+
6459
6488
  // src/public-cli/option-definitions.ts
6460
6489
  var SHARED_PROJECT_SEMANTICS = {
6461
6490
  id: "project",
@@ -6819,7 +6848,7 @@ var ROLE_COMMAND_HELP = {
6819
6848
  },
6820
6849
  collector: {
6821
6850
  command: "collector",
6822
- summary: "Collect GitHub PR review evidence (one-shot).",
6851
+ summary: "Collect GitHub PR review evidence.",
6823
6852
  usage: ["ak-role collector --pr <number> [options] [instruction]"],
6824
6853
  examples: [
6825
6854
  "ak-role collector --pr 42 --repo owner/repository",
@@ -6828,7 +6857,7 @@ var ROLE_COMMAND_HELP = {
6828
6857
  },
6829
6858
  doctor: {
6830
6859
  command: "doctor",
6831
- summary: "Diagnose one retained case (one-shot).",
6860
+ summary: "Diagnose one retained case.",
6832
6861
  usage: ["ak-role doctor --issue <number> [options] [instruction]"],
6833
6862
  examples: [
6834
6863
  'ak-role doctor --issue 115 "Diagnose this retained case."'
@@ -6925,7 +6954,7 @@ var SUPPORT_COMMAND_HELP = {
6925
6954
  },
6926
6955
  resume: {
6927
6956
  command: "resume",
6928
- summary: "Resume a role run under the live seat table (model/host/engine); session principal must still exist.",
6957
+ summary: "Resume a role run under the live seat table (model/host/engine); session principal must still exist. [message] applies only to seats that accept caller instruction; Notary/\u7B26\u5B9D\u90CE must omit message and derives evidence from the existing source-run/dossier binding.",
6929
6958
  usage: ["ak-role resume <runId> [message]"],
6930
6959
  examples: [
6931
6960
  "ak-role resume 01abc\u2026",
@@ -8379,6 +8408,208 @@ import { Value as Value5 } from "typebox/value";
8379
8408
  // src/submission-ledger.ts
8380
8409
  init_activation_ledger_topology();
8381
8410
 
8411
+ // src/gatekeeper-role.ts
8412
+ import { Type as Type16 } from "typebox";
8413
+ var INSPECTOR_OUTPUT_TOOL = INSPECTOR_OUTPUT_TOOL_NAME;
8414
+ var NOTARY_OUTPUT_TOOL = "ak_notary_output";
8415
+ var SUBJECT_TOOL = "ak_gatekeeper_subject";
8416
+ function gateSeatLabel(stage) {
8417
+ switch (stage) {
8418
+ case "gatekeeper":
8419
+ return "\u95E8\u4E0B\u7701";
8420
+ case "inspector":
8421
+ return "\u5BDF\u9662";
8422
+ case "notary":
8423
+ return "\u7B26\u5B9D\u90CE";
8424
+ }
8425
+ }
8426
+ var GatekeeperEscalationError = class extends Error {
8427
+ gatekeeper;
8428
+ constructor(gatekeeper) {
8429
+ super(`\u95E8\u4E0B\u7701${gateSeatLabel(gatekeeper.officer)}\u4E0A\u5448`);
8430
+ this.name = "GatekeeperEscalationError";
8431
+ this.gatekeeper = gatekeeper;
8432
+ }
8433
+ };
8434
+ var officerDecisionSchema = openToolObject(Type16.Object({
8435
+ status: Type16.Unknown({ description: "pass | bounce | escalate \u2014 \u5F62\u72B6\u6307\u5F15\uFF0C\u975E schema \u95F8" }),
8436
+ reason: Type16.Optional(Type16.Unknown({ description: "status \u4E3A escalate \u65F6\u7684\u7406\u7531" })),
8437
+ findings: Type16.Unknown({ description: "string[] findings\uFF0C\u968F pass\u3001bounce \u6216 escalate \u7559\u5B58" })
8438
+ }));
8439
+ var GATEKEEPER_TOOL_SPEC = {
8440
+ name: GATEKEEPER_OUTPUT_TOOL_NAME,
8441
+ label: "\u95E8\u4E0B\u7701\u51B3\u8BAE",
8442
+ description: "\u95E8\u4E0B\u7701\u7EC8\u5C40\u51B3\u8BAE\uFF0C\u72B6\u6001\u4E3A dispatch \u6216 pass\u3002",
8443
+ promptSnippet: "\u95E8\u4E0B\u7701\u51B3\u8BAE",
8444
+ parameters: gatekeeperOutputSchema
8445
+ };
8446
+ function result(content, details) {
8447
+ return { content: [{ type: "text", text: content }], details };
8448
+ }
8449
+ function subjectTool(subject) {
8450
+ return {
8451
+ name: SUBJECT_TOOL,
8452
+ description: "\u8BFB\u53D6\u5DF2\u53D7\u7406\u5377\u5B97\uFF1B\u53EA\u4F9B\u53D6\u9605\uFF0C\u4E0D\u8BC4\u5224\u4E0D\u6539\u52A8\u3002",
8453
+ parameters: Type16.Object({}, { additionalProperties: false }),
8454
+ async execute() {
8455
+ return result(JSON.stringify(subject), subject);
8456
+ }
8457
+ };
8458
+ }
8459
+ function createOfficerDecisionTool(name) {
8460
+ return {
8461
+ name,
8462
+ description: "\u63D0\u4EA4\u4E00\u4EFD typed pass/bounce/escalate \u51B3\u8BAE\u3002",
8463
+ parameters: officerDecisionSchema,
8464
+ async execute(_id, args) {
8465
+ return result(`\u5DF2\u6536 ${String(args?.status)}`, args);
8466
+ }
8467
+ };
8468
+ }
8469
+ function createGatekeeperOutputTool() {
8470
+ return {
8471
+ name: GATEKEEPER_OUTPUT_TOOL_NAME,
8472
+ description: "\u63D0\u4EA4\u95E8\u4E0B\u7701\u6D3E\u5B98\u51B3\u5B9A\u3002",
8473
+ parameters: gatekeeperDecisionSchema,
8474
+ async execute(_id, args) {
8475
+ return result(`\u5DF2\u6536 ${String(args?.status)}`, args);
8476
+ }
8477
+ };
8478
+ }
8479
+ async function defaultLoadSoul(role) {
8480
+ return loadGatekeeperSessionMaterials(role);
8481
+ }
8482
+ function failureReason(error) {
8483
+ if (error instanceof AggregateError) return error.errors.map(failureReason).join("; ");
8484
+ return error instanceof Error ? `${error.name}: ${error.message}` : String(error);
8485
+ }
8486
+ function asStringArray3(value) {
8487
+ if (!Array.isArray(value)) return [];
8488
+ return value.filter((item) => typeof item === "string");
8489
+ }
8490
+ var MISSING_ARGUMENTS_SUBMISSION = Object.freeze({ missing: "arguments" });
8491
+ function isRecord11(value) {
8492
+ return typeof value === "object" && value !== null && !Array.isArray(value);
8493
+ }
8494
+ function retainedSubmission(decision) {
8495
+ return decision === void 0 || isRecord11(decision) && Object.keys(decision).length === 0 ? MISSING_ARGUMENTS_SUBMISSION : decision;
8496
+ }
8497
+ function noUsableReleaseFailure(stage, decision) {
8498
+ return {
8499
+ status: "transport_failure",
8500
+ stage,
8501
+ reason: stage === "gatekeeper" ? "decision \u65E0\u663E\u5F0F dispatch" : "decision \u65E0\u663E\u5F0F pass/bounce/escalate",
8502
+ submission: retainedSubmission(decision)
8503
+ };
8504
+ }
8505
+ function readRecord(value) {
8506
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
8507
+ return value;
8508
+ }
8509
+ function projectProvinceDecision(decision) {
8510
+ const projected = projectLawfulGatekeeperOutput(decision);
8511
+ if (projected === void 0) return noUsableReleaseFailure("gatekeeper", decision);
8512
+ if (projected.status === "dispatch") {
8513
+ return { status: "dispatch", officer: projected.officer };
8514
+ }
8515
+ return { status: "pass", findings: projected.findings ?? [] };
8516
+ }
8517
+ function projectOfficerDecision(officer, decision) {
8518
+ const record4 = readRecord(decision);
8519
+ if (record4 === void 0) return noUsableReleaseFailure(officer, decision);
8520
+ if (record4.status === "bounce") {
8521
+ return {
8522
+ status: "bounce",
8523
+ officer,
8524
+ disposition: "rewrite",
8525
+ findings: asStringArray3(record4.findings),
8526
+ submission: retainedSubmission(decision)
8527
+ };
8528
+ }
8529
+ if (record4.status === "pass") {
8530
+ return {
8531
+ status: "pass",
8532
+ officer,
8533
+ findings: asStringArray3(record4.findings)
8534
+ };
8535
+ }
8536
+ if (record4.status === "escalate") {
8537
+ return {
8538
+ status: "escalate",
8539
+ officer,
8540
+ ...Object.hasOwn(record4, "reason") ? { reason: record4.reason } : {},
8541
+ findings: record4.findings,
8542
+ submission: retainedSubmission(decision)
8543
+ };
8544
+ }
8545
+ return noUsableReleaseFailure(officer, decision);
8546
+ }
8547
+ async function runGatekeeper(options) {
8548
+ const loadSoul = options.loadSoul ?? defaultLoadSoul;
8549
+ let provinceRun;
8550
+ try {
8551
+ provinceRun = await executeAuditorChild({
8552
+ context: options.context,
8553
+ roleLabel: "Gatekeeper",
8554
+ gateSeat: "gatekeeper",
8555
+ systemPrompt: await loadSoul("gatekeeper"),
8556
+ prompt: "\u5377\u5B97\u5DF2\u53D7\u7406\u3002",
8557
+ tool: createGatekeeperOutputTool(),
8558
+ dossierTool: subjectTool(options.subject),
8559
+ ...options.signal === void 0 ? {} : { signal: options.signal },
8560
+ ...options.runDirectory === void 0 ? {} : { runDirectory: options.runDirectory }
8561
+ });
8562
+ } catch (error) {
8563
+ return { status: "transport_failure", stage: "gatekeeper", reason: failureReason(error) };
8564
+ }
8565
+ if (provinceRun.noReceiptLifecycle !== void 0) {
8566
+ return { status: "no_receipt", stage: "gatekeeper", reason: `${gateSeatLabel("gatekeeper")}\u672A\u4EA7\u751F\u5DF2\u63A5\u53D7\u56DE\u6267\u5373\u6563\u5C40`, facts: provinceRun.noReceiptLifecycle };
8567
+ }
8568
+ const province = projectProvinceDecision(provinceRun.decision);
8569
+ if (province.status !== "dispatch") return province;
8570
+ const officer = province.officer;
8571
+ try {
8572
+ const roleLabel = officer === "inspector" ? "Inspector" : "Notary";
8573
+ const officerRun = await executeAuditorChild({
8574
+ context: options.context,
8575
+ roleLabel,
8576
+ gateSeat: officer,
8577
+ systemPrompt: await loadSoul(officer),
8578
+ prompt: "\u5377\u5B97\u5DF2\u53D7\u7406\u3002",
8579
+ tool: createOfficerDecisionTool(officer === "inspector" ? INSPECTOR_OUTPUT_TOOL : NOTARY_OUTPUT_TOOL),
8580
+ dossierTool: subjectTool(options.subject),
8581
+ ...options.signal === void 0 ? {} : { signal: options.signal },
8582
+ ...options.runDirectory === void 0 ? {} : { runDirectory: options.runDirectory }
8583
+ });
8584
+ if (officerRun.noReceiptLifecycle !== void 0) {
8585
+ return { status: "no_receipt", stage: officer, reason: `${gateSeatLabel(officer)}\u672A\u4EA7\u751F\u5DF2\u63A5\u53D7\u56DE\u6267\u5373\u6563\u5C40`, facts: officerRun.noReceiptLifecycle };
8586
+ }
8587
+ return projectOfficerDecision(officer, officerRun.decision);
8588
+ } catch (error) {
8589
+ return { status: "transport_failure", stage: officer, reason: failureReason(error) };
8590
+ }
8591
+ }
8592
+ async function requireGatekeeperPass(options) {
8593
+ const gatekeeper = await runGatekeeper({
8594
+ context: options.context,
8595
+ subject: options.subject,
8596
+ ...options.signal === void 0 ? {} : { signal: options.signal }
8597
+ });
8598
+ if (gatekeeper.status === "pass") return;
8599
+ if (gatekeeper.status === "transport_failure") {
8600
+ const error = new Error(`\u95E8\u4E0B\u7701 transport_failure\uFF08${gatekeeper.stage}\uFF09\uFF1A${gatekeeper.reason}`);
8601
+ error.stage = gatekeeper.stage;
8602
+ error.reason = gatekeeper.reason;
8603
+ if (gatekeeper.submission !== void 0) error.submission = gatekeeper.submission;
8604
+ options.hostActions.failInfrastructure(error, options.context, options.toolCallId);
8605
+ }
8606
+ if (gatekeeper.status === "escalate") {
8607
+ throw new GatekeeperEscalationError(gatekeeper);
8608
+ }
8609
+ options.hostActions.bindSubmissionNonPass(options.toolCallId, gatekeeper);
8610
+ throw new GatekeeperDecisionError(gatekeeper);
8611
+ }
8612
+
8382
8613
  // src/run-terminal-artifacts.ts
8383
8614
  import { basename as basename6, dirname as dirname13, join as join20 } from "node:path";
8384
8615
  function runIdFromRunDirectory(runDirectory) {
@@ -8399,8 +8630,16 @@ function runIdentity(context) {
8399
8630
  if (typeof headerId === "string" && headerId.length > 0) return headerId;
8400
8631
  throw new Error("\u63D0\u4EA4\u8D26\u9700\u8981\u5DF2\u53D7\u7406\u7684 run \u8EAB\u4EFD");
8401
8632
  }
8633
+ function latestUserAttemptId(entries) {
8634
+ const ordered = [...entries];
8635
+ for (let index = ordered.length - 1; index >= 0; index -= 1) {
8636
+ const entry = ordered[index];
8637
+ if (entry?.message?.role === "user" && typeof entry.id === "string") return entry.id;
8638
+ }
8639
+ return void 0;
8640
+ }
8402
8641
  function attemptIdentity(context, runId) {
8403
- return context.sessionManager.getHeader?.()?.id ?? context.sessionManager.getLeafId?.() ?? `${runId}:initial`;
8642
+ return latestUserAttemptId(context.sessionManager.getEntries?.() ?? []) ?? context.sessionManager.getHeader?.()?.id ?? context.sessionManager.getLeafId?.() ?? `${runId}:initial`;
8404
8643
  }
8405
8644
  function submissionRecordFile(cwd, runId, home) {
8406
8645
  const ledgerHome = resolveActivationLedgerHome(home);
@@ -8529,6 +8768,12 @@ function createSubmissionLedgerHost(host, outputTools, failInfrastructure2 = (er
8529
8768
  const append = (event) => appendFor(state, context, runId, attemptId, event);
8530
8769
  if (state.sealed) throw new Error("\u63D0\u4EA4\u8D26\u5DF2\u5C01\u8D26");
8531
8770
  append({ type: "candidate", attemptId, toolCallId, toolName: tool2.name, sequence: ++state.sequence });
8771
+ const projectOfficerEscalation = (officer, original, deliveredOutput = original) => projectAuditEscalation({
8772
+ ...original,
8773
+ status: "escalate",
8774
+ officer,
8775
+ reason: original.reason === void 0 ? `\u95E8\u4E0B\u7701${officer}\u4E0A\u5448\uFF08\u539F\u5377\u672A\u9644 reason\uFF09` : original.reason
8776
+ }, deliveredOutput);
8532
8777
  let result2;
8533
8778
  try {
8534
8779
  failOnInfrastructureFailureDeclaration(
@@ -8544,7 +8789,14 @@ function createSubmissionLedgerHost(host, outputTools, failInfrastructure2 = (er
8544
8789
  );
8545
8790
  result2 = await tool2.execute(toolCallId, params, signal, update, context);
8546
8791
  } catch (error) {
8547
- if (isCorrectableExecuteError(error)) {
8792
+ if (error instanceof GatekeeperEscalationError) {
8793
+ const decision = error.gatekeeper;
8794
+ result2 = projectOfficerEscalation(
8795
+ error.gatekeeper.officer,
8796
+ decision,
8797
+ params
8798
+ );
8799
+ } else if (isCorrectableExecuteError(error)) {
8548
8800
  append({
8549
8801
  type: "outcome",
8550
8802
  attemptId,
@@ -8553,6 +8805,7 @@ function createSubmissionLedgerHost(host, outputTools, failInfrastructure2 = (er
8553
8805
  code: "typed-bounce",
8554
8806
  diagnostic: error instanceof Error ? error.message : String(error)
8555
8807
  });
8808
+ throw error;
8556
8809
  } else {
8557
8810
  append({
8558
8811
  type: "outcome",
@@ -8561,8 +8814,12 @@ function createSubmissionLedgerHost(host, outputTools, failInfrastructure2 = (er
8561
8814
  outcome: "infrastructure",
8562
8815
  diagnostic: error instanceof Error ? error.message : String(error)
8563
8816
  });
8817
+ throw error;
8564
8818
  }
8565
- throw error;
8819
+ }
8820
+ if ((role === "inspector" || role === "notary") && typeof result2.details === "object" && result2.details !== null && !Array.isArray(result2.details) && result2.details.status === "escalate") {
8821
+ const details = result2.details;
8822
+ result2 = projectOfficerEscalation(role, details);
8566
8823
  }
8567
8824
  if (isAuditEscalationProjection(result2.details)) {
8568
8825
  const candidates2 = rounds.get(attemptId) ?? [];
@@ -8606,463 +8863,62 @@ function createSubmissionLedgerHost(host, outputTools, failInfrastructure2 = (er
8606
8863
  };
8607
8864
  }
8608
8865
 
8609
- // src/activation-trace.ts
8610
- import { Type as Type16 } from "typebox";
8611
- var causeSchema = Type16.Object({
8612
- identity: Type16.String({ minLength: 1 }),
8613
- name: Type16.String({ minLength: 1 }),
8614
- message: Type16.String(),
8615
- evidenceId: Type16.Optional(Type16.String({ minLength: 1 }))
8616
- }, { additionalProperties: false });
8617
- var activationTraceRecordSchema = Type16.Object({
8618
- role: Type16.String({ minLength: 1 }),
8619
- stageId: Type16.String({ pattern: "^[a-z][a-z0-9-]*$" }),
8620
- status: Type16.Literal("failed"),
8621
- timestamp: Type16.String({ format: "date-time" }),
8622
- cause: causeSchema
8623
- }, { additionalProperties: false });
8624
- var activationCauseEvidence = 0;
8625
- var retainedActivationCauses = /* @__PURE__ */ new Map();
8626
- function namedActivationCause(error) {
8627
- const evidenceId = `activation-cause-${++activationCauseEvidence}`;
8628
- retainedActivationCauses.set(evidenceId, error);
8629
- if (error instanceof Error) {
8630
- const code = error.code;
8631
- const name = error.name || "Error";
8632
- return { identity: typeof code === "string" && code.length > 0 ? code : name, name, message: error.message, evidenceId };
8633
- }
8634
- let message;
8635
- try {
8636
- message = typeof error === "string" ? error : JSON.stringify(error) ?? String(error);
8637
- return { identity: "UnknownThrownCause", name: "UnknownThrownCause", message, evidenceId };
8638
- } catch {
8639
- return { identity: "UnknownThrownCause", name: "UnknownThrownCause", message: String(error), evidenceId };
8640
- }
8641
- }
8642
-
8643
- // src/role-runtime.ts
8644
- init_activation_ledger_topology();
8866
+ // src/collector-ledger.ts
8867
+ import Value3 from "typebox/value";
8645
8868
 
8646
- // src/activation-ledger.ts
8647
- init_activation_ledger_topology();
8648
- init_activation_ledger_git();
8649
- import {
8650
- constants,
8651
- closeSync,
8652
- fstatSync,
8653
- openSync,
8654
- writeSync
8655
- } from "node:fs";
8656
- import { dirname as dirname14, isAbsolute as isAbsolute6, resolve as resolve15 } from "node:path";
8657
-
8658
- // src/activation-ledger-session.ts
8659
- init_activation_ledger_topology();
8660
- import {
8661
- lstatSync as lstatSync2,
8662
- realpathSync as realpathSync3,
8663
- statSync as statSync3,
8664
- writeFileSync as writeFileSync4
8665
- } from "node:fs";
8666
- import { isAbsolute as isAbsolute5, resolve as resolve14 } from "node:path";
8667
- var ActivationSessionFileMissingError = class extends Error {
8668
- code = "AK_ACTIVATION_SESSION_FILE_MISSING";
8669
- path;
8670
- constructor(path, options) {
8671
- super(
8672
- `Workflow role activation durable session file does not exist: ${path}`,
8673
- options?.cause === void 0 ? void 0 : { cause: options.cause }
8674
- );
8675
- this.name = "ActivationSessionFileMissingError";
8676
- this.path = path;
8677
- }
8678
- };
8679
- function materializeDeferredSessionFile(sessionManager, resolvedFile) {
8680
- const header = sessionManager.getHeader?.();
8681
- if (header === null || header === void 0 || header.type !== "session") {
8682
- throw new ActivationSessionFileMissingError(resolvedFile);
8683
- }
8684
- try {
8685
- writeFileSync4(resolvedFile, `${JSON.stringify(header)}
8686
- `, { flag: "wx" });
8687
- } catch (error) {
8688
- if (errnoCode(error) !== "EEXIST") {
8689
- throw new Error(
8690
- `Workflow role activation failed to materialize durable session file (${resolvedFile}): ${errorText(error)}`,
8691
- { cause: error }
8692
- );
8693
- }
8694
- }
8695
- if (typeof sessionManager.setSessionFile === "function") {
8696
- sessionManager.setSessionFile(resolvedFile);
8697
- }
8698
- }
8699
- function durableSessionPointer(sessionManager) {
8700
- const file = sessionManager.getSessionFile?.();
8701
- if (typeof file !== "string" || file.length === 0) {
8702
- throw new Error(
8703
- "Workflow role activation requires a durable Pi session file principal (getSessionFile); directory-only or --no-session invocations are rejected"
8704
- );
8705
- }
8706
- if (!isAbsolute5(file)) {
8707
- throw new Error(
8708
- `Workflow role activation requires an absolute durable session file path; got relative path: ${file}`
8709
- );
8710
- }
8711
- const resolvedFile = resolve14(file);
8712
- try {
8713
- lstatSync2(resolvedFile);
8714
- } catch (error) {
8715
- if (errnoCode(error) !== "ENOENT") {
8716
- throw new Error(
8717
- `Workflow role activation failed to stat durable session file (${resolvedFile}): ${errorText(error)}`,
8718
- { cause: error }
8719
- );
8720
- }
8721
- try {
8722
- materializeDeferredSessionFile(sessionManager, resolvedFile);
8723
- } catch (materializeError) {
8724
- if (materializeError instanceof ActivationSessionFileMissingError) {
8725
- throw new ActivationSessionFileMissingError(resolvedFile, { cause: error });
8869
+ // src/collector-evidence.ts
8870
+ import { createHash as createHash8 } from "node:crypto";
8871
+ var COLLECTOR_ELIGIBILITY_MS = 15 * 60 * 1e3;
8872
+ function createSystemCollectorClock() {
8873
+ const start = process.hrtime.bigint();
8874
+ return {
8875
+ wallNow: () => /* @__PURE__ */ new Date(),
8876
+ monoNow: () => Number(process.hrtime.bigint() - start) / 1e6,
8877
+ sleep: (ms, signal) => new Promise((resolve17, reject) => {
8878
+ if (signal?.aborted) {
8879
+ reject(signal.reason ?? new Error("aborted"));
8880
+ return;
8726
8881
  }
8727
- throw materializeError;
8728
- }
8729
- }
8730
- let realFile;
8731
- try {
8732
- realFile = realpathSync3(resolvedFile);
8733
- } catch (error) {
8734
- throw new ActivationSessionFileMissingError(resolvedFile, { cause: error });
8735
- }
8736
- let info;
8737
- try {
8738
- info = statSync3(realFile);
8739
- } catch (error) {
8740
- throw new Error(
8741
- `Workflow role activation failed to stat durable session file (${realFile}): ${errorText(error)}`,
8742
- { cause: error }
8743
- );
8744
- }
8745
- if (info.isDirectory()) {
8746
- throw new Error(
8747
- `Workflow role activation durable session principal must be a file, not a directory: ${realFile}`
8748
- );
8749
- }
8750
- if (!info.isFile()) {
8751
- throw new Error(
8752
- `Workflow role activation durable session principal is not a regular file: ${realFile}`
8753
- );
8754
- }
8755
- return { kind: "session-file", path: realFile };
8882
+ const timer = setTimeout(resolve17, ms);
8883
+ const onAbort = () => {
8884
+ clearTimeout(timer);
8885
+ reject(signal?.reason ?? new Error("aborted"));
8886
+ };
8887
+ signal?.addEventListener("abort", onAbort, { once: true });
8888
+ })
8889
+ };
8756
8890
  }
8757
-
8758
- // src/activation-ledger.ts
8759
- init_activation_ledger_topology();
8760
- var ACTIVATION_LEDGER_APPEND_OPEN_FLAGS = constants.O_APPEND | constants.O_CREAT | constants.O_WRONLY | constants.O_NOFOLLOW;
8761
- var ACCEPTED_ACTIVATION_EVENT = "accepted-activation";
8762
- var ACCEPTED_ACTIVATION_FACT_KEYS = Object.freeze([
8763
- "event",
8764
- "role",
8765
- "observedAt",
8766
- "bookKey",
8767
- "session",
8768
- "correlation"
8769
- ]);
8770
- function correlationIdentityFromEnv(env = process.env) {
8771
- const raw = env.AK_CORRELATION_ID;
8772
- if (typeof raw === "string" && raw.trim().length > 0) {
8773
- return { kind: "caller", id: raw };
8891
+ function sha256Text(text) {
8892
+ return createHash8("sha256").update(text, "utf8").digest("hex");
8893
+ }
8894
+ function computeWindowRelation(authoritativeTime, activationTime, deadlineTime) {
8895
+ if (authoritativeTime === void 0 || authoritativeTime === null || authoritativeTime.length === 0) {
8896
+ return "uncertain";
8774
8897
  }
8775
- return { kind: "absent" };
8898
+ const ms = Date.parse(authoritativeTime);
8899
+ if (!Number.isFinite(ms)) return "uncertain";
8900
+ const activationMs = activationTime.getTime();
8901
+ const deadlineMs = deadlineTime.getTime();
8902
+ if (ms < activationMs) return "before";
8903
+ if (ms <= deadlineMs) return "within";
8904
+ return "after";
8776
8905
  }
8777
- function projectAcceptedActivationFact(input) {
8778
- const closed = {
8779
- event: ACCEPTED_ACTIVATION_EVENT,
8780
- role: input.role,
8781
- observedAt: input.observedAt,
8782
- bookKey: input.bookKey,
8783
- session: { kind: "session-file", path: input.session.path },
8784
- correlation: input.correlation.kind === "caller" ? { kind: "caller", id: input.correlation.id } : { kind: "absent" }
8785
- };
8786
- return Object.fromEntries(
8787
- ACCEPTED_ACTIVATION_FACT_KEYS.map((key) => [key, closed[key]])
8788
- );
8906
+ function stableId(kind, githubId) {
8907
+ return `${kind}:${githubId}`;
8789
8908
  }
8790
- function buildAcceptedActivationFact(input) {
8791
- return projectAcceptedActivationFact(input);
8909
+ function versionDigest(parts) {
8910
+ return sha256Text(JSON.stringify(parts));
8792
8911
  }
8793
- function serializeAcceptedActivationFact(fact) {
8794
- return `${JSON.stringify(projectAcceptedActivationFact(fact))}
8795
- `;
8912
+ function evidenceIdFor(kind, versionId) {
8913
+ return sha256Text(`${kind}:${versionId}`).slice(0, 16);
8796
8914
  }
8797
- function appendActivationLedgerLine(ledgerPath, line2, options) {
8798
- if (!isAbsolute6(options.ledgerHome)) {
8799
- throw new ActivationLedgerError(
8800
- `activation ledger home must be absolute: ${options.ledgerHome}`
8801
- );
8802
- }
8803
- const resolvedLedger = resolve15(ledgerPath);
8804
- const resolvedHome = resolve15(options.ledgerHome);
8805
- const parent = dirname14(resolvedLedger);
8806
- ensureRealDirectoryTree(resolvedHome, parent);
8807
- assertLedgerFileInsideHome(resolvedLedger, resolvedHome);
8808
- if (typeof constants.O_NOFOLLOW !== "number") {
8809
- throw new ActivationLedgerError(
8810
- "activation ledger append requires O_NOFOLLOW open-flag support (anti-symlink TOCTOU protection must not be silently dropped); refusing to append"
8811
- );
8812
- }
8813
- const bytes = Buffer.isBuffer(line2) ? line2 : Buffer.from(line2);
8814
- let ledgerFd;
8815
- let primaryFailure;
8816
- try {
8817
- try {
8818
- ledgerFd = openSync(resolvedLedger, ACTIVATION_LEDGER_APPEND_OPEN_FLAGS, 420);
8819
- } catch (error) {
8820
- throw new ActivationLedgerError(
8821
- `activation ledger failed to open ledger file (${resolvedLedger}): ${errorText(error)}`,
8822
- { cause: error }
8823
- );
8824
- }
8825
- let opened;
8826
- try {
8827
- opened = fstatSync(ledgerFd);
8828
- } catch (error) {
8829
- throw new ActivationLedgerError(
8830
- `activation ledger failed to fstat ledger file (${resolvedLedger}): ${errorText(error)}`,
8831
- { cause: error }
8832
- );
8833
- }
8834
- if (!opened.isFile()) {
8835
- throw new ActivationLedgerError(
8836
- `activation ledger is not a regular file: ${resolvedLedger}`
8837
- );
8838
- }
8839
- const written = writeSync(ledgerFd, bytes, 0, bytes.length, null);
8840
- if (written !== bytes.length) {
8841
- throw new ActivationLedgerError(
8842
- `activation ledger short write: wrote ${written} of ${bytes.length} bytes to ${resolvedLedger}`
8843
- );
8844
- }
8845
- } catch (error) {
8846
- primaryFailure = error;
8847
- }
8848
- if (ledgerFd !== void 0) {
8849
- try {
8850
- closeSync(ledgerFd);
8851
- } catch (closeFailure) {
8852
- if (primaryFailure !== void 0) {
8853
- throw new AggregateError(
8854
- [primaryFailure, closeFailure],
8855
- "activation ledger operation and close failed",
8856
- { cause: primaryFailure }
8857
- );
8858
- }
8859
- throw closeFailure;
8860
- }
8861
- }
8862
- if (primaryFailure !== void 0) throw primaryFailure;
8863
- }
8864
- function appendAcceptedActivationFact(ledgerPath, fact, options) {
8865
- appendActivationLedgerLine(
8866
- ledgerPath,
8867
- Buffer.from(serializeAcceptedActivationFact(fact), "utf8"),
8868
- { ledgerHome: options.ledgerHome }
8869
- );
8870
- }
8871
- function appendAcceptedActivationToBook(options) {
8872
- appendAcceptedActivationFact(
8873
- activationWaitingLedgerPath(options.ledgerHome, options.fact.bookKey),
8874
- options.fact,
8875
- { ledgerHome: options.ledgerHome }
8876
- );
8877
- }
8878
-
8879
- // src/stderr-jsonl.ts
8880
- import { writeSync as writeSync2 } from "node:fs";
8881
- var STDERR_JSONL_WRITE_RETRY_LIMIT = 100;
8882
- function writeStderrJsonlRecord(record4, write = writeSync2) {
8883
- const bytes = Buffer.from(`${JSON.stringify(record4)}
8884
- `);
8885
- let offset = 0;
8886
- let retries = 0;
8887
- while (offset < bytes.length) {
8888
- try {
8889
- const written = write(2, bytes, offset, bytes.length - offset);
8890
- if (written <= 0) throw new Error("stderr JSONL write made no progress");
8891
- offset += written;
8892
- retries = 0;
8893
- } catch (error) {
8894
- const code = error.code;
8895
- if ((code === "EAGAIN" || code === "EINTR") && retries++ < STDERR_JSONL_WRITE_RETRY_LIMIT) continue;
8896
- throw error;
8897
- }
8898
- }
8899
- }
8900
-
8901
- // src/tool-execution-observation.ts
8902
- import { writeSync as writeSync3 } from "node:fs";
8903
- import { Type as Type17 } from "typebox";
8904
- import { Value as Value3 } from "typebox/value";
8905
- var TOOL_EXECUTION_UPDATE_THROTTLE_MS = 3e4;
8906
- var observationBase = {
8907
- role: Type17.String({ minLength: 1 }),
8908
- toolCallId: Type17.String({ minLength: 1 }),
8909
- toolName: Type17.String({ minLength: 1 }),
8910
- timestamp: Type17.String({ format: "date-time" })
8911
- };
8912
- var toolExecutionObservationRecordSchema = Type17.Union([
8913
- Type17.Object({
8914
- ...observationBase,
8915
- event: Type17.Literal("tool_execution_start")
8916
- }, { additionalProperties: true }),
8917
- Type17.Object({
8918
- ...observationBase,
8919
- event: Type17.Literal("tool_execution_update")
8920
- }, { additionalProperties: true }),
8921
- Type17.Object({
8922
- ...observationBase,
8923
- event: Type17.Literal("tool_execution_end"),
8924
- isError: Type17.Boolean()
8925
- }, { additionalProperties: true })
8926
- ]);
8927
- function validateToolExecutionObservationRecord(record4) {
8928
- if (!Value3.Check(toolExecutionObservationRecordSchema, record4)) {
8929
- throw new TypeError("Tool execution observation record does not match its contract");
8930
- }
8931
- return record4;
8932
- }
8933
- function writeToolExecutionObservationRecord(record4, write = writeSync3) {
8934
- writeStderrJsonlRecord(validateToolExecutionObservationRecord(record4), write);
8935
- }
8936
- function isProducingToolUpdate(partialResult) {
8937
- if (partialResult == null) return false;
8938
- if (typeof partialResult !== "object") return true;
8939
- const content = partialResult.content;
8940
- if (!Array.isArray(content)) return true;
8941
- if (content.length === 0) return false;
8942
- return content.some((part) => {
8943
- if (typeof part !== "object" || part === null) return true;
8944
- const text = part.text;
8945
- if (typeof text === "string") return text.length > 0;
8946
- return true;
8947
- });
8948
- }
8949
- function systemToolExecutionObservationMonoNow() {
8950
- return performance.now();
8951
- }
8952
- function createToolExecutionObservationFace(options) {
8953
- const states = /* @__PURE__ */ new Map();
8954
- async function emit(record4) {
8955
- await options.write(validateToolExecutionObservationRecord(record4));
8956
- }
8957
- function activeRole() {
8958
- if (!options.admitted()) return void 0;
8959
- const role = options.role();
8960
- return role === void 0 || role === "" ? void 0 : role;
8961
- }
8962
- return {
8963
- reset() {
8964
- states.clear();
8965
- },
8966
- async onStart(event) {
8967
- const role = activeRole();
8968
- if (role === void 0) return;
8969
- states.set(event.toolCallId, { lastUpdateEmitMonoMs: void 0 });
8970
- await emit({
8971
- event: "tool_execution_start",
8972
- role,
8973
- toolCallId: event.toolCallId,
8974
- toolName: event.toolName,
8975
- timestamp: options.clock()
8976
- });
8977
- },
8978
- async onUpdate(event) {
8979
- const role = activeRole();
8980
- if (role === void 0) return;
8981
- if (!isProducingToolUpdate(event.partialResult)) return;
8982
- const now = options.monoNow();
8983
- const state = states.get(event.toolCallId) ?? { lastUpdateEmitMonoMs: void 0 };
8984
- if (state.lastUpdateEmitMonoMs !== void 0 && now - state.lastUpdateEmitMonoMs < TOOL_EXECUTION_UPDATE_THROTTLE_MS) {
8985
- return;
8986
- }
8987
- state.lastUpdateEmitMonoMs = now;
8988
- states.set(event.toolCallId, state);
8989
- await emit({
8990
- event: "tool_execution_update",
8991
- role,
8992
- toolCallId: event.toolCallId,
8993
- toolName: event.toolName,
8994
- timestamp: options.clock()
8995
- });
8996
- },
8997
- async onEnd(event) {
8998
- const role = activeRole();
8999
- if (role === void 0) return;
9000
- states.delete(event.toolCallId);
9001
- await emit({
9002
- event: "tool_execution_end",
9003
- role,
9004
- toolCallId: event.toolCallId,
9005
- toolName: event.toolName,
9006
- timestamp: options.clock(),
9007
- isError: event.isError
9008
- });
9009
- }
9010
- };
9011
- }
9012
-
9013
- // src/collector-evidence.ts
9014
- import { createHash as createHash8 } from "node:crypto";
9015
- var COLLECTOR_ELIGIBILITY_MS = 15 * 60 * 1e3;
9016
- function createSystemCollectorClock() {
9017
- const start = process.hrtime.bigint();
9018
- return {
9019
- wallNow: () => /* @__PURE__ */ new Date(),
9020
- monoNow: () => Number(process.hrtime.bigint() - start) / 1e6,
9021
- sleep: (ms, signal) => new Promise((resolve17, reject) => {
9022
- if (signal?.aborted) {
9023
- reject(signal.reason ?? new Error("aborted"));
9024
- return;
9025
- }
9026
- const timer = setTimeout(resolve17, ms);
9027
- const onAbort = () => {
9028
- clearTimeout(timer);
9029
- reject(signal?.reason ?? new Error("aborted"));
9030
- };
9031
- signal?.addEventListener("abort", onAbort, { once: true });
9032
- })
9033
- };
9034
- }
9035
- function sha256Text(text) {
9036
- return createHash8("sha256").update(text, "utf8").digest("hex");
9037
- }
9038
- function computeWindowRelation(authoritativeTime, activationTime, deadlineTime) {
9039
- if (authoritativeTime === void 0 || authoritativeTime === null || authoritativeTime.length === 0) {
9040
- return "uncertain";
9041
- }
9042
- const ms = Date.parse(authoritativeTime);
9043
- if (!Number.isFinite(ms)) return "uncertain";
9044
- const activationMs = activationTime.getTime();
9045
- const deadlineMs = deadlineTime.getTime();
9046
- if (ms < activationMs) return "before";
9047
- if (ms <= deadlineMs) return "within";
9048
- return "after";
9049
- }
9050
- function stableId(kind, githubId) {
9051
- return `${kind}:${githubId}`;
9052
- }
9053
- function versionDigest(parts) {
9054
- return sha256Text(JSON.stringify(parts));
9055
- }
9056
- function evidenceIdFor(kind, versionId) {
9057
- return sha256Text(`${kind}:${versionId}`).slice(0, 16);
9058
- }
9059
- function normalizeAuthenticatedUserEvidence(user, observedAt) {
9060
- const login = user.login.toLowerCase();
9061
- const rawId = user.raw?.id;
9062
- const stableNumericOrStringId = typeof rawId === "number" || typeof rawId === "string" ? rawId : void 0;
9063
- const retainedRaw = { login };
9064
- if (stableNumericOrStringId !== void 0) {
9065
- retainedRaw.id = stableNumericOrStringId;
8915
+ function normalizeAuthenticatedUserEvidence(user, observedAt) {
8916
+ const login = user.login.toLowerCase();
8917
+ const rawId = user.raw?.id;
8918
+ const stableNumericOrStringId = typeof rawId === "number" || typeof rawId === "string" ? rawId : void 0;
8919
+ const retainedRaw = { login };
8920
+ if (stableNumericOrStringId !== void 0) {
8921
+ retainedRaw.id = stableNumericOrStringId;
9066
8922
  }
9067
8923
  const contentDigest = versionDigest({
9068
8924
  login,
@@ -9296,28 +9152,25 @@ function assignWindowRelations(records2, activationTime, deadlineTime) {
9296
9152
  }
9297
9153
  }
9298
9154
 
9299
- // src/collector-ledger.ts
9300
- import Value4 from "typebox/value";
9301
-
9302
9155
  // src/collector-tool-schemas.ts
9303
- import { Type as Type18 } from "typebox";
9304
- var collectorObserveArgsSchema = Type18.Object({}, { additionalProperties: false });
9305
- var collectorRequestArgsSchema = Type18.Object({
9306
- requestId: Type18.String({ minLength: 1, description: "\u914D\u7F6E\u8BF7\u6C42\u8EAB\u4EFD" }),
9307
- snapshotId: Type18.String({ minLength: 1, description: "\u6700\u65B0\u7559\u5B58\u89C2\u5BDF\u5FEB\u7167" })
9156
+ import { Type as Type17 } from "typebox";
9157
+ var collectorObserveArgsSchema = Type17.Object({}, { additionalProperties: false });
9158
+ var collectorRequestArgsSchema = Type17.Object({
9159
+ requestId: Type17.String({ minLength: 1, description: "\u914D\u7F6E\u8BF7\u6C42\u8EAB\u4EFD" }),
9160
+ snapshotId: Type17.String({ minLength: 1, description: "\u6700\u65B0\u7559\u5B58\u89C2\u5BDF\u5FEB\u7167" })
9308
9161
  }, { additionalProperties: false });
9309
- var collectorReadArgsSchema = Type18.Object({
9310
- evidenceId: Type18.String({ minLength: 1, description: "observe \u8FD4\u56DE\u7684\u6750\u6599\u8BC1\u636E id\uFF08evidenceId\uFF09" })
9162
+ var collectorReadArgsSchema = Type17.Object({
9163
+ evidenceId: Type17.String({ minLength: 1, description: "observe \u8FD4\u56DE\u7684\u6750\u6599\u8BC1\u636E id\uFF08evidenceId\uFF09" })
9311
9164
  }, { additionalProperties: false });
9312
- var collectorWaitArgsSchema = Type18.Object({
9313
- durationMs: Type18.Integer({ minimum: 1, maximum: COLLECTOR_ELIGIBILITY_MS, description: "\u7B49\u5F85\u6BEB\u79D2\uFF1B\u5355\u6B21\u4E0A\u9650\u4E94\u5206\u949F\u4E14\u4E0D\u8D85\u5269\u4F59\u8D44\u683C" })
9165
+ var collectorWaitArgsSchema = Type17.Object({
9166
+ durationMs: Type17.Integer({ minimum: 1, maximum: COLLECTOR_ELIGIBILITY_MS, description: "\u7B49\u5F85\u6BEB\u79D2\uFF1B\u5355\u6B21\u4E0A\u9650\u4E94\u5206\u949F\u4E14\u4E0D\u8D85\u5269\u4F59\u8D44\u683C" })
9314
9167
  }, { additionalProperties: false });
9315
- var collectorFindingArgsSchema = Type18.Object({
9316
- evidenceId: Type18.String({ minLength: 1, description: "observe \u8FD4\u56DE\u7684\u6750\u6599\u8BC1\u636E id\uFF08evidenceId\uFF09" }),
9317
- category: Type18.Optional(Type18.String({ minLength: 1, maxLength: 200, description: "\u8BE5 finding \u7684\u7B80\u77ED\u5F52\u7C7B\u6807\u7B7E\uFF1B\u9700\u8981\u5934\u90E8\u4E4B\u5916\u7684\u6B63\u6587\u65F6\u5148\u7528 ak_collector_read \u5F00\u5377\u518D\u5224\u8BFB\uFF0C\u4E0D\u5F97\u8A8A\u5199\u8BC4\u8BBA\u6B63\u6587" }))
9168
+ var collectorFindingArgsSchema = Type17.Object({
9169
+ evidenceId: Type17.String({ minLength: 1, description: "observe \u8FD4\u56DE\u7684\u6750\u6599\u8BC1\u636E id\uFF08evidenceId\uFF09" }),
9170
+ category: Type17.Optional(Type17.String({ minLength: 1, maxLength: 200, description: "\u8BE5 finding \u7684\u7B80\u77ED\u5F52\u7C7B\u6807\u7B7E\uFF1B\u9700\u8981\u5934\u90E8\u4E4B\u5916\u7684\u6B63\u6587\u65F6\u5148\u7528 ak_collector_read \u5F00\u5377\u518D\u5224\u8BFB\uFF0C\u4E0D\u5F97\u8A8A\u5199\u8BC4\u8BBA\u6B63\u6587" }))
9318
9171
  }, { additionalProperties: false });
9319
- var collectorOutputBaseSchema = Type18.Object({
9320
- findings: Type18.Optional(Type18.Array(collectorFindingArgsSchema, {
9172
+ var collectorOutputBaseSchema = Type17.Object({
9173
+ findings: Type17.Optional(Type17.Array(collectorFindingArgsSchema, {
9321
9174
  description: "\u672C\u6B21\u6536\u96C6\u5230\u7684\u9010\u6761 findings\uFF1B\u96F6 finding \u7684\u6A21\u677F\u901A\u77E5\u4E0D\u5F97\u8FDB\u5165\u3002\u6B63\u5E38\u5B8C\u5DE5\u65E0 finding \u65F6\u7701\u7565\u3002"
9322
9175
  }))
9323
9176
  }, { additionalProperties: true, description: "\u6B63\u5E38\u5B8C\u5DE5\u63D0\u4EA4\u7A7A\u5BF9\u8C61 {}\uFF1B\u4EC5\u5728\u57FA\u7840\u8BBE\u65BD\u771F\u5B9E\u5931\u8D25\u65F6\u624D\u586B\u5199 infrastructureFailure\uFF0C\u65E0\u5931\u8D25\u65F6\u5FC5\u987B\u7701\u7565\u8BE5\u5B57\u6BB5\u3002" });
@@ -9351,13 +9204,20 @@ function projectObserveContextView(modelView) {
9351
9204
  evidence: modelView.evidence.map((entry) => entry.body === void 0 ? entry : { ...entry, body: utf8SafePrefix(entry.body, COLLECTOR_OBSERVE_BODY_HEAD_BYTES) })
9352
9205
  };
9353
9206
  }
9207
+ var COLLECTOR_ACTIVATION_ENTRY_TYPE = "ak-collector-activation";
9208
+ var COLLECTOR_SNAPSHOT_ENTRY_TYPE = "ak-collector-snapshot";
9209
+ var COLLECTOR_REQUEST_ENTRY_TYPE = "ak-collector-request";
9210
+ var COLLECTOR_WAIT_ENTRY_TYPE = "ak-collector-wait";
9354
9211
  function isOperationalTool(name) {
9355
9212
  return COLLECTOR_OPERATIONAL_TOOLS.includes(name);
9356
9213
  }
9357
- function createCollectorLedger(config) {
9214
+ function createCollectorLedger(config, options) {
9215
+ const clock = options?.clock;
9216
+ const journal = options?.journal;
9358
9217
  let fatal2 = false;
9359
9218
  let fatalReason;
9360
- let outputAccepted = false;
9219
+ let outputCandidate = false;
9220
+ let pendingOutputCallId;
9361
9221
  let activationTime;
9362
9222
  let deadlineTime;
9363
9223
  let activationMono;
@@ -9395,14 +9255,14 @@ function createCollectorLedger(config) {
9395
9255
  evidenceById.set(record4.evidenceId, record4);
9396
9256
  return record4;
9397
9257
  };
9398
- const monoNowOrThrow = (clock) => clock.monoNow();
9399
- const pastCutoff = (clock) => {
9258
+ const monoNowOrThrow = (clock2) => clock2.monoNow();
9259
+ const pastCutoff = (clock2) => {
9400
9260
  if (deadlineMono === void 0) return false;
9401
- return monoNowOrThrow(clock) >= deadlineMono;
9261
+ return monoNowOrThrow(clock2) >= deadlineMono;
9402
9262
  };
9403
- const remainingMs = (clock) => {
9263
+ const remainingMs = (clock2) => {
9404
9264
  if (deadlineMono === void 0) return COLLECTOR_ELIGIBILITY_MS;
9405
- return Math.max(0, deadlineMono - monoNowOrThrow(clock));
9265
+ return Math.max(0, deadlineMono - monoNowOrThrow(clock2));
9406
9266
  };
9407
9267
  const prIdentity = (pr) => `${pr.state}|${pr.headOid}|${pr.updatedAt ?? ""}`;
9408
9268
  const fetchObserveSurfaces = async (transport, observedAt, signal) => {
@@ -9444,6 +9304,172 @@ function createCollectorLedger(config) {
9444
9304
  });
9445
9305
  return { user, prInitial, reviews, reactions, issueComments, reviewComments, prTerminal };
9446
9306
  };
9307
+ const appendJournal = (customType, data) => {
9308
+ journal?.append(customType, data);
9309
+ };
9310
+ const bindDeadlineMonoFromWall = () => {
9311
+ if (clock === void 0 || activationTime === void 0 || deadlineTime === void 0) return;
9312
+ const wallNow = clock.wallNow().getTime();
9313
+ const monoNow = clock.monoNow();
9314
+ activationMono = monoNow - (wallNow - activationTime.getTime());
9315
+ deadlineMono = monoNow + (deadlineTime.getTime() - wallNow);
9316
+ };
9317
+ const rebindSnapshotCompletedMono = (snapshot) => {
9318
+ const copy = { ...snapshot, evidenceIds: [...snapshot.evidenceIds] };
9319
+ if (deadlineTime !== void 0 && deadlineMono !== void 0 && copy.completedAt !== void 0) {
9320
+ const completedWall = new Date(copy.completedAt).getTime();
9321
+ copy.completedMono = deadlineMono + (completedWall - deadlineTime.getTime());
9322
+ }
9323
+ return copy;
9324
+ };
9325
+ const commitActivationWindow = (nextActivation, nextDeadline) => {
9326
+ if (activationTime !== void 0) return;
9327
+ activationTime = nextActivation;
9328
+ deadlineTime = nextDeadline;
9329
+ bindDeadlineMonoFromWall();
9330
+ };
9331
+ const recoverAmbiguousRequestLosses = (snapshotId, observedRecords) => {
9332
+ for (const failure2 of transportFailures) {
9333
+ if (failure2.recovered || failure2.kind !== "ambiguous_request_loss") continue;
9334
+ if (failure2.marker === void 0 || failure2.requestId === void 0) continue;
9335
+ const found = observedRecords.find(
9336
+ (record4) => record4.kind === "issue_comment" && record4.authorLogin === requesterLogin && typeof record4.body === "string" && record4.body.includes(failure2.marker)
9337
+ );
9338
+ if (found === void 0) continue;
9339
+ failure2.recovered = true;
9340
+ const attempt = attempts.find(
9341
+ (item) => item.status === "ambiguous_loss" && item.requestId === failure2.requestId && item.marker === failure2.marker
9342
+ );
9343
+ if (attempt !== void 0) {
9344
+ attempt.status = "recovered";
9345
+ attempt.commentEvidenceId = found.evidenceId;
9346
+ attempt.recoverySnapshotId = snapshotId;
9347
+ }
9348
+ }
9349
+ };
9350
+ const finalizeObservedSnapshot = (snapshot) => {
9351
+ if (requesterLogin === void 0) {
9352
+ for (const id of snapshot.evidenceIds) {
9353
+ const record4 = evidenceById.get(id);
9354
+ if (record4?.kind === "authenticated_user" && record4.authorLogin !== void 0) {
9355
+ requesterLogin = record4.authorLogin.toLowerCase();
9356
+ break;
9357
+ }
9358
+ }
9359
+ }
9360
+ const stored = rebindSnapshotCompletedMono(snapshot);
9361
+ snapshots.push(stored);
9362
+ latestCompleteSnapshotId = stored.snapshotId;
9363
+ const observedRecords = stored.evidenceIds.flatMap((id) => {
9364
+ const record4 = evidenceById.get(id);
9365
+ return record4 === void 0 ? [] : [record4];
9366
+ });
9367
+ recoverAmbiguousRequestLosses(stored.snapshotId, observedRecords);
9368
+ observedGeneration = mutationGeneration;
9369
+ if (finalObservationRequired && stored.completedMono !== void 0 && deadlineMono !== void 0 && stored.completedMono >= deadlineMono) {
9370
+ finalObservationCompleted = true;
9371
+ } else if (clock !== void 0 && deadlineMono !== void 0 && clock.monoNow() >= deadlineMono && stored.completedMono !== void 0 && stored.completedMono >= deadlineMono) {
9372
+ finalObservationRequired = true;
9373
+ finalObservationCompleted = true;
9374
+ }
9375
+ return stored;
9376
+ };
9377
+ const commitObservedSnapshot = (snapshot, evidenceRecords) => {
9378
+ for (const record4 of evidenceRecords) {
9379
+ storeEvidence(record4);
9380
+ }
9381
+ return finalizeObservedSnapshot(snapshot);
9382
+ };
9383
+ const commitRequestAttempt = (attempt, attemptKey, commentEvidence) => {
9384
+ if (commentEvidence !== void 0) {
9385
+ storeEvidence(commentEvidence);
9386
+ }
9387
+ const existing = attempts.find((item) => item.attemptId === attempt.attemptId);
9388
+ if (existing === void 0) {
9389
+ attempts.push({ ...attempt });
9390
+ attemptKeys.add(attemptKey);
9391
+ } else {
9392
+ Object.assign(existing, attempt);
9393
+ }
9394
+ if (attempt.status === "ambiguous_loss" && !transportFailures.some((failure2) => failure2.requestId === attempt.requestId && failure2.observedHead === attempt.observedHead)) {
9395
+ transportFailures.push({
9396
+ failureId: sha256Text(`loss:${attempt.attemptId}`).slice(0, 16),
9397
+ kind: "ambiguous_request_loss",
9398
+ message: attempt.responseDiagnostics ?? "ambiguous request loss",
9399
+ requestId: attempt.requestId,
9400
+ observedHead: attempt.observedHead,
9401
+ marker: attempt.marker,
9402
+ recovered: false
9403
+ });
9404
+ }
9405
+ if (attempt.status === "succeeded" || attempt.status === "ambiguous_loss") {
9406
+ mutationGeneration += 1;
9407
+ finalObservationCompleted = false;
9408
+ }
9409
+ };
9410
+ const commitWaitRecord = (wait) => {
9411
+ waits.push({ ...wait });
9412
+ if (wait.cutoffReached) finalObservationRequired = true;
9413
+ mutationGeneration += 1;
9414
+ finalObservationCompleted = false;
9415
+ };
9416
+ const replayDossierEntries = (entries) => {
9417
+ const orderedEntries = Array.from(entries);
9418
+ const finalRequestStatus = /* @__PURE__ */ new Map();
9419
+ for (const raw of orderedEntries) {
9420
+ if (typeof raw !== "object" || raw === null) continue;
9421
+ const entry = raw;
9422
+ if (entry.type !== "custom" || entry.customType !== COLLECTOR_REQUEST_ENTRY_TYPE || typeof entry.data !== "object" || entry.data === null) continue;
9423
+ const attempt = entry.data.attempt;
9424
+ if (attempt?.attemptId !== void 0) finalRequestStatus.set(attempt.attemptId, attempt.status);
9425
+ }
9426
+ for (const raw of orderedEntries) {
9427
+ if (typeof raw !== "object" || raw === null) continue;
9428
+ const entry = raw;
9429
+ if (entry.type !== "custom" || typeof entry.data !== "object" || entry.data === null) continue;
9430
+ const data = entry.data;
9431
+ if (entry.customType === COLLECTOR_ACTIVATION_ENTRY_TYPE) {
9432
+ if (typeof data.activationTime === "string" && typeof data.deadlineTime === "string") {
9433
+ commitActivationWindow(new Date(data.activationTime), new Date(data.deadlineTime));
9434
+ }
9435
+ continue;
9436
+ }
9437
+ if (entry.customType === COLLECTOR_SNAPSHOT_ENTRY_TYPE) {
9438
+ const snapshot = data.snapshot;
9439
+ if (snapshot?.snapshotId === void 0 || !Array.isArray(data.evidence)) continue;
9440
+ commitObservedSnapshot(snapshot, data.evidence);
9441
+ continue;
9442
+ }
9443
+ if (entry.customType === COLLECTOR_REQUEST_ENTRY_TYPE) {
9444
+ const attempt = data.attempt;
9445
+ if (attempt?.attemptId === void 0) continue;
9446
+ const attemptKey = typeof data.attemptKey === "string" ? data.attemptKey : [config.repository.canonical, String(config.prNumber), attempt.observedHead, attempt.requestId].join("|");
9447
+ const commentEvidence = data.commentEvidence;
9448
+ const replayAttempt = attempt.status === "started" && finalRequestStatus.get(attempt.attemptId) === "started" ? {
9449
+ ...attempt,
9450
+ status: "ambiguous_loss",
9451
+ responseDiagnostics: "request interrupted after dispatch before completion was recorded"
9452
+ } : attempt;
9453
+ commitRequestAttempt(replayAttempt, attemptKey, commentEvidence);
9454
+ continue;
9455
+ }
9456
+ if (entry.customType === COLLECTOR_WAIT_ENTRY_TYPE) {
9457
+ const wait = data.waitRecord;
9458
+ if (wait?.waitId === void 0) continue;
9459
+ commitWaitRecord(wait);
9460
+ }
9461
+ }
9462
+ };
9463
+ if (options?.dossierEntries !== void 0) {
9464
+ replayDossierEntries(options.dossierEntries);
9465
+ }
9466
+ if (clock !== void 0 && deadlineMono !== void 0 && clock.monoNow() >= deadlineMono) {
9467
+ finalObservationRequired = true;
9468
+ const lastSnap = snapshots.find((item) => item.snapshotId === latestCompleteSnapshotId);
9469
+ if (lastSnap?.completedMono !== void 0 && lastSnap.completedMono >= deadlineMono) {
9470
+ finalObservationCompleted = true;
9471
+ }
9472
+ }
9447
9473
  const ledger = {
9448
9474
  get config() {
9449
9475
  return config;
@@ -9454,8 +9480,8 @@ function createCollectorLedger(config) {
9454
9480
  get fatalReason() {
9455
9481
  return fatalReason;
9456
9482
  },
9457
- get outputAccepted() {
9458
- return outputAccepted;
9483
+ get outputCandidate() {
9484
+ return outputCandidate || pendingOutputCallId !== void 0;
9459
9485
  },
9460
9486
  get activationRecorded() {
9461
9487
  return activationTime !== void 0;
@@ -9495,18 +9521,30 @@ function createCollectorLedger(config) {
9495
9521
  },
9496
9522
  latchFatal,
9497
9523
  assertNotFatal,
9498
- recordActivation(clock) {
9524
+ recordActivation(clock2) {
9499
9525
  assertNotFatal();
9500
9526
  if (activationTime !== void 0) return;
9501
- activationTime = clock.wallNow();
9502
- activationMono = clock.monoNow();
9527
+ activationTime = clock2.wallNow();
9528
+ activationMono = clock2.monoNow();
9503
9529
  deadlineTime = new Date(activationTime.getTime() + COLLECTOR_ELIGIBILITY_MS);
9504
9530
  deadlineMono = activationMono + COLLECTOR_ELIGIBILITY_MS;
9531
+ appendJournal(COLLECTOR_ACTIVATION_ENTRY_TYPE, {
9532
+ activationTime: activationTime.toISOString(),
9533
+ deadlineTime: deadlineTime.toISOString()
9534
+ });
9535
+ },
9536
+ recordOutputCandidate() {
9537
+ assertNotFatal();
9538
+ outputCandidate = true;
9505
9539
  },
9506
9540
  beginOperational(toolName, toolCallId) {
9507
9541
  assertNotFatal();
9508
- if (outputAccepted && toolName !== COLLECTOR_OUTPUT_TOOL) {
9509
- throw latchFatal("\u56DE\u6267\u5DF2\u53D7\u7406\uFF0C\u672C\u5C40\u4E0D\u518D\u53D7\u7406\u64CD\u4F5C");
9542
+ if (toolName !== COLLECTOR_OUTPUT_TOOL && (outputCandidate || pendingOutputCallId !== void 0)) {
9543
+ throw new Error("\u901A\u8FDB\u53F8\u5DF2\u4EA7\u51FA\u8F93\u51FA\u5019\u9009\uFF0C\u672C\u5C40\u4E0D\u518D\u53D7\u7406\u64CD\u4F5C");
9544
+ }
9545
+ if (toolName === COLLECTOR_OUTPUT_TOOL) {
9546
+ pendingOutputCallId = toolCallId;
9547
+ return;
9510
9548
  }
9511
9549
  if (activeOperationalCallId === toolCallId) {
9512
9550
  return;
@@ -9514,28 +9552,23 @@ function createCollectorLedger(config) {
9514
9552
  if (activeOperationalCallId !== void 0) {
9515
9553
  throw latchFatal("\u901A\u8FDB\u53F8\u64CD\u4F5C\u8C03\u7528\u5DF2\u5728\u8FDB\u884C");
9516
9554
  }
9517
- if (toolName === COLLECTOR_OUTPUT_TOOL) {
9518
- return;
9519
- }
9520
9555
  if (!isOperationalTool(toolName)) {
9521
9556
  throw latchFatal(`\u672A\u77E5\u901A\u8FDB\u53F8\u5DE5\u5177 ${toolName}`);
9522
9557
  }
9523
9558
  activeOperationalCallId = toolCallId;
9524
9559
  },
9525
9560
  completeOperational(toolCallId) {
9561
+ if (pendingOutputCallId === toolCallId) {
9562
+ pendingOutputCallId = void 0;
9563
+ }
9526
9564
  if (activeOperationalCallId === toolCallId) {
9527
9565
  activeOperationalCallId = void 0;
9528
9566
  }
9529
9567
  },
9530
- markOutputAccepted() {
9531
- assertNotFatal();
9532
- if (outputAccepted) throw latchFatal("\u901A\u8FDB\u53F8\u56DE\u6267\u4E3A\u552F\u4E00\u7EC8\u5C40");
9533
- outputAccepted = true;
9534
- },
9535
9568
  noteCutoffObserved() {
9536
9569
  finalObservationRequired = true;
9537
9570
  },
9538
- assertOutputObservationLaw(clock) {
9571
+ assertOutputObservationLaw(clock2) {
9539
9572
  assertNotFatal();
9540
9573
  if (activationTime === void 0 || deadlineTime === void 0 || deadlineMono === void 0) {
9541
9574
  throw new Error("\u901A\u8FDB\u53F8\u56DE\u6267\u9700\u8981\u6FC0\u6D3B\u65F6\u95F4\u7EBF");
@@ -9552,7 +9585,7 @@ function createCollectorLedger(config) {
9552
9585
  if (snapshot === void 0 || !snapshot.complete) {
9553
9586
  throw new Error("\u901A\u8FDB\u53F8\u7EC8\u5C40\u5FEB\u7167\u7F3A\u5931\u6216\u4E0D\u5B8C\u6574");
9554
9587
  }
9555
- const mono = monoNowOrThrow(clock);
9588
+ const mono = monoNowOrThrow(clock2);
9556
9589
  const atOrAfterCutoff = mono >= deadlineMono;
9557
9590
  if (atOrAfterCutoff) {
9558
9591
  finalObservationRequired = true;
@@ -9564,7 +9597,7 @@ function createCollectorLedger(config) {
9564
9597
  finalObservationCompleted = true;
9565
9598
  }
9566
9599
  },
9567
- async observe(transport, clock, signal) {
9600
+ async observe(transport, clock2, signal) {
9568
9601
  assertNotFatal();
9569
9602
  if (activationTime === void 0) {
9570
9603
  throw latchFatal("\u901A\u8FDB\u53F8\u89C2\u5BDF\u9700\u8981\u6FC0\u6D3B");
@@ -9573,8 +9606,8 @@ function createCollectorLedger(config) {
9573
9606
  const abortMessage = signal.reason instanceof Error ? signal.reason.message : String(signal.reason ?? "\u5DF2\u4E2D\u6B62");
9574
9607
  throw latchFatal(`\u901A\u8FDB\u53F8\u89C2\u5BDF\u5931\u8D25\uFF1A${abortMessage}`, signal.reason);
9575
9608
  }
9576
- const observedAt = clock.wallNow().toISOString();
9577
- const cutoff = pastCutoff(clock);
9609
+ const observedAt = clock2.wallNow().toISOString();
9610
+ const cutoff = pastCutoff(clock2);
9578
9611
  if (cutoff) {
9579
9612
  finalObservationRequired = true;
9580
9613
  }
@@ -9593,8 +9626,8 @@ function createCollectorLedger(config) {
9593
9626
  const message = error instanceof Error ? error.message : "\u672A\u77E5\u5931\u8D25";
9594
9627
  throw latchFatal(`\u901A\u8FDB\u53F8\u89C2\u5BDF\u5931\u8D25\uFF1A${message}`, error);
9595
9628
  }
9596
- const firstObservedAt = clock.wallNow().toISOString();
9597
- const firstObservedMono = monoNowOrThrow(clock);
9629
+ const firstObservedAt = clock2.wallNow().toISOString();
9630
+ const firstObservedMono = monoNowOrThrow(clock2);
9598
9631
  const pr = surfaces.prTerminal;
9599
9632
  const { user, reviews, reactions, issueComments, reviewComments } = surfaces;
9600
9633
  requesterLogin = user.login.toLowerCase();
@@ -9638,29 +9671,11 @@ function createCollectorLedger(config) {
9638
9671
  }
9639
9672
  return stored;
9640
9673
  });
9641
- const completedAt = clock.wallNow().toISOString();
9642
- const completedMono = clock.monoNow();
9674
+ const completedAt = clock2.wallNow().toISOString();
9675
+ const completedMono = clock2.monoNow();
9643
9676
  const snapshotId = sha256Text(
9644
9677
  `${completedAt}:${pr.headOid}:${storedIds.join(",")}`
9645
9678
  ).slice(0, 16);
9646
- for (const failure2 of transportFailures) {
9647
- if (failure2.recovered || failure2.kind !== "ambiguous_request_loss") continue;
9648
- if (failure2.marker === void 0 || failure2.requestId === void 0) continue;
9649
- const found = storedRecords.find(
9650
- (record4) => record4.kind === "issue_comment" && record4.authorLogin === requesterLogin && typeof record4.body === "string" && record4.body.includes(failure2.marker)
9651
- );
9652
- if (found) {
9653
- failure2.recovered = true;
9654
- const attempt = attempts.find(
9655
- (item) => item.status === "ambiguous_loss" && item.requestId === failure2.requestId && item.marker === failure2.marker
9656
- );
9657
- if (attempt) {
9658
- attempt.status = "recovered";
9659
- attempt.commentEvidenceId = found.evidenceId;
9660
- attempt.recoverySnapshotId = snapshotId;
9661
- }
9662
- }
9663
- }
9664
9679
  const snapshot = {
9665
9680
  snapshotId,
9666
9681
  observedAt,
@@ -9676,28 +9691,38 @@ function createCollectorLedger(config) {
9676
9691
  pageDiagnostics,
9677
9692
  normalizedByteLength
9678
9693
  };
9679
- snapshots.push(snapshot);
9680
- latestCompleteSnapshotId = snapshotId;
9681
- observedGeneration = mutationGeneration;
9682
- if (finalObservationRequired && completedMono >= (deadlineMono ?? 0)) {
9683
- finalObservationCompleted = true;
9684
- } else if (cutoff) {
9685
- finalObservationCompleted = true;
9694
+ if (cutoff) {
9695
+ finalObservationRequired = true;
9686
9696
  }
9697
+ const committed = finalizeObservedSnapshot(snapshot);
9698
+ appendJournal(COLLECTOR_SNAPSHOT_ENTRY_TYPE, {
9699
+ snapshot: committed,
9700
+ evidence: committed.evidenceIds.flatMap((id) => {
9701
+ const record4 = evidenceById.get(id);
9702
+ return record4 === void 0 ? [] : [record4];
9703
+ })
9704
+ });
9687
9705
  const modelView = buildObserveModelView({
9688
- snapshot,
9689
- records: storedRecords,
9706
+ snapshot: committed,
9707
+ records: committed.evidenceIds.flatMap((id) => {
9708
+ const record4 = evidenceById.get(id);
9709
+ return record4 === void 0 ? [] : [record4];
9710
+ }),
9690
9711
  requesterLogin,
9691
9712
  attempts
9692
9713
  });
9693
- return { snapshot, contextView: projectObserveContextView(modelView) };
9714
+ return {
9715
+ snapshot: committed,
9716
+ modelView,
9717
+ contextView: projectObserveContextView(modelView)
9718
+ };
9694
9719
  },
9695
- async request(input, transport, clock, signal) {
9720
+ async request(input, transport, clock2, signal) {
9696
9721
  assertNotFatal();
9697
9722
  if (activationTime === void 0 || deadlineTime === void 0) {
9698
9723
  throw latchFatal("\u901A\u8FDB\u53F8\u8BF7\u6C42\u9700\u8981\u6FC0\u6D3B");
9699
9724
  }
9700
- if (pastCutoff(clock)) {
9725
+ if (pastCutoff(clock2)) {
9701
9726
  finalObservationRequired = true;
9702
9727
  throw latchFatal("\u901A\u8FDB\u53F8\u8BF7\u6C42\u4E0D\u5728\u8D44\u683C\u622A\u6B62\u524D");
9703
9728
  }
@@ -9744,7 +9769,7 @@ function createCollectorLedger(config) {
9744
9769
  `\u901A\u8FDB\u53F8\u8FDB\u7A0B\u5185\u8BF7\u6C42 "${request.id}" \u5728 HEAD ${snapshot.headOid} \u7684 attempt \u5DF2\u7528`
9745
9770
  );
9746
9771
  }
9747
- const startedAt = clock.wallNow().toISOString();
9772
+ const startedAt = clock2.wallNow().toISOString();
9748
9773
  const attemptId = sha256Text(`${attemptKey}:${startedAt}`).slice(0, 16);
9749
9774
  const attempt = {
9750
9775
  attemptId,
@@ -9756,8 +9781,11 @@ function createCollectorLedger(config) {
9756
9781
  startedAt,
9757
9782
  status: "started"
9758
9783
  };
9759
- attempts.push(attempt);
9760
- attemptKeys.add(attemptKey);
9784
+ commitRequestAttempt(attempt, attemptKey, void 0);
9785
+ appendJournal(COLLECTOR_REQUEST_ENTRY_TYPE, {
9786
+ attempt: { ...attempt },
9787
+ attemptKey
9788
+ });
9761
9789
  const result2 = await transport.createIssueComment({
9762
9790
  owner: config.repository.owner,
9763
9791
  repo: config.repository.repo,
@@ -9765,14 +9793,25 @@ function createCollectorLedger(config) {
9765
9793
  body,
9766
9794
  ...signal === void 0 ? {} : { signal }
9767
9795
  });
9768
- mutationGeneration += 1;
9769
- finalObservationCompleted = false;
9796
+ const journalRequest = (commentEvidence) => {
9797
+ const attemptKey2 = [
9798
+ config.repository.canonical,
9799
+ String(config.prNumber),
9800
+ attempt.observedHead,
9801
+ attempt.requestId
9802
+ ].join("|");
9803
+ appendJournal(COLLECTOR_REQUEST_ENTRY_TYPE, {
9804
+ attempt: { ...attempt },
9805
+ attemptKey: attemptKey2,
9806
+ commentEvidence
9807
+ });
9808
+ };
9770
9809
  if (result2.kind === "success") {
9771
- const record4 = storeEvidence(
9772
- normalizeIssueCommentEvidence(result2.comment, startedAt)
9773
- );
9810
+ const record4 = normalizeIssueCommentEvidence(result2.comment, startedAt);
9774
9811
  attempt.status = "succeeded";
9775
9812
  attempt.commentEvidenceId = record4.evidenceId;
9813
+ commitRequestAttempt(attempt, attemptKey, record4);
9814
+ journalRequest(record4);
9776
9815
  return {
9777
9816
  status: "succeeded",
9778
9817
  attemptId,
@@ -9785,15 +9824,8 @@ function createCollectorLedger(config) {
9785
9824
  if (result2.kind === "ambiguous_loss") {
9786
9825
  attempt.status = "ambiguous_loss";
9787
9826
  attempt.responseDiagnostics = result2.diagnostics;
9788
- transportFailures.push({
9789
- failureId: sha256Text(`loss:${attemptId}`).slice(0, 16),
9790
- kind: "ambiguous_request_loss",
9791
- message: result2.diagnostics,
9792
- requestId: request.id,
9793
- observedHead: snapshot.headOid,
9794
- marker,
9795
- recovered: false
9796
- });
9827
+ commitRequestAttempt(attempt, attemptKey, void 0);
9828
+ journalRequest(void 0);
9797
9829
  return {
9798
9830
  status: "ambiguous_loss",
9799
9831
  attemptId,
@@ -9805,9 +9837,11 @@ function createCollectorLedger(config) {
9805
9837
  }
9806
9838
  attempt.status = "rejected";
9807
9839
  attempt.responseDiagnostics = result2.diagnostics;
9840
+ commitRequestAttempt(attempt, attemptKey, void 0);
9841
+ journalRequest(void 0);
9808
9842
  throw latchFatal(`\u901A\u8FDB\u53F8\u8BF7\u6C42\u88AB\u62D2\uFF1A${result2.diagnostics}`);
9809
9843
  },
9810
- async wait(input, clock, signal) {
9844
+ async wait(input, clock2, signal) {
9811
9845
  assertNotFatal();
9812
9846
  if (activationTime === void 0) {
9813
9847
  throw latchFatal("\u901A\u8FDB\u53F8\u7B49\u5F85\u9700\u8981\u6FC0\u6D3B");
@@ -9820,25 +9854,22 @@ function createCollectorLedger(config) {
9820
9854
  `\u901A\u8FDB\u53F8\u7B49\u5F85 durationMs \u81F3\u591A\u4E3A ${COLLECTOR_ELIGIBILITY_MS}`
9821
9855
  );
9822
9856
  }
9823
- if (pastCutoff(clock)) {
9857
+ if (pastCutoff(clock2)) {
9824
9858
  finalObservationRequired = true;
9825
9859
  throw latchFatal("\u901A\u8FDB\u53F8\u7B49\u5F85\u4E0D\u5728\u8D44\u683C\u622A\u6B62\u524D");
9826
9860
  }
9827
- const remaining = remainingMs(clock);
9861
+ const remaining = remainingMs(clock2);
9828
9862
  const COLLECTOR_SINGLE_WAIT_MAX_MS = 3e5;
9829
9863
  const effectiveMs = Math.min(
9830
9864
  input.durationMs,
9831
9865
  remaining,
9832
9866
  COLLECTOR_SINGLE_WAIT_MAX_MS
9833
9867
  );
9834
- const startedAt = clock.wallNow().toISOString();
9868
+ const startedAt = clock2.wallNow().toISOString();
9835
9869
  const waitId = sha256Text(`wait:${startedAt}:${effectiveMs}`).slice(0, 16);
9836
- await clock.sleep(effectiveMs, signal);
9837
- const endedAt = clock.wallNow().toISOString();
9838
- const cutoffReached = pastCutoff(clock);
9839
- if (cutoffReached) finalObservationRequired = true;
9840
- mutationGeneration += 1;
9841
- finalObservationCompleted = false;
9870
+ await clock2.sleep(effectiveMs, signal);
9871
+ const endedAt = clock2.wallNow().toISOString();
9872
+ const cutoffReached = pastCutoff(clock2);
9842
9873
  const record4 = {
9843
9874
  waitId,
9844
9875
  requestedMs: input.durationMs,
@@ -9847,13 +9878,16 @@ function createCollectorLedger(config) {
9847
9878
  endedAt,
9848
9879
  cutoffReached
9849
9880
  };
9850
- waits.push(record4);
9881
+ commitWaitRecord(record4);
9882
+ appendJournal(COLLECTOR_WAIT_ENTRY_TYPE, {
9883
+ waitRecord: record4
9884
+ });
9851
9885
  return {
9852
9886
  waitId,
9853
9887
  requestedMs: input.durationMs,
9854
9888
  effectiveMs,
9855
9889
  cutoffReached,
9856
- remainingMsAfter: remainingMs(clock)
9890
+ remainingMsAfter: remainingMs(clock2)
9857
9891
  };
9858
9892
  },
9859
9893
  getSnapshot(snapshotId) {
@@ -9922,6 +9956,410 @@ function buildObserveModelView(input) {
9922
9956
  };
9923
9957
  }
9924
9958
 
9959
+ // src/activation-trace.ts
9960
+ import { Type as Type18 } from "typebox";
9961
+ var causeSchema = Type18.Object({
9962
+ identity: Type18.String({ minLength: 1 }),
9963
+ name: Type18.String({ minLength: 1 }),
9964
+ message: Type18.String(),
9965
+ evidenceId: Type18.Optional(Type18.String({ minLength: 1 }))
9966
+ }, { additionalProperties: false });
9967
+ var activationTraceRecordSchema = Type18.Object({
9968
+ role: Type18.String({ minLength: 1 }),
9969
+ stageId: Type18.String({ pattern: "^[a-z][a-z0-9-]*$" }),
9970
+ status: Type18.Literal("failed"),
9971
+ timestamp: Type18.String({ format: "date-time" }),
9972
+ cause: causeSchema
9973
+ }, { additionalProperties: false });
9974
+ var activationCauseEvidence = 0;
9975
+ var retainedActivationCauses = /* @__PURE__ */ new Map();
9976
+ function namedActivationCause(error) {
9977
+ const evidenceId = `activation-cause-${++activationCauseEvidence}`;
9978
+ retainedActivationCauses.set(evidenceId, error);
9979
+ if (error instanceof Error) {
9980
+ const code = error.code;
9981
+ const name = error.name || "Error";
9982
+ return { identity: typeof code === "string" && code.length > 0 ? code : name, name, message: error.message, evidenceId };
9983
+ }
9984
+ let message;
9985
+ try {
9986
+ message = typeof error === "string" ? error : JSON.stringify(error) ?? String(error);
9987
+ return { identity: "UnknownThrownCause", name: "UnknownThrownCause", message, evidenceId };
9988
+ } catch {
9989
+ return { identity: "UnknownThrownCause", name: "UnknownThrownCause", message: String(error), evidenceId };
9990
+ }
9991
+ }
9992
+
9993
+ // src/role-runtime.ts
9994
+ init_activation_ledger_topology();
9995
+
9996
+ // src/activation-ledger.ts
9997
+ init_activation_ledger_topology();
9998
+ init_activation_ledger_git();
9999
+ import {
10000
+ constants,
10001
+ closeSync,
10002
+ fstatSync,
10003
+ openSync,
10004
+ writeSync
10005
+ } from "node:fs";
10006
+ import { dirname as dirname14, isAbsolute as isAbsolute6, resolve as resolve15 } from "node:path";
10007
+
10008
+ // src/activation-ledger-session.ts
10009
+ init_activation_ledger_topology();
10010
+ import {
10011
+ lstatSync as lstatSync2,
10012
+ realpathSync as realpathSync3,
10013
+ statSync as statSync3,
10014
+ writeFileSync as writeFileSync4
10015
+ } from "node:fs";
10016
+ import { isAbsolute as isAbsolute5, resolve as resolve14 } from "node:path";
10017
+ var ActivationSessionFileMissingError = class extends Error {
10018
+ code = "AK_ACTIVATION_SESSION_FILE_MISSING";
10019
+ path;
10020
+ constructor(path, options) {
10021
+ super(
10022
+ `Workflow role activation durable session file does not exist: ${path}`,
10023
+ options?.cause === void 0 ? void 0 : { cause: options.cause }
10024
+ );
10025
+ this.name = "ActivationSessionFileMissingError";
10026
+ this.path = path;
10027
+ }
10028
+ };
10029
+ function materializeDeferredSessionFile(sessionManager, resolvedFile) {
10030
+ const header = sessionManager.getHeader?.();
10031
+ if (header === null || header === void 0 || header.type !== "session") {
10032
+ throw new ActivationSessionFileMissingError(resolvedFile);
10033
+ }
10034
+ try {
10035
+ writeFileSync4(resolvedFile, `${JSON.stringify(header)}
10036
+ `, { flag: "wx" });
10037
+ } catch (error) {
10038
+ if (errnoCode(error) !== "EEXIST") {
10039
+ throw new Error(
10040
+ `Workflow role activation failed to materialize durable session file (${resolvedFile}): ${errorText(error)}`,
10041
+ { cause: error }
10042
+ );
10043
+ }
10044
+ }
10045
+ if (typeof sessionManager.setSessionFile === "function") {
10046
+ sessionManager.setSessionFile(resolvedFile);
10047
+ }
10048
+ }
10049
+ function durableSessionPointer(sessionManager) {
10050
+ const file = sessionManager.getSessionFile?.();
10051
+ if (typeof file !== "string" || file.length === 0) {
10052
+ throw new Error(
10053
+ "Workflow role activation requires a durable Pi session file principal (getSessionFile); directory-only or --no-session invocations are rejected"
10054
+ );
10055
+ }
10056
+ if (!isAbsolute5(file)) {
10057
+ throw new Error(
10058
+ `Workflow role activation requires an absolute durable session file path; got relative path: ${file}`
10059
+ );
10060
+ }
10061
+ const resolvedFile = resolve14(file);
10062
+ try {
10063
+ lstatSync2(resolvedFile);
10064
+ } catch (error) {
10065
+ if (errnoCode(error) !== "ENOENT") {
10066
+ throw new Error(
10067
+ `Workflow role activation failed to stat durable session file (${resolvedFile}): ${errorText(error)}`,
10068
+ { cause: error }
10069
+ );
10070
+ }
10071
+ try {
10072
+ materializeDeferredSessionFile(sessionManager, resolvedFile);
10073
+ } catch (materializeError) {
10074
+ if (materializeError instanceof ActivationSessionFileMissingError) {
10075
+ throw new ActivationSessionFileMissingError(resolvedFile, { cause: error });
10076
+ }
10077
+ throw materializeError;
10078
+ }
10079
+ }
10080
+ let realFile;
10081
+ try {
10082
+ realFile = realpathSync3(resolvedFile);
10083
+ } catch (error) {
10084
+ throw new ActivationSessionFileMissingError(resolvedFile, { cause: error });
10085
+ }
10086
+ let info;
10087
+ try {
10088
+ info = statSync3(realFile);
10089
+ } catch (error) {
10090
+ throw new Error(
10091
+ `Workflow role activation failed to stat durable session file (${realFile}): ${errorText(error)}`,
10092
+ { cause: error }
10093
+ );
10094
+ }
10095
+ if (info.isDirectory()) {
10096
+ throw new Error(
10097
+ `Workflow role activation durable session principal must be a file, not a directory: ${realFile}`
10098
+ );
10099
+ }
10100
+ if (!info.isFile()) {
10101
+ throw new Error(
10102
+ `Workflow role activation durable session principal is not a regular file: ${realFile}`
10103
+ );
10104
+ }
10105
+ return { kind: "session-file", path: realFile };
10106
+ }
10107
+
10108
+ // src/activation-ledger.ts
10109
+ init_activation_ledger_topology();
10110
+ var ACTIVATION_LEDGER_APPEND_OPEN_FLAGS = constants.O_APPEND | constants.O_CREAT | constants.O_WRONLY | constants.O_NOFOLLOW;
10111
+ var ACCEPTED_ACTIVATION_EVENT = "accepted-activation";
10112
+ var ACCEPTED_ACTIVATION_FACT_KEYS = Object.freeze([
10113
+ "event",
10114
+ "role",
10115
+ "observedAt",
10116
+ "bookKey",
10117
+ "session",
10118
+ "correlation"
10119
+ ]);
10120
+ function correlationIdentityFromEnv(env = process.env) {
10121
+ const raw = env.AK_CORRELATION_ID;
10122
+ if (typeof raw === "string" && raw.trim().length > 0) {
10123
+ return { kind: "caller", id: raw };
10124
+ }
10125
+ return { kind: "absent" };
10126
+ }
10127
+ function projectAcceptedActivationFact(input) {
10128
+ const closed = {
10129
+ event: ACCEPTED_ACTIVATION_EVENT,
10130
+ role: input.role,
10131
+ observedAt: input.observedAt,
10132
+ bookKey: input.bookKey,
10133
+ session: { kind: "session-file", path: input.session.path },
10134
+ correlation: input.correlation.kind === "caller" ? { kind: "caller", id: input.correlation.id } : { kind: "absent" }
10135
+ };
10136
+ return Object.fromEntries(
10137
+ ACCEPTED_ACTIVATION_FACT_KEYS.map((key) => [key, closed[key]])
10138
+ );
10139
+ }
10140
+ function buildAcceptedActivationFact(input) {
10141
+ return projectAcceptedActivationFact(input);
10142
+ }
10143
+ function serializeAcceptedActivationFact(fact) {
10144
+ return `${JSON.stringify(projectAcceptedActivationFact(fact))}
10145
+ `;
10146
+ }
10147
+ function appendActivationLedgerLine(ledgerPath, line2, options) {
10148
+ if (!isAbsolute6(options.ledgerHome)) {
10149
+ throw new ActivationLedgerError(
10150
+ `activation ledger home must be absolute: ${options.ledgerHome}`
10151
+ );
10152
+ }
10153
+ const resolvedLedger = resolve15(ledgerPath);
10154
+ const resolvedHome = resolve15(options.ledgerHome);
10155
+ const parent = dirname14(resolvedLedger);
10156
+ ensureRealDirectoryTree(resolvedHome, parent);
10157
+ assertLedgerFileInsideHome(resolvedLedger, resolvedHome);
10158
+ if (typeof constants.O_NOFOLLOW !== "number") {
10159
+ throw new ActivationLedgerError(
10160
+ "activation ledger append requires O_NOFOLLOW open-flag support (anti-symlink TOCTOU protection must not be silently dropped); refusing to append"
10161
+ );
10162
+ }
10163
+ const bytes = Buffer.isBuffer(line2) ? line2 : Buffer.from(line2);
10164
+ let ledgerFd;
10165
+ let primaryFailure;
10166
+ try {
10167
+ try {
10168
+ ledgerFd = openSync(resolvedLedger, ACTIVATION_LEDGER_APPEND_OPEN_FLAGS, 420);
10169
+ } catch (error) {
10170
+ throw new ActivationLedgerError(
10171
+ `activation ledger failed to open ledger file (${resolvedLedger}): ${errorText(error)}`,
10172
+ { cause: error }
10173
+ );
10174
+ }
10175
+ let opened;
10176
+ try {
10177
+ opened = fstatSync(ledgerFd);
10178
+ } catch (error) {
10179
+ throw new ActivationLedgerError(
10180
+ `activation ledger failed to fstat ledger file (${resolvedLedger}): ${errorText(error)}`,
10181
+ { cause: error }
10182
+ );
10183
+ }
10184
+ if (!opened.isFile()) {
10185
+ throw new ActivationLedgerError(
10186
+ `activation ledger is not a regular file: ${resolvedLedger}`
10187
+ );
10188
+ }
10189
+ const written = writeSync(ledgerFd, bytes, 0, bytes.length, null);
10190
+ if (written !== bytes.length) {
10191
+ throw new ActivationLedgerError(
10192
+ `activation ledger short write: wrote ${written} of ${bytes.length} bytes to ${resolvedLedger}`
10193
+ );
10194
+ }
10195
+ } catch (error) {
10196
+ primaryFailure = error;
10197
+ }
10198
+ if (ledgerFd !== void 0) {
10199
+ try {
10200
+ closeSync(ledgerFd);
10201
+ } catch (closeFailure) {
10202
+ if (primaryFailure !== void 0) {
10203
+ throw new AggregateError(
10204
+ [primaryFailure, closeFailure],
10205
+ "activation ledger operation and close failed",
10206
+ { cause: primaryFailure }
10207
+ );
10208
+ }
10209
+ throw closeFailure;
10210
+ }
10211
+ }
10212
+ if (primaryFailure !== void 0) throw primaryFailure;
10213
+ }
10214
+ function appendAcceptedActivationFact(ledgerPath, fact, options) {
10215
+ appendActivationLedgerLine(
10216
+ ledgerPath,
10217
+ Buffer.from(serializeAcceptedActivationFact(fact), "utf8"),
10218
+ { ledgerHome: options.ledgerHome }
10219
+ );
10220
+ }
10221
+ function appendAcceptedActivationToBook(options) {
10222
+ appendAcceptedActivationFact(
10223
+ activationWaitingLedgerPath(options.ledgerHome, options.fact.bookKey),
10224
+ options.fact,
10225
+ { ledgerHome: options.ledgerHome }
10226
+ );
10227
+ }
10228
+
10229
+ // src/stderr-jsonl.ts
10230
+ import { writeSync as writeSync2 } from "node:fs";
10231
+ var STDERR_JSONL_WRITE_RETRY_LIMIT = 100;
10232
+ function writeStderrJsonlRecord(record4, write = writeSync2) {
10233
+ const bytes = Buffer.from(`${JSON.stringify(record4)}
10234
+ `);
10235
+ let offset = 0;
10236
+ let retries = 0;
10237
+ while (offset < bytes.length) {
10238
+ try {
10239
+ const written = write(2, bytes, offset, bytes.length - offset);
10240
+ if (written <= 0) throw new Error("stderr JSONL write made no progress");
10241
+ offset += written;
10242
+ retries = 0;
10243
+ } catch (error) {
10244
+ const code = error.code;
10245
+ if ((code === "EAGAIN" || code === "EINTR") && retries++ < STDERR_JSONL_WRITE_RETRY_LIMIT) continue;
10246
+ throw error;
10247
+ }
10248
+ }
10249
+ }
10250
+
10251
+ // src/tool-execution-observation.ts
10252
+ import { writeSync as writeSync3 } from "node:fs";
10253
+ import { Type as Type19 } from "typebox";
10254
+ import { Value as Value4 } from "typebox/value";
10255
+ var TOOL_EXECUTION_UPDATE_THROTTLE_MS = 3e4;
10256
+ var observationBase = {
10257
+ role: Type19.String({ minLength: 1 }),
10258
+ toolCallId: Type19.String({ minLength: 1 }),
10259
+ toolName: Type19.String({ minLength: 1 }),
10260
+ timestamp: Type19.String({ format: "date-time" })
10261
+ };
10262
+ var toolExecutionObservationRecordSchema = Type19.Union([
10263
+ Type19.Object({
10264
+ ...observationBase,
10265
+ event: Type19.Literal("tool_execution_start")
10266
+ }, { additionalProperties: true }),
10267
+ Type19.Object({
10268
+ ...observationBase,
10269
+ event: Type19.Literal("tool_execution_update")
10270
+ }, { additionalProperties: true }),
10271
+ Type19.Object({
10272
+ ...observationBase,
10273
+ event: Type19.Literal("tool_execution_end"),
10274
+ isError: Type19.Boolean()
10275
+ }, { additionalProperties: true })
10276
+ ]);
10277
+ function validateToolExecutionObservationRecord(record4) {
10278
+ if (!Value4.Check(toolExecutionObservationRecordSchema, record4)) {
10279
+ throw new TypeError("Tool execution observation record does not match its contract");
10280
+ }
10281
+ return record4;
10282
+ }
10283
+ function writeToolExecutionObservationRecord(record4, write = writeSync3) {
10284
+ writeStderrJsonlRecord(validateToolExecutionObservationRecord(record4), write);
10285
+ }
10286
+ function isProducingToolUpdate(partialResult) {
10287
+ if (partialResult == null) return false;
10288
+ if (typeof partialResult !== "object") return true;
10289
+ const content = partialResult.content;
10290
+ if (!Array.isArray(content)) return true;
10291
+ if (content.length === 0) return false;
10292
+ return content.some((part) => {
10293
+ if (typeof part !== "object" || part === null) return true;
10294
+ const text = part.text;
10295
+ if (typeof text === "string") return text.length > 0;
10296
+ return true;
10297
+ });
10298
+ }
10299
+ function systemToolExecutionObservationMonoNow() {
10300
+ return performance.now();
10301
+ }
10302
+ function createToolExecutionObservationFace(options) {
10303
+ const states = /* @__PURE__ */ new Map();
10304
+ async function emit(record4) {
10305
+ await options.write(validateToolExecutionObservationRecord(record4));
10306
+ }
10307
+ function activeRole() {
10308
+ if (!options.admitted()) return void 0;
10309
+ const role = options.role();
10310
+ return role === void 0 || role === "" ? void 0 : role;
10311
+ }
10312
+ return {
10313
+ reset() {
10314
+ states.clear();
10315
+ },
10316
+ async onStart(event) {
10317
+ const role = activeRole();
10318
+ if (role === void 0) return;
10319
+ states.set(event.toolCallId, { lastUpdateEmitMonoMs: void 0 });
10320
+ await emit({
10321
+ event: "tool_execution_start",
10322
+ role,
10323
+ toolCallId: event.toolCallId,
10324
+ toolName: event.toolName,
10325
+ timestamp: options.clock()
10326
+ });
10327
+ },
10328
+ async onUpdate(event) {
10329
+ const role = activeRole();
10330
+ if (role === void 0) return;
10331
+ if (!isProducingToolUpdate(event.partialResult)) return;
10332
+ const now = options.monoNow();
10333
+ const state = states.get(event.toolCallId) ?? { lastUpdateEmitMonoMs: void 0 };
10334
+ if (state.lastUpdateEmitMonoMs !== void 0 && now - state.lastUpdateEmitMonoMs < TOOL_EXECUTION_UPDATE_THROTTLE_MS) {
10335
+ return;
10336
+ }
10337
+ state.lastUpdateEmitMonoMs = now;
10338
+ states.set(event.toolCallId, state);
10339
+ await emit({
10340
+ event: "tool_execution_update",
10341
+ role,
10342
+ toolCallId: event.toolCallId,
10343
+ toolName: event.toolName,
10344
+ timestamp: options.clock()
10345
+ });
10346
+ },
10347
+ async onEnd(event) {
10348
+ const role = activeRole();
10349
+ if (role === void 0) return;
10350
+ states.delete(event.toolCallId);
10351
+ await emit({
10352
+ event: "tool_execution_end",
10353
+ role,
10354
+ toolCallId: event.toolCallId,
10355
+ toolName: event.toolName,
10356
+ timestamp: options.clock(),
10357
+ isError: event.isError
10358
+ });
10359
+ }
10360
+ };
10361
+ }
10362
+
9925
10363
  // src/collector-identity.ts
9926
10364
  function identityKey(identity) {
9927
10365
  if (identity === null) return "unassigned";
@@ -10047,7 +10485,6 @@ function fail4(message) {
10047
10485
  }
10048
10486
  function buildCollectorReceipt(ledger, candidateRaw, clock) {
10049
10487
  ledger.assertNotFatal();
10050
- if (ledger.outputAccepted) fail4("Collector output is singleton");
10051
10488
  if (ledger.unresolvedTransportFailure) fail4("Collector cannot output while a transport failure is unrecovered");
10052
10489
  if (ledger.latestCompleteSnapshotId === void 0) fail4("Collector output requires a complete final snapshot");
10053
10490
  if (ledger.activationTime === void 0 || ledger.deadlineTime === void 0) fail4("Collector output requires activation timeline");
@@ -10251,10 +10688,13 @@ function createCollectorRoleRuntime(pi, dependencies, hostActions) {
10251
10688
  reason: `\u901A\u8FDB\u53F8\u7981\u7528\u5DE5\u5177 ${event.toolName}`
10252
10689
  };
10253
10690
  }
10254
- if (activation.ledger.outputAccepted && event.toolName !== COLLECTOR_OUTPUT_TOOL) {
10691
+ if (event.toolName === COLLECTOR_OUTPUT_TOOL) {
10692
+ activation.ledger.beginOperational(COLLECTOR_OUTPUT_TOOL, event.toolCallId);
10693
+ }
10694
+ if (activation.ledger.outputCandidate && event.toolName !== COLLECTOR_OUTPUT_TOOL) {
10255
10695
  return {
10256
10696
  block: true,
10257
- reason: "\u56DE\u6267\u5DF2\u53D7\u7406\uFF0C\u672C\u5C40\u4E0D\u518D\u53D7\u7406\u64CD\u4F5C"
10697
+ reason: "\u901A\u8FDB\u53F8\u5DF2\u4EA7\u51FA\u8F93\u51FA\u5019\u9009\uFF0C\u672C\u5C40\u4E0D\u518D\u53D7\u7406\u64CD\u4F5C"
10258
10698
  };
10259
10699
  }
10260
10700
  return void 0;
@@ -10265,7 +10705,7 @@ function createCollectorRoleRuntime(pi, dependencies, hostActions) {
10265
10705
  });
10266
10706
  pi.on("session_shutdown", () => {
10267
10707
  if (activation === void 0) return;
10268
- if (!activation.ledger.outputAccepted || activation.ledger.fatal) {
10708
+ if (activation.ledger.fatal) {
10269
10709
  if (process.exitCode === void 0 || process.exitCode === 0) {
10270
10710
  process.exitCode = 1;
10271
10711
  }
@@ -10433,8 +10873,7 @@ function createCollectorRoleRuntime(pi, dependencies, hostActions) {
10433
10873
  params,
10434
10874
  activation.clock
10435
10875
  );
10436
- activation.ledger.markOutputAccepted();
10437
- activation.ledger.completeOperational(toolCallId);
10876
+ activation.ledger.recordOutputCandidate();
10438
10877
  const acceptedDetails = receipt;
10439
10878
  return {
10440
10879
  content: [{
@@ -10449,6 +10888,8 @@ function createCollectorRoleRuntime(pi, dependencies, hostActions) {
10449
10888
  hostActions.failInfrastructure(error, ctx, toolCallId);
10450
10889
  }
10451
10890
  throw error;
10891
+ } finally {
10892
+ activation.ledger.completeOperational(toolCallId);
10452
10893
  }
10453
10894
  }
10454
10895
  });
@@ -10462,7 +10903,7 @@ function createCollectorRoleRuntime(pi, dependencies, hostActions) {
10462
10903
  `Collector supports only print or json mode (got ${ctx.mode})`
10463
10904
  );
10464
10905
  }
10465
- if (event.reason === "resume" || event.reason === "fork" || event.reason === "reload") {
10906
+ if (event.reason === "fork" || event.reason === "reload") {
10466
10907
  throw new Error(
10467
10908
  `Collector does not support session_start reason ${event.reason}`
10468
10909
  );
@@ -10529,11 +10970,14 @@ function createCollectorRoleRuntime(pi, dependencies, hostActions) {
10529
10970
  }
10530
10971
  const clock = dependencies.createClock?.() ?? createSystemCollectorClock();
10531
10972
  const transport = dependencies.createTransport();
10532
- const ledger = createCollectorLedger({
10533
- repository,
10534
- prNumber,
10535
- manifest
10536
- });
10973
+ const ledger = dependencies.createLedger(
10974
+ { repository, prNumber, manifest },
10975
+ clock,
10976
+ ctx
10977
+ );
10978
+ if (ledger.activationRecorded) {
10979
+ firstDispatchDone = true;
10980
+ }
10537
10981
  activation = {
10538
10982
  soul,
10539
10983
  repository,
@@ -10702,7 +11146,7 @@ function createNotaryRoleRuntime(pi, dependencies, host) {
10702
11146
  pi.registerTool({
10703
11147
  name: NOTARY_OUTPUT_TOOL_NAME,
10704
11148
  label: "\u7B26\u5B9D\u90CE\u8F93\u51FA",
10705
- description: "\u63D0\u4EA4\u5F15\u6587\u4FDD\u771F\u4E0E\u7968\u9762\u5BF9\u9F50\u7684 typed pass/bounce \u51B3\u8BAE\u3002",
11149
+ description: "\u63D0\u4EA4\u5F15\u6587\u4FDD\u771F\u4E0E\u7968\u9762\u5BF9\u9F50\u7684 typed pass/bounce/escalate \u51B3\u8BAE\u3002",
10706
11150
  promptSnippet: "\u63D0\u4EA4\u7B26\u5B9D\u90CE\u51B3\u8BAE",
10707
11151
  parameters: notaryOutputSchema,
10708
11152
  async execute(toolCallId, parameters, _signal, _onUpdate, ctx) {
@@ -10745,24 +11189,24 @@ function createNotaryRoleRuntime(pi, dependencies, host) {
10745
11189
  }
10746
11190
 
10747
11191
  // src/countersign-role.ts
10748
- import { Type as Type19 } from "typebox";
11192
+ import { Type as Type20 } from "typebox";
10749
11193
  var countersignVerdictSchema = withInfrastructureFailureDeclaration(
10750
- Type19.Object(
11194
+ Type20.Object(
10751
11195
  {
10752
11196
  countersignStatus: stringEnum(["converged", "continue", "escalate"], { description: "converged | continue | escalate" }),
10753
- fix: Type19.Optional(
10754
- Type19.Object(
10755
- { summary: Type19.String({ minLength: 1, description: "\u9000\u56DE\u6458\u8981" }) },
11197
+ fix: Type20.Optional(
11198
+ Type20.Object(
11199
+ { summary: Type20.String({ minLength: 1, description: "\u9000\u56DE\u6458\u8981" }) },
10756
11200
  { additionalProperties: false, description: "\u9000\u56DE\u8BF4\u660E" }
10757
11201
  )
10758
11202
  ),
10759
- note: Type19.Optional(Type19.String({ minLength: 1, description: "\u9644\u6CE8" })),
10760
- evidence: Type19.Optional(Type19.Unknown({ description: "\u7559\u5B58\u8BC1\u636E" })),
10761
- decisionGate: Type19.Optional(
10762
- Type19.Object(
11203
+ note: Type20.Optional(Type20.String({ minLength: 1, description: "\u9644\u6CE8" })),
11204
+ evidence: Type20.Optional(Type20.Unknown({ description: "\u7559\u5B58\u8BC1\u636E" })),
11205
+ decisionGate: Type20.Optional(
11206
+ Type20.Object(
10763
11207
  {
10764
- question: Type19.String({ minLength: 1 }),
10765
- options: Type19.Array(Type19.String({ minLength: 1 }), { minItems: 1 })
11208
+ question: Type20.String({ minLength: 1 }),
11209
+ options: Type20.Array(Type20.String({ minLength: 1 }), { minItems: 1 })
10766
11210
  },
10767
11211
  { additionalProperties: false, description: "\u9700\u965B\u4E0B\u5904\u7F6E\u7684\u95EE\u9898\u4E0E\u9009\u9879" }
10768
11212
  )
@@ -10781,18 +11225,18 @@ var COUNTERSIGN_TOOL_SPEC = {
10781
11225
  };
10782
11226
 
10783
11227
  // src/gleaner-left-role.ts
10784
- import { Type as Type20 } from "typebox";
11228
+ import { Type as Type21 } from "typebox";
10785
11229
  var gleanerLeftOutputSchema = withInfrastructureFailureDeclaration(
10786
11230
  openToolObject(
10787
- Type20.Object({
10788
- status: Type20.Unknown({
11231
+ Type21.Object({
11232
+ status: Type21.Unknown({
10789
11233
  description: "completed \u2014 \u5F62\u72B6\u6307\u5F15\uFF0C\u975E schema \u95F8"
10790
11234
  }),
10791
- findings: Type20.Array(
10792
- Type20.Object(
11235
+ findings: Type21.Array(
11236
+ Type21.Object(
10793
11237
  {
10794
- pointer: Type20.String({ description: "\u6587\u4EF6/\u884C\u6307\u9488" }),
10795
- statement: Type20.String({ description: "\u7591\u70B9\u9648\u8FF0" })
11238
+ pointer: Type21.String({ description: "\u6587\u4EF6/\u884C\u6307\u9488" }),
11239
+ statement: Type21.String({ description: "\u7591\u70B9\u9648\u8FF0" })
10796
11240
  },
10797
11241
  { additionalProperties: true, description: "\u4E00\u6761\u5F39\u7AE0" }
10798
11242
  ),
@@ -10810,208 +11254,30 @@ var GLEANER_LEFT_TOOL_SPEC = {
10810
11254
  };
10811
11255
 
10812
11256
  // src/inspector-role.ts
10813
- import { Type as Type21 } from "typebox";
11257
+ import { Type as Type22 } from "typebox";
10814
11258
  var inspectorOutputSchema = withInfrastructureFailureDeclaration(
10815
11259
  openToolObject(
10816
- Type21.Object({
10817
- status: Type21.Unknown({
10818
- description: "pass | bounce \u2014 \u5F62\u72B6\u6307\u5F15\uFF0C\u975E schema \u95F8"
11260
+ Type22.Object({
11261
+ status: Type22.Unknown({
11262
+ description: "pass | bounce | escalate \u2014 \u5F62\u72B6\u6307\u5F15\uFF0C\u975E schema \u95F8"
10819
11263
  }),
10820
- findings: Type21.Unknown({
11264
+ findings: Type22.Unknown({
10821
11265
  description: "\u968F\u4EA4\u5377\u7559\u5B58\u7684\u95EE\u9898\u8BB0\u5F55"
10822
- })
11266
+ }),
11267
+ reason: Type22.Optional(Type22.Unknown({
11268
+ description: "status \u4E3A escalate \u65F6\u7684\u4E0A\u5448\u7406\u7531"
11269
+ }))
10823
11270
  })
10824
11271
  )
10825
11272
  );
10826
11273
  var INSPECTOR_TOOL_SPEC = {
10827
11274
  name: INSPECTOR_OUTPUT_TOOL_NAME,
10828
11275
  label: "\u5BDF\u9662\u8F93\u51FA",
10829
- description: "\u5BDF\u9662\u7EC8\u5C40\u56DE\u6267\uFF0C\u72B6\u6001\u4E3A pass \u6216 bounce\u3002",
11276
+ description: "\u5BDF\u9662\u7EC8\u5C40\u56DE\u6267\uFF0C\u72B6\u6001\u4E3A pass\u3001bounce \u6216 escalate\u3002",
10830
11277
  promptSnippet: "\u5BDF\u9662\u7EC8\u5C40\u56DE\u6267",
10831
11278
  parameters: inspectorOutputSchema
10832
11279
  };
10833
11280
 
10834
- // src/gatekeeper-role.ts
10835
- import { Type as Type22 } from "typebox";
10836
- var INSPECTOR_OUTPUT_TOOL = INSPECTOR_OUTPUT_TOOL_NAME;
10837
- var NOTARY_OUTPUT_TOOL = "ak_notary_output";
10838
- var SUBJECT_TOOL = "ak_gatekeeper_subject";
10839
- function gateSeatLabel(stage) {
10840
- switch (stage) {
10841
- case "gatekeeper":
10842
- return "\u95E8\u4E0B\u7701";
10843
- case "inspector":
10844
- return "\u5BDF\u9662";
10845
- case "notary":
10846
- return "\u7B26\u5B9D\u90CE";
10847
- }
10848
- }
10849
- var officerDecisionSchema = openToolObject(Type22.Object({
10850
- status: Type22.Unknown({ description: "pass | bounce \u2014 \u5F62\u72B6\u6307\u5F15\uFF0C\u975E schema \u95F8" }),
10851
- findings: Type22.Unknown({ description: "string[] findings\uFF0C\u968F pass \u6216 bounce \u7559\u5B58" })
10852
- }));
10853
- var GATEKEEPER_TOOL_SPEC = {
10854
- name: GATEKEEPER_OUTPUT_TOOL_NAME,
10855
- label: "\u95E8\u4E0B\u7701\u51B3\u8BAE",
10856
- description: "\u95E8\u4E0B\u7701\u7EC8\u5C40\u51B3\u8BAE\uFF0C\u72B6\u6001\u4E3A dispatch \u6216 pass\u3002",
10857
- promptSnippet: "\u95E8\u4E0B\u7701\u51B3\u8BAE",
10858
- parameters: gatekeeperOutputSchema
10859
- };
10860
- function result(content, details) {
10861
- return { content: [{ type: "text", text: content }], details };
10862
- }
10863
- function subjectTool(subject) {
10864
- return {
10865
- name: SUBJECT_TOOL,
10866
- description: "\u8BFB\u53D6\u5DF2\u53D7\u7406\u5377\u5B97\uFF1B\u53EA\u4F9B\u53D6\u9605\uFF0C\u4E0D\u8BC4\u5224\u4E0D\u6539\u52A8\u3002",
10867
- parameters: Type22.Object({}, { additionalProperties: false }),
10868
- async execute() {
10869
- return result(JSON.stringify(subject), subject);
10870
- }
10871
- };
10872
- }
10873
- function createOfficerDecisionTool(name) {
10874
- return {
10875
- name,
10876
- description: "\u63D0\u4EA4\u4E00\u4EFD typed pass/bounce \u51B3\u8BAE\u3002",
10877
- parameters: officerDecisionSchema,
10878
- async execute(_id, args) {
10879
- return result(`\u5DF2\u6536 ${String(args?.status)}`, args);
10880
- }
10881
- };
10882
- }
10883
- function createGatekeeperOutputTool() {
10884
- return {
10885
- name: GATEKEEPER_OUTPUT_TOOL_NAME,
10886
- description: "\u63D0\u4EA4\u95E8\u4E0B\u7701\u6D3E\u5B98\u51B3\u5B9A\u3002",
10887
- parameters: gatekeeperDecisionSchema,
10888
- async execute(_id, args) {
10889
- return result(`\u5DF2\u6536 ${String(args?.status)}`, args);
10890
- }
10891
- };
10892
- }
10893
- async function defaultLoadSoul(role) {
10894
- return loadGatekeeperSessionMaterials(role);
10895
- }
10896
- function failureReason(error) {
10897
- if (error instanceof AggregateError) return error.errors.map(failureReason).join("; ");
10898
- return error instanceof Error ? `${error.name}: ${error.message}` : String(error);
10899
- }
10900
- function asStringArray3(value) {
10901
- if (!Array.isArray(value)) return [];
10902
- return value.filter((item) => typeof item === "string");
10903
- }
10904
- var MISSING_ARGUMENTS_SUBMISSION = Object.freeze({ missing: "arguments" });
10905
- function isRecord11(value) {
10906
- return typeof value === "object" && value !== null && !Array.isArray(value);
10907
- }
10908
- function retainedSubmission(decision) {
10909
- return decision === void 0 || isRecord11(decision) && Object.keys(decision).length === 0 ? MISSING_ARGUMENTS_SUBMISSION : decision;
10910
- }
10911
- function noUsableReleaseFailure(stage, decision) {
10912
- return {
10913
- status: "transport_failure",
10914
- stage,
10915
- reason: stage === "gatekeeper" ? "decision \u65E0\u663E\u5F0F dispatch" : "decision \u65E0\u663E\u5F0F pass/bounce",
10916
- submission: retainedSubmission(decision)
10917
- };
10918
- }
10919
- function readRecord(value) {
10920
- if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
10921
- return value;
10922
- }
10923
- function projectProvinceDecision(decision) {
10924
- const projected = projectLawfulGatekeeperOutput(decision);
10925
- if (projected === void 0) return noUsableReleaseFailure("gatekeeper", decision);
10926
- if (projected.status === "dispatch") {
10927
- return { status: "dispatch", officer: projected.officer };
10928
- }
10929
- return { status: "pass", findings: projected.findings ?? [] };
10930
- }
10931
- function projectOfficerDecision(officer, decision) {
10932
- const record4 = readRecord(decision);
10933
- if (record4 === void 0) return noUsableReleaseFailure(officer, decision);
10934
- if (record4.status === "bounce") {
10935
- return {
10936
- status: "bounce",
10937
- officer,
10938
- disposition: "rewrite",
10939
- findings: asStringArray3(record4.findings),
10940
- submission: retainedSubmission(decision)
10941
- };
10942
- }
10943
- if (record4.status === "pass") {
10944
- return {
10945
- status: "pass",
10946
- officer,
10947
- findings: asStringArray3(record4.findings)
10948
- };
10949
- }
10950
- return noUsableReleaseFailure(officer, decision);
10951
- }
10952
- async function runGatekeeper(options) {
10953
- const loadSoul = options.loadSoul ?? defaultLoadSoul;
10954
- let provinceRun;
10955
- try {
10956
- provinceRun = await executeAuditorChild({
10957
- context: options.context,
10958
- roleLabel: "Gatekeeper",
10959
- gateSeat: "gatekeeper",
10960
- systemPrompt: await loadSoul("gatekeeper"),
10961
- prompt: "\u5377\u5B97\u5DF2\u53D7\u7406\u3002",
10962
- tool: createGatekeeperOutputTool(),
10963
- dossierTool: subjectTool(options.subject),
10964
- ...options.signal === void 0 ? {} : { signal: options.signal },
10965
- ...options.runDirectory === void 0 ? {} : { runDirectory: options.runDirectory }
10966
- });
10967
- } catch (error) {
10968
- return { status: "transport_failure", stage: "gatekeeper", reason: failureReason(error) };
10969
- }
10970
- if (provinceRun.noReceiptLifecycle !== void 0) {
10971
- return { status: "no_receipt", stage: "gatekeeper", reason: `${gateSeatLabel("gatekeeper")}\u672A\u4EA7\u751F\u5DF2\u63A5\u53D7\u56DE\u6267\u5373\u6563\u5C40`, facts: provinceRun.noReceiptLifecycle };
10972
- }
10973
- const province = projectProvinceDecision(provinceRun.decision);
10974
- if (province.status !== "dispatch") return province;
10975
- const officer = province.officer;
10976
- try {
10977
- const roleLabel = officer === "inspector" ? "Inspector" : "Notary";
10978
- const officerRun = await executeAuditorChild({
10979
- context: options.context,
10980
- roleLabel,
10981
- gateSeat: officer,
10982
- systemPrompt: await loadSoul(officer),
10983
- prompt: "\u5377\u5B97\u5DF2\u53D7\u7406\u3002",
10984
- tool: createOfficerDecisionTool(officer === "inspector" ? INSPECTOR_OUTPUT_TOOL : NOTARY_OUTPUT_TOOL),
10985
- dossierTool: subjectTool(options.subject),
10986
- ...options.signal === void 0 ? {} : { signal: options.signal },
10987
- ...options.runDirectory === void 0 ? {} : { runDirectory: options.runDirectory }
10988
- });
10989
- if (officerRun.noReceiptLifecycle !== void 0) {
10990
- return { status: "no_receipt", stage: officer, reason: `${gateSeatLabel(officer)}\u672A\u4EA7\u751F\u5DF2\u63A5\u53D7\u56DE\u6267\u5373\u6563\u5C40`, facts: officerRun.noReceiptLifecycle };
10991
- }
10992
- return projectOfficerDecision(officer, officerRun.decision);
10993
- } catch (error) {
10994
- return { status: "transport_failure", stage: officer, reason: failureReason(error) };
10995
- }
10996
- }
10997
- async function requireGatekeeperPass(options) {
10998
- const gatekeeper = await runGatekeeper({
10999
- context: options.context,
11000
- subject: options.subject,
11001
- ...options.signal === void 0 ? {} : { signal: options.signal }
11002
- });
11003
- if (gatekeeper.status === "pass") return;
11004
- if (gatekeeper.status === "transport_failure") {
11005
- const error = new Error(`\u95E8\u4E0B\u7701 transport_failure\uFF08${gatekeeper.stage}\uFF09\uFF1A${gatekeeper.reason}`);
11006
- error.stage = gatekeeper.stage;
11007
- error.reason = gatekeeper.reason;
11008
- if (gatekeeper.submission !== void 0) error.submission = gatekeeper.submission;
11009
- options.hostActions.failInfrastructure(error, options.context, options.toolCallId);
11010
- }
11011
- options.hostActions.bindSubmissionNonPass(options.toolCallId, gatekeeper);
11012
- throw new GatekeeperDecisionError(gatekeeper);
11013
- }
11014
-
11015
11281
  // src/navigator-role.ts
11016
11282
  var NAVIGATOR_TOOL_SPEC = {
11017
11283
  name: NAVIGATOR_OUTPUT_TOOL_NAME,
@@ -11027,25 +11293,37 @@ init_upstream_error_testimony();
11027
11293
 
11028
11294
  // src/public-cli/settlement.ts
11029
11295
  var NAVIGATOR_POST_ROLE_GRACE_MS = 1e4;
11030
- function raceNavigatorGrace(work, graceMs = NAVIGATOR_POST_ROLE_GRACE_MS, sleep = (ms) => new Promise((resolve17) => setTimeout(resolve17, ms))) {
11296
+ function defaultNavigatorGraceSleep() {
11297
+ let timer;
11298
+ const sleep = ((ms) => new Promise((resolve17) => {
11299
+ timer = setTimeout(() => {
11300
+ timer = void 0;
11301
+ resolve17();
11302
+ }, ms);
11303
+ }));
11304
+ sleep.cancel = () => {
11305
+ if (timer !== void 0) {
11306
+ clearTimeout(timer);
11307
+ timer = void 0;
11308
+ }
11309
+ };
11310
+ return sleep;
11311
+ }
11312
+ function raceNavigatorGrace(work, graceMs = NAVIGATOR_POST_ROLE_GRACE_MS, sleep = defaultNavigatorGraceSleep()) {
11031
11313
  return new Promise((resolve17, reject) => {
11032
11314
  let settled = false;
11315
+ const finish = (action) => {
11316
+ if (settled) return;
11317
+ settled = true;
11318
+ sleep.cancel?.();
11319
+ action();
11320
+ };
11033
11321
  void work.then(
11034
- (value) => {
11035
- if (settled) return;
11036
- settled = true;
11037
- resolve17({ status: "done", value });
11038
- },
11039
- (error) => {
11040
- if (settled) return;
11041
- settled = true;
11042
- reject(error);
11043
- }
11322
+ (value) => finish(() => resolve17({ status: "done", value })),
11323
+ (error) => finish(() => reject(error))
11044
11324
  );
11045
11325
  void sleep(graceMs).then(() => {
11046
- if (settled) return;
11047
- settled = true;
11048
- resolve17({ status: "timeout" });
11326
+ finish(() => resolve17({ status: "timeout" }));
11049
11327
  });
11050
11328
  });
11051
11329
  }
@@ -13148,6 +13426,20 @@ function createRoleRuntimeExtension(dependencies) {
13148
13426
  }
13149
13427
  return dependencies.createCollectorTransport();
13150
13428
  },
13429
+ createLedger(config, collectorClock, context) {
13430
+ const append = context.sessionManager?.appendCustomEntry;
13431
+ return createCollectorLedger(config, {
13432
+ clock: collectorClock,
13433
+ ...append === void 0 ? {} : {
13434
+ journal: {
13435
+ append(customType, data) {
13436
+ context.sessionManager?.appendCustomEntry?.(customType, data);
13437
+ }
13438
+ }
13439
+ },
13440
+ dossierEntries: context.sessionManager?.getEntries?.() ?? []
13441
+ });
13442
+ },
13151
13443
  ...dependencies.createCollectorClock === void 0 ? {} : { createClock: dependencies.createCollectorClock },
13152
13444
  ...dependencies.collectorPackageExtensionPath === void 0 ? {} : {
13153
13445
  packageExtensionPath: dependencies.collectorPackageExtensionPath
@@ -14115,8 +14407,8 @@ async function prepareGrokRoleEnvelope(options) {
14115
14407
  rejection = value;
14116
14408
  },
14117
14409
  capabilities: {
14118
- skillExpansion(prompt2) {
14119
- return buildGrokSkillExpansion(methodSkills, prompt2);
14410
+ skillExpansion(prompt) {
14411
+ return buildGrokSkillExpansion(methodSkills, prompt);
14120
14412
  }
14121
14413
  },
14122
14414
  registerFlag(name, definition) {
@@ -14448,54 +14740,67 @@ async function prepareGrokRoleEnvelope(options) {
14448
14740
  };
14449
14741
  return { accepted: false, failure: failure2 };
14450
14742
  };
14451
- await emit("session_start", { reason: request.continuation.kind });
14452
- const inputResults = await emit("input", { text: request.continuation.prompt, source: "interactive" });
14453
- let prompt = request.continuation.prompt;
14454
- for (const value of inputResults) {
14455
- if (typeof value !== "object" || value === null) continue;
14456
- const record4 = value;
14457
- if (record4.action === "transform" && typeof record4.text === "string") prompt = record4.text;
14458
- }
14459
- if (typeof prompt === "string" && prompt.trim() !== "") {
14460
- sessionEntries.push({
14461
- type: "message",
14462
- message: { role: "user", content: prompt }
14743
+ try {
14744
+ await emit("session_start", { reason: request.continuation.kind });
14745
+ const inputResults = await emit("input", { text: request.continuation.prompt, source: "interactive" });
14746
+ let prompt = request.continuation.prompt;
14747
+ for (const value of inputResults) {
14748
+ if (typeof value !== "object" || value === null) continue;
14749
+ const record4 = value;
14750
+ if (record4.action === "transform" && typeof record4.text === "string") prompt = record4.text;
14751
+ }
14752
+ if (typeof prompt === "string" && prompt.trim() !== "") {
14753
+ sessionEntries.push({
14754
+ type: "message",
14755
+ message: { role: "user", content: prompt }
14756
+ });
14757
+ }
14758
+ const basePrompt = await loadMainRoleSessionMaterials(request.activation.role);
14759
+ const methodPrompt = (await Promise.all(request.methods.map(({ path }) => readFile13(path, "utf8")))).join("\n\n");
14760
+ const promptResults = await emit("before_agent_start", {
14761
+ prompt,
14762
+ systemPrompt: [basePrompt, methodPrompt].filter(Boolean).join("\n\n"),
14763
+ systemPromptOptions: {}
14463
14764
  });
14765
+ const systemPromptBody = [...promptResults].reverse().find((value) => typeof value === "object" && value !== null && "systemPrompt" in value && typeof value.systemPrompt === "string")?.systemPrompt ?? [basePrompt, methodPrompt].filter(Boolean).join("\n\n");
14766
+ const readingMaterials = [];
14767
+ for (const value of promptResults) {
14768
+ if (typeof value !== "object" || value === null) continue;
14769
+ if (!("readingMaterial" in value)) continue;
14770
+ const material = value.readingMaterial;
14771
+ if (material !== void 0) readingMaterials.push(material);
14772
+ }
14773
+ priorAkRoleRunDir = process.env.AK_ROLE_RUN_DIR;
14774
+ process.env.AK_ROLE_RUN_DIR = request.runDirectory;
14775
+ runDirInjected = true;
14776
+ return {
14777
+ mcpServers: [{
14778
+ name: `ak-${request.activation.role}`,
14779
+ command: process.execPath,
14780
+ args: [relay],
14781
+ env: [
14782
+ { name: "AK_GROK_MCP_SOCKET", value: options.socketPath },
14783
+ { name: "AK_GROK_MCP_TOKEN", value: token }
14784
+ ]
14785
+ }],
14786
+ systemPrompt: { body: systemPromptBody, materials: readingMaterials },
14787
+ prompt,
14788
+ abortSignal: hostAbort.signal,
14789
+ closeRound,
14790
+ dispose
14791
+ };
14792
+ } catch (error) {
14793
+ try {
14794
+ await dispose();
14795
+ } catch (cleanupFailure) {
14796
+ throw new AggregateError(
14797
+ [error, cleanupFailure],
14798
+ "prepareGrokRoleEnvelope activation failed and its dispose cleanup also failed",
14799
+ { cause: error }
14800
+ );
14801
+ }
14802
+ throw error;
14464
14803
  }
14465
- const basePrompt = await loadMainRoleSessionMaterials(request.activation.role);
14466
- const methodPrompt = (await Promise.all(request.methods.map(({ path }) => readFile13(path, "utf8")))).join("\n\n");
14467
- const promptResults = await emit("before_agent_start", {
14468
- prompt,
14469
- systemPrompt: [basePrompt, methodPrompt].filter(Boolean).join("\n\n"),
14470
- systemPromptOptions: {}
14471
- });
14472
- const systemPromptBody = [...promptResults].reverse().find((value) => typeof value === "object" && value !== null && "systemPrompt" in value && typeof value.systemPrompt === "string")?.systemPrompt ?? [basePrompt, methodPrompt].filter(Boolean).join("\n\n");
14473
- const readingMaterials = [];
14474
- for (const value of promptResults) {
14475
- if (typeof value !== "object" || value === null) continue;
14476
- if (!("readingMaterial" in value)) continue;
14477
- const material = value.readingMaterial;
14478
- if (material !== void 0) readingMaterials.push(material);
14479
- }
14480
- priorAkRoleRunDir = process.env.AK_ROLE_RUN_DIR;
14481
- process.env.AK_ROLE_RUN_DIR = request.runDirectory;
14482
- runDirInjected = true;
14483
- return {
14484
- mcpServers: [{
14485
- name: `ak-${request.activation.role}`,
14486
- command: process.execPath,
14487
- args: [relay],
14488
- env: [
14489
- { name: "AK_GROK_MCP_SOCKET", value: options.socketPath },
14490
- { name: "AK_GROK_MCP_TOKEN", value: token }
14491
- ]
14492
- }],
14493
- systemPrompt: { body: systemPromptBody, materials: readingMaterials },
14494
- prompt,
14495
- abortSignal: hostAbort.signal,
14496
- closeRound,
14497
- dispose
14498
- };
14499
14804
  }
14500
14805
 
14501
14806
  // src/grok/session-identity.ts