@akagilnc/pi-workflow-roles 0.1.4586 → 0.1.4631

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 (63) hide show
  1. package/README.md +2 -2
  2. package/README.zh-CN.md +3 -3
  3. package/dist/acp-host/production-host.js +1184 -717
  4. package/dist/activation-ledger-topology.js +0 -4
  5. package/dist/archivist-record-topology.js +27 -35
  6. package/dist/headless-host/description.js +7 -4
  7. package/dist/headless-host/production-host.js +998 -595
  8. package/dist/migrate-book-topology.js +3 -6
  9. package/dist/navigator-attendance.js +146 -241
  10. package/dist/navigator-public-session.js +81 -15
  11. package/dist/package-contracts/navigator-output.js +30 -12
  12. package/dist/pi/role-turn-host.js +0 -3
  13. package/dist/public-cli/auto-resume.js +26 -0
  14. package/dist/public-cli/judge-run.js +2 -2
  15. package/dist/public-cli/main.js +1119 -870
  16. package/dist/public-cli/option-definitions.js +1 -1
  17. package/dist/public-cli/post-admission.js +103 -9
  18. package/dist/public-cli/process-cancel.js +57 -0
  19. package/dist/public-cli/run-lifecycle.js +29 -7
  20. package/dist/public-cli/settlement.js +46 -32
  21. package/dist/public-cli/terminal.js +8 -27
  22. package/dist/public-role-summons.js +22 -4
  23. package/dist/submission-ledger.js +56 -23
  24. package/package.json +1 -1
  25. package/resources/836-deleted-machine-instruction-inventory.md +2 -0
  26. package/resources/navigator-route-playbook.md +9 -0
  27. package/scripts/build-package.mjs +6 -2
  28. package/src/acp-host/role-turn-host.ts +129 -13
  29. package/src/activation-ledger-topology.ts +1 -6
  30. package/src/activation-ledger.ts +5 -236
  31. package/src/analyst-entry.ts +19 -2
  32. package/src/analyst-ledger.ts +111 -6
  33. package/src/archivist-record-entry.ts +1 -1
  34. package/src/headless-host/description.ts +17 -7
  35. package/src/headless-host/role-turn-host.ts +42 -11
  36. package/src/navigator-attendance.ts +290 -425
  37. package/src/navigator-public-session.ts +126 -25
  38. package/src/navigator-role.ts +2 -2
  39. package/src/package-contracts/navigator-output.ts +41 -25
  40. package/src/pi/role-turn-host.ts +0 -3
  41. package/src/public-cli/auto-resume.ts +34 -0
  42. package/src/public-cli/cli.ts +30 -0
  43. package/src/public-cli/coder-run.ts +2 -2
  44. package/src/public-cli/fixer-run.ts +2 -2
  45. package/src/public-cli/judge-run.ts +2 -2
  46. package/src/public-cli/main.ts +25 -3
  47. package/src/public-cli/merger-run.ts +2 -2
  48. package/src/public-cli/option-definitions.ts +1 -1
  49. package/src/public-cli/post-admission.ts +175 -7
  50. package/src/public-cli/process-cancel.ts +75 -0
  51. package/src/public-cli/run-lifecycle.ts +37 -7
  52. package/src/public-cli/settlement.ts +42 -33
  53. package/src/public-cli/terminal.ts +12 -37
  54. package/src/public-role-summons.ts +34 -5
  55. package/src/role-envelope.ts +89 -4
  56. package/src/role-runtime.ts +78 -65
  57. package/src/submission-ledger.ts +63 -21
  58. package/dist/activation-reconciliation.js +0 -61
  59. package/dist/public-cli/command-renderer.js +0 -5
  60. package/dist/public-command-renderer.js +0 -29
  61. package/src/activation-reconciliation.ts +0 -163
  62. package/src/public-cli/command-renderer.ts +0 -9
  63. package/src/public-command-renderer.ts +0 -55
@@ -62,7 +62,7 @@ async function spawnEngineDetourOnce(input) {
62
62
  }
63
63
  const command = input.argv[0];
64
64
  const args = input.argv.slice(1);
65
- return await new Promise((resolve22, reject) => {
65
+ return await new Promise((resolve21, reject) => {
66
66
  let settled = false;
67
67
  const signal = input.signal;
68
68
  const child = spawn(command, args, {
@@ -92,7 +92,7 @@ async function spawnEngineDetourOnce(input) {
92
92
  if (signal !== void 0) {
93
93
  signal.removeEventListener("abort", onAbort);
94
94
  }
95
- resolve22(result);
95
+ resolve21(result);
96
96
  };
97
97
  const onAbort = () => {
98
98
  fail4(signal !== void 0 ? abortReasonError(signal) : new Error("aborted"));
@@ -202,7 +202,6 @@ var activation_ledger_topology_exports = {};
202
202
  __export(activation_ledger_topology_exports, {
203
203
  ActivationLedgerError: () => ActivationLedgerError,
204
204
  activationBookDirectory: () => activationBookDirectory,
205
- activationWaitingLedgerPath: () => activationWaitingLedgerPath,
206
205
  assertLedgerFileInsideHome: () => assertLedgerFileInsideHome,
207
206
  ensureRealDirectoryTree: () => ensureRealDirectoryTree,
208
207
  errnoCode: () => errnoCode,
@@ -265,9 +264,6 @@ function resolveActivationLedgerHomeForPath(path) {
265
264
  function activationBookDirectory(ledgerHome, bookKey) {
266
265
  return join2(ledgerHome, "books", bookKey);
267
266
  }
268
- function activationWaitingLedgerPath(ledgerHome, bookKey) {
269
- return join2(activationBookDirectory(ledgerHome, bookKey), "waiting.jsonl");
270
- }
271
267
  function pathContainedIn(root, candidate) {
272
268
  const rel = relative(root, candidate);
273
269
  return rel !== "" && rel !== ".." && !rel.startsWith(`..${sep}`) && !isAbsolute(rel);
@@ -1807,7 +1803,48 @@ var init_collector_output = __esm({
1807
1803
  });
1808
1804
 
1809
1805
  // src/package-contracts/navigator-output.ts
1806
+ var navigator_output_exports = {};
1807
+ __export(navigator_output_exports, {
1808
+ NAVIGATOR_ACCEPTED_TEXT: () => NAVIGATOR_ACCEPTED_TEXT,
1809
+ NAVIGATOR_OUTPUT_TOOL_NAME: () => NAVIGATOR_OUTPUT_TOOL_NAME,
1810
+ navigatorOutputSchema: () => navigatorOutputSchema,
1811
+ navigatorProseFromUnknown: () => navigatorProseFromUnknown,
1812
+ projectLawfulNavigatorOutput: () => projectLawfulNavigatorOutput,
1813
+ validateRecordedNavigatorOutput: () => validateRecordedNavigatorOutput
1814
+ });
1810
1815
  import { Type as Type5 } from "typebox";
1816
+ function projectLawfulNavigatorOutput(value) {
1817
+ if (value === void 0 || value === null) return void 0;
1818
+ if (typeof value === "string") return { prose: value };
1819
+ if (typeof value === "object" && !Array.isArray(value)) {
1820
+ const record4 = value;
1821
+ if (typeof record4.prose === "string") return { prose: record4.prose };
1822
+ if (record4.prose !== void 0 && record4.prose !== null) {
1823
+ return { prose: typeof record4.prose === "string" ? record4.prose : String(record4.prose) };
1824
+ }
1825
+ const keys = Object.keys(record4);
1826
+ if (keys.length === 0) return { prose: "" };
1827
+ try {
1828
+ return { prose: JSON.stringify(record4) };
1829
+ } catch {
1830
+ return { prose: String(record4) };
1831
+ }
1832
+ }
1833
+ return { prose: String(value) };
1834
+ }
1835
+ function validateRecordedNavigatorOutput(value) {
1836
+ const projected = projectLawfulNavigatorOutput(value);
1837
+ if (projected === void 0) {
1838
+ throw new Error("Navigator output is empty");
1839
+ }
1840
+ return projected;
1841
+ }
1842
+ function navigatorProseFromUnknown(value) {
1843
+ const projected = projectLawfulNavigatorOutput(value);
1844
+ if (projected === void 0) return void 0;
1845
+ const trimmed = projected.prose.trim();
1846
+ return trimmed === "" ? void 0 : projected.prose;
1847
+ }
1811
1848
  var NAVIGATOR_OUTPUT_TOOL_NAME, NAVIGATOR_ACCEPTED_TEXT, navigatorOutputSchema;
1812
1849
  var init_navigator_output = __esm({
1813
1850
  "src/package-contracts/navigator-output.ts"() {
@@ -1819,11 +1856,8 @@ var init_navigator_output = __esm({
1819
1856
  navigatorOutputSchema = withTerminatingOutputDeclarations(
1820
1857
  openToolObject(
1821
1858
  Type5.Object({
1822
- status: Type5.Unknown({
1823
- description: "advice \u2014 \u5F62\u72B6\u6307\u5F15\uFF0C\u975E schema \u95F8"
1824
- }),
1825
- candidates: Type5.Unknown({
1826
- description: "\u6392\u597D\u5E8F\u7684\u8DEF\u7EBF\u5EFA\u8BAE\u6570\u7EC4\uFF0C\u5143\u7D20\u542B next/phase/reason \u2014 \u5F62\u72B6\u6307\u5F15\uFF0C\u975E schema \u95F8"
1859
+ prose: Type5.Unknown({
1860
+ description: "\u6E38\u5955\u4F7F\u6563\u6587\u5EFA\u8BAE\uFF0C\u539F\u6837\u5448\u73B0\u3002\u4E0D\u8981\u6C42 candidates/next \u7B49\u7ED3\u6784\u5316\u5B57\u6BB5\u3002\u5F62\u72B6\u6307\u5F15\uFF0C\u975E schema \u95F8"
1827
1861
  })
1828
1862
  })
1829
1863
  )
@@ -3405,9 +3439,6 @@ ${paths.join("\n")}`
3405
3439
  if (typeof process.env.AK_ROLE_AUDITOR_SUBJECT === "string" && process.env.AK_ROLE_AUDITOR_SUBJECT.trim() !== "") {
3406
3440
  env.AK_ROLE_AUDITOR_SUBJECT = process.env.AK_ROLE_AUDITOR_SUBJECT;
3407
3441
  }
3408
- if (request.correlationId !== void 0 && request.correlationId.trim() !== "") {
3409
- env.AK_CORRELATION_ID = request.correlationId;
3410
- }
3411
3442
  if (config.recordLaunchedRolePackageIdentity !== void 0 && config.observeLaunchedRolePackageIdentity !== void 0) {
3412
3443
  await config.recordLaunchedRolePackageIdentity(
3413
3444
  request.runDirectory,
@@ -4754,7 +4785,7 @@ function normalizeReviewComment(raw) {
4754
4785
  function createGhApiRunner(options = {}) {
4755
4786
  const spawnImpl = options.spawnImpl ?? spawn3;
4756
4787
  return async (args, runOptions = {}) => {
4757
- return await new Promise((resolve22, reject) => {
4788
+ return await new Promise((resolve21, reject) => {
4758
4789
  const signal = runOptions.signal;
4759
4790
  if (signal?.aborted) {
4760
4791
  reject(signal.reason ?? new Error("aborted"));
@@ -4827,11 +4858,11 @@ function createGhApiRunner(options = {}) {
4827
4858
  const value = line2.slice(idx + 1).trim();
4828
4859
  headers[name] = value;
4829
4860
  }
4830
- resolve22({ status, headers, bodyText });
4861
+ resolve21({ status, headers, bodyText });
4831
4862
  return;
4832
4863
  }
4833
4864
  if (code === 0) {
4834
- resolve22({ status: 200, headers: {}, bodyText: stdout });
4865
+ resolve21({ status: 200, headers: {}, bodyText: stdout });
4835
4866
  return;
4836
4867
  }
4837
4868
  const failure2 = new Error(
@@ -5420,6 +5451,56 @@ var init_typed_provider_http = __esm({
5420
5451
  });
5421
5452
 
5422
5453
  // src/public-cli/run-lifecycle.ts
5454
+ var run_lifecycle_exports = {};
5455
+ __export(run_lifecycle_exports, {
5456
+ AUTO_RESUME_LIMIT: () => AUTO_RESUME_LIMIT,
5457
+ GATE_DOSSIER_POINTER_PREFIX: () => GATE_DOSSIER_POINTER_PREFIX,
5458
+ RESUME_TRANSPORT_ENVELOPE: () => RESUME_TRANSPORT_ENVELOPE,
5459
+ RunWriterLeaseHeldError: () => RunWriterLeaseHeldError,
5460
+ V1_RESUMABLE_PROVIDERS: () => V1_RESUMABLE_PROVIDERS,
5461
+ acquireRunWriterLease: () => acquireRunWriterLease,
5462
+ autopsyWriterLock: () => autopsyWriterLock,
5463
+ buildAutoResumeContinuationPrompt: () => buildAutoResumeContinuationPrompt,
5464
+ buildResumeContinuationPrompt: () => buildResumeContinuationPrompt,
5465
+ clearCurrentCourt: () => clearCurrentCourt,
5466
+ clearTypedProviderHttpObservation: () => clearTypedProviderHttpObservation,
5467
+ describeErrorIdentity: () => describeErrorIdentity,
5468
+ findLatestRunIdForSeatTicket: () => findLatestRunIdForSeatTicket,
5469
+ findRunDirectoryById: () => findRunDirectoryById,
5470
+ isDurablePrincipalAvailable: () => isDurablePrincipalAvailable,
5471
+ isV1ResumableProvider: () => isV1ResumableProvider,
5472
+ loadResumableCoderRun: () => loadResumableCoderRun,
5473
+ loadResumableCollectorRun: () => loadResumableCollectorRun,
5474
+ loadResumableCountersignRun: () => loadResumableCountersignRun,
5475
+ loadResumableDiaristRun: () => loadResumableDiaristRun,
5476
+ loadResumableDoctorRun: () => loadResumableDoctorRun,
5477
+ loadResumableFixerRun: () => loadResumableFixerRun,
5478
+ loadResumableGleanerLeftRun: () => loadResumableGleanerLeftRun,
5479
+ loadResumableInspectorRun: () => loadResumableInspectorRun,
5480
+ loadResumableInstructionSeatRun: () => loadResumableInstructionSeatRun,
5481
+ loadResumableJudgeRun: () => loadResumableJudgeRun,
5482
+ loadResumableMergerRun: () => loadResumableMergerRun,
5483
+ loadResumableNotaryRun: () => loadResumableNotaryRun,
5484
+ loadResumableReviewerRun: () => loadResumableReviewerRun,
5485
+ loadResumableSecretariatRun: () => loadResumableSecretariatRun,
5486
+ markRunAdmitted: () => markRunAdmitted,
5487
+ markRunResumable: () => markRunResumable,
5488
+ markRunRunning: () => markRunRunning,
5489
+ markRunTerminal: () => markRunTerminal,
5490
+ parentRunPathFromGatePointerInstruction: () => parentRunPathFromGatePointerInstruction,
5491
+ peekRoleRunRole: () => peekRoleRunRole,
5492
+ readCurrentCourt: () => readCurrentCourt,
5493
+ readLatestTypedProviderHttpObservation: () => readLatestTypedProviderHttpObservation,
5494
+ readRoleRunIdentity: () => readRoleRunIdentity,
5495
+ readRoleRunState: () => readRoleRunState,
5496
+ readRunParentPath: () => readRunParentPath,
5497
+ readTypedHttp429Observation: () => readTypedHttp429Observation,
5498
+ recordCurrentCourt: () => recordCurrentCourt,
5499
+ recordTypedProviderHttpStatus: () => recordTypedProviderHttpStatus,
5500
+ renderResumeCommand: () => renderResumeCommand,
5501
+ selectResumeContinuationPrompt: () => selectResumeContinuationPrompt,
5502
+ writeRoleRunState: () => writeRoleRunState
5503
+ });
5423
5504
  import { chmod, lstat as lstat2, open, readdir as readdir4, readFile as readFile9, unlink as unlink2, writeFile as writeFile4 } from "node:fs/promises";
5424
5505
  import { basename as basename4, join as join15 } from "node:path";
5425
5506
  function selectResumeContinuationPrompt(message, engineMaterial) {
@@ -5435,6 +5516,15 @@ function buildResumeContinuationPrompt(options) {
5435
5516
  })
5436
5517
  );
5437
5518
  }
5519
+ function buildAutoResumeContinuationPrompt(options) {
5520
+ return selectResumeContinuationPrompt(
5521
+ RESUME_TRANSPORT_ENVELOPE,
5522
+ engineSessionMaterialFromOptions({
5523
+ packageRoot: options.packageRoot,
5524
+ ...pickEngineAxis(options)
5525
+ })
5526
+ );
5527
+ }
5438
5528
  function isV1ResumableProvider(provider) {
5439
5529
  return V1_RESUMABLE_PROVIDERS.includes(provider);
5440
5530
  }
@@ -5598,6 +5688,11 @@ function materializeRoleRunFromDisk(disk, authority) {
5598
5688
  return void 0;
5599
5689
  }
5600
5690
  }
5691
+ async function readRoleRunState(runDirectory, authority) {
5692
+ const disk = await readRoleRunStateDisk(runDirectory);
5693
+ if (disk === void 0) return void 0;
5694
+ return materializeRoleRunFromDisk(disk, authority)?.run;
5695
+ }
5601
5696
  async function readRoleRunIdentity(runDirectory) {
5602
5697
  const disk = await readRoleRunStateDisk(runDirectory);
5603
5698
  if (disk === void 0) return void 0;
@@ -6331,6 +6426,75 @@ async function loadResumableJudgeRun(home, runId, authority) {
6331
6426
  };
6332
6427
  return seatLoadedResult(loaded, admitted);
6333
6428
  }
6429
+ async function loadResumableCoderRun(home, runId, authority) {
6430
+ const loaded = await loadResumableRunRecord(home, runId, authority);
6431
+ if (loaded.run.role !== "coder") {
6432
+ throw new CliUsageError(
6433
+ `role run ${runId} belongs to ${loaded.run.role}, not coder`
6434
+ );
6435
+ }
6436
+ const phase = loaded.admittedFields.phase ?? loaded.run.phase;
6437
+ if (phase !== "plan" && phase !== "apply") {
6438
+ throw new CliUsageError(
6439
+ `role run admitted coder phase is missing: ${runId}`
6440
+ );
6441
+ }
6442
+ const taskPath = loaded.admittedFields.taskPath;
6443
+ if (taskPath === void 0) {
6444
+ throw new CliUsageError(
6445
+ `role run admitted coder task path is missing: ${runId}`
6446
+ );
6447
+ }
6448
+ if (loaded.admittedFields.instruction.trim() === "") {
6449
+ throw new CliUsageError(
6450
+ `role run admitted coder task is blank: ${runId}`
6451
+ );
6452
+ }
6453
+ const admitted = {
6454
+ role: "coder",
6455
+ phase,
6456
+ ...resumedBaseAdmitted(loaded),
6457
+ instructionEmpty: false,
6458
+ taskPath
6459
+ };
6460
+ return seatLoadedResult(loaded, admitted);
6461
+ }
6462
+ async function loadResumableFixerRun(home, runId, authority) {
6463
+ const loaded = await loadResumableRunRecord(home, runId, authority);
6464
+ if (loaded.run.role !== "fixer") {
6465
+ throw new CliUsageError(
6466
+ `role run ${runId} belongs to ${loaded.run.role}, not fixer`
6467
+ );
6468
+ }
6469
+ const phase = loaded.admittedFields.phase ?? loaded.run.phase;
6470
+ if (phase !== "plan" && phase !== "apply") {
6471
+ throw new CliUsageError(
6472
+ `role run admitted fixer phase is missing: ${runId}`
6473
+ );
6474
+ }
6475
+ const packetPath = loaded.admittedFields.packetPath;
6476
+ if (packetPath === void 0) {
6477
+ throw new CliUsageError(
6478
+ `role run admitted fixer packet path is missing: ${runId}`
6479
+ );
6480
+ }
6481
+ if (loaded.admittedFields.instruction.trim() === "") {
6482
+ throw new CliUsageError(
6483
+ `role run admitted fixer instruction is blank: ${runId}`
6484
+ );
6485
+ }
6486
+ const prerequisites = loaded.admittedFields.prerequisites ?? Object.freeze([]);
6487
+ const admitted = {
6488
+ role: "fixer",
6489
+ phase,
6490
+ ...resumedBaseAdmitted(loaded),
6491
+ instructionEmpty: false,
6492
+ packetPath,
6493
+ ...loaded.admittedFields.prerequisitesPath === void 0 ? {} : { prerequisitesPath: loaded.admittedFields.prerequisitesPath },
6494
+ prerequisites
6495
+ };
6496
+ return seatLoadedResult(loaded, admitted);
6497
+ }
6334
6498
  async function loadResumableReviewerRun(home, runId, authority) {
6335
6499
  const loaded = await loadResumableRunRecord(home, runId, authority);
6336
6500
  if (loaded.run.role !== "reviewer") {
@@ -6404,6 +6568,26 @@ async function loadResumableInstructionSeatRun(home, runId, authority) {
6404
6568
  };
6405
6569
  return seatLoadedResult(loaded, admitted);
6406
6570
  }
6571
+ async function loadResumableGleanerLeftRun(home, runId, authority) {
6572
+ const loaded = await loadResumableRunRecord(home, runId, authority);
6573
+ if (loaded.run.role !== "gleaner-left") {
6574
+ throw new CliUsageError(
6575
+ `role run ${runId} belongs to ${loaded.run.role}, not gleaner-left`
6576
+ );
6577
+ }
6578
+ const baseRevision = loaded.admittedFields.baseRevision;
6579
+ if (baseRevision === void 0 || baseRevision.trim() === "") {
6580
+ throw new CliUsageError(
6581
+ `role run admitted gleaner-left base revision is missing: ${runId}`
6582
+ );
6583
+ }
6584
+ const admitted = {
6585
+ role: "gleaner-left",
6586
+ ...resumedBaseAdmitted(loaded),
6587
+ baseRevision
6588
+ };
6589
+ return seatLoadedResult(loaded, admitted);
6590
+ }
6407
6591
  async function loadResumableDiaristRun(home, runId, authority) {
6408
6592
  const loaded = await loadResumableRunRecord(home, runId, authority);
6409
6593
  if (loaded.run.role !== "diarist") {
@@ -6417,6 +6601,88 @@ async function loadResumableDiaristRun(home, runId, authority) {
6417
6601
  };
6418
6602
  return seatLoadedResult(loaded, admitted);
6419
6603
  }
6604
+ async function loadResumableSecretariatRun(home, runId, authority) {
6605
+ const loaded = await loadResumableRunRecord(home, runId, authority);
6606
+ if (loaded.run.role !== "secretariat") {
6607
+ throw new CliUsageError(
6608
+ `role run ${runId} belongs to ${loaded.run.role}, not secretariat`
6609
+ );
6610
+ }
6611
+ const admitted = {
6612
+ role: "secretariat",
6613
+ ...resumedBaseAdmitted(loaded)
6614
+ };
6615
+ return seatLoadedResult(loaded, admitted);
6616
+ }
6617
+ async function loadResumableMergerRun(home, runId, authority) {
6618
+ const loaded = await loadResumableRunRecord(home, runId, authority);
6619
+ if (loaded.run.role !== "merger") {
6620
+ throw new CliUsageError(
6621
+ `role run ${runId} belongs to ${loaded.run.role}, not merger`
6622
+ );
6623
+ }
6624
+ const mergerInputPath = loaded.admittedFields.mergerInputPath;
6625
+ if (mergerInputPath === void 0) {
6626
+ throw new CliUsageError(
6627
+ `role run admitted merger input path is missing: ${runId}`
6628
+ );
6629
+ }
6630
+ const derived = loaded.admittedFields.derived;
6631
+ if (derived === void 0) {
6632
+ throw new CliUsageError(
6633
+ `role run admitted merger envelope is missing: ${runId}`
6634
+ );
6635
+ }
6636
+ if (loaded.admittedFields.instruction.trim() === "") {
6637
+ throw new CliUsageError(
6638
+ `role run admitted merger task is blank: ${runId}`
6639
+ );
6640
+ }
6641
+ const admitted = {
6642
+ role: "merger",
6643
+ ...resumedBaseAdmitted(loaded),
6644
+ instructionEmpty: false,
6645
+ mergerInputPath,
6646
+ derived
6647
+ };
6648
+ return seatLoadedResult(loaded, admitted);
6649
+ }
6650
+ async function loadResumableCollectorRun(home, runId, authority) {
6651
+ const loaded = await loadResumableRunRecord(home, runId, authority);
6652
+ if (loaded.run.role !== "collector") {
6653
+ throw new CliUsageError(
6654
+ `role run ${runId} belongs to ${loaded.run.role}, not collector`
6655
+ );
6656
+ }
6657
+ const { prNumber, repository, repositoryDisplay, manifestDigest } = loaded.admittedFields;
6658
+ if (repository === void 0 || repositoryDisplay === void 0 || manifestDigest === void 0) {
6659
+ throw new CliUsageError(
6660
+ `role run admitted collector repository identity is missing: ${runId}`
6661
+ );
6662
+ }
6663
+ let parsedRepository;
6664
+ try {
6665
+ parsedRepository = parseCollectorRepository(repositoryDisplay);
6666
+ } catch (error) {
6667
+ const detail = error instanceof Error ? error.message : String(error);
6668
+ throw new CliUsageError(detail, { cause: error });
6669
+ }
6670
+ if (parsedRepository.canonical !== repository) {
6671
+ throw new CliUsageError(
6672
+ `role run admitted collector repository does not match its canonical form: ${runId}`
6673
+ );
6674
+ }
6675
+ const admitted = {
6676
+ role: "collector",
6677
+ ...resumedBaseAdmitted(loaded),
6678
+ ...prNumber === void 0 ? {} : { prNumber },
6679
+ repository: parsedRepository,
6680
+ ...loaded.admittedFields.requestManifestPath === void 0 ? {} : { requestManifestPath: loaded.admittedFields.requestManifestPath },
6681
+ ...loaded.admittedFields.waitWindowMs === void 0 ? {} : { waitWindowMs: loaded.admittedFields.waitWindowMs },
6682
+ manifestDigest
6683
+ };
6684
+ return seatLoadedResult(loaded, admitted);
6685
+ }
6420
6686
  async function loadResumableDoctorRun(home, runId, authority) {
6421
6687
  const loaded = await loadResumableRunRecord(home, runId, authority);
6422
6688
  if (loaded.run.role !== "doctor") {
@@ -6474,6 +6740,12 @@ async function loadResumableInspectorRun(home, runId, authority) {
6474
6740
  };
6475
6741
  return seatLoadedResult(loaded, admitted);
6476
6742
  }
6743
+ async function peekRoleRunRole(home, runId) {
6744
+ const runDirectory = await findRunDirectoryById(home, runId);
6745
+ if (runDirectory === void 0) return void 0;
6746
+ const run = await readRoleRunIdentity(runDirectory);
6747
+ return run?.role;
6748
+ }
6477
6749
  var V1_RESUMABLE_PROVIDERS, AUTO_RESUME_LIMIT, RESUME_TRANSPORT_ENVELOPE, RUN_STATE_FILE, WRITER_LOCK_FILE, RunWriterLeaseHeldError, WRITER_LEASE_RECLAIM_ROUNDS, GATE_DOSSIER_POINTER_PREFIX;
6478
6750
  var init_run_lifecycle = __esm({
6479
6751
  "src/public-cli/run-lifecycle.ts"() {
@@ -6490,7 +6762,7 @@ var init_run_lifecycle = __esm({
6490
6762
  init_invocation();
6491
6763
  V1_RESUMABLE_PROVIDERS = ["openai-codex", "xai"];
6492
6764
  AUTO_RESUME_LIMIT = 2;
6493
- RESUME_TRANSPORT_ENVELOPE = "[ak-role:resume-continue]";
6765
+ RESUME_TRANSPORT_ENVELOPE = "\u7EE7\u7EED\u3002";
6494
6766
  RUN_STATE_FILE = "run-state.json";
6495
6767
  WRITER_LOCK_FILE = "writer.lock";
6496
6768
  RunWriterLeaseHeldError = class extends Error {
@@ -7545,7 +7817,7 @@ var init_option_definitions = __esm({
7545
7817
  },
7546
7818
  navigator: {
7547
7819
  command: "navigator",
7548
- summary: "Direct Navigator (\u6E38\u5955\u4F7F) route advice: ordered next-role candidates.",
7820
+ summary: "Direct Navigator (\u6E38\u5955\u4F7F) free-form prose route advice.",
7549
7821
  usage: ["ak-role navigator [options] [instruction]"],
7550
7822
  examples: [
7551
7823
  'ak-role navigator "\u521A\u5B8C\u6210 coder apply \u6536\u655B\uFF0C\u4E0B\u4E00\u6B65\uFF1F"'
@@ -11835,31 +12107,58 @@ async function restoreState(cwd, runId, scope) {
11835
12107
  }, 0)
11836
12108
  };
11837
12109
  }
12110
+ function sessionParentFromHostContext(context) {
12111
+ const runDirectory = runDirectoryFromHostContext(context);
12112
+ if (runDirectory !== void 0) return join24(runDirectory, "session", "session.jsonl");
12113
+ const sessionFile = context.sessionManager.getSessionFile?.();
12114
+ if (typeof sessionFile === "string" && sessionFile.length > 0) return sessionFile;
12115
+ const sessionDir = context.sessionManager.getSessionDir?.();
12116
+ if (typeof sessionDir === "string" && sessionDir.length > 0) {
12117
+ return join24(sessionDir, "session.jsonl");
12118
+ }
12119
+ return void 0;
12120
+ }
12121
+ function homeFromHostContext(context, home) {
12122
+ if (home !== void 0) return home;
12123
+ const sessionParent = sessionParentFromHostContext(context);
12124
+ return sessionParent !== void 0 ? tryHomeFromAkRolesPath(sessionParent) : void 0;
12125
+ }
12126
+ async function sealAcceptedSubmission(options) {
12127
+ const runId = runIdentity(options.context);
12128
+ const attemptId = attemptIdentity(options.context, runId);
12129
+ const sessionParent = sessionParentFromHostContext(options.context);
12130
+ const home = homeFromHostContext(options.context, options.home);
12131
+ const state = await restoreState(options.context.cwd, runId, {
12132
+ ...home === void 0 ? {} : { home },
12133
+ ...sessionParent === void 0 ? {} : { sessionParent }
12134
+ });
12135
+ const pointer = sitianReport({
12136
+ level: "event",
12137
+ kind: "sealed",
12138
+ subject: { runId, attemptId },
12139
+ ...state.prior === void 0 ? {} : { priorEventId: state.prior.identity },
12140
+ payload: {
12141
+ type: "sealed",
12142
+ attemptId,
12143
+ toolCallId: options.toolCallId,
12144
+ role: options.role,
12145
+ accepted: options.accepted
12146
+ },
12147
+ source: "role-runtime",
12148
+ cwd: options.context.cwd,
12149
+ ...home !== void 0 ? { home } : {},
12150
+ ...sessionParent === void 0 ? {} : { sessionParent }
12151
+ });
12152
+ state.prior = pointer;
12153
+ }
11838
12154
  function createSubmissionLedgerHost(host, outputTools, failInfrastructure2 = (error) => {
11839
12155
  throw error;
11840
12156
  }, projectClosure = () => void 0, options) {
11841
12157
  const states = /* @__PURE__ */ new Map();
11842
- const sessionParentFromContext = (context) => {
11843
- const runDirectory = runDirectoryFromHostContext(context);
11844
- if (runDirectory !== void 0) {
11845
- return join24(runDirectory, "session", "session.jsonl");
11846
- }
11847
- const sessionFile = context.sessionManager.getSessionFile?.();
11848
- if (typeof sessionFile === "string" && sessionFile.length > 0) return sessionFile;
11849
- const sessionDir = context.sessionManager.getSessionDir?.();
11850
- if (typeof sessionDir === "string" && sessionDir.length > 0) {
11851
- return join24(sessionDir, "session.jsonl");
11852
- }
11853
- return void 0;
11854
- };
11855
- const resolveHomeFromContext = (context) => {
11856
- if (options?.home !== void 0) return options.home;
11857
- const sessionParent = sessionParentFromContext(context);
11858
- return sessionParent !== void 0 ? tryHomeFromAkRolesPath(sessionParent) : void 0;
11859
- };
12158
+ const resolveHomeFromContext = (context) => homeFromHostContext(context, options?.home);
11860
12159
  const stateFor = (context, runId) => states.get(runId) ?? (() => {
11861
12160
  const home = resolveHomeFromContext(context);
11862
- const sessionParent = sessionParentFromContext(context);
12161
+ const sessionParent = sessionParentFromHostContext(context);
11863
12162
  const pending = restoreState(context.cwd, runId, {
11864
12163
  ...home === void 0 ? {} : { home },
11865
12164
  ...sessionParent === void 0 ? {} : { sessionParent }
@@ -11869,7 +12168,7 @@ function createSubmissionLedgerHost(host, outputTools, failInfrastructure2 = (er
11869
12168
  })();
11870
12169
  const appendFor = (state, context, runId, attemptId, event) => {
11871
12170
  const home = resolveHomeFromContext(context);
11872
- const sessionParent = sessionParentFromContext(context);
12171
+ const sessionParent = sessionParentFromHostContext(context);
11873
12172
  const pointer = sitianReport({
11874
12173
  level: "event",
11875
12174
  kind: event.type,
@@ -12312,12 +12611,12 @@ function createSystemCollectorClock() {
12312
12611
  return {
12313
12612
  wallNow: () => /* @__PURE__ */ new Date(),
12314
12613
  monoNow: () => Number(process.hrtime.bigint() - start) / 1e6,
12315
- sleep: (ms, signal) => new Promise((resolve22, reject) => {
12614
+ sleep: (ms, signal) => new Promise((resolve21, reject) => {
12316
12615
  if (signal?.aborted) {
12317
12616
  reject(signal.reason ?? new Error("aborted"));
12318
12617
  return;
12319
12618
  }
12320
- const timer = setTimeout(resolve22, ms);
12619
+ const timer = setTimeout(resolve21, ms);
12321
12620
  const onAbort = () => {
12322
12621
  clearTimeout(timer);
12323
12622
  reject(signal?.reason ?? new Error("aborted"));
@@ -14197,44 +14496,6 @@ var init_receipt_delivery_policy = __esm({
14197
14496
  }
14198
14497
  });
14199
14498
 
14200
- // src/public-command-renderer.ts
14201
- function isPublicCallableRole2(role) {
14202
- return PUBLIC_CALLABLE_ROLES3.has(role);
14203
- }
14204
- function renderPublicAkRoleCommand(target) {
14205
- if (!isPublicCallableRole2(target.role)) return void 0;
14206
- const role = target.role;
14207
- const metadata = packagedRoleMetadata(role);
14208
- if (metadata !== void 0 && "bareCommand" in metadata && metadata.bareCommand === false) {
14209
- return void 0;
14210
- }
14211
- if (target.phase === null || target.phase === void 0) {
14212
- return `ak-role ${role}`;
14213
- }
14214
- if (role === "coder" || role === "fixer") {
14215
- return `ak-role ${role} ${target.phase}`;
14216
- }
14217
- return `ak-role ${role}`;
14218
- }
14219
- var PUBLIC_CALLABLE_ROLES3;
14220
- var init_public_command_renderer = __esm({
14221
- "src/public-command-renderer.ts"() {
14222
- "use strict";
14223
- init_packaged_role_registry();
14224
- PUBLIC_CALLABLE_ROLES3 = new Set(
14225
- PACKAGED_ROLE_REGISTRY.map((entry) => entry.role)
14226
- );
14227
- }
14228
- });
14229
-
14230
- // src/public-cli/command-renderer.ts
14231
- var init_command_renderer = __esm({
14232
- "src/public-cli/command-renderer.ts"() {
14233
- "use strict";
14234
- init_public_command_renderer();
14235
- }
14236
- });
14237
-
14238
14499
  // src/public-cli/terminal.ts
14239
14500
  function encodeTerminalField(value) {
14240
14501
  return JSON.stringify(value);
@@ -14245,14 +14506,10 @@ function isLawfulTypedTerminalOutcome(outcome) {
14245
14506
  function exitCodeForTerminalOutcome(outcome) {
14246
14507
  return isLawfulTypedTerminalOutcome(outcome) ? 0 : 1;
14247
14508
  }
14248
- function recommendationNavigatorFact(input) {
14249
- const command = typeof input.modelCommand === "string" && input.modelCommand.trim() !== "" ? input.modelCommand : isPublicCallableRole2(input.next.role) ? renderPublicAkRoleCommand(input.next) : void 0;
14509
+ function adviceNavigatorFact(input) {
14250
14510
  return {
14251
- disposition: "recommendation",
14252
- next: input.next,
14253
- reason: input.reason,
14254
- ...command === void 0 ? {} : { command },
14255
- ...input.route === void 0 ? {} : { route: input.route },
14511
+ disposition: "advice",
14512
+ prose: input.prose,
14256
14513
  ...input.advisoryDiagnostic === void 0 ? {} : { advisoryDiagnostic: input.advisoryDiagnostic }
14257
14514
  };
14258
14515
  }
@@ -14280,14 +14537,8 @@ function formatTerminalResult(result) {
14280
14537
  if (result.navigator.advisoryDiagnostic !== void 0) {
14281
14538
  lines.push(`navigator-advisory ${encodeTerminalField(result.navigator.advisoryDiagnostic)}`);
14282
14539
  }
14283
- if (result.navigator.disposition === "recommendation") {
14284
- lines.push(
14285
- `next ${result.navigator.next.role} ${result.navigator.next.phase ?? "none"}`
14286
- );
14287
- lines.push(`reason ${encodeTerminalField(result.navigator.reason)}`);
14288
- if (result.navigator.command !== void 0) {
14289
- lines.push(`command ${encodeTerminalField(result.navigator.command)}`);
14290
- }
14540
+ if (result.navigator.disposition === "advice") {
14541
+ lines.push(`prose ${encodeTerminalField(result.navigator.prose)}`);
14291
14542
  } else if (result.navigator.disposition === "unavailable") {
14292
14543
  lines.push(
14293
14544
  `unavailable ${result.navigator.source} ${encodeTerminalField(result.navigator.reason)}`
@@ -14336,7 +14587,6 @@ function formatTerminalResult(result) {
14336
14587
  var init_terminal = __esm({
14337
14588
  "src/public-cli/terminal.ts"() {
14338
14589
  "use strict";
14339
- init_command_renderer();
14340
14590
  }
14341
14591
  });
14342
14592
 
@@ -15316,10 +15566,6 @@ async function appendRunAttemptHistory(source, outcome) {
15316
15566
  } catch {
15317
15567
  }
15318
15568
  }
15319
- function navigatorPhaseValue(value) {
15320
- if (value === "plan" || value === "apply") return value;
15321
- return null;
15322
- }
15323
15569
  function navigatorAttendanceCorrelatedWithBoundMarker(details, attendanceIndex, terminalIndex, marker) {
15324
15570
  if (attendanceIndex <= terminalIndex) return false;
15325
15571
  if (details.invocationId !== marker.invocationId) return false;
@@ -15328,29 +15574,33 @@ function navigatorAttendanceCorrelatedWithBoundMarker(details, attendanceIndex,
15328
15574
  function parseNavigatorAttendanceDetails(details) {
15329
15575
  const disposition = details.disposition;
15330
15576
  const advisoryDiagnostic = typeof details.routePlaybookReadFailure === "string" ? { advisoryDiagnostic: details.routePlaybookReadFailure } : {};
15331
- if (disposition === "recommendation") {
15332
- const next = details.next;
15333
- if (!isRecord11(next) || typeof next.role !== "string") {
15577
+ if (disposition === "advice" || disposition === "recommendation") {
15578
+ let prose;
15579
+ if (typeof details.prose === "string" && details.prose.trim() !== "") {
15580
+ prose = details.prose;
15581
+ } else {
15582
+ const next = isRecord11(details.next) && typeof details.next.role === "string" ? details.next.role : void 0;
15583
+ const reason = typeof details.reason === "string" && details.reason.trim() !== "" ? details.reason : void 0;
15584
+ const command = typeof details.command === "string" && details.command.trim() !== "" ? details.command : void 0;
15585
+ if (reason !== void 0 && next !== void 0) {
15586
+ prose = `${reason}\uFF08\u4E0B\u4E00\u6B65\uFF1A${next}\uFF09`;
15587
+ } else if (reason !== void 0) {
15588
+ prose = reason;
15589
+ } else if (next !== void 0) {
15590
+ prose = `\u4E0B\u4E00\u6B65\uFF1A${next}`;
15591
+ } else if (command !== void 0) {
15592
+ prose = command;
15593
+ }
15594
+ }
15595
+ if (prose === void 0 || prose.trim() === "") {
15334
15596
  return {
15335
- disposition: "unavailable",
15336
- source: "unknown",
15337
- reason: "navigator recommendation missing typed next role"
15597
+ disposition: "no-advice",
15598
+ ...advisoryDiagnostic
15338
15599
  };
15339
15600
  }
15340
- const reason = typeof details.reason === "string" ? details.reason : "";
15341
- const route = Array.isArray(details.route) ? details.route.filter(isRecord11).map((target) => ({
15342
- role: String(target.role),
15343
- phase: navigatorPhaseValue(target.phase)
15344
- })) : void 0;
15345
- return recommendationNavigatorFact({
15346
- ...advisoryDiagnostic,
15347
- next: {
15348
- role: next.role,
15349
- phase: navigatorPhaseValue(next.phase)
15350
- },
15351
- reason,
15352
- ...route === void 0 ? {} : { route },
15353
- ...typeof details.command === "string" ? { modelCommand: details.command } : {}
15601
+ return adviceNavigatorFact({
15602
+ prose,
15603
+ ...advisoryDiagnostic
15354
15604
  });
15355
15605
  }
15356
15606
  if (disposition === "unavailable") {
@@ -16776,10 +17026,10 @@ function presentFailureTerminal(terminal, io) {
16776
17026
  }
16777
17027
  function defaultNavigatorGraceSleep() {
16778
17028
  let timer;
16779
- const sleep = ((ms) => new Promise((resolve22) => {
17029
+ const sleep = ((ms) => new Promise((resolve21) => {
16780
17030
  timer = setTimeout(() => {
16781
17031
  timer = void 0;
16782
- resolve22();
17032
+ resolve21();
16783
17033
  }, ms);
16784
17034
  }));
16785
17035
  sleep.cancel = () => {
@@ -16791,7 +17041,7 @@ function defaultNavigatorGraceSleep() {
16791
17041
  return sleep;
16792
17042
  }
16793
17043
  function raceNavigatorGrace(work, graceMs = NAVIGATOR_POST_ROLE_GRACE_MS, sleep = defaultNavigatorGraceSleep()) {
16794
- return new Promise((resolve22, reject) => {
17044
+ return new Promise((resolve21, reject) => {
16795
17045
  let settled = false;
16796
17046
  const finish = (action) => {
16797
17047
  if (settled) return;
@@ -16800,11 +17050,11 @@ function raceNavigatorGrace(work, graceMs = NAVIGATOR_POST_ROLE_GRACE_MS, sleep
16800
17050
  action();
16801
17051
  };
16802
17052
  void work.then(
16803
- (value) => finish(() => resolve22({ status: "done", value })),
17053
+ (value) => finish(() => resolve21({ status: "done", value })),
16804
17054
  (error) => finish(() => reject(error))
16805
17055
  );
16806
17056
  void sleep(graceMs).then(() => {
16807
- finish(() => resolve22({ status: "timeout" }));
17057
+ finish(() => resolve21({ status: "timeout" }));
16808
17058
  });
16809
17059
  });
16810
17060
  }
@@ -17810,6 +18060,24 @@ var init_public_run_credentials = __esm({
17810
18060
  }
17811
18061
  });
17812
18062
 
18063
+ // src/public-cli/process-cancel.ts
18064
+ function processCancelSignalName(signal) {
18065
+ if (signal === void 0 || signal.aborted !== true) return void 0;
18066
+ const reason = signal.reason;
18067
+ if (reason === "SIGTERM" || reason === "SIGINT" || reason === "SIGHUP") {
18068
+ return reason;
18069
+ }
18070
+ return void 0;
18071
+ }
18072
+ function processCancelDiagnostic(signalName) {
18073
+ return `ak-role terminated by ${signalName}`;
18074
+ }
18075
+ var init_process_cancel = __esm({
18076
+ "src/public-cli/process-cancel.ts"() {
18077
+ "use strict";
18078
+ }
18079
+ });
18080
+
17813
18081
  // src/public-cli/auto-resume.ts
17814
18082
  import { constants as fsConstants2 } from "node:fs";
17815
18083
  import { randomUUID as randomUUID5 } from "node:crypto";
@@ -18112,6 +18380,10 @@ async function runWithAutoResumeLoop(options) {
18112
18380
  if (terminal !== void 0) presentTerminal(terminal, options.io);
18113
18381
  return result;
18114
18382
  }
18383
+ if (processCancelSignalName(options.signal) !== void 0) {
18384
+ if (terminal !== void 0) presentTerminal(terminal, options.io);
18385
+ return result;
18386
+ }
18115
18387
  }
18116
18388
  if (result !== void 0) {
18117
18389
  const terminal = result.terminal;
@@ -18145,6 +18417,28 @@ async function runWithAutoResumeLoop(options) {
18145
18417
  terminal
18146
18418
  };
18147
18419
  }
18420
+ const cancelName = processCancelSignalName(options.signal);
18421
+ if (cancelName !== void 0) {
18422
+ const terminal = await attachDispatchExceptionTerminal(
18423
+ options.admitted,
18424
+ dispatchExceptionFailureTerminal({
18425
+ role: options.admitted.role,
18426
+ runId: options.admitted.runId,
18427
+ causeError: lastThrownError,
18428
+ errorFiles: retainedErrorFiles,
18429
+ autoResumeAttempts,
18430
+ endReason: `ak-role terminated by ${cancelName}`,
18431
+ everyAttemptThrew
18432
+ }),
18433
+ options.io
18434
+ );
18435
+ await finalizeExceptionRunBestEffort(options.admitted.runDirectory, options.io);
18436
+ presentTerminal(terminal, options.io);
18437
+ return {
18438
+ exitCode: 1,
18439
+ terminal
18440
+ };
18441
+ }
18148
18442
  if (!await isPrincipalAvailable(options.admitted.principal)) {
18149
18443
  const terminal = await attachDispatchExceptionTerminal(
18150
18444
  options.admitted,
@@ -18181,6 +18475,7 @@ var init_auto_resume = __esm({
18181
18475
  init_role_run_placement();
18182
18476
  init_run_lifecycle();
18183
18477
  init_config();
18478
+ init_process_cancel();
18184
18479
  init_terminal();
18185
18480
  init_settlement();
18186
18481
  dummyIo = { stdout: () => {
@@ -18213,6 +18508,36 @@ function describeCaughtError(error) {
18213
18508
  function isStationChildOfficerDialogue(role, env) {
18214
18509
  return env.stationChild === true && isOfficerReviewSeat(role);
18215
18510
  }
18511
+ function withProcessCancelSkipAutoResume(result, signal) {
18512
+ if (processCancelSignalName(signal) === void 0) {
18513
+ return result;
18514
+ }
18515
+ return { ...result, skipAutoResume: true };
18516
+ }
18517
+ async function settleProcessCancelAfterTurn(input) {
18518
+ const failed = await settleAfterTurnStarted(
18519
+ input.admitted,
18520
+ withEngineDetourInvocationScope(
18521
+ {
18522
+ timedOut: input.result.timedOut,
18523
+ code: input.result.code,
18524
+ stderr: input.result.stderr,
18525
+ knownDiagnostic: processCancelDiagnostic(input.cancelName)
18526
+ },
18527
+ input.invocationScopeId
18528
+ ),
18529
+ input.adapters,
18530
+ input.env.principalAuthority,
18531
+ input.io,
18532
+ input.persistRunState
18533
+ );
18534
+ return {
18535
+ ...failed,
18536
+ turnDispatched: true,
18537
+ skipAutoResume: true,
18538
+ ...input.deferredPersist
18539
+ };
18540
+ }
18216
18541
  function withOnceSuccessfulBeforeDispatch(adapters) {
18217
18542
  const hook = adapters.beforeDispatch;
18218
18543
  if (hook === void 0) return adapters;
@@ -18373,6 +18698,31 @@ async function dispatchPostAdmissionTurn(input) {
18373
18698
  const finishAfterTurn = async (result) => {
18374
18699
  if (afterDispatchApplied) return result;
18375
18700
  afterDispatchApplied = true;
18701
+ const cancelBeforeFinish = processCancelSignalName(env.signal);
18702
+ if (cancelBeforeFinish !== void 0 && result.terminal !== void 0 && isLawfulTypedTerminalOutcome(result.terminal.roleOutcome)) {
18703
+ result = {
18704
+ ...await settleAfterTurnStarted(
18705
+ admitted,
18706
+ withEngineDetourInvocationScope(
18707
+ {
18708
+ timedOut: false,
18709
+ code: null,
18710
+ stderr: "",
18711
+ knownDiagnostic: processCancelDiagnostic(cancelBeforeFinish),
18712
+ skipRunStateWrite: true
18713
+ },
18714
+ request.invocationScopeId
18715
+ ),
18716
+ adapters,
18717
+ env.principalAuthority,
18718
+ io,
18719
+ persistRunState
18720
+ ),
18721
+ turnDispatched: true,
18722
+ skipAutoResume: true,
18723
+ ...deferredPersist
18724
+ };
18725
+ }
18376
18726
  try {
18377
18727
  if (admitted.ticketNumber === void 0) {
18378
18728
  const rows = await readRecordedSubmissionRows(
@@ -18519,20 +18869,26 @@ async function dispatchPostAdmissionTurn(input) {
18519
18869
  try {
18520
18870
  result = await env.roleTurnHost.executeTurn(turnRequest);
18521
18871
  } catch (error) {
18872
+ const processCancelName = processCancelSignalName(env.signal);
18522
18873
  const settled2 = await settleAfterTurnStarted(
18523
18874
  admitted,
18524
18875
  withEngineDetourInvocationScope({
18525
18876
  timedOut: false,
18526
18877
  code: null,
18527
18878
  stderr: "",
18528
- thrown: error
18879
+ thrown: processCancelName === void 0 ? error : new Error(processCancelDiagnostic(processCancelName), { cause: error })
18529
18880
  }, request.invocationScopeId),
18530
18881
  adapters,
18531
18882
  env.principalAuthority,
18532
18883
  io,
18533
18884
  persistRunState
18534
18885
  );
18535
- return await finishAfterTurn({ ...settled2, turnDispatched: true, ...deferredPersist });
18886
+ return await finishAfterTurn(
18887
+ withProcessCancelSkipAutoResume(
18888
+ { ...settled2, turnDispatched: true, ...deferredPersist },
18889
+ env.signal
18890
+ )
18891
+ );
18536
18892
  }
18537
18893
  let stderrLogWriteFailure;
18538
18894
  try {
@@ -18572,7 +18928,8 @@ async function dispatchPostAdmissionTurn(input) {
18572
18928
  credential: credentialFailure,
18573
18929
  runDirectory: admitted.runDirectory
18574
18930
  });
18575
- const directHostFailureSignal = result.timedOut || result.knownFailure !== void 0 || runnerKnownFailure !== void 0 || credentialFailure !== void 0;
18931
+ const processCancelName = processCancelSignalName(env.signal);
18932
+ const directHostFailureSignal = result.timedOut || result.knownFailure !== void 0 || runnerKnownFailure !== void 0 || credentialFailure !== void 0 || processCancelName !== void 0;
18576
18933
  hostSignalFailed = directHostFailureSignal || result.code !== null && result.code !== 0 || resolution.knownFailure !== void 0;
18577
18934
  settled = await adapters.trySettle(admitted, env.principalAuthority, courtScope);
18578
18935
  if (settled !== void 0) {
@@ -18580,7 +18937,8 @@ async function dispatchPostAdmissionTurn(input) {
18580
18937
  }
18581
18938
  const settledIsFreshThisAttempt = settled === void 0 || settled.roleOutcome.kind !== "accepted" && settled.roleOutcome.kind !== "audit_escalation" ? true : await attemptProducedFreshSubmission(admitted, courtScope);
18582
18939
  const staleAcceptanceOutranksRealFailure = !settledIsFreshThisAttempt && hostSignalFailed;
18583
- if (settled !== void 0 && shouldPresent(settled) && !directHostFailureSignal && !staleAcceptanceOutranksRealFailure && stderrLogWriteFailure === void 0) {
18940
+ const cancelAfterSettle = processCancelSignalName(env.signal);
18941
+ if (settled !== void 0 && shouldPresent(settled) && !directHostFailureSignal && !staleAcceptanceOutranksRealFailure && stderrLogWriteFailure === void 0 && cancelAfterSettle === void 0) {
18584
18942
  if (settled.roleOutcome.kind === "accepted" && request.courtAttemptId !== void 0 && request.courtAttemptId.length > 0) {
18585
18943
  try {
18586
18944
  await clearCurrentCourt(admitted.runDirectory, request.courtAttemptId);
@@ -18617,6 +18975,22 @@ async function dispatchPostAdmissionTurn(input) {
18617
18975
  return await finishAfterTurn({ ...settledFailure, turnDispatched: true, ...deferredPersist });
18618
18976
  }
18619
18977
  if (settledOutcome !== void 0) {
18978
+ const lateCancel = processCancelSignalName(env.signal);
18979
+ if (lateCancel !== void 0) {
18980
+ return await finishAfterTurn(
18981
+ await settleProcessCancelAfterTurn({
18982
+ admitted,
18983
+ cancelName: lateCancel,
18984
+ result,
18985
+ adapters,
18986
+ env,
18987
+ io,
18988
+ persistRunState,
18989
+ deferredPersist,
18990
+ invocationScopeId: request.invocationScopeId
18991
+ })
18992
+ );
18993
+ }
18620
18994
  if (persistRunState) {
18621
18995
  try {
18622
18996
  await persistReturnedRunState(admitted, env.principalAuthority, { lawful: true });
@@ -18635,13 +19009,19 @@ async function dispatchPostAdmissionTurn(input) {
18635
19009
  io,
18636
19010
  persistRunState
18637
19011
  );
18638
- return await finishAfterTurn({ ...failed, turnDispatched: true, ...deferredPersist });
19012
+ return await finishAfterTurn(
19013
+ withProcessCancelSkipAutoResume(
19014
+ { ...failed, turnDispatched: true, ...deferredPersist },
19015
+ env.signal
19016
+ )
19017
+ );
18639
19018
  }
18640
19019
  }
18641
19020
  return await finishAfterTurn({ ...settledOutcome, ...deferredPersist });
18642
19021
  }
18643
19022
  if (hostSignalFailed) {
18644
19023
  const resolutionInput = controlledFailureInputFromResolution(resolution);
19024
+ const processCancelName = processCancelSignalName(env.signal);
18645
19025
  const stderrLogWriteDetails = stderrLogWriteFailure === void 0 ? void 0 : { stderrLogWriteFailure: describeCaughtError(stderrLogWriteFailure) };
18646
19026
  const failed = await settleAfterTurnStarted(
18647
19027
  admitted,
@@ -18650,6 +19030,7 @@ async function dispatchPostAdmissionTurn(input) {
18650
19030
  code: result.code,
18651
19031
  stderr: result.stderr,
18652
19032
  ...resolutionInput,
19033
+ ...processCancelName === void 0 ? {} : { knownDiagnostic: processCancelDiagnostic(processCancelName) },
18653
19034
  // Secondary fact only — never the cause. Rides on whichever channel
18654
19035
  // classification actually reads (knownFailure.details owns it when
18655
19036
  // a knownFailure exists; the top-level knownDetails otherwise).
@@ -18665,7 +19046,12 @@ async function dispatchPostAdmissionTurn(input) {
18665
19046
  io,
18666
19047
  persistRunState
18667
19048
  );
18668
- return await finishAfterTurn({ ...failed, turnDispatched: true, ...deferredPersist });
19049
+ return await finishAfterTurn(
19050
+ withProcessCancelSkipAutoResume(
19051
+ { ...failed, turnDispatched: true, ...deferredPersist },
19052
+ env.signal
19053
+ )
19054
+ );
18669
19055
  }
18670
19056
  if (stderrLogWriteFailure !== void 0) {
18671
19057
  const failed = await settleAfterTurnStarted(
@@ -18688,8 +19074,24 @@ async function dispatchPostAdmissionTurn(input) {
18688
19074
  await settleHostEndedNoReceipt(admitted, env.principalAuthority, courtScope),
18689
19075
  courtScope
18690
19076
  );
18691
- if (persistRunState) {
18692
- try {
19077
+ const noReceiptCancel = processCancelSignalName(env.signal);
19078
+ if (noReceiptCancel !== void 0) {
19079
+ return await finishAfterTurn(
19080
+ await settleProcessCancelAfterTurn({
19081
+ admitted,
19082
+ cancelName: noReceiptCancel,
19083
+ result,
19084
+ adapters,
19085
+ env,
19086
+ io,
19087
+ persistRunState,
19088
+ deferredPersist,
19089
+ invocationScopeId: request.invocationScopeId
19090
+ })
19091
+ );
19092
+ }
19093
+ if (persistRunState) {
19094
+ try {
18693
19095
  await persistReturnedRunState(admitted, env.principalAuthority, { lawful: true });
18694
19096
  } catch (error) {
18695
19097
  const failed = await settleAfterTurnStarted(
@@ -18706,7 +19108,12 @@ async function dispatchPostAdmissionTurn(input) {
18706
19108
  io,
18707
19109
  persistRunState
18708
19110
  );
18709
- return await finishAfterTurn({ ...failed, turnDispatched: true, ...deferredPersist });
19111
+ return await finishAfterTurn(
19112
+ withProcessCancelSkipAutoResume(
19113
+ { ...failed, turnDispatched: true, ...deferredPersist },
19114
+ env.signal
19115
+ )
19116
+ );
18710
19117
  }
18711
19118
  }
18712
19119
  return await finishAfterTurn({
@@ -18902,6 +19309,7 @@ async function runPostAdmissionSeatResume(input) {
18902
19309
  io: input.io,
18903
19310
  sessionAppender: env.sessionAppender,
18904
19311
  autoResumeLimit: env.autoResumeLimit,
19312
+ ...env.signal === void 0 ? {} : { signal: env.signal },
18905
19313
  buildInitialPayload: () => ({ resumeTurn: false }),
18906
19314
  buildResumePayload: () => ({ resumeTurn: true }),
18907
19315
  // Same as public manual resume: prior-court sealed acceptance is not a
@@ -18977,7 +19385,7 @@ async function runPostAdmissionOneShot(input) {
18977
19385
  ...input.request,
18978
19386
  continuation: {
18979
19387
  kind: "resume",
18980
- prompt: buildResumeContinuationPrompt({
19388
+ prompt: buildAutoResumeContinuationPrompt({
18981
19389
  packageRoot: input.env.packageRoot,
18982
19390
  ...pickEngineAxis({
18983
19391
  engine: input.effectiveEngine ?? input.env.engine,
@@ -19005,6 +19413,7 @@ async function runPostAdmissionResumable(input) {
19005
19413
  io,
19006
19414
  sessionAppender: env.sessionAppender,
19007
19415
  autoResumeLimit: env.autoResumeLimit,
19416
+ ...env.signal === void 0 ? {} : { signal: env.signal },
19008
19417
  buildInitialPayload: buildScopedInitial,
19009
19418
  buildResumePayload: buildScopedResume,
19010
19419
  dispatch: async (request, lease, _isFirst, attemptIo) => {
@@ -19113,6 +19522,7 @@ var init_post_admission = __esm({
19113
19522
  init_host_transition_prior_native();
19114
19523
  init_public_run_credentials();
19115
19524
  init_run_lifecycle();
19525
+ init_process_cancel();
19116
19526
  init_activation_ledger_topology();
19117
19527
  init_settlement();
19118
19528
  init_terminal();
@@ -19849,7 +20259,7 @@ async function runPublicJudge(argv, env, io, parseJudgeArgv2) {
19849
20259
  ...admitted.correlationId === void 0 && env.correlationId === void 0 ? {} : { correlationId: admitted.correlationId ?? env.correlationId },
19850
20260
  continuation: {
19851
20261
  kind: "resume",
19852
- prompt: buildResumeContinuationPrompt({
20262
+ prompt: buildAutoResumeContinuationPrompt({
19853
20263
  packageRoot: env.packageRoot,
19854
20264
  ...pickEngineAxis(env)
19855
20265
  })
@@ -21232,14 +21642,32 @@ async function summonPublicRole(options) {
21232
21642
  case "navigator":
21233
21643
  case "gatekeeper": {
21234
21644
  const seat2 = options.role;
21235
- const [{ runPublicInstructionSeat: runPublicInstructionSeat2 }, invocation] = await Promise.all([
21645
+ const [{ runPublicInstructionSeat: runPublicInstructionSeat2, runPublicInstructionSeatResume: runPublicInstructionSeatResume2 }, invocation] = await Promise.all([
21236
21646
  Promise.resolve().then(() => (init_instruction_seat_run(), instruction_seat_run_exports)),
21237
21647
  Promise.resolve().then(() => (init_invocation(), invocation_exports))
21238
21648
  ]);
21239
21649
  const parse = seat2 === "auditor" ? invocation.parseAuditorArgv : seat2 === "navigator" ? invocation.parseNavigatorArgv : invocation.parseGatekeeperArgv;
21240
- const stepped = await runPrepared(parse, (env, once) => runPublicInstructionSeat2(options.argv, env, io, seat2, once));
21241
- if ("fail" in stepped) return stepped.fail;
21242
- result = stepped.ok;
21650
+ const resumeRunId = typeof options.resumeRunId === "string" && options.resumeRunId.trim() !== "" ? options.resumeRunId.trim() : void 0;
21651
+ if (resumeRunId !== void 0) {
21652
+ const instruction = options.argv[0] ?? "";
21653
+ const stepped = await runPrepared(parse, (env) => runPublicInstructionSeatResume2(
21654
+ {
21655
+ runId: resumeRunId,
21656
+ summons: {
21657
+ instruction,
21658
+ instructionEmpty: instruction.trim() === ""
21659
+ }
21660
+ },
21661
+ env,
21662
+ io
21663
+ ));
21664
+ if ("fail" in stepped) return stepped.fail;
21665
+ result = stepped.ok;
21666
+ } else {
21667
+ const stepped = await runPrepared(parse, (env, once) => runPublicInstructionSeat2(options.argv, env, io, seat2, once));
21668
+ if ("fail" in stepped) return stepped.fail;
21669
+ result = stepped.ok;
21670
+ }
21243
21671
  break;
21244
21672
  }
21245
21673
  case "judge": {
@@ -21653,14 +22081,14 @@ var init_public_role_summons = __esm({
21653
22081
  });
21654
22082
 
21655
22083
  // src/acp-host/production-host.ts
21656
- import { randomUUID as randomUUID9 } from "node:crypto";
22084
+ import { randomUUID as randomUUID10 } from "node:crypto";
21657
22085
 
21658
22086
  // src/role-envelope.ts
21659
22087
  init_engine_detour();
21660
- import { randomUUID as randomUUID8 } from "node:crypto";
21661
- import { mkdir as mkdir7, writeFile as writeFile12 } from "node:fs/promises";
22088
+ import { randomUUID as randomUUID9 } from "node:crypto";
22089
+ import { appendFile as appendFile3, mkdir as mkdir7, writeFile as writeFile12 } from "node:fs/promises";
21662
22090
  import { createServer } from "node:net";
21663
- import { dirname as dirname22, join as join41 } from "node:path";
22091
+ import { dirname as dirname21, join as join41 } from "node:path";
21664
22092
  import { fileURLToPath as fileURLToPath2 } from "node:url";
21665
22093
 
21666
22094
  // src/gatekeeper-pass-envelope.ts
@@ -21788,7 +22216,8 @@ init_host_contracts();
21788
22216
  init_sitian_facade();
21789
22217
  init_submission_ledger();
21790
22218
  init_collector_ledger();
21791
- import { readFileSync as readFileSync6, writeSync as writeSync4 } from "node:fs";
22219
+ import { randomUUID as randomUUID8 } from "node:crypto";
22220
+ import { readFileSync as readFileSync6, writeSync as writeSync3 } from "node:fs";
21792
22221
  import { join as join40 } from "node:path";
21793
22222
  import { Value as Value4 } from "typebox/value";
21794
22223
 
@@ -21830,16 +22259,7 @@ function namedActivationCause(error) {
21830
22259
  init_activation_ledger_topology();
21831
22260
 
21832
22261
  // src/activation-ledger.ts
21833
- init_activation_ledger_topology();
21834
22262
  init_activation_ledger_git();
21835
- import {
21836
- constants as constants2,
21837
- closeSync as closeSync2,
21838
- fstatSync,
21839
- openSync as openSync2,
21840
- writeSync
21841
- } from "node:fs";
21842
- import { dirname as dirname19, isAbsolute as isAbsolute10, resolve as resolve16 } from "node:path";
21843
22263
 
21844
22264
  // src/activation-ledger-session.ts
21845
22265
  init_activation_ledger_topology();
@@ -21943,129 +22363,11 @@ function durableSessionPointer(sessionManager) {
21943
22363
 
21944
22364
  // src/activation-ledger.ts
21945
22365
  init_activation_ledger_topology();
21946
- var ACTIVATION_LEDGER_APPEND_OPEN_FLAGS = constants2.O_APPEND | constants2.O_CREAT | constants2.O_WRONLY | constants2.O_NOFOLLOW;
21947
- var ACCEPTED_ACTIVATION_EVENT = "accepted-activation";
21948
- var ACCEPTED_ACTIVATION_FACT_KEYS = Object.freeze([
21949
- "event",
21950
- "role",
21951
- "observedAt",
21952
- "bookKey",
21953
- "session",
21954
- "correlation"
21955
- ]);
21956
- function correlationIdentityFromEnv(env = process.env) {
21957
- const raw = env.AK_CORRELATION_ID;
21958
- if (typeof raw === "string" && raw.trim().length > 0) {
21959
- return { kind: "caller", id: raw };
21960
- }
21961
- return { kind: "absent" };
21962
- }
21963
- function projectAcceptedActivationFact(input) {
21964
- const closed = {
21965
- event: ACCEPTED_ACTIVATION_EVENT,
21966
- role: input.role,
21967
- observedAt: input.observedAt,
21968
- bookKey: input.bookKey,
21969
- session: { kind: "session-file", path: input.session.path },
21970
- correlation: input.correlation.kind === "caller" ? { kind: "caller", id: input.correlation.id } : { kind: "absent" }
21971
- };
21972
- return Object.fromEntries(
21973
- ACCEPTED_ACTIVATION_FACT_KEYS.map((key) => [key, closed[key]])
21974
- );
21975
- }
21976
- function buildAcceptedActivationFact(input) {
21977
- return projectAcceptedActivationFact(input);
21978
- }
21979
- function serializeAcceptedActivationFact(fact) {
21980
- return `${JSON.stringify(projectAcceptedActivationFact(fact))}
21981
- `;
21982
- }
21983
- function appendActivationLedgerLine(ledgerPath, line2, options) {
21984
- if (!isAbsolute10(options.ledgerHome)) {
21985
- throw new ActivationLedgerError(
21986
- `activation ledger home must be absolute: ${options.ledgerHome}`
21987
- );
21988
- }
21989
- const resolvedLedger = resolve16(ledgerPath);
21990
- const resolvedHome = resolve16(options.ledgerHome);
21991
- const parent = dirname19(resolvedLedger);
21992
- ensureRealDirectoryTree(resolvedHome, parent);
21993
- assertLedgerFileInsideHome(resolvedLedger, resolvedHome);
21994
- if (typeof constants2.O_NOFOLLOW !== "number") {
21995
- throw new ActivationLedgerError(
21996
- "activation ledger append requires O_NOFOLLOW open-flag support (anti-symlink TOCTOU protection must not be silently dropped); refusing to append"
21997
- );
21998
- }
21999
- const bytes = Buffer.isBuffer(line2) ? line2 : Buffer.from(line2);
22000
- let ledgerFd;
22001
- let primaryFailure;
22002
- try {
22003
- try {
22004
- ledgerFd = openSync2(resolvedLedger, ACTIVATION_LEDGER_APPEND_OPEN_FLAGS, 420);
22005
- } catch (error) {
22006
- throw new ActivationLedgerError(
22007
- `activation ledger failed to open ledger file (${resolvedLedger}): ${errorText(error)}`,
22008
- { cause: error }
22009
- );
22010
- }
22011
- let opened;
22012
- try {
22013
- opened = fstatSync(ledgerFd);
22014
- } catch (error) {
22015
- throw new ActivationLedgerError(
22016
- `activation ledger failed to fstat ledger file (${resolvedLedger}): ${errorText(error)}`,
22017
- { cause: error }
22018
- );
22019
- }
22020
- if (!opened.isFile()) {
22021
- throw new ActivationLedgerError(
22022
- `activation ledger is not a regular file: ${resolvedLedger}`
22023
- );
22024
- }
22025
- const written = writeSync(ledgerFd, bytes, 0, bytes.length, null);
22026
- if (written !== bytes.length) {
22027
- throw new ActivationLedgerError(
22028
- `activation ledger short write: wrote ${written} of ${bytes.length} bytes to ${resolvedLedger}`
22029
- );
22030
- }
22031
- } catch (error) {
22032
- primaryFailure = error;
22033
- }
22034
- if (ledgerFd !== void 0) {
22035
- try {
22036
- closeSync2(ledgerFd);
22037
- } catch (closeFailure) {
22038
- if (primaryFailure !== void 0) {
22039
- throw new AggregateError(
22040
- [primaryFailure, closeFailure],
22041
- "activation ledger operation and close failed",
22042
- { cause: primaryFailure }
22043
- );
22044
- }
22045
- throw closeFailure;
22046
- }
22047
- }
22048
- if (primaryFailure !== void 0) throw primaryFailure;
22049
- }
22050
- function appendAcceptedActivationFact(ledgerPath, fact, options) {
22051
- appendActivationLedgerLine(
22052
- ledgerPath,
22053
- Buffer.from(serializeAcceptedActivationFact(fact), "utf8"),
22054
- { ledgerHome: options.ledgerHome }
22055
- );
22056
- }
22057
- function appendAcceptedActivationToBook(options) {
22058
- appendAcceptedActivationFact(
22059
- activationWaitingLedgerPath(options.ledgerHome, options.fact.bookKey),
22060
- options.fact,
22061
- { ledgerHome: options.ledgerHome }
22062
- );
22063
- }
22064
22366
 
22065
22367
  // src/stderr-jsonl.ts
22066
- import { writeSync as writeSync2 } from "node:fs";
22368
+ import { writeSync } from "node:fs";
22067
22369
  var STDERR_JSONL_WRITE_RETRY_LIMIT = 100;
22068
- function writeStderrJsonlRecord(record4, write = writeSync2) {
22370
+ function writeStderrJsonlRecord(record4, write = writeSync) {
22069
22371
  const bytes = Buffer.from(`${JSON.stringify(record4)}
22070
22372
  `);
22071
22373
  let offset = 0;
@@ -22085,7 +22387,7 @@ function writeStderrJsonlRecord(record4, write = writeSync2) {
22085
22387
  }
22086
22388
 
22087
22389
  // src/tool-execution-observation.ts
22088
- import { writeSync as writeSync3 } from "node:fs";
22390
+ import { writeSync as writeSync2 } from "node:fs";
22089
22391
  import { Type as Type13 } from "typebox";
22090
22392
  import { Value as Value2 } from "typebox/value";
22091
22393
  var TOOL_EXECUTION_UPDATE_THROTTLE_MS = 3e4;
@@ -22116,7 +22418,7 @@ function validateToolExecutionObservationRecord(record4) {
22116
22418
  }
22117
22419
  return record4;
22118
22420
  }
22119
- function writeToolExecutionObservationRecord(record4, write = writeSync3) {
22421
+ function writeToolExecutionObservationRecord(record4, write = writeSync2) {
22120
22422
  writeStderrJsonlRecord(validateToolExecutionObservationRecord(record4), write);
22121
22423
  }
22122
22424
  function isProducingToolUpdate(partialResult) {
@@ -22353,9 +22655,9 @@ import { join as join38, sep as sep6 } from "node:path";
22353
22655
  // src/atomic-write.ts
22354
22656
  import { randomUUID as randomUUID7 } from "node:crypto";
22355
22657
  import { rename as rename3, rm as rm5, writeFile as writeFile11 } from "node:fs/promises";
22356
- import { dirname as dirname20, join as join37 } from "node:path";
22658
+ import { dirname as dirname19, join as join37 } from "node:path";
22357
22659
  async function writeFileAtomically(destination, contents) {
22358
- const parent = dirname20(destination);
22660
+ const parent = dirname19(destination);
22359
22661
  const temporary = join37(parent, `.atomic-write-${randomUUID7()}.tmp`);
22360
22662
  try {
22361
22663
  await writeFile11(temporary, contents);
@@ -23634,7 +23936,7 @@ init_navigator_output();
23634
23936
  var NAVIGATOR_TOOL_SPEC = {
23635
23937
  name: NAVIGATOR_OUTPUT_TOOL_NAME,
23636
23938
  label: "\u6E38\u5955\u4F7F\u5EFA\u8BAE",
23637
- description: "\u6E38\u5955\u4F7F\u7EC8\u5C40\u56DE\u6267\uFF1A\u6392\u597D\u5E8F\u7684\u4E0B\u4E00\u6B65\u89D2\u8272\u8DEF\u7EBF\u5EFA\u8BAE\u3002",
23939
+ description: "\u6E38\u5955\u4F7F\u7EC8\u5C40\u56DE\u6267\uFF1A\u6563\u6587\u5EFA\u8BAE\uFF0C\u539F\u6837\u5448\u73B0\u3002",
23638
23940
  promptSnippet: "\u6E38\u5955\u4F7F\u5EFA\u8BAE",
23639
23941
  parameters: navigatorOutputSchema
23640
23942
  };
@@ -23659,12 +23961,13 @@ import { createHash as createHash9 } from "node:crypto";
23659
23961
  init_navigator_invocation_identity();
23660
23962
  init_packaged_role_registry();
23661
23963
  init_activation_ledger_topology();
23662
- import { resolve as resolve17 } from "node:path";
23964
+ import { resolve as resolve16 } from "node:path";
23663
23965
  import "@earendil-works/pi-coding-agent";
23664
23966
  import { Type as Type22 } from "typebox";
23665
23967
 
23666
23968
  // src/navigator-public-session.ts
23667
23969
  init_sitian_facade();
23970
+ import { basename as basename10 } from "node:path";
23668
23971
 
23669
23972
  // src/navigator-session-contracts.ts
23670
23973
  import { Type as Type21 } from "typebox";
@@ -23852,6 +24155,7 @@ async function resolveNavigatorSeatSelection(context) {
23852
24155
 
23853
24156
  // src/navigator-public-session.ts
23854
24157
  init_host_contracts();
24158
+ init_cli_errors();
23855
24159
  async function resolveNavigatorLedgerHome(context) {
23856
24160
  const { tryHomeFromAkRolesPath: tryHomeFromAkRolesPath2 } = await Promise.resolve().then(() => (init_activation_ledger_topology(), activation_ledger_topology_exports));
23857
24161
  const runDirectory = runDirectoryFromHostContext(context);
@@ -23866,7 +24170,42 @@ async function resolveNavigatorLedgerHome(context) {
23866
24170
  }
23867
24171
  return void 0;
23868
24172
  }
23869
- function createNativeNavigatorSessionFactory() {
24173
+ var NAVIGATOR_HOST_RUN_POINTER_ENTRY = "ak-navigator-host-run";
24174
+ function exactRecord2(value) {
24175
+ return typeof value === "object" && value !== null && !Array.isArray(value);
24176
+ }
24177
+ function runIdFromNavigatorDirectory(runDirectory) {
24178
+ const entry = basename10(runDirectory);
24179
+ const suffix = "@navigator";
24180
+ if (!entry.endsWith(suffix)) return void 0;
24181
+ const runId = entry.slice(0, entry.length - suffix.length);
24182
+ return runId.length > 0 ? runId : void 0;
24183
+ }
24184
+ function readNavigatorHostRunPointer(entries) {
24185
+ for (let index = entries.length - 1; index >= 0; index -= 1) {
24186
+ const entry = entries[index];
24187
+ if (!exactRecord2(entry)) continue;
24188
+ if (entry.type === "custom" && entry.customType === NAVIGATOR_HOST_RUN_POINTER_ENTRY) {
24189
+ const data = entry.data;
24190
+ if (exactRecord2(data) && typeof data.runId === "string" && data.runId.trim() !== "") {
24191
+ return data.runId.trim();
24192
+ }
24193
+ }
24194
+ }
24195
+ return void 0;
24196
+ }
24197
+ async function navigatorHostRunResumable(home, runId) {
24198
+ const { piDurablePrincipalAuthority: piDurablePrincipalAuthority2 } = await Promise.resolve().then(() => (init_durable_principal(), durable_principal_exports));
24199
+ const { loadResumableInstructionSeatRun: loadResumableInstructionSeatRun2 } = await Promise.resolve().then(() => (init_run_lifecycle(), run_lifecycle_exports));
24200
+ try {
24201
+ const loaded = await loadResumableInstructionSeatRun2(home, runId, piDurablePrincipalAuthority2);
24202
+ return loaded.admitted.role === "navigator";
24203
+ } catch (error) {
24204
+ if (error instanceof CliUsageError) return false;
24205
+ throw error;
24206
+ }
24207
+ }
24208
+ function createNativeNavigatorSessionFactory(deps) {
23870
24209
  return async ({ context, subject, tool }) => {
23871
24210
  let thinkingLevel;
23872
24211
  const { createRecordSession: createRecordSession2, NAVIGATOR_RECORD_KIND: NAVIGATOR_RECORD_KIND2 } = await Promise.resolve().then(() => (init_archivist_record_entry(), archivist_record_entry_exports));
@@ -23882,6 +24221,11 @@ function createNativeNavigatorSessionFactory() {
23882
24221
  let noReceipt;
23883
24222
  let disposed = false;
23884
24223
  let inFlightPrompt;
24224
+ let hostRunId = readNavigatorHostRunPointer(sessionManager.getEntries());
24225
+ const summon = deps?.summonPublicRole ?? (async (options) => {
24226
+ const { summonPublicRole: summonPublicRole2 } = await Promise.resolve().then(() => (init_public_role_summons(), public_role_summons_exports));
24227
+ return summonPublicRole2(options);
24228
+ });
23885
24229
  return {
23886
24230
  prompt: async (text) => {
23887
24231
  if (disposed) {
@@ -23891,14 +24235,24 @@ function createNativeNavigatorSessionFactory() {
23891
24235
  noReceipt = void 0;
23892
24236
  const run = (async () => {
23893
24237
  try {
23894
- const { summonPublicRole: summonPublicRole2 } = await Promise.resolve().then(() => (init_public_role_summons(), public_role_summons_exports));
23895
24238
  const summonHome = await resolveNavigatorLedgerHome(context);
23896
- const summoned = await summonPublicRole2({
24239
+ const resumeRunId = hostRunId;
24240
+ const baseSummon = {
23897
24241
  role: "navigator",
23898
24242
  argv: [text],
23899
24243
  cwd: context.cwd,
23900
24244
  ...summonHome === void 0 ? {} : { home: summonHome }
23901
- });
24245
+ };
24246
+ const resumable = deps?.hostRunResumable ?? navigatorHostRunResumable;
24247
+ let summoned;
24248
+ if (resumeRunId === void 0 || summonHome === void 0) {
24249
+ summoned = await summon(baseSummon);
24250
+ } else if (await resumable(summonHome, resumeRunId)) {
24251
+ summoned = await summon({ ...baseSummon, resumeRunId });
24252
+ } else {
24253
+ hostRunId = void 0;
24254
+ summoned = await summon(baseSummon);
24255
+ }
23902
24256
  const outcome = summoned.terminal?.roleOutcome;
23903
24257
  if (outcome === void 0) {
23904
24258
  const detail = summoned.stderr?.trim() || `exit ${summoned.exitCode}`;
@@ -23921,21 +24275,31 @@ function createNativeNavigatorSessionFactory() {
23921
24275
  noReceipt = outcome;
23922
24276
  return;
23923
24277
  }
24278
+ const runDirectory = summoned.runDirectory ?? (typeof summoned.admitted?.runDirectory === "string" ? summoned.admitted.runDirectory : void 0);
24279
+ if (typeof runDirectory === "string" && runDirectory.trim() !== "") {
24280
+ const nextRunId = runIdFromNavigatorDirectory(runDirectory);
24281
+ if (nextRunId !== void 0) {
24282
+ hostRunId = nextRunId;
24283
+ sessionManager.appendCustomEntry(NAVIGATOR_HOST_RUN_POINTER_ENTRY, { runId: nextRunId });
24284
+ }
24285
+ }
23924
24286
  if (outcome.kind !== "accepted") {
23925
24287
  return;
23926
24288
  }
24289
+ const { navigatorProseFromUnknown: navigatorProseFromUnknown2 } = await Promise.resolve().then(() => (init_navigator_output(), navigator_output_exports));
24290
+ const proseParts = [];
23927
24291
  for (const payload of outcome.payloads ?? []) {
23928
- if (typeof payload !== "object" || payload === null || Array.isArray(payload)) continue;
23929
- const candidates = payload.candidates;
23930
- if (!Array.isArray(candidates)) continue;
23931
- await tool.execute(
23932
- "navigator-public-prepare",
23933
- { candidates },
23934
- void 0,
23935
- void 0,
23936
- context
23937
- );
24292
+ const prose = navigatorProseFromUnknown2(payload);
24293
+ if (prose !== void 0) proseParts.push(prose);
23938
24294
  }
24295
+ if (proseParts.length === 0) return;
24296
+ await tool.execute(
24297
+ "navigator-public-prepare",
24298
+ { prose: proseParts.join("\n\n") },
24299
+ void 0,
24300
+ void 0,
24301
+ context
24302
+ );
23939
24303
  } catch (error) {
23940
24304
  if (error instanceof NavigatorUnavailableError) throw error;
23941
24305
  const fact = navigatorProviderFailureFromError(error);
@@ -23989,9 +24353,9 @@ function createNativeNavigatorSessionFactory() {
23989
24353
 
23990
24354
  // src/navigator-attendance.ts
23991
24355
  init_sitian_facade();
23992
- init_public_command_renderer();
23993
24356
  init_work_subject_identity();
23994
24357
  init_receipt_delivery_policy();
24358
+ init_navigator_output();
23995
24359
  var NAVIGATOR_EVENT_TYPE = "ak-navigator-attendance";
23996
24360
  var NAVIGATOR_PREPARE_ACCEPTED_TEXT = "\u6E38\u5955\u4F7F\u51C6\u5907\u5DF2\u63A5\u53D7";
23997
24361
  function resolveNavigatorAuthorityMaterial(roleInput, fileAuthority) {
@@ -24001,107 +24365,40 @@ function resolveNavigatorAuthorityMaterial(roleInput, fileAuthority) {
24001
24365
  }
24002
24366
  var NAVIGATOR_TARGETS = PACKAGED_ROLE_REGISTRY.map(({ role, phases }) => ({ role, phases }));
24003
24367
  var prepareSchema = Type22.Object({
24004
- candidates: Type22.Optional(Type22.Unknown({
24005
- description: "\u65B9\u5411\u5019\u9009\uFF1Bcandidates[].next.role \u5FC5\u586B\uFF0Cphase \u53EF\u9009\uFF0Croute/matches/reason/command \u53EF\u9009\u4E0A\u4E0B\u6587\uFF0C\u975E\u53D7\u7406\u95F8"
24368
+ prose: Type22.Optional(Type22.Unknown({
24369
+ description: "\u6E38\u5955\u4F7F\u6563\u6587\u5EFA\u8BAE\uFF0C\u539F\u6837\u5448\u73B0\u3002\u4E0D\u8981\u6C42 candidates/next \u7ED3\u6784\u3002\u975E\u53D7\u7406\u95F8"
24006
24370
  }))
24007
24371
  }, { additionalProperties: true });
24008
- var ROUTE_ENTRY = "ak-navigator-route";
24009
24372
  var CONTEXT_ENTRY = "ak-navigator-context";
24010
24373
  var INVOCATION_ENTRY = NAVIGATOR_INVOCATION_ENTRY;
24011
24374
  var SETTLEMENT_ENTRY = "ak-navigator-settlement";
24012
- var targetRoles = new Set(NAVIGATOR_TARGETS.map(({ role }) => role));
24013
- function exactRecord2(value) {
24375
+ function exactRecord3(value) {
24014
24376
  return typeof value === "object" && value !== null && !Array.isArray(value);
24015
24377
  }
24016
24378
  function rejectedPrepareReason(entries, start) {
24017
24379
  const recent = entries.slice(start);
24018
24380
  const prepareCalls = /* @__PURE__ */ new Set();
24019
24381
  for (const entry of recent) {
24020
- if (!exactRecord2(entry) || entry.type !== "message" || !exactRecord2(entry.message) || entry.message.role !== "assistant" || !Array.isArray(entry.message.content)) continue;
24382
+ if (!exactRecord3(entry) || entry.type !== "message" || !exactRecord3(entry.message) || entry.message.role !== "assistant" || !Array.isArray(entry.message.content)) continue;
24021
24383
  for (const part of entry.message.content) {
24022
- if (exactRecord2(part) && part.type === "toolCall" && part.name === NAVIGATOR_PREPARE_TOOL_NAME && typeof part.id === "string") prepareCalls.add(part.id);
24384
+ if (exactRecord3(part) && part.type === "toolCall" && part.name === NAVIGATOR_PREPARE_TOOL_NAME && typeof part.id === "string") prepareCalls.add(part.id);
24023
24385
  }
24024
24386
  }
24025
24387
  let reason;
24026
24388
  for (const entry of recent) {
24027
- if (!exactRecord2(entry) || entry.type !== "message" || !exactRecord2(entry.message) || entry.message.role !== "toolResult" || entry.message.isError !== true) continue;
24389
+ if (!exactRecord3(entry) || entry.type !== "message" || !exactRecord3(entry.message) || entry.message.role !== "toolResult" || entry.message.isError !== true) continue;
24028
24390
  const callId = entry.message.toolCallId;
24029
24391
  if (entry.message.toolName !== NAVIGATOR_PREPARE_TOOL_NAME || typeof callId !== "string" || !prepareCalls.has(callId)) {
24030
24392
  return void 0;
24031
24393
  }
24032
24394
  const content = entry.message.content;
24033
- const text = Array.isArray(content) ? content.flatMap((part) => exactRecord2(part) && typeof part.text === "string" ? [part.text] : []).join("") : typeof content === "string" ? content : "";
24395
+ const text = Array.isArray(content) ? content.flatMap((part) => exactRecord3(part) && typeof part.text === "string" ? [part.text] : []).join("") : typeof content === "string" ? content : "";
24034
24396
  if (text.trim() !== "") reason = text.trim();
24035
24397
  }
24036
24398
  return reason;
24037
24399
  }
24038
- function targetIsValid(value) {
24039
- if (!exactRecord2(value) || !targetRoles.has(String(value.role))) return false;
24040
- const metadata = packagedRoleMetadata(String(value.role));
24041
- return metadata !== void 0 && metadata.phases.includes(value.phase);
24042
- }
24043
- function normalizeTarget(value) {
24044
- if (!exactRecord2(value)) return void 0;
24045
- const role = typeof value.role === "string" ? value.role.trim() : "";
24046
- if (role === "") return void 0;
24047
- if (value.phase === void 0 || value.phase === null) {
24048
- return { role, phase: null };
24049
- }
24050
- if (value.phase === "plan" || value.phase === "apply") {
24051
- return { role, phase: value.phase };
24052
- }
24053
- return { role, phase: null };
24054
- }
24055
- function normalizeMatches(value) {
24056
- if (!exactRecord2(value)) return void 0;
24057
- if (typeof value.role !== "string" || value.role.trim() === "") return void 0;
24058
- if (value.kind !== "accepted") return void 0;
24059
- let phase;
24060
- if (value.phase === void 0 || value.phase === null) phase = null;
24061
- else if (value.phase === "plan" || value.phase === "apply") phase = value.phase;
24062
- else return void 0;
24063
- if (value.statuses !== void 0) {
24064
- if (!Array.isArray(value.statuses) || value.statuses.some((status) => typeof status !== "string" || status.trim() === "")) {
24065
- return void 0;
24066
- }
24067
- return {
24068
- role: value.role,
24069
- phase,
24070
- kind: "accepted",
24071
- statuses: [...value.statuses]
24072
- };
24073
- }
24074
- return { role: value.role, phase, kind: "accepted" };
24075
- }
24076
- function normalizeCandidate(value) {
24077
- if (!exactRecord2(value)) return void 0;
24078
- const next = normalizeTarget(value.next);
24079
- const route = Array.isArray(value.route) ? value.route.map(normalizeTarget).filter((target) => target !== void 0) : void 0;
24080
- const matches = normalizeMatches(value.matches);
24081
- const id = typeof value.id === "string" && value.id.trim() !== "" ? value.id : void 0;
24082
- const reason = typeof value.reason === "string" && value.reason.trim() !== "" ? value.reason : void 0;
24083
- const command = typeof value.command === "string" ? value.command : void 0;
24084
- return {
24085
- ...id === void 0 ? {} : { id },
24086
- ...matches === void 0 ? {} : { matches },
24087
- ...route === void 0 || route.length === 0 ? {} : { route },
24088
- ...next === void 0 ? {} : { next },
24089
- ...reason === void 0 ? {} : { reason },
24090
- ...command === void 0 ? {} : { command }
24091
- };
24092
- }
24093
- function normalizePrepareOutput(value) {
24094
- if (!exactRecord2(value) || !Array.isArray(value.candidates)) return [];
24095
- return value.candidates.map(normalizeCandidate).filter((candidate) => candidate !== void 0);
24096
- }
24097
- function routeEqual(a, b) {
24098
- return a !== void 0 && a.length === b.length && a.every((target, index) => target.role === b[index].role && target.phase === b[index].phase);
24099
- }
24100
- function routeText(route) {
24101
- return route.map((target) => target.phase === null ? target.role : `${target.role} ${target.phase}`).join(" \u2192 ");
24102
- }
24103
- function targetText(target) {
24104
- return target.phase === null ? target.role : `${target.role} ${target.phase}`;
24400
+ function normalizePrepareProse(value) {
24401
+ return navigatorProseFromUnknown(value);
24105
24402
  }
24106
24403
  function navigatorSubjectKey(subjectRoot, subject, provenance = "role_input") {
24107
24404
  if (issueRoot(subjectRoot) !== void 0 || !subjectRoot.includes("/.ak/work/")) return subjectRoot;
@@ -24112,7 +24409,7 @@ function navigatorSubjectKey(subjectRoot, subject, provenance = "role_input") {
24112
24409
  }
24113
24410
  function navigatorSubjectKeyForInput(subjectRoot, reference, cwd = process.cwd()) {
24114
24411
  if (issueRoot(subjectRoot) !== void 0 || !subjectRoot.includes("/.ak/work/")) return subjectRoot;
24115
- const resolvedReference = resolve17(cwd, reference);
24412
+ const resolvedReference = resolve16(cwd, reference);
24116
24413
  const marker = "/runs/";
24117
24414
  if (resolvedReference.includes(marker)) {
24118
24415
  return subjectRoot;
@@ -24123,7 +24420,7 @@ function createNavigatorPrepareTool(onOutput) {
24123
24420
  return {
24124
24421
  name: NAVIGATOR_PREPARE_TOOL_NAME,
24125
24422
  label: "\u6E38\u5955\u4F7F\u51C6\u5907",
24126
- description: "\u63D0\u4EA4\u6E38\u5955\u4F7F\u65B9\u5411\u5EFA\u8BAE\u3002",
24423
+ description: "\u63D0\u4EA4\u6E38\u5955\u4F7F\u6563\u6587\u5EFA\u8BAE\u3002",
24127
24424
  parameters: prepareSchema,
24128
24425
  async execute(_id, value) {
24129
24426
  onOutput(value);
@@ -24131,34 +24428,6 @@ function createNavigatorPrepareTool(onOutput) {
24131
24428
  }
24132
24429
  };
24133
24430
  }
24134
- function selectNavigatorCandidate(candidates, settlement) {
24135
- if (settlement.kind !== "accepted") return void 0;
24136
- const usable = candidates.filter((candidate) => candidate.next !== void 0);
24137
- if (usable.length === 0) return void 0;
24138
- const rolePhaseMatched = usable.filter(
24139
- (candidate) => candidate.matches !== void 0 && candidate.matches.role === settlement.role && candidate.matches.phase === settlement.phase
24140
- );
24141
- if (rolePhaseMatched.length > 0) {
24142
- if (settlement.status !== void 0) {
24143
- const statusSpecific = rolePhaseMatched.find(
24144
- (candidate) => candidate.matches?.statuses !== void 0 && candidate.matches.statuses.includes(settlement.status)
24145
- );
24146
- if (statusSpecific !== void 0) {
24147
- return { candidate: statusSpecific, matchedToSettlement: true };
24148
- }
24149
- }
24150
- const rolePhaseGeneric = rolePhaseMatched.find(
24151
- (candidate) => candidate.matches?.statuses === void 0
24152
- );
24153
- if (rolePhaseGeneric !== void 0) {
24154
- return { candidate: rolePhaseGeneric, matchedToSettlement: true };
24155
- }
24156
- return void 0;
24157
- }
24158
- const unbound = usable.find((candidate) => candidate.matches === void 0);
24159
- if (unbound === void 0) return void 0;
24160
- return { candidate: unbound, matchedToSettlement: false };
24161
- }
24162
24431
  function formatNavigatorReport(report) {
24163
24432
  const playbookFailure = report.routePlaybookReadFailure === void 0 ? [] : [`\u8DEF\u4E66\u8BFB\u53D6\u5931\u8D25\uFF1A${report.routePlaybookReadFailure}`];
24164
24433
  if (report.disposition === "no-advice") return playbookFailure.join("\n");
@@ -24168,31 +24437,24 @@ function formatNavigatorReport(report) {
24168
24437
  if (report.disposition === "arrival") {
24169
24438
  return [...playbookFailure, ...report.arrivalMessage ? [report.arrivalMessage] : []].join("\n");
24170
24439
  }
24171
- return [
24172
- ...playbookFailure,
24173
- ...report.route === void 0 ? [] : [`\u8DEF\u7EBF\uFF1A${routeText(report.route)}`],
24174
- ...report.next === void 0 ? [] : [`\u4E0B\u4E00\u6B65\uFF1A${targetText(report.next)}`],
24175
- ...report.reason === void 0 || report.reason.trim() === "" ? [] : [`\u7406\u7531\uFF1A${report.reason}`],
24176
- ...report.command === void 0 || report.command.trim() === "" ? [] : [`\u547D\u4EE4\uFF1A${report.command}`]
24177
- ].join("\n");
24440
+ return [...playbookFailure, ...report.prose ? [report.prose] : []].join("\n");
24178
24441
  }
24179
24442
  function createNavigatorAttendance(options) {
24180
24443
  let preparation;
24444
+ let preparationInFlight = false;
24181
24445
  let sessionReady;
24182
24446
  let session;
24183
24447
  let subjectKey = options.subjectKey;
24184
24448
  let subject = options.subject;
24185
24449
  let authority = options.authority;
24186
24450
  let contextError = options.contextError;
24187
- let candidates;
24451
+ let preparedProse;
24188
24452
  const invocationPrincipal = options.invocationId ?? mintNavigatorInvocationId();
24189
24453
  let activeInvocationId = invocationPrincipal;
24190
- let previousRoute;
24191
24454
  let outputSink;
24192
24455
  let settlementTail = Promise.resolve();
24193
24456
  let settlementFailure;
24194
24457
  let preparationFailure;
24195
- let preparationNoReceipt = false;
24196
24458
  let routePlaybookReadFailure;
24197
24459
  let disposed = false;
24198
24460
  let warmedHelp;
@@ -24219,12 +24481,7 @@ function createNavigatorAttendance(options) {
24219
24481
  };
24220
24482
  let routePlaybookSettlement;
24221
24483
  let prepareBoundSettlement;
24222
- const prepare = async () => {
24223
- const boundSettlement = prepareBoundSettlement;
24224
- prepareBoundSettlement = void 0;
24225
- preparationNoReceipt = false;
24226
- const invocationId = invocationPrincipal;
24227
- activeInvocationId = invocationId;
24484
+ const loadMaterialsAndSession = async (invocationId) => {
24228
24485
  if (contextError !== void 0) throw navigatorUnavailableError("context", contextError);
24229
24486
  if (typeof authority !== "string" || authority.trim() === "") {
24230
24487
  throw navigatorUnavailableError(
@@ -24282,21 +24539,6 @@ function createNavigatorAttendance(options) {
24282
24539
  const helpContext = help.map(({ role, help: text }) => `<role_help role="${role}">
24283
24540
  ${text}
24284
24541
  </role_help>`).join("\n");
24285
- let output;
24286
- let prepareBatchRejected = false;
24287
- outputSink = (value) => {
24288
- if (output === void 0) {
24289
- output = value;
24290
- return;
24291
- }
24292
- const prior2 = output.candidates;
24293
- const next = value.candidates;
24294
- const merged = [
24295
- ...Array.isArray(prior2) ? prior2 : prior2 === void 0 ? [] : [prior2],
24296
- ...Array.isArray(next) ? next : next === void 0 ? [] : [next]
24297
- ];
24298
- output = { ...value, candidates: merged };
24299
- };
24300
24542
  const tool = createNavigatorPrepareTool((value) => {
24301
24543
  outputSink?.(value);
24302
24544
  });
@@ -24304,7 +24546,12 @@ ${text}
24304
24546
  sessionReady = (async () => {
24305
24547
  let created;
24306
24548
  try {
24307
- created = await options.createSession({ context: options.context, subject: subjectKey, ...options.modelSettingPath === void 0 ? {} : { modelSettingPath: options.modelSettingPath }, tool });
24549
+ created = await options.createSession({
24550
+ context: options.context,
24551
+ subject: subjectKey,
24552
+ ...options.modelSettingPath === void 0 ? {} : { modelSettingPath: options.modelSettingPath },
24553
+ tool
24554
+ });
24308
24555
  } catch (error) {
24309
24556
  throw navigatorUnavailableError("session", error);
24310
24557
  }
@@ -24335,26 +24582,40 @@ ${text}
24335
24582
  session.appendEntry(INVOCATION_ENTRY, { invocationId, role: options.role, phase: options.phase, subjectKey });
24336
24583
  }
24337
24584
  if (disposed) throw navigatorUnavailableError("session", new Error("Navigator attendance was disposed"));
24338
- const activeSession = session;
24339
- if (activeSession === void 0) throw new Error("Navigator session was not created");
24340
- const prior = activeSession.entries().filter((entry) => exactRecord2(entry) && entry.type === "custom" && entry.customType === ROUTE_ENTRY && exactRecord2(entry.data) && entry.data.subjectKey === subjectKey).at(-1)?.data;
24341
- if (exactRecord2(prior) && Array.isArray(prior.route) && prior.route.every((target) => targetIsValid(target))) {
24342
- previousRoute = prior.route.map((target) => ({ role: target.role, phase: target.phase }));
24343
- }
24344
- const publicSettlementHistory = activeSession.entries().filter((entry) => exactRecord2(entry) && entry.type === "custom" && entry.customType === SETTLEMENT_ENTRY && exactRecord2(entry.data)).map((entry) => entry.data);
24585
+ if (session === void 0) throw new Error("Navigator session was not created");
24586
+ return { soul, routePlaybook, helpContext, modelSetting, model, help, activeSession: session };
24587
+ };
24588
+ const prepare = async (materialsBundle) => {
24589
+ const boundSettlement = prepareBoundSettlement;
24590
+ prepareBoundSettlement = void 0;
24591
+ const invocationId = invocationPrincipal;
24592
+ activeInvocationId = invocationId;
24593
+ let output;
24594
+ let prepareBatchRejected = false;
24595
+ outputSink = (value) => {
24596
+ if (output === void 0) {
24597
+ output = value;
24598
+ return;
24599
+ }
24600
+ const prior = normalizePrepareProse(output) ?? "";
24601
+ const next = normalizePrepareProse(value) ?? "";
24602
+ const merged = [prior, next].filter((part) => part.trim() !== "").join("\n\n");
24603
+ output = { prose: merged };
24604
+ };
24605
+ const { soul, routePlaybook, helpContext, help, activeSession } = materialsBundle ?? await loadMaterialsAndSession(invocationId);
24606
+ const publicSettlementHistory = activeSession.entries().filter((entry) => exactRecord3(entry) && entry.type === "custom" && entry.customType === SETTLEMENT_ENTRY && exactRecord3(entry.data)).map((entry) => entry.data);
24345
24607
  const projection = {
24346
24608
  subjectKey,
24347
24609
  subject,
24348
24610
  authority,
24349
24611
  currentRole: { role: options.role, phase: options.phase },
24350
24612
  ...boundSettlement === void 0 ? {} : { currentSettlement: boundSettlement },
24351
- priorRoute: exactRecord2(prior) && Array.isArray(prior.route) && prior.route.every((target) => targetIsValid(target)) ? prior.route.map((target) => ({ role: target.role, phase: target.phase })) : null,
24352
24613
  publicSettlementHistory,
24353
24614
  liveRoleHelp: help
24354
24615
  };
24355
24616
  activeSession.appendEntry(CONTEXT_ENTRY, projection);
24356
- const request = [
24357
- "\u672C\u6B21\u5BFC\u822A\u6750\u6599\u5982\u4E0B\uFF1A",
24617
+ const request = boundSettlement === void 0 ? [
24618
+ "\u672C\u8F6E\u4E3A\u5F85\u547D\u8F6E\u3002",
24358
24619
  `<navigator_soul>
24359
24620
  ${soul}
24360
24621
  </navigator_soul>`,
@@ -24370,12 +24631,32 @@ ${authority}
24370
24631
  `<current_role>
24371
24632
  ${JSON.stringify({ role: options.role, phase: options.phase })}
24372
24633
  </current_role>`,
24373
- ...boundSettlement === void 0 ? [] : [`<current_settlement>
24634
+ `<public_settlement_history>
24635
+ ${JSON.stringify(projection.publicSettlementHistory)}
24636
+ </public_settlement_history>`,
24637
+ `<live_role_help>
24638
+ ${helpContext}
24639
+ </live_role_help>`
24640
+ ].join("\n\n") : [
24641
+ "\u672C\u8F6E\u4E3A\u7ED3\u7B97\u6295\u5582\u8F6E\u3002",
24642
+ `<navigator_soul>
24643
+ ${soul}
24644
+ </navigator_soul>`,
24645
+ ...routePlaybookReadFailure === void 0 ? [`<route_playbook>
24646
+ ${routePlaybook}
24647
+ </route_playbook>`] : ["\u53EF\u9009\u8DEF\u7EBF\u624B\u518C\u672A\u80FD\u8BFB\u53D6\u3002"],
24648
+ `<work_subject>
24649
+ ${subject}
24650
+ </work_subject>`,
24651
+ `<controlling_authority>
24652
+ ${authority}
24653
+ </controlling_authority>`,
24654
+ `<current_role>
24655
+ ${JSON.stringify({ role: options.role, phase: options.phase })}
24656
+ </current_role>`,
24657
+ `<current_settlement>
24374
24658
  ${JSON.stringify(boundSettlement)}
24375
- </current_settlement>`],
24376
- `<prior_route>
24377
- ${JSON.stringify(prior ?? null)}
24378
- </prior_route>`,
24659
+ </current_settlement>`,
24379
24660
  `<public_settlement_history>
24380
24661
  ${JSON.stringify(projection.publicSettlementHistory)}
24381
24662
  </public_settlement_history>`,
@@ -24416,33 +24697,47 @@ ${helpContext}
24416
24697
  if (deliveryRequest && output === void 0) delivery.recordDeliveryRequest();
24417
24698
  };
24418
24699
  await promptAllowingRejectedPrepare(request, false);
24419
- while (output === void 0 && delivery.nextAction() === "request-delivery") {
24420
- await promptAllowingRejectedPrepare(RECEIPT_DELIVERY_PROMPT, true);
24421
- }
24422
- if (output === void 0 && delivery.nextAction() === "no-receipt" && activeSession.providerFailure?.() === void 0) {
24423
- const facts = delivery.facts({ runPointer: activeSession.recordPointer(), attemptPointer: invocationId });
24424
- activeSession.appendEntry(NO_RECEIPT_LIFECYCLE_ENTRY_TYPE, facts);
24425
- preparationNoReceipt = true;
24426
- candidates = [];
24427
- return candidates;
24700
+ if (boundSettlement !== void 0) {
24701
+ while (output === void 0 && prepareBatchRejected && delivery.nextAction() === "request-delivery") {
24702
+ await promptAllowingRejectedPrepare(RECEIPT_DELIVERY_PROMPT, true);
24703
+ }
24704
+ if (output === void 0 && delivery.nextAction() === "request-delivery") {
24705
+ while (delivery.nextAction() === "request-delivery") {
24706
+ delivery.recordDeliveryRequest();
24707
+ }
24708
+ }
24709
+ if (output === void 0 && delivery.nextAction() === "no-receipt" && activeSession.providerFailure?.() === void 0) {
24710
+ const facts = delivery.facts({ runPointer: activeSession.recordPointer(), attemptPointer: invocationId });
24711
+ activeSession.appendEntry(NO_RECEIPT_LIFECYCLE_ENTRY_TYPE, facts);
24712
+ preparedProse = void 0;
24713
+ return void 0;
24714
+ }
24428
24715
  }
24429
24716
  } catch (error) {
24430
24717
  throw error instanceof NavigatorUnavailableError ? error : navigatorUnavailableError("transport", error);
24431
24718
  }
24432
24719
  if (output === void 0) {
24720
+ if (boundSettlement === void 0) {
24721
+ preparedProse = void 0;
24722
+ return void 0;
24723
+ }
24433
24724
  const nativeFailure = [...activeSession.entries()].reverse().find((entry) => {
24434
- if (!exactRecord2(entry) || entry.type !== "message" || !exactRecord2(entry.message)) return false;
24725
+ if (!exactRecord3(entry) || entry.type !== "message" || !exactRecord3(entry.message)) return false;
24435
24726
  return entry.message.role === "assistant" && typeof entry.message.errorMessage === "string" && entry.message.errorMessage.trim() !== "";
24436
24727
  });
24437
- const nativeMessage = exactRecord2(nativeFailure) && exactRecord2(nativeFailure.message) ? nativeFailure.message : void 0;
24728
+ const nativeMessage = exactRecord3(nativeFailure) && exactRecord3(nativeFailure.message) ? nativeFailure.message : void 0;
24438
24729
  const errorMessage = nativeMessage !== void 0 && typeof nativeMessage.errorMessage === "string" ? nativeMessage.errorMessage : "Navigator did not submit direction advice";
24439
24730
  const providerFailure = activeSession.providerFailure?.();
24440
24731
  const source = providerFailure?.source ?? "unknown";
24441
24732
  const cause = providerFailure?.cause ?? source;
24442
24733
  throw navigatorUnavailableError(source, errorMessage, cause);
24443
24734
  }
24444
- candidates = normalizePrepareOutput(output);
24445
- return candidates;
24735
+ if (boundSettlement === void 0) {
24736
+ preparedProse = void 0;
24737
+ return void 0;
24738
+ }
24739
+ preparedProse = normalizePrepareProse(output);
24740
+ return preparedProse;
24446
24741
  } finally {
24447
24742
  outputSink = void 0;
24448
24743
  }
@@ -24453,7 +24748,6 @@ ${helpContext}
24453
24748
  if (next.subjectKey !== subjectKey && session !== void 0) {
24454
24749
  const previous = session;
24455
24750
  session = void 0;
24456
- previousRoute = void 0;
24457
24751
  closing = previous.dispose();
24458
24752
  }
24459
24753
  subjectKey = next.subjectKey;
@@ -24475,13 +24769,16 @@ ${helpContext}
24475
24769
  prepare() {
24476
24770
  if (disposed || preparation !== void 0) return;
24477
24771
  preparationFailure = void 0;
24478
- preparation = prepare();
24772
+ preparationInFlight = true;
24773
+ preparation = prepare().finally(() => {
24774
+ preparationInFlight = false;
24775
+ });
24479
24776
  void preparation.catch((error) => {
24480
24777
  preparationFailure = error;
24481
24778
  });
24482
24779
  },
24483
24780
  isPreparing() {
24484
- return preparation !== void 0 || sessionReady !== void 0;
24781
+ return preparationInFlight;
24485
24782
  },
24486
24783
  knownRoutePlaybookReadFailure() {
24487
24784
  return routePlaybookReadFailure;
@@ -24505,81 +24802,70 @@ ${helpContext}
24505
24802
  if (disposed) return;
24506
24803
  const invocationId = activeInvocationId ?? invocationPrincipal;
24507
24804
  let report;
24508
- if (settlement.kind === "human_decision" || settlement.kind === "role_infrastructure_failure") {
24509
- if (sessionReady !== void 0) {
24510
- try {
24511
- await sessionReady;
24512
- } catch (error) {
24513
- preparationFailure ??= error;
24514
- }
24805
+ if (sessionReady !== void 0) {
24806
+ try {
24807
+ await sessionReady;
24808
+ } catch (error) {
24809
+ preparationFailure ??= error;
24515
24810
  }
24516
- if (preparation !== void 0) {
24517
- try {
24518
- await preparation;
24519
- } catch (error) {
24520
- preparationFailure ??= error;
24521
- }
24811
+ }
24812
+ if (preparation !== void 0) {
24813
+ try {
24814
+ await preparation;
24815
+ } catch (error) {
24816
+ preparationFailure ??= error;
24522
24817
  }
24523
- session?.appendEntry(SETTLEMENT_ENTRY, { invocationId, subjectKey, role: settlement.role, phase: settlement.phase, kind: settlement.kind, ...settlement.kind === "human_decision" ? { status: settlement.status } : {} });
24818
+ preparation = void 0;
24819
+ }
24820
+ const settlementFact = {
24821
+ invocationId,
24822
+ subjectKey,
24823
+ role: settlement.role,
24824
+ phase: settlement.phase,
24825
+ kind: settlement.kind,
24826
+ ..."status" in settlement && settlement.status !== void 0 ? { status: settlement.status } : {}
24827
+ };
24828
+ let drainedProse;
24829
+ if (settlement.kind === "arrival") {
24830
+ session?.appendEntry(SETTLEMENT_ENTRY, settlementFact);
24524
24831
  if (preparationFailure !== void 0) {
24525
24832
  report = unavailable(invocationId, preparationFailure);
24526
24833
  } else {
24527
- report = { disposition: "no-advice" };
24834
+ report = {
24835
+ disposition: "arrival",
24836
+ ...settlement.message === void 0 ? {} : { arrivalMessage: settlement.message }
24837
+ };
24528
24838
  }
24529
- } else if (settlement.kind === "arrival") {
24530
- if (sessionReady !== void 0) {
24839
+ } else {
24840
+ if (session !== void 0) preparationFailure = void 0;
24841
+ let coldMaterials;
24842
+ if (session === void 0 && preparationFailure === void 0) {
24531
24843
  try {
24532
- await sessionReady;
24844
+ coldMaterials = await loadMaterialsAndSession(invocationId);
24533
24845
  } catch (error) {
24534
- preparationFailure ??= error;
24846
+ preparationFailure = error;
24535
24847
  }
24536
24848
  }
24537
- if (preparation !== void 0) {
24849
+ session?.appendEntry(SETTLEMENT_ENTRY, settlementFact);
24850
+ if (preparationFailure === void 0) {
24851
+ prepareBoundSettlement = settlement;
24852
+ preparation = prepare(coldMaterials);
24853
+ void preparation.catch((error) => {
24854
+ preparationFailure = error;
24855
+ });
24538
24856
  try {
24539
- await preparation;
24857
+ drainedProse = await preparation;
24540
24858
  } catch (error) {
24541
24859
  preparationFailure ??= error;
24542
24860
  }
24861
+ preparation = void 0;
24543
24862
  }
24544
- report = preparationFailure === void 0 ? { disposition: "arrival", ...settlement.message === void 0 ? {} : { arrivalMessage: settlement.message } } : unavailable(invocationId, preparationFailure);
24545
- } else if (preparation === void 0) {
24546
- report = unavailable(invocationId, "Navigator preparation did not start");
24547
- } else {
24548
- try {
24549
- if (sessionReady !== void 0) await sessionReady;
24550
- let prepared = await preparation;
24551
- session?.appendEntry(SETTLEMENT_ENTRY, { invocationId, subjectKey, role: settlement.role, phase: settlement.phase, kind: settlement.kind, ...settlement.status === void 0 ? {} : { status: settlement.status } });
24552
- let selected = selectNavigatorCandidate(prepared, settlement);
24553
- if (selected?.candidate.next !== void 0 && !selected.matchedToSettlement) {
24554
- if (disposed) return;
24555
- prepareBoundSettlement = settlement;
24556
- prepared = await prepare();
24557
- if (disposed) return;
24558
- selected = selectNavigatorCandidate(prepared, settlement);
24559
- }
24560
- const selectedCandidate = selected?.candidate;
24561
- if (selectedCandidate?.next === void 0 && preparationNoReceipt) {
24562
- report = { disposition: "no-advice" };
24563
- } else if (selectedCandidate?.next === void 0) {
24564
- throw new Error("Navigator prepared no machine-usable next direction");
24565
- } else {
24566
- const selectedRoute = selectedCandidate.route;
24567
- const routeChanged = selectedRoute !== void 0 && !routeEqual(previousRoute, selectedRoute);
24568
- const command = typeof selectedCandidate.command === "string" && selectedCandidate.command.trim() !== "" ? selectedCandidate.command : renderPublicAkRoleCommand(selectedCandidate.next);
24569
- report = {
24570
- disposition: "recommendation",
24571
- ...routeChanged ? { route: selectedRoute } : {},
24572
- next: selectedCandidate.next,
24573
- ...selectedCandidate.reason === void 0 ? {} : { reason: selectedCandidate.reason },
24574
- ...command === void 0 ? {} : { command }
24575
- };
24576
- if (selectedRoute !== void 0) {
24577
- previousRoute = selectedRoute;
24578
- session?.appendEntry(ROUTE_ENTRY, { invocationId, subjectKey, route: selectedRoute });
24579
- }
24580
- }
24581
- } catch (error) {
24582
- report = unavailable(invocationId, error);
24863
+ if (preparationFailure !== void 0) {
24864
+ report = unavailable(invocationId, preparationFailure);
24865
+ } else if (typeof drainedProse === "string" && drainedProse.trim() !== "") {
24866
+ report = { disposition: "advice", prose: drainedProse };
24867
+ } else {
24868
+ report = { disposition: "no-advice" };
24583
24869
  }
24584
24870
  }
24585
24871
  await routePlaybookSettlement;
@@ -24593,10 +24879,7 @@ ${helpContext}
24593
24879
  role: options.role,
24594
24880
  phase: options.phase,
24595
24881
  subjectKey,
24596
- ...report.route === void 0 ? {} : { route: report.route },
24597
- ...report.next === void 0 ? {} : { next: report.next },
24598
- ...report.reason === void 0 ? {} : { reason: report.reason },
24599
- ...report.command === void 0 ? {} : { command: report.command },
24882
+ ...report.prose === void 0 ? {} : { prose: report.prose },
24600
24883
  ...report.unavailableReason === void 0 ? {} : { unavailableReason: report.unavailableReason },
24601
24884
  ...report.unavailableSource === void 0 ? {} : { unavailableSource: report.unavailableSource },
24602
24885
  ...report.unavailableCause === void 0 ? {} : { unavailableCause: report.unavailableCause },
@@ -24612,9 +24895,8 @@ ${helpContext}
24612
24895
  }
24613
24896
  preparation = void 0;
24614
24897
  sessionReady = void 0;
24615
- candidates = void 0;
24898
+ preparedProse = void 0;
24616
24899
  preparationFailure = void 0;
24617
- preparationNoReceipt = false;
24618
24900
  routePlaybookSettlement = void 0;
24619
24901
  routePlaybookReadFailure = void 0;
24620
24902
  }
@@ -24829,7 +25111,7 @@ init_submission_errors();
24829
25111
  init_submission_errors();
24830
25112
  import { execFileSync as execFileSync4 } from "node:child_process";
24831
25113
  import { existsSync as existsSync12, lstatSync as lstatSync3, readdirSync as readdirSync3, readFileSync as readFileSync5, rmdirSync, rmSync } from "node:fs";
24832
- import { resolve as resolve18 } from "node:path";
25114
+ import { resolve as resolve17 } from "node:path";
24833
25115
  var WORKER_SUBMISSION_GATE_RECORD_KIND = WORKER_SUBMISSION_GATE_KIND;
24834
25116
  var WORKER_COMMIT_BASELINE_ENTRY_TYPE = "commit-baseline";
24835
25117
  var WORKER_COMMIT_REMINDER_BOUNCE_ENTRY_TYPE = "commit-reminder-bounce";
@@ -24878,7 +25160,7 @@ function escapeGitConfigValueRegex(value) {
24878
25160
  function unsetOwnedHooksPath(file) {
24879
25161
  const owned = [];
24880
25162
  for (const value of tryGetAll(file, "core.hooksPath")) {
24881
- if (!ownedHook(resolve18(value, HOOK_FILE))) continue;
25163
+ if (!ownedHook(resolve17(value, HOOK_FILE))) continue;
24882
25164
  try {
24883
25165
  gitFile(file, [
24884
25166
  "--unset-all",
@@ -24893,15 +25175,15 @@ function unsetOwnedHooksPath(file) {
24893
25175
  return owned;
24894
25176
  }
24895
25177
  function rmOwnedDir(dir) {
24896
- const hookPath = resolve18(dir, HOOK_FILE);
25178
+ const hookPath = resolve17(dir, HOOK_FILE);
24897
25179
  if (!ownedHook(hookPath)) return;
24898
25180
  rmSync(hookPath, { force: true });
24899
25181
  if (existsSync12(dir) && readdirSync3(dir).length === 0) rmdirSync(dir);
24900
25182
  }
24901
25183
  function linkedGitDirs(commonDir) {
24902
- const root = resolve18(commonDir, "worktrees");
25184
+ const root = resolve17(commonDir, "worktrees");
24903
25185
  if (!existsSync12(root)) return [];
24904
- return readdirSync3(root).map((name) => resolve18(root, name)).filter((dir) => lstatSync3(dir).isDirectory());
25186
+ return readdirSync3(root).map((name) => resolve17(root, name)).filter((dir) => lstatSync3(dir).isDirectory());
24905
25187
  }
24906
25188
  function uninstallPackageWorkerHooks(cwd) {
24907
25189
  let inside;
@@ -24915,14 +25197,14 @@ function uninstallPackageWorkerHooks(cwd) {
24915
25197
  const clear = (configFile) => {
24916
25198
  for (const hooks of unsetOwnedHooksPath(configFile)) rmOwnedDir(hooks);
24917
25199
  };
24918
- clear(resolve18(commonDir, "config"));
24919
- clear(resolve18(commonDir, "config.worktree"));
24920
- rmOwnedDir(resolve18(commonDir, HOOKS_DIR));
24921
- const legacy = resolve18(commonDir, "hooks", HOOK_FILE);
25200
+ clear(resolve17(commonDir, "config"));
25201
+ clear(resolve17(commonDir, "config.worktree"));
25202
+ rmOwnedDir(resolve17(commonDir, HOOKS_DIR));
25203
+ const legacy = resolve17(commonDir, "hooks", HOOK_FILE);
24922
25204
  if (ownedHook(legacy)) rmSync(legacy, { force: true });
24923
25205
  for (const gitDir of linkedGitDirs(commonDir)) {
24924
- clear(resolve18(gitDir, "config.worktree"));
24925
- rmOwnedDir(resolve18(gitDir, HOOKS_DIR));
25206
+ clear(resolve17(gitDir, "config.worktree"));
25207
+ rmOwnedDir(resolve17(gitDir, HOOKS_DIR));
24926
25208
  }
24927
25209
  }
24928
25210
  function isRecord13(value) {
@@ -25675,7 +25957,7 @@ async function executeActivationStage(role, stage, infrastructure) {
25675
25957
  throw activationError;
25676
25958
  }
25677
25959
  }
25678
- function writeActivationTraceRecord(record4, write = writeSync4) {
25960
+ function writeActivationTraceRecord(record4, write = writeSync3) {
25679
25961
  writeStderrJsonlRecord(record4, write);
25680
25962
  }
25681
25963
  var ActivationBarrierError = class extends Error {
@@ -26101,6 +26383,21 @@ function createCountersignRoleRuntime(roleHost, dependencies, hostActions) {
26101
26383
  dependencies
26102
26384
  );
26103
26385
  }
26386
+ function lastAssistantProse(messages) {
26387
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
26388
+ const message = messages[index];
26389
+ if (message?.role !== "assistant" || !Array.isArray(message.content)) continue;
26390
+ const texts = [];
26391
+ for (const part of message.content) {
26392
+ if (part.type === "text" && typeof part.text === "string" && part.text.length > 0) {
26393
+ texts.push(part.text);
26394
+ }
26395
+ }
26396
+ if (texts.length === 0) continue;
26397
+ return texts.join("");
26398
+ }
26399
+ return void 0;
26400
+ }
26104
26401
  function createRoleRuntimeExtension(dependencies) {
26105
26402
  return (envelopeHost) => {
26106
26403
  let projectClosedSubmission = async () => {
@@ -26159,10 +26456,6 @@ function createRoleRuntimeExtension(dependencies) {
26159
26456
  if (settlement === void 0 || attendance === void 0) return;
26160
26457
  const workContext = navigatorWorkContext;
26161
26458
  const pending = (async () => {
26162
- if (settlement.kind !== "accepted") {
26163
- await attendance.settle(settlement);
26164
- return;
26165
- }
26166
26459
  const settlePromise = attendance.settle(settlement);
26167
26460
  void settlePromise.catch(() => void 0);
26168
26461
  const raced = await raceNavigatorGrace(settlePromise, NAVIGATOR_POST_ROLE_GRACE_MS);
@@ -26363,10 +26656,8 @@ function createRoleRuntimeExtension(dependencies) {
26363
26656
  pendingSubmissionNonPassByToolCallId.delete(event.toolCallId);
26364
26657
  return { details: submissionNonPass, isError: true };
26365
26658
  }
26366
- if (event.isError) return;
26367
- return;
26368
26659
  });
26369
- roleHost.on("agent_end", (event, ctx) => {
26660
+ roleHost.on("agent_end", async (event, ctx) => {
26370
26661
  const lastMessage = event.messages.at(-1);
26371
26662
  if (lastMessage?.role === "assistant" && (lastMessage.stopReason === "error" || lastMessage.stopReason === "aborted")) {
26372
26663
  if (receiptDelivery.nextAction() !== "accepted") {
@@ -26374,6 +26665,47 @@ function createRoleRuntimeExtension(dependencies) {
26374
26665
  }
26375
26666
  return;
26376
26667
  }
26668
+ const role = selectedRole ?? roleHost.getFlag(ROLE_FLAG.name);
26669
+ if (role === "navigator" && receiptDelivery.nextAction() !== "accepted") {
26670
+ const prose = lastAssistantProse(event.messages);
26671
+ if (prose !== void 0 && prose.trim() !== "") {
26672
+ const accepted = { prose };
26673
+ await sealAcceptedSubmission({
26674
+ context: ctx,
26675
+ role: "navigator",
26676
+ accepted,
26677
+ toolCallId: `navigator-prose-exit:${randomUUID8()}`
26678
+ });
26679
+ await projectClosedSubmission(
26680
+ { role: "navigator", kind: "accepted", accepted },
26681
+ ctx
26682
+ );
26683
+ return;
26684
+ }
26685
+ if (!noReceiptRecorded) {
26686
+ const runPointer = runDirectoryFromHostContext(ctx);
26687
+ if (runPointer !== void 0) {
26688
+ noReceiptRecorded = true;
26689
+ while (receiptDelivery.nextAction() === "request-delivery") {
26690
+ receiptDelivery.recordDeliveryRequest();
26691
+ }
26692
+ const facts = receiptDelivery.facts({ runPointer, attemptPointer: `current:${runPointer}` });
26693
+ envelopeHost.appendEntry(NO_RECEIPT_LIFECYCLE_ENTRY_TYPE, facts);
26694
+ try {
26695
+ sitianReport({
26696
+ level: "event",
26697
+ kind: "no-receipt-lifecycle",
26698
+ cwd: ctx.cwd,
26699
+ sessionParent: ctx.sessionManager.getSessionFile(),
26700
+ payload: facts,
26701
+ source: "role-runtime"
26702
+ });
26703
+ } catch {
26704
+ }
26705
+ }
26706
+ }
26707
+ return;
26708
+ }
26377
26709
  if (receiptDelivery.nextAction() === "request-delivery") {
26378
26710
  receiptDelivery.recordDeliveryRequest();
26379
26711
  envelopeHost.appendEntry("ak-receipt-delivery-request");
@@ -26857,11 +27189,8 @@ function createRoleRuntimeExtension(dependencies) {
26857
27189
  }
26858
27190
  };
26859
27191
  try {
26860
- const bookKey = resolveBookKeyFromGit(ctx.cwd);
26861
- const correlation = correlationIdentityFromEnv();
26862
- const sessionFile = ctx.sessionManager.getSessionFile?.() || ctx.sessionManager.getSessionDir?.();
26863
- const ledgerHome = resolveActivationLedgerHomeForPath(sessionFile);
26864
- const session = durableSessionPointer(ctx.sessionManager);
27192
+ resolveBookKeyFromGit(ctx.cwd);
27193
+ durableSessionPointer(ctx.sessionManager);
26865
27194
  const isStationChild = roleHost.getFlag(STATION_CHILD_FLAG.name) === true;
26866
27195
  if (dependencies.createNavigatorAttendance !== void 0 && entry.role !== "navigator" && !isStationChild) {
26867
27196
  navigatorSessionParent = ctx.sessionManager.getSessionFile();
@@ -26948,16 +27277,6 @@ function createRoleRuntimeExtension(dependencies) {
26948
27277
  if (entry.role === "coder") coder.armSubmissionGate(ctx.cwd, ctx.sessionManager);
26949
27278
  else fixer.armSubmissionGate(ctx.cwd, ctx.sessionManager);
26950
27279
  }
26951
- appendAcceptedActivationToBook({
26952
- ledgerHome,
26953
- fact: buildAcceptedActivationFact({
26954
- role: entry.role,
26955
- observedAt: clock(),
26956
- bookKey,
26957
- session,
26958
- correlation
26959
- })
26960
- });
26961
27280
  admitted = true;
26962
27281
  } catch (error) {
26963
27282
  failInfrastructure(error, ctx);
@@ -26971,11 +27290,11 @@ init_role_activation_flags();
26971
27290
  init_submission_correctable_error();
26972
27291
  init_navigator_invocation_identity();
26973
27292
  async function listen(server, path) {
26974
- await new Promise((resolve22, reject) => {
27293
+ await new Promise((resolve21, reject) => {
26975
27294
  server.once("error", reject);
26976
27295
  server.listen(path, () => {
26977
27296
  server.off("error", reject);
26978
- resolve22();
27297
+ resolve21();
26979
27298
  });
26980
27299
  });
26981
27300
  }
@@ -27008,10 +27327,10 @@ async function prepareRoleEnvelope(options) {
27008
27327
  let rejection;
27009
27328
  let infrastructureRoundFailure;
27010
27329
  const hostAbort = new AbortController();
27011
- const runId = request.runDirectory.split("/").filter(Boolean).at(-1) ?? randomUUID8();
27330
+ const runId = request.runDirectory.split("/").filter(Boolean).at(-1) ?? randomUUID9();
27012
27331
  await mkdir7(request.runDirectory, { recursive: true });
27013
27332
  let sessionFile = options.sessionFile ?? join41(request.runDirectory, "session", "session.jsonl");
27014
- await mkdir7(dirname22(sessionFile), { recursive: true });
27333
+ await mkdir7(dirname21(sessionFile), { recursive: true });
27015
27334
  if (request.continuation.kind !== "resume") {
27016
27335
  try {
27017
27336
  await writeFile12(
@@ -27030,6 +27349,25 @@ async function prepareRoleEnvelope(options) {
27030
27349
  if (error.code !== "EEXIST") throw error;
27031
27350
  }
27032
27351
  }
27352
+ let durableWriteChain = Promise.resolve();
27353
+ let armDurableWriteFailure;
27354
+ const persistPackageSessionEntry = (entry) => {
27355
+ const customType = typeof entry.customType === "string" ? entry.customType : "unknown";
27356
+ const line2 = `${JSON.stringify({
27357
+ ...entry,
27358
+ id: typeof entry.id === "string" ? entry.id : randomUUID9(),
27359
+ timestamp: typeof entry.timestamp === "string" ? entry.timestamp : (/* @__PURE__ */ new Date()).toISOString()
27360
+ })}
27361
+ `;
27362
+ durableWriteChain = durableWriteChain.then(async () => {
27363
+ try {
27364
+ await appendFile3(sessionFile, line2, "utf8");
27365
+ } catch (error) {
27366
+ const diagnostic = error instanceof Error ? error.message : String(error);
27367
+ armDurableWriteFailure?.(customType, diagnostic);
27368
+ }
27369
+ });
27370
+ };
27033
27371
  const context = {
27034
27372
  cwd: request.cwd,
27035
27373
  mode: "print",
@@ -27042,7 +27380,7 @@ async function prepareRoleEnvelope(options) {
27042
27380
  getLeafEntry: () => sessionEntries.at(-1),
27043
27381
  getLeafId: () => runId,
27044
27382
  getEntries: () => sessionEntries,
27045
- getSessionDir: () => dirname22(sessionFile),
27383
+ getSessionDir: () => dirname21(sessionFile),
27046
27384
  getSessionFile: () => sessionFile,
27047
27385
  getHeader: () => ({ type: "session", id: runId }),
27048
27386
  setSessionFile(path) {
@@ -27052,6 +27390,7 @@ async function prepareRoleEnvelope(options) {
27052
27390
  const entry = { type: "custom", customType, data };
27053
27391
  sessionEntries.push(entry);
27054
27392
  customEntries.push({ customType, data });
27393
+ persistPackageSessionEntry(entry);
27055
27394
  }
27056
27395
  },
27057
27396
  abort() {
@@ -27065,6 +27404,7 @@ async function prepareRoleEnvelope(options) {
27065
27404
  const entry = { type: "custom_message", customType, ...payload, message: payload };
27066
27405
  sessionEntries.push(entry);
27067
27406
  customEntries.push({ customType, data: message.details ?? message.content });
27407
+ persistPackageSessionEntry(entry);
27068
27408
  };
27069
27409
  const emit = async (event, value) => {
27070
27410
  const results = [];
@@ -27144,7 +27484,7 @@ async function prepareRoleEnvelope(options) {
27144
27484
  }
27145
27485
  };
27146
27486
  createRoleRuntimeExtension(options.dependencies)(envelope);
27147
- const token = randomUUID8();
27487
+ const token = randomUUID9();
27148
27488
  const server = createServer((socket) => serveSocket(socket));
27149
27489
  function rememberProjectedRejection(details, toolCallId, content) {
27150
27490
  if (typeof details !== "object" || details === null) return;
@@ -27180,6 +27520,17 @@ async function prepareRoleEnvelope(options) {
27180
27520
  };
27181
27521
  hostAbort.abort();
27182
27522
  }
27523
+ armDurableWriteFailure = (customType, diagnostic) => {
27524
+ rememberInfrastructureFailure(
27525
+ {
27526
+ cause: "infrastructure",
27527
+ kind: "role_infrastructure_failure",
27528
+ code: "durable-session-write-failed",
27529
+ customType
27530
+ },
27531
+ [{ type: "text", text: `ak-role: durable session entry flush failed (${customType}): ${diagnostic}` }]
27532
+ );
27533
+ };
27183
27534
  function declareRoundInfrastructureFailure(error) {
27184
27535
  const diagnostic = error instanceof Error ? error.message : String(error);
27185
27536
  const content = [{ type: "text", text: diagnostic }];
@@ -27225,7 +27576,7 @@ async function prepareRoleEnvelope(options) {
27225
27576
  async function invokeAkTool(name, args) {
27226
27577
  const tool = tools.get(name);
27227
27578
  if (tool === void 0) throw new Error(`Unknown AK tool: ${name}`);
27228
- const toolCallId = randomUUID8();
27579
+ const toolCallId = randomUUID9();
27229
27580
  calls.push({ toolCallId, toolName: name });
27230
27581
  sessionEntries.push({
27231
27582
  type: "message",
@@ -27341,6 +27692,15 @@ async function prepareRoleEnvelope(options) {
27341
27692
  const relay = fileURLToPath2(new URL("./mcp-relay.mjs", import.meta.url));
27342
27693
  await listen(server, options.socketPath);
27343
27694
  let disposed = false;
27695
+ let durableFailureHandedToCloseRound = false;
27696
+ const settleDurableWrites = async () => {
27697
+ await durableWriteChain;
27698
+ if (infrastructureRoundFailure !== void 0) {
27699
+ durableFailureHandedToCloseRound = true;
27700
+ return { accepted: false, failure: infrastructureRoundFailure };
27701
+ }
27702
+ return void 0;
27703
+ };
27344
27704
  const dispose = async () => {
27345
27705
  if (disposed) return;
27346
27706
  disposed = true;
@@ -27350,11 +27710,25 @@ async function prepareRoleEnvelope(options) {
27350
27710
  } catch (error) {
27351
27711
  cleanupFailures.push(error);
27352
27712
  }
27713
+ try {
27714
+ const alreadyHanded = durableFailureHandedToCloseRound;
27715
+ const durableFailure = await settleDurableWrites();
27716
+ if (durableFailure !== void 0 && !alreadyHanded) {
27717
+ cleanupFailures.push(
27718
+ Object.assign(
27719
+ new Error(durableFailure.failure.diagnostic ?? "durable session entry flush failed"),
27720
+ { code: durableFailure.failure.identity?.code ?? "durable-session-write-failed" }
27721
+ )
27722
+ );
27723
+ }
27724
+ } catch (error) {
27725
+ cleanupFailures.push(error);
27726
+ }
27353
27727
  try {
27354
27728
  const closeAll = server.closeAllConnections;
27355
27729
  if (typeof closeAll === "function") closeAll.call(server);
27356
- await new Promise((resolve22, reject) => {
27357
- server.close((error) => error ? reject(error) : resolve22());
27730
+ await new Promise((resolve21, reject) => {
27731
+ server.close((error) => error ? reject(error) : resolve21());
27358
27732
  });
27359
27733
  } catch (error) {
27360
27734
  cleanupFailures.push(error);
@@ -27371,6 +27745,7 @@ async function prepareRoleEnvelope(options) {
27371
27745
  if (calls.some((call) => call.toolName === terminatingToolName)) return;
27372
27746
  await invokeAkTool(terminatingToolName, params ?? {});
27373
27747
  }
27748
+ ;
27374
27749
  const closeRound = async () => {
27375
27750
  if (calls.length > 0) {
27376
27751
  const roundCalls = [...calls];
@@ -27378,6 +27753,7 @@ async function prepareRoleEnvelope(options) {
27378
27753
  await emit("turn_end", { turnIndex: 0, calls: roundCalls });
27379
27754
  }
27380
27755
  if (infrastructureRoundFailure !== void 0) {
27756
+ durableFailureHandedToCloseRound = true;
27381
27757
  return { accepted: false, failure: infrastructureRoundFailure };
27382
27758
  }
27383
27759
  let closure;
@@ -27389,6 +27765,8 @@ async function prepareRoleEnvelope(options) {
27389
27765
  }
27390
27766
  if (closure !== void 0) {
27391
27767
  await emit("agent_settled", {});
27768
+ const durableFailure2 = await settleDurableWrites();
27769
+ if (durableFailure2 !== void 0) return durableFailure2;
27392
27770
  return { accepted: true };
27393
27771
  }
27394
27772
  if (rejection !== void 0) {
@@ -27398,9 +27776,13 @@ async function prepareRoleEnvelope(options) {
27398
27776
  message: rejection.message
27399
27777
  };
27400
27778
  rejection = void 0;
27779
+ const durableFailure2 = await settleDurableWrites();
27780
+ if (durableFailure2 !== void 0) return durableFailure2;
27401
27781
  return { accepted: false, retry };
27402
27782
  }
27403
27783
  await emit("agent_settled", {});
27784
+ const durableFailure = await settleDurableWrites();
27785
+ if (durableFailure !== void 0) return durableFailure;
27404
27786
  return { accepted: true };
27405
27787
  };
27406
27788
  try {
@@ -27488,12 +27870,12 @@ import { join as join42 } from "node:path";
27488
27870
  // src/canonical-skill-binding.ts
27489
27871
  import { readFile as readFile20, realpath as realpath8 } from "node:fs/promises";
27490
27872
  import { homedir } from "node:os";
27491
- import { dirname as dirname23, resolve as resolve19 } from "node:path";
27873
+ import { dirname as dirname22, resolve as resolve18 } from "node:path";
27492
27874
  import { stripFrontmatter } from "@earendil-works/pi-coding-agent";
27493
27875
  function captureCanonicalSkillExpansion(name, snapshot, configuredPath, evidence, originalRequest) {
27494
27876
  const matchedPath = evidence?.location === configuredPath ? configuredPath : evidence?.location === snapshot.path ? snapshot.path : void 0;
27495
27877
  const expectedContent = matchedPath === void 0 ? void 0 : snapshot.body;
27496
- const prefixedContent = matchedPath === void 0 ? void 0 : `References are relative to ${dirname23(matchedPath)}.
27878
+ const prefixedContent = matchedPath === void 0 ? void 0 : `References are relative to ${dirname22(matchedPath)}.
27497
27879
 
27498
27880
  ${snapshot.body}`;
27499
27881
  if (evidence?.name !== name || matchedPath === void 0 || evidence.content !== expectedContent && evidence.content !== prefixedContent || evidence.userMessage !== originalRequest) {
@@ -27511,7 +27893,7 @@ var CanonicalSkillUnavailableError = class extends Error {
27511
27893
  code = "canonical-skill-unavailable";
27512
27894
  };
27513
27895
  async function loadCanonicalSkillBinding(name) {
27514
- const configuredPath = resolve19(
27896
+ const configuredPath = resolve18(
27515
27897
  homedir(),
27516
27898
  `.agents/skills/${name}/SKILL.md`
27517
27899
  );
@@ -27530,7 +27912,7 @@ async function loadCanonicalSkillBinding(name) {
27530
27912
  const snapshot = Object.freeze({
27531
27913
  raw,
27532
27914
  path,
27533
- baseDir: dirname23(path),
27915
+ baseDir: dirname22(path),
27534
27916
  body,
27535
27917
  snapshotIdentity: Object.freeze({ text: raw })
27536
27918
  });
@@ -27559,7 +27941,7 @@ init_doctor_evidence();
27559
27941
  init_doctor_evidence();
27560
27942
  init_host_contracts();
27561
27943
  import { readFile as readFile21 } from "node:fs/promises";
27562
- import { resolve as resolve20 } from "node:path";
27944
+ import { resolve as resolve19 } from "node:path";
27563
27945
  init_notary_source_run();
27564
27946
  init_packaged_role_registry();
27565
27947
  init_invocation();
@@ -27567,7 +27949,7 @@ function navigatorInputReference(getFlag, role) {
27567
27949
  if (getFlag === void 0) return void 0;
27568
27950
  const name = packagedRoleInputFlag(role);
27569
27951
  const value = name === void 0 ? void 0 : getFlag(name);
27570
- return typeof value === "string" && value !== "" ? resolve20(value) : void 0;
27952
+ return typeof value === "string" && value !== "" ? resolve19(value) : void 0;
27571
27953
  }
27572
27954
  async function loadNavigatorWorkContext(options) {
27573
27955
  const reference = navigatorInputReference(options.getFlag, options.role);
@@ -27588,7 +27970,7 @@ async function loadNavigatorWorkContext(options) {
27588
27970
  }
27589
27971
  const publicRunDir = runDirectoryFromHostContext(options.context);
27590
27972
  const currentSessionDir = options.context.sessionManager.getSessionDir();
27591
- const isBoundPublicRun = publicRunDir !== void 0 && resolve20(currentSessionDir) === resolve20(publicRunDir, "session");
27973
+ const isBoundPublicRun = publicRunDir !== void 0 && resolve19(currentSessionDir) === resolve19(publicRunDir, "session");
27592
27974
  if (options.role === "judge" && isBoundPublicRun) {
27593
27975
  let admitted;
27594
27976
  try {
@@ -27621,9 +28003,9 @@ async function loadNavigatorWorkContext(options) {
27621
28003
  }
27622
28004
  const workRoot = subjectRoot.includes("/.ak/work/") ? subjectRoot : void 0;
27623
28005
  const authorityFiles = workRoot === void 0 ? [] : [
27624
- resolve20(workRoot, "authority.md"),
27625
- resolve20(workRoot, "authority.txt"),
27626
- resolve20(workRoot, "design-v2/owner-direction.md")
28006
+ resolve19(workRoot, "authority.md"),
28007
+ resolve19(workRoot, "authority.txt"),
28008
+ resolve19(workRoot, "design-v2/owner-direction.md")
27627
28009
  ];
27628
28010
  let authorityMaterial;
27629
28011
  for (const path of authorityFiles) {
@@ -27653,7 +28035,7 @@ async function loadNavigatorWorkContext(options) {
27653
28035
  init_notary_source_run();
27654
28036
 
27655
28037
  // src/package-resources/method-skill-binding.ts
27656
- import { dirname as dirname24 } from "node:path";
28038
+ import { dirname as dirname23 } from "node:path";
27657
28039
  init_method_skill();
27658
28040
  async function loadPackagedCanonicalSkillBinding(packageRoot, name) {
27659
28041
  const material = await loadPackagedMethodSkillMaterial(packageRoot, name);
@@ -27661,7 +28043,7 @@ async function loadPackagedCanonicalSkillBinding(packageRoot, name) {
27661
28043
  const snapshot = Object.freeze({
27662
28044
  raw: material.raw,
27663
28045
  path: material.skillPath,
27664
- baseDir: dirname24(material.skillPath),
28046
+ baseDir: dirname23(material.skillPath),
27665
28047
  body: material.body,
27666
28048
  snapshotIdentity: Object.freeze({ text: material.raw })
27667
28049
  });
@@ -27807,7 +28189,7 @@ function hostAbortedError(message = "host aborted") {
27807
28189
  function raceAgainstHostAbort(work, abortSignal, message = "host aborted") {
27808
28190
  if (abortSignal?.aborted) return Promise.reject(hostAbortedError(message));
27809
28191
  if (abortSignal === void 0) return work;
27810
- return new Promise((resolve22, reject) => {
28192
+ return new Promise((resolve21, reject) => {
27811
28193
  let settled = false;
27812
28194
  const onAbort = () => {
27813
28195
  if (settled) return;
@@ -27822,7 +28204,7 @@ function raceAgainstHostAbort(work, abortSignal, message = "host aborted") {
27822
28204
  if (settled) return;
27823
28205
  settled = true;
27824
28206
  abortSignal.removeEventListener("abort", onAbort);
27825
- resolve22(value);
28207
+ resolve21(value);
27826
28208
  },
27827
28209
  (error) => {
27828
28210
  if (settled) return;
@@ -27914,6 +28296,9 @@ function reportHostSessionEvent(input) {
27914
28296
  });
27915
28297
  }
27916
28298
 
28299
+ // src/acp-host/role-turn-host.ts
28300
+ init_navigator_output();
28301
+
27917
28302
  // src/agent-start-materials.ts
27918
28303
  function renderAgentStartMaterials(body, materials) {
27919
28304
  if (materials.length === 0) return body;
@@ -27926,7 +28311,42 @@ function renderSystemPromptOverride(authority) {
27926
28311
  }
27927
28312
 
27928
28313
  // src/acp-host/role-turn-host.ts
27929
- function failure(cause, name, code, details) {
28314
+ function acpAgentTextChunk(params) {
28315
+ let kind;
28316
+ let content;
28317
+ let textFallback;
28318
+ const nested = params.update;
28319
+ if (typeof nested === "object" && nested !== null && !Array.isArray(nested)) {
28320
+ const record4 = nested;
28321
+ kind = record4.sessionUpdate;
28322
+ content = record4.content;
28323
+ textFallback = record4.text;
28324
+ } else {
28325
+ kind = params.sessionUpdate ?? nested;
28326
+ content = params.content;
28327
+ textFallback = params.text;
28328
+ }
28329
+ if (kind !== "agent_message_chunk" && kind !== "agent_message") return void 0;
28330
+ if (typeof content === "string" && content.length > 0) return content;
28331
+ if (typeof content === "object" && content !== null && !Array.isArray(content)) {
28332
+ const record4 = content;
28333
+ if (typeof record4.text === "string" && record4.text.length > 0) return record4.text;
28334
+ }
28335
+ if (Array.isArray(content)) {
28336
+ const parts = [];
28337
+ for (const part of content) {
28338
+ if (typeof part === "string" && part.length > 0) parts.push(part);
28339
+ else if (typeof part === "object" && part !== null) {
28340
+ const record4 = part;
28341
+ if (typeof record4.text === "string" && record4.text.length > 0) parts.push(record4.text);
28342
+ }
28343
+ }
28344
+ if (parts.length > 0) return parts.join("");
28345
+ }
28346
+ if (typeof textFallback === "string" && textFallback.length > 0) return textFallback;
28347
+ return void 0;
28348
+ }
28349
+ function failure(cause, name, code, details, diagnostic) {
27930
28350
  return {
27931
28351
  code: null,
27932
28352
  stderr: "",
@@ -27934,10 +28354,24 @@ function failure(cause, name, code, details) {
27934
28354
  knownFailure: {
27935
28355
  cause,
27936
28356
  identity: { name, code },
28357
+ ...diagnostic === void 0 ? {} : { diagnostic },
27937
28358
  ...details === void 0 ? {} : { details }
27938
28359
  }
27939
28360
  };
27940
28361
  }
28362
+ function withCleanupFailure(outcome, cleanupError) {
28363
+ const message = cleanupError instanceof Error ? cleanupError.message : String(cleanupError);
28364
+ if (outcome.knownFailure === void 0) {
28365
+ return failure("session", "AcpDisposeFailure", "dispose-failed", { cleanupError: message }, message);
28366
+ }
28367
+ return {
28368
+ ...outcome,
28369
+ knownFailure: {
28370
+ ...outcome.knownFailure,
28371
+ details: { ...outcome.knownFailure.details ?? {}, cleanupError: message }
28372
+ }
28373
+ };
28374
+ }
27941
28375
  function acpError(code, message, cause) {
27942
28376
  return Object.assign(new Error(message, cause === void 0 ? void 0 : { cause }), { code });
27943
28377
  }
@@ -28010,8 +28444,8 @@ function connectAcpStdio(options) {
28010
28444
  request(method, params) {
28011
28445
  if (closed) return Promise.reject(terminalError ?? acpError("acp-connection-closed", "ACP connection is closed"));
28012
28446
  const id = ++nextId;
28013
- return new Promise((resolve22, reject) => {
28014
- pending.set(id, { resolve: resolve22, reject });
28447
+ return new Promise((resolve21, reject) => {
28448
+ pending.set(id, { resolve: resolve21, reject });
28015
28449
  child.stdin.write(`${JSON.stringify({ jsonrpc: "2.0", id, method, params })}
28016
28450
  `, (error) => {
28017
28451
  if (error === null || error === void 0) return;
@@ -28038,7 +28472,7 @@ function connectAcpStdio(options) {
28038
28472
  settleClosed(acpError("acp-connection-closed", "ACP connection is closed"));
28039
28473
  child.stdin.end();
28040
28474
  child.kill("SIGTERM");
28041
- await new Promise((resolve22) => child.once("close", () => resolve22()));
28475
+ await new Promise((resolve21) => child.once("close", () => resolve21()));
28042
28476
  }
28043
28477
  });
28044
28478
  }
@@ -28049,137 +28483,168 @@ function createAcpRoleTurnHost(config) {
28049
28483
  let connection;
28050
28484
  let sessionId;
28051
28485
  let accepted = false;
28486
+ let outcome = failure("session", "AcpNoOutcome", "no-outcome");
28052
28487
  try {
28053
28488
  if (prepared.mcpServers.length === 0) {
28054
- return failure("activation", "UncontrolledAcpSession", "ak-config-missing");
28055
- }
28056
- connection = await config.connect(request);
28057
- const sessionParent = config.sessionIdentity.resolveSessionFile(request.principal);
28058
- const recordAbort = new AbortController();
28059
- let hostSessionRecordFailure;
28060
- const hostSessionRecordResult = () => ({
28061
- code: null,
28062
- stderr: "",
28063
- timedOut: false,
28064
- knownFailure: hostSessionRecordFailure
28065
- });
28066
- const noteHostSessionRecordFailure = (error) => {
28067
- if (hostSessionRecordFailure !== void 0) return;
28068
- hostSessionRecordFailure = {
28069
- cause: "session",
28070
- identity: { name: "HostSessionRecordFailure", code: "host-session-record-failed" },
28071
- diagnostic: error instanceof Error ? error.message : String(error)
28072
- };
28073
- try {
28074
- recordAbort.abort();
28075
- } catch {
28076
- }
28077
- };
28078
- const rpc = (method, params) => raceAgainstHostAbort(connection.request(method, params), recordAbort.signal, "host-session-record-failed");
28079
- connection.onNotification?.((method, params) => {
28080
- if (method !== "session/update" || hostSessionRecordFailure !== void 0) return;
28081
- try {
28082
- reportHostSessionEvent({
28083
- host: config.hostName,
28084
- cwd: request.cwd,
28085
- sessionParent,
28086
- source: "acp-host",
28087
- event: { method, params }
28088
- });
28089
- } catch (error) {
28090
- noteHostSessionRecordFailure(error);
28091
- }
28092
- });
28093
- try {
28094
- const initialized = await rpc("initialize", {
28095
- protocolVersion: 1,
28096
- clientCapabilities: {}
28489
+ outcome = failure("activation", "UncontrolledAcpSession", "ak-config-missing");
28490
+ } else {
28491
+ connection = await config.connect(request);
28492
+ const sessionParent = config.sessionIdentity.resolveSessionFile(request.principal);
28493
+ const recordAbort = new AbortController();
28494
+ let hostSessionRecordFailure;
28495
+ const hostSessionRecordResult = () => ({
28496
+ code: null,
28497
+ stderr: "",
28498
+ timedOut: false,
28499
+ knownFailure: hostSessionRecordFailure
28097
28500
  });
28098
- const initializeMeta = initialized._meta;
28099
- const availableModels = Array.isArray(initializeMeta?.modelState?.availableModels) ? initializeMeta.modelState.availableModels : void 0;
28100
- if (request.model !== void 0 && availableModels !== void 0 && !availableModels.some((entry) => typeof entry === "object" && entry !== null && entry.modelId === acpModelId(config.modelPassing, request.model))) {
28101
- return failure("activation", "AcpHostModelMismatch", "host-model-mismatch", {
28102
- provider: request.model.provider,
28103
- model: request.model.model
28104
- });
28105
- }
28106
- const sessionBindParams = {
28107
- cwd: request.cwd,
28108
- mcpServers: prepared.mcpServers,
28109
- _meta: { systemPromptOverride, yoloMode: false }
28110
- };
28111
- const loadSession = async (bindSessionId) => {
28112
- const loaded = await rpc("session/load", {
28113
- sessionId: bindSessionId,
28114
- ...sessionBindParams
28115
- });
28116
- return typeof loaded.sessionId === "string" && loaded.sessionId !== "" ? loaded.sessionId : bindSessionId;
28501
+ const noteHostSessionRecordFailure = (error) => {
28502
+ if (hostSessionRecordFailure !== void 0) return;
28503
+ hostSessionRecordFailure = {
28504
+ cause: "session",
28505
+ identity: { name: "HostSessionRecordFailure", code: "host-session-record-failed" },
28506
+ diagnostic: error instanceof Error ? error.message : String(error)
28507
+ };
28508
+ try {
28509
+ recordAbort.abort();
28510
+ } catch {
28511
+ }
28117
28512
  };
28118
- if (request.continuation.kind === "resume" && config.boundResume === "session/load") {
28119
- const boundSessionId = await config.sessionIdentity.load(request.principal);
28120
- if (boundSessionId !== void 0 && boundSessionId !== "") {
28121
- sessionId = await loadSession(boundSessionId);
28513
+ const rpc = (method, params) => raceAgainstHostAbort(connection.request(method, params), recordAbort.signal, "host-session-record-failed");
28514
+ const agentProseChunks = [];
28515
+ let collectAgentProse = false;
28516
+ connection.onNotification?.((method, params) => {
28517
+ if (method !== "session/update" || hostSessionRecordFailure !== void 0) return;
28518
+ if (collectAgentProse) {
28519
+ const chunk = acpAgentTextChunk(params);
28520
+ if (chunk !== void 0) agentProseChunks.push(chunk);
28122
28521
  }
28123
- }
28124
- if (sessionId === void 0) {
28125
- const session = await rpc("session/new", sessionBindParams);
28126
- sessionId = typeof session.sessionId === "string" ? session.sessionId : void 0;
28127
- if (sessionId === void 0 || sessionId === "") {
28128
- return failure("session", "AcpSessionFailure", "session-id-missing");
28522
+ try {
28523
+ reportHostSessionEvent({
28524
+ host: config.hostName,
28525
+ cwd: request.cwd,
28526
+ sessionParent,
28527
+ source: "acp-host",
28528
+ event: { method, params }
28529
+ });
28530
+ } catch (error) {
28531
+ noteHostSessionRecordFailure(error);
28129
28532
  }
28130
- await config.sessionIdentity.bind(request.principal, sessionId);
28131
- }
28132
- if (config.modelPassing === "set_model" && request.model !== void 0 && sessionId !== void 0) {
28133
- await rpc("session/set_model", {
28134
- sessionId,
28135
- modelId: acpModelId(config.modelPassing, request.model)
28533
+ });
28534
+ try {
28535
+ const initialized = await rpc("initialize", {
28536
+ protocolVersion: 1,
28537
+ clientCapabilities: {}
28136
28538
  });
28137
- sessionId = await loadSession(sessionId);
28138
- }
28139
- const activeConnection = connection;
28140
- const activeSessionId = sessionId;
28141
- const turnResult = await driveExternalRoleTurnRounds(prepared, request, {
28142
- roundLimitName: "AcpRoundLimit",
28143
- currentSessionId: () => sessionId,
28144
- async runRound({ prompt, abortSignal }) {
28145
- if (hostSessionRecordFailure !== void 0) return { status: "terminal", result: hostSessionRecordResult() };
28146
- const abortParts = [recordAbort.signal];
28147
- if (abortSignal !== void 0) abortParts.push(abortSignal);
28148
- const combinedAbort = AbortSignal.any(abortParts);
28149
- let result;
28150
- try {
28151
- result = await raceAgainstHostAbort(
28152
- activeConnection.request("session/prompt", {
28153
- sessionId: activeSessionId,
28154
- prompt: [{ type: "text", text: prompt }]
28155
- }),
28156
- combinedAbort,
28157
- "ACP host aborted"
28158
- );
28159
- } catch (error) {
28160
- if (hostSessionRecordFailure !== void 0) {
28161
- return { status: "terminal", result: hostSessionRecordResult() };
28539
+ const initializeMeta = initialized._meta;
28540
+ const availableModels = Array.isArray(initializeMeta?.modelState?.availableModels) ? initializeMeta.modelState.availableModels : void 0;
28541
+ if (request.model !== void 0 && availableModels !== void 0 && !availableModels.some((entry) => typeof entry === "object" && entry !== null && entry.modelId === acpModelId(config.modelPassing, request.model))) {
28542
+ outcome = failure("activation", "AcpHostModelMismatch", "host-model-mismatch", {
28543
+ provider: request.model.provider,
28544
+ model: request.model.model
28545
+ });
28546
+ } else {
28547
+ const sessionBindParams = {
28548
+ cwd: request.cwd,
28549
+ mcpServers: prepared.mcpServers,
28550
+ _meta: { systemPromptOverride, yoloMode: false }
28551
+ };
28552
+ const loadSession = async (bindSessionId) => {
28553
+ const loaded = await rpc("session/load", {
28554
+ sessionId: bindSessionId,
28555
+ ...sessionBindParams
28556
+ });
28557
+ return typeof loaded.sessionId === "string" && loaded.sessionId !== "" ? loaded.sessionId : bindSessionId;
28558
+ };
28559
+ if (request.continuation.kind === "resume" && config.boundResume === "session/load") {
28560
+ const boundSessionId = await config.sessionIdentity.load(request.principal);
28561
+ if (boundSessionId !== void 0 && boundSessionId !== "") {
28562
+ sessionId = await loadSession(boundSessionId);
28162
28563
  }
28163
- throw error;
28164
28564
  }
28165
- if (result.stopReason === "refusal") {
28166
- return {
28167
- status: "terminal",
28168
- result: failure("output", "AcpRefusal", "refusal", { sessionId })
28169
- };
28565
+ let sessionReady = true;
28566
+ if (sessionId === void 0) {
28567
+ const session = await rpc("session/new", sessionBindParams);
28568
+ sessionId = typeof session.sessionId === "string" ? session.sessionId : void 0;
28569
+ if (sessionId === void 0 || sessionId === "") {
28570
+ outcome = failure("session", "AcpSessionFailure", "session-id-missing");
28571
+ sessionReady = false;
28572
+ } else {
28573
+ await config.sessionIdentity.bind(request.principal, sessionId);
28574
+ }
28575
+ }
28576
+ if (sessionReady) {
28577
+ if (config.modelPassing === "set_model" && request.model !== void 0 && sessionId !== void 0) {
28578
+ await rpc("session/set_model", {
28579
+ sessionId,
28580
+ modelId: acpModelId(config.modelPassing, request.model)
28581
+ });
28582
+ sessionId = await loadSession(sessionId);
28583
+ }
28584
+ const activeConnection = connection;
28585
+ const activeSessionId = sessionId;
28586
+ const turnResult = await driveExternalRoleTurnRounds(prepared, request, {
28587
+ roundLimitName: "AcpRoundLimit",
28588
+ currentSessionId: () => sessionId,
28589
+ async runRound({ prompt, abortSignal }) {
28590
+ if (hostSessionRecordFailure !== void 0) return { status: "terminal", result: hostSessionRecordResult() };
28591
+ const abortParts = [recordAbort.signal];
28592
+ if (abortSignal !== void 0) abortParts.push(abortSignal);
28593
+ const combinedAbort = AbortSignal.any(abortParts);
28594
+ let result;
28595
+ agentProseChunks.length = 0;
28596
+ collectAgentProse = prepared.terminatingToolName === NAVIGATOR_OUTPUT_TOOL_NAME;
28597
+ try {
28598
+ result = await raceAgainstHostAbort(
28599
+ activeConnection.request("session/prompt", {
28600
+ sessionId: activeSessionId,
28601
+ prompt: [{ type: "text", text: prompt }]
28602
+ }),
28603
+ combinedAbort,
28604
+ "ACP host aborted"
28605
+ );
28606
+ } catch (error) {
28607
+ collectAgentProse = false;
28608
+ agentProseChunks.length = 0;
28609
+ if (hostSessionRecordFailure !== void 0) {
28610
+ return { status: "terminal", result: hostSessionRecordResult() };
28611
+ }
28612
+ throw error;
28613
+ }
28614
+ collectAgentProse = false;
28615
+ if (result.stopReason === "refusal") {
28616
+ agentProseChunks.length = 0;
28617
+ return {
28618
+ status: "terminal",
28619
+ result: failure("output", "AcpRefusal", "refusal", { sessionId })
28620
+ };
28621
+ }
28622
+ if (prepared.terminatingToolName === NAVIGATOR_OUTPUT_TOOL_NAME) {
28623
+ const prose = agentProseChunks.join("");
28624
+ agentProseChunks.length = 0;
28625
+ if (navigatorProseFromUnknown(prose) !== void 0) {
28626
+ await prepared.ingestStructuredOutput({ prose });
28627
+ }
28628
+ } else {
28629
+ agentProseChunks.length = 0;
28630
+ }
28631
+ return { status: "delivered", stderr: activeConnection.stderr?.() ?? "" };
28632
+ },
28633
+ async afterAccepted() {
28634
+ await rpc("session/close", { sessionId: activeSessionId });
28635
+ accepted = true;
28636
+ }
28637
+ });
28638
+ outcome = hostSessionRecordFailure !== void 0 ? hostSessionRecordResult() : turnResult;
28170
28639
  }
28171
- return { status: "delivered", stderr: activeConnection.stderr?.() ?? "" };
28172
- },
28173
- async afterAccepted() {
28174
- await rpc("session/close", { sessionId: activeSessionId });
28175
- accepted = true;
28176
28640
  }
28177
- });
28178
- if (hostSessionRecordFailure !== void 0) return hostSessionRecordResult();
28179
- return turnResult;
28180
- } catch (error) {
28181
- if (hostSessionRecordFailure !== void 0) return hostSessionRecordResult();
28182
- throw error;
28641
+ } catch (error) {
28642
+ if (hostSessionRecordFailure !== void 0) {
28643
+ outcome = hostSessionRecordResult();
28644
+ } else {
28645
+ throw error;
28646
+ }
28647
+ }
28183
28648
  }
28184
28649
  } finally {
28185
28650
  if (connection !== void 0) {
@@ -28196,16 +28661,18 @@ function createAcpRoleTurnHost(config) {
28196
28661
  }
28197
28662
  try {
28198
28663
  await prepared.dispose?.();
28199
- } catch {
28664
+ } catch (cleanupError) {
28665
+ outcome = withCleanupFailure(outcome, cleanupError);
28200
28666
  }
28201
28667
  }
28668
+ return outcome;
28202
28669
  });
28203
28670
  }
28204
28671
 
28205
28672
  // src/acp-host/seat-profile-soul.ts
28206
- import { constants as constants3 } from "node:fs";
28673
+ import { constants as constants2 } from "node:fs";
28207
28674
  import { access as access4, copyFile, lstat as lstat8, mkdir as mkdir8, readlink as readlink2, symlink as symlink2, unlink as unlink3 } from "node:fs/promises";
28208
- import { dirname as dirname25, join as join44, relative as relative4, resolve as resolve21 } from "node:path";
28675
+ import { dirname as dirname24, join as join44, relative as relative4, resolve as resolve20 } from "node:path";
28209
28676
  function seatProfileName(spec, role) {
28210
28677
  return `${spec.namePrefix}${role}`;
28211
28678
  }
@@ -28214,7 +28681,7 @@ function packageRoleSoulPath(packageRoot, role) {
28214
28681
  }
28215
28682
  async function pathExists2(path) {
28216
28683
  try {
28217
- await access4(path, constants3.F_OK);
28684
+ await access4(path, constants2.F_OK);
28218
28685
  return true;
28219
28686
  } catch {
28220
28687
  return false;
@@ -28223,13 +28690,13 @@ async function pathExists2(path) {
28223
28690
  async function ensureSeatProfileSoul(options) {
28224
28691
  const { spec, operatorHome, packageRoot, role } = options;
28225
28692
  const profileName = seatProfileName(spec, role);
28226
- const soulTarget = resolve21(packageRoleSoulPath(packageRoot, role));
28693
+ const soulTarget = resolve20(packageRoleSoulPath(packageRoot, role));
28227
28694
  if (!await pathExists2(soulTarget)) {
28228
28695
  throw new Error(`packaged role soul missing: ${soulTarget}`);
28229
28696
  }
28230
28697
  const profilesRoot = join44(operatorHome, ...spec.profilesRootFromHome);
28231
28698
  const profileDir = join44(profilesRoot, profileName);
28232
- const hostRoot = dirname25(profilesRoot);
28699
+ const hostRoot = dirname24(profilesRoot);
28233
28700
  const soulPath = join44(profileDir, spec.soulFileName);
28234
28701
  if (!await pathExists2(profileDir)) {
28235
28702
  await mkdir8(profileDir, { recursive: true });
@@ -28269,7 +28736,7 @@ function createComposedAcpRoleTurnHost(config) {
28269
28736
  request,
28270
28737
  dependencies: config.roleRuntimeDependencies,
28271
28738
  sessionFile: config.sessionIdentity.resolveSessionFile(request.principal),
28272
- socketPath: config.socketPath?.(request) ?? `/tmp/ak-acp-mcp-${randomUUID9()}.sock`
28739
+ socketPath: config.socketPath?.(request) ?? `/tmp/ak-acp-mcp-${randomUUID10()}.sock`
28273
28740
  })
28274
28741
  });
28275
28742
  }