@akagilnc/pi-workflow-roles 0.1.4586 → 0.1.4620

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 (47) hide show
  1. package/README.md +2 -2
  2. package/README.zh-CN.md +2 -2
  3. package/dist/acp-host/production-host.js +951 -497
  4. package/dist/archivist-record-topology.js +27 -35
  5. package/dist/headless-host/description.js +7 -4
  6. package/dist/headless-host/production-host.js +783 -393
  7. package/dist/migrate-book-topology.js +3 -6
  8. package/dist/navigator-attendance.js +146 -241
  9. package/dist/navigator-public-session.js +81 -15
  10. package/dist/package-contracts/navigator-output.js +30 -12
  11. package/dist/public-cli/judge-run.js +2 -2
  12. package/dist/public-cli/main.js +69 -94
  13. package/dist/public-cli/option-definitions.js +1 -1
  14. package/dist/public-cli/post-admission.js +2 -2
  15. package/dist/public-cli/run-lifecycle.js +29 -7
  16. package/dist/public-cli/settlement.js +46 -32
  17. package/dist/public-cli/terminal.js +8 -27
  18. package/dist/public-role-summons.js +22 -4
  19. package/dist/submission-ledger.js +56 -23
  20. package/package.json +1 -1
  21. package/resources/836-deleted-machine-instruction-inventory.md +2 -0
  22. package/resources/navigator-route-playbook.md +9 -0
  23. package/scripts/build-package.mjs +6 -1
  24. package/src/acp-host/role-turn-host.ts +129 -13
  25. package/src/headless-host/description.ts +17 -7
  26. package/src/headless-host/role-turn-host.ts +42 -11
  27. package/src/navigator-attendance.ts +290 -425
  28. package/src/navigator-public-session.ts +126 -25
  29. package/src/navigator-role.ts +2 -2
  30. package/src/package-contracts/navigator-output.ts +41 -25
  31. package/src/public-cli/coder-run.ts +2 -2
  32. package/src/public-cli/fixer-run.ts +2 -2
  33. package/src/public-cli/judge-run.ts +2 -2
  34. package/src/public-cli/merger-run.ts +2 -2
  35. package/src/public-cli/option-definitions.ts +1 -1
  36. package/src/public-cli/post-admission.ts +2 -1
  37. package/src/public-cli/run-lifecycle.ts +37 -7
  38. package/src/public-cli/settlement.ts +42 -33
  39. package/src/public-cli/terminal.ts +12 -37
  40. package/src/public-role-summons.ts +34 -5
  41. package/src/role-envelope.ts +89 -4
  42. package/src/role-runtime.ts +74 -14
  43. package/src/submission-ledger.ts +63 -21
  44. package/dist/public-cli/command-renderer.js +0 -5
  45. package/dist/public-command-renderer.js +0 -29
  46. package/src/public-cli/command-renderer.ts +0 -9
  47. package/src/public-command-renderer.ts +0 -55
@@ -2110,7 +2110,48 @@ var init_collector_output = __esm({
2110
2110
  });
2111
2111
 
2112
2112
  // src/package-contracts/navigator-output.ts
2113
+ var navigator_output_exports = {};
2114
+ __export(navigator_output_exports, {
2115
+ NAVIGATOR_ACCEPTED_TEXT: () => NAVIGATOR_ACCEPTED_TEXT,
2116
+ NAVIGATOR_OUTPUT_TOOL_NAME: () => NAVIGATOR_OUTPUT_TOOL_NAME,
2117
+ navigatorOutputSchema: () => navigatorOutputSchema,
2118
+ navigatorProseFromUnknown: () => navigatorProseFromUnknown,
2119
+ projectLawfulNavigatorOutput: () => projectLawfulNavigatorOutput,
2120
+ validateRecordedNavigatorOutput: () => validateRecordedNavigatorOutput
2121
+ });
2113
2122
  import { Type as Type5 } from "typebox";
2123
+ function projectLawfulNavigatorOutput(value) {
2124
+ if (value === void 0 || value === null) return void 0;
2125
+ if (typeof value === "string") return { prose: value };
2126
+ if (typeof value === "object" && !Array.isArray(value)) {
2127
+ const record4 = value;
2128
+ if (typeof record4.prose === "string") return { prose: record4.prose };
2129
+ if (record4.prose !== void 0 && record4.prose !== null) {
2130
+ return { prose: typeof record4.prose === "string" ? record4.prose : String(record4.prose) };
2131
+ }
2132
+ const keys = Object.keys(record4);
2133
+ if (keys.length === 0) return { prose: "" };
2134
+ try {
2135
+ return { prose: JSON.stringify(record4) };
2136
+ } catch {
2137
+ return { prose: String(record4) };
2138
+ }
2139
+ }
2140
+ return { prose: String(value) };
2141
+ }
2142
+ function validateRecordedNavigatorOutput(value) {
2143
+ const projected = projectLawfulNavigatorOutput(value);
2144
+ if (projected === void 0) {
2145
+ throw new Error("Navigator output is empty");
2146
+ }
2147
+ return projected;
2148
+ }
2149
+ function navigatorProseFromUnknown(value) {
2150
+ const projected = projectLawfulNavigatorOutput(value);
2151
+ if (projected === void 0) return void 0;
2152
+ const trimmed = projected.prose.trim();
2153
+ return trimmed === "" ? void 0 : projected.prose;
2154
+ }
2114
2155
  var NAVIGATOR_OUTPUT_TOOL_NAME, NAVIGATOR_ACCEPTED_TEXT, navigatorOutputSchema;
2115
2156
  var init_navigator_output = __esm({
2116
2157
  "src/package-contracts/navigator-output.ts"() {
@@ -2122,11 +2163,8 @@ var init_navigator_output = __esm({
2122
2163
  navigatorOutputSchema = withTerminatingOutputDeclarations(
2123
2164
  openToolObject(
2124
2165
  Type5.Object({
2125
- status: Type5.Unknown({
2126
- description: "advice \u2014 \u5F62\u72B6\u6307\u5F15\uFF0C\u975E schema \u95F8"
2127
- }),
2128
- candidates: Type5.Unknown({
2129
- 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"
2166
+ prose: Type5.Unknown({
2167
+ 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"
2130
2168
  })
2131
2169
  })
2132
2170
  )
@@ -4912,6 +4950,56 @@ var init_typed_provider_http = __esm({
4912
4950
  });
4913
4951
 
4914
4952
  // src/public-cli/run-lifecycle.ts
4953
+ var run_lifecycle_exports = {};
4954
+ __export(run_lifecycle_exports, {
4955
+ AUTO_RESUME_LIMIT: () => AUTO_RESUME_LIMIT,
4956
+ GATE_DOSSIER_POINTER_PREFIX: () => GATE_DOSSIER_POINTER_PREFIX,
4957
+ RESUME_TRANSPORT_ENVELOPE: () => RESUME_TRANSPORT_ENVELOPE,
4958
+ RunWriterLeaseHeldError: () => RunWriterLeaseHeldError,
4959
+ V1_RESUMABLE_PROVIDERS: () => V1_RESUMABLE_PROVIDERS,
4960
+ acquireRunWriterLease: () => acquireRunWriterLease,
4961
+ autopsyWriterLock: () => autopsyWriterLock,
4962
+ buildAutoResumeContinuationPrompt: () => buildAutoResumeContinuationPrompt,
4963
+ buildResumeContinuationPrompt: () => buildResumeContinuationPrompt,
4964
+ clearCurrentCourt: () => clearCurrentCourt,
4965
+ clearTypedProviderHttpObservation: () => clearTypedProviderHttpObservation,
4966
+ describeErrorIdentity: () => describeErrorIdentity,
4967
+ findLatestRunIdForSeatTicket: () => findLatestRunIdForSeatTicket,
4968
+ findRunDirectoryById: () => findRunDirectoryById,
4969
+ isDurablePrincipalAvailable: () => isDurablePrincipalAvailable,
4970
+ isV1ResumableProvider: () => isV1ResumableProvider,
4971
+ loadResumableCoderRun: () => loadResumableCoderRun,
4972
+ loadResumableCollectorRun: () => loadResumableCollectorRun,
4973
+ loadResumableCountersignRun: () => loadResumableCountersignRun,
4974
+ loadResumableDiaristRun: () => loadResumableDiaristRun,
4975
+ loadResumableDoctorRun: () => loadResumableDoctorRun,
4976
+ loadResumableFixerRun: () => loadResumableFixerRun,
4977
+ loadResumableGleanerLeftRun: () => loadResumableGleanerLeftRun,
4978
+ loadResumableInspectorRun: () => loadResumableInspectorRun,
4979
+ loadResumableInstructionSeatRun: () => loadResumableInstructionSeatRun,
4980
+ loadResumableJudgeRun: () => loadResumableJudgeRun,
4981
+ loadResumableMergerRun: () => loadResumableMergerRun,
4982
+ loadResumableNotaryRun: () => loadResumableNotaryRun,
4983
+ loadResumableReviewerRun: () => loadResumableReviewerRun,
4984
+ loadResumableSecretariatRun: () => loadResumableSecretariatRun,
4985
+ markRunAdmitted: () => markRunAdmitted,
4986
+ markRunResumable: () => markRunResumable,
4987
+ markRunRunning: () => markRunRunning,
4988
+ markRunTerminal: () => markRunTerminal,
4989
+ parentRunPathFromGatePointerInstruction: () => parentRunPathFromGatePointerInstruction,
4990
+ peekRoleRunRole: () => peekRoleRunRole,
4991
+ readCurrentCourt: () => readCurrentCourt,
4992
+ readLatestTypedProviderHttpObservation: () => readLatestTypedProviderHttpObservation,
4993
+ readRoleRunIdentity: () => readRoleRunIdentity,
4994
+ readRoleRunState: () => readRoleRunState,
4995
+ readRunParentPath: () => readRunParentPath,
4996
+ readTypedHttp429Observation: () => readTypedHttp429Observation,
4997
+ recordCurrentCourt: () => recordCurrentCourt,
4998
+ recordTypedProviderHttpStatus: () => recordTypedProviderHttpStatus,
4999
+ renderResumeCommand: () => renderResumeCommand,
5000
+ selectResumeContinuationPrompt: () => selectResumeContinuationPrompt,
5001
+ writeRoleRunState: () => writeRoleRunState
5002
+ });
4915
5003
  import { chmod, lstat as lstat2, open, readdir as readdir4, readFile as readFile10, unlink as unlink2, writeFile as writeFile4 } from "node:fs/promises";
4916
5004
  import { basename as basename4, join as join13 } from "node:path";
4917
5005
  function selectResumeContinuationPrompt(message, engineMaterial) {
@@ -4927,6 +5015,15 @@ function buildResumeContinuationPrompt(options) {
4927
5015
  })
4928
5016
  );
4929
5017
  }
5018
+ function buildAutoResumeContinuationPrompt(options) {
5019
+ return selectResumeContinuationPrompt(
5020
+ RESUME_TRANSPORT_ENVELOPE,
5021
+ engineSessionMaterialFromOptions({
5022
+ packageRoot: options.packageRoot,
5023
+ ...pickEngineAxis(options)
5024
+ })
5025
+ );
5026
+ }
4930
5027
  function isV1ResumableProvider(provider) {
4931
5028
  return V1_RESUMABLE_PROVIDERS.includes(provider);
4932
5029
  }
@@ -5090,6 +5187,11 @@ function materializeRoleRunFromDisk(disk, authority) {
5090
5187
  return void 0;
5091
5188
  }
5092
5189
  }
5190
+ async function readRoleRunState(runDirectory, authority) {
5191
+ const disk = await readRoleRunStateDisk(runDirectory);
5192
+ if (disk === void 0) return void 0;
5193
+ return materializeRoleRunFromDisk(disk, authority)?.run;
5194
+ }
5093
5195
  async function readRoleRunIdentity(runDirectory) {
5094
5196
  const disk = await readRoleRunStateDisk(runDirectory);
5095
5197
  if (disk === void 0) return void 0;
@@ -5823,6 +5925,75 @@ async function loadResumableJudgeRun(home, runId, authority) {
5823
5925
  };
5824
5926
  return seatLoadedResult(loaded, admitted);
5825
5927
  }
5928
+ async function loadResumableCoderRun(home, runId, authority) {
5929
+ const loaded = await loadResumableRunRecord(home, runId, authority);
5930
+ if (loaded.run.role !== "coder") {
5931
+ throw new CliUsageError(
5932
+ `role run ${runId} belongs to ${loaded.run.role}, not coder`
5933
+ );
5934
+ }
5935
+ const phase = loaded.admittedFields.phase ?? loaded.run.phase;
5936
+ if (phase !== "plan" && phase !== "apply") {
5937
+ throw new CliUsageError(
5938
+ `role run admitted coder phase is missing: ${runId}`
5939
+ );
5940
+ }
5941
+ const taskPath = loaded.admittedFields.taskPath;
5942
+ if (taskPath === void 0) {
5943
+ throw new CliUsageError(
5944
+ `role run admitted coder task path is missing: ${runId}`
5945
+ );
5946
+ }
5947
+ if (loaded.admittedFields.instruction.trim() === "") {
5948
+ throw new CliUsageError(
5949
+ `role run admitted coder task is blank: ${runId}`
5950
+ );
5951
+ }
5952
+ const admitted = {
5953
+ role: "coder",
5954
+ phase,
5955
+ ...resumedBaseAdmitted(loaded),
5956
+ instructionEmpty: false,
5957
+ taskPath
5958
+ };
5959
+ return seatLoadedResult(loaded, admitted);
5960
+ }
5961
+ async function loadResumableFixerRun(home, runId, authority) {
5962
+ const loaded = await loadResumableRunRecord(home, runId, authority);
5963
+ if (loaded.run.role !== "fixer") {
5964
+ throw new CliUsageError(
5965
+ `role run ${runId} belongs to ${loaded.run.role}, not fixer`
5966
+ );
5967
+ }
5968
+ const phase = loaded.admittedFields.phase ?? loaded.run.phase;
5969
+ if (phase !== "plan" && phase !== "apply") {
5970
+ throw new CliUsageError(
5971
+ `role run admitted fixer phase is missing: ${runId}`
5972
+ );
5973
+ }
5974
+ const packetPath = loaded.admittedFields.packetPath;
5975
+ if (packetPath === void 0) {
5976
+ throw new CliUsageError(
5977
+ `role run admitted fixer packet path is missing: ${runId}`
5978
+ );
5979
+ }
5980
+ if (loaded.admittedFields.instruction.trim() === "") {
5981
+ throw new CliUsageError(
5982
+ `role run admitted fixer instruction is blank: ${runId}`
5983
+ );
5984
+ }
5985
+ const prerequisites = loaded.admittedFields.prerequisites ?? Object.freeze([]);
5986
+ const admitted = {
5987
+ role: "fixer",
5988
+ phase,
5989
+ ...resumedBaseAdmitted(loaded),
5990
+ instructionEmpty: false,
5991
+ packetPath,
5992
+ ...loaded.admittedFields.prerequisitesPath === void 0 ? {} : { prerequisitesPath: loaded.admittedFields.prerequisitesPath },
5993
+ prerequisites
5994
+ };
5995
+ return seatLoadedResult(loaded, admitted);
5996
+ }
5826
5997
  async function loadResumableReviewerRun(home, runId, authority) {
5827
5998
  const loaded = await loadResumableRunRecord(home, runId, authority);
5828
5999
  if (loaded.run.role !== "reviewer") {
@@ -5896,6 +6067,26 @@ async function loadResumableInstructionSeatRun(home, runId, authority) {
5896
6067
  };
5897
6068
  return seatLoadedResult(loaded, admitted);
5898
6069
  }
6070
+ async function loadResumableGleanerLeftRun(home, runId, authority) {
6071
+ const loaded = await loadResumableRunRecord(home, runId, authority);
6072
+ if (loaded.run.role !== "gleaner-left") {
6073
+ throw new CliUsageError(
6074
+ `role run ${runId} belongs to ${loaded.run.role}, not gleaner-left`
6075
+ );
6076
+ }
6077
+ const baseRevision = loaded.admittedFields.baseRevision;
6078
+ if (baseRevision === void 0 || baseRevision.trim() === "") {
6079
+ throw new CliUsageError(
6080
+ `role run admitted gleaner-left base revision is missing: ${runId}`
6081
+ );
6082
+ }
6083
+ const admitted = {
6084
+ role: "gleaner-left",
6085
+ ...resumedBaseAdmitted(loaded),
6086
+ baseRevision
6087
+ };
6088
+ return seatLoadedResult(loaded, admitted);
6089
+ }
5899
6090
  async function loadResumableDiaristRun(home, runId, authority) {
5900
6091
  const loaded = await loadResumableRunRecord(home, runId, authority);
5901
6092
  if (loaded.run.role !== "diarist") {
@@ -5909,6 +6100,88 @@ async function loadResumableDiaristRun(home, runId, authority) {
5909
6100
  };
5910
6101
  return seatLoadedResult(loaded, admitted);
5911
6102
  }
6103
+ async function loadResumableSecretariatRun(home, runId, authority) {
6104
+ const loaded = await loadResumableRunRecord(home, runId, authority);
6105
+ if (loaded.run.role !== "secretariat") {
6106
+ throw new CliUsageError(
6107
+ `role run ${runId} belongs to ${loaded.run.role}, not secretariat`
6108
+ );
6109
+ }
6110
+ const admitted = {
6111
+ role: "secretariat",
6112
+ ...resumedBaseAdmitted(loaded)
6113
+ };
6114
+ return seatLoadedResult(loaded, admitted);
6115
+ }
6116
+ async function loadResumableMergerRun(home, runId, authority) {
6117
+ const loaded = await loadResumableRunRecord(home, runId, authority);
6118
+ if (loaded.run.role !== "merger") {
6119
+ throw new CliUsageError(
6120
+ `role run ${runId} belongs to ${loaded.run.role}, not merger`
6121
+ );
6122
+ }
6123
+ const mergerInputPath = loaded.admittedFields.mergerInputPath;
6124
+ if (mergerInputPath === void 0) {
6125
+ throw new CliUsageError(
6126
+ `role run admitted merger input path is missing: ${runId}`
6127
+ );
6128
+ }
6129
+ const derived = loaded.admittedFields.derived;
6130
+ if (derived === void 0) {
6131
+ throw new CliUsageError(
6132
+ `role run admitted merger envelope is missing: ${runId}`
6133
+ );
6134
+ }
6135
+ if (loaded.admittedFields.instruction.trim() === "") {
6136
+ throw new CliUsageError(
6137
+ `role run admitted merger task is blank: ${runId}`
6138
+ );
6139
+ }
6140
+ const admitted = {
6141
+ role: "merger",
6142
+ ...resumedBaseAdmitted(loaded),
6143
+ instructionEmpty: false,
6144
+ mergerInputPath,
6145
+ derived
6146
+ };
6147
+ return seatLoadedResult(loaded, admitted);
6148
+ }
6149
+ async function loadResumableCollectorRun(home, runId, authority) {
6150
+ const loaded = await loadResumableRunRecord(home, runId, authority);
6151
+ if (loaded.run.role !== "collector") {
6152
+ throw new CliUsageError(
6153
+ `role run ${runId} belongs to ${loaded.run.role}, not collector`
6154
+ );
6155
+ }
6156
+ const { prNumber, repository, repositoryDisplay, manifestDigest } = loaded.admittedFields;
6157
+ if (repository === void 0 || repositoryDisplay === void 0 || manifestDigest === void 0) {
6158
+ throw new CliUsageError(
6159
+ `role run admitted collector repository identity is missing: ${runId}`
6160
+ );
6161
+ }
6162
+ let parsedRepository;
6163
+ try {
6164
+ parsedRepository = parseCollectorRepository(repositoryDisplay);
6165
+ } catch (error) {
6166
+ const detail = error instanceof Error ? error.message : String(error);
6167
+ throw new CliUsageError(detail, { cause: error });
6168
+ }
6169
+ if (parsedRepository.canonical !== repository) {
6170
+ throw new CliUsageError(
6171
+ `role run admitted collector repository does not match its canonical form: ${runId}`
6172
+ );
6173
+ }
6174
+ const admitted = {
6175
+ role: "collector",
6176
+ ...resumedBaseAdmitted(loaded),
6177
+ ...prNumber === void 0 ? {} : { prNumber },
6178
+ repository: parsedRepository,
6179
+ ...loaded.admittedFields.requestManifestPath === void 0 ? {} : { requestManifestPath: loaded.admittedFields.requestManifestPath },
6180
+ ...loaded.admittedFields.waitWindowMs === void 0 ? {} : { waitWindowMs: loaded.admittedFields.waitWindowMs },
6181
+ manifestDigest
6182
+ };
6183
+ return seatLoadedResult(loaded, admitted);
6184
+ }
5912
6185
  async function loadResumableDoctorRun(home, runId, authority) {
5913
6186
  const loaded = await loadResumableRunRecord(home, runId, authority);
5914
6187
  if (loaded.run.role !== "doctor") {
@@ -5966,6 +6239,12 @@ async function loadResumableInspectorRun(home, runId, authority) {
5966
6239
  };
5967
6240
  return seatLoadedResult(loaded, admitted);
5968
6241
  }
6242
+ async function peekRoleRunRole(home, runId) {
6243
+ const runDirectory = await findRunDirectoryById(home, runId);
6244
+ if (runDirectory === void 0) return void 0;
6245
+ const run = await readRoleRunIdentity(runDirectory);
6246
+ return run?.role;
6247
+ }
5969
6248
  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;
5970
6249
  var init_run_lifecycle = __esm({
5971
6250
  "src/public-cli/run-lifecycle.ts"() {
@@ -5982,7 +6261,7 @@ var init_run_lifecycle = __esm({
5982
6261
  init_invocation();
5983
6262
  V1_RESUMABLE_PROVIDERS = ["openai-codex", "xai"];
5984
6263
  AUTO_RESUME_LIMIT = 2;
5985
- RESUME_TRANSPORT_ENVELOPE = "[ak-role:resume-continue]";
6264
+ RESUME_TRANSPORT_ENVELOPE = "\u7EE7\u7EED\u3002";
5986
6265
  RUN_STATE_FILE = "run-state.json";
5987
6266
  WRITER_LOCK_FILE = "writer.lock";
5988
6267
  RunWriterLeaseHeldError = class extends Error {
@@ -7037,7 +7316,7 @@ var init_option_definitions = __esm({
7037
7316
  },
7038
7317
  navigator: {
7039
7318
  command: "navigator",
7040
- summary: "Direct Navigator (\u6E38\u5955\u4F7F) route advice: ordered next-role candidates.",
7319
+ summary: "Direct Navigator (\u6E38\u5955\u4F7F) free-form prose route advice.",
7041
7320
  usage: ["ak-role navigator [options] [instruction]"],
7042
7321
  examples: [
7043
7322
  'ak-role navigator "\u521A\u5B8C\u6210 coder apply \u6536\u655B\uFF0C\u4E0B\u4E00\u6B65\uFF1F"'
@@ -11327,31 +11606,58 @@ async function restoreState(cwd, runId, scope) {
11327
11606
  }, 0)
11328
11607
  };
11329
11608
  }
11609
+ function sessionParentFromHostContext(context) {
11610
+ const runDirectory = runDirectoryFromHostContext(context);
11611
+ if (runDirectory !== void 0) return join22(runDirectory, "session", "session.jsonl");
11612
+ const sessionFile = context.sessionManager.getSessionFile?.();
11613
+ if (typeof sessionFile === "string" && sessionFile.length > 0) return sessionFile;
11614
+ const sessionDir = context.sessionManager.getSessionDir?.();
11615
+ if (typeof sessionDir === "string" && sessionDir.length > 0) {
11616
+ return join22(sessionDir, "session.jsonl");
11617
+ }
11618
+ return void 0;
11619
+ }
11620
+ function homeFromHostContext(context, home) {
11621
+ if (home !== void 0) return home;
11622
+ const sessionParent = sessionParentFromHostContext(context);
11623
+ return sessionParent !== void 0 ? tryHomeFromAkRolesPath(sessionParent) : void 0;
11624
+ }
11625
+ async function sealAcceptedSubmission(options) {
11626
+ const runId = runIdentity(options.context);
11627
+ const attemptId = attemptIdentity(options.context, runId);
11628
+ const sessionParent = sessionParentFromHostContext(options.context);
11629
+ const home = homeFromHostContext(options.context, options.home);
11630
+ const state = await restoreState(options.context.cwd, runId, {
11631
+ ...home === void 0 ? {} : { home },
11632
+ ...sessionParent === void 0 ? {} : { sessionParent }
11633
+ });
11634
+ const pointer = sitianReport({
11635
+ level: "event",
11636
+ kind: "sealed",
11637
+ subject: { runId, attemptId },
11638
+ ...state.prior === void 0 ? {} : { priorEventId: state.prior.identity },
11639
+ payload: {
11640
+ type: "sealed",
11641
+ attemptId,
11642
+ toolCallId: options.toolCallId,
11643
+ role: options.role,
11644
+ accepted: options.accepted
11645
+ },
11646
+ source: "role-runtime",
11647
+ cwd: options.context.cwd,
11648
+ ...home !== void 0 ? { home } : {},
11649
+ ...sessionParent === void 0 ? {} : { sessionParent }
11650
+ });
11651
+ state.prior = pointer;
11652
+ }
11330
11653
  function createSubmissionLedgerHost(host, outputTools, failInfrastructure2 = (error) => {
11331
11654
  throw error;
11332
11655
  }, projectClosure = () => void 0, options) {
11333
11656
  const states = /* @__PURE__ */ new Map();
11334
- const sessionParentFromContext = (context) => {
11335
- const runDirectory = runDirectoryFromHostContext(context);
11336
- if (runDirectory !== void 0) {
11337
- return join22(runDirectory, "session", "session.jsonl");
11338
- }
11339
- const sessionFile = context.sessionManager.getSessionFile?.();
11340
- if (typeof sessionFile === "string" && sessionFile.length > 0) return sessionFile;
11341
- const sessionDir = context.sessionManager.getSessionDir?.();
11342
- if (typeof sessionDir === "string" && sessionDir.length > 0) {
11343
- return join22(sessionDir, "session.jsonl");
11344
- }
11345
- return void 0;
11346
- };
11347
- const resolveHomeFromContext = (context) => {
11348
- if (options?.home !== void 0) return options.home;
11349
- const sessionParent = sessionParentFromContext(context);
11350
- return sessionParent !== void 0 ? tryHomeFromAkRolesPath(sessionParent) : void 0;
11351
- };
11657
+ const resolveHomeFromContext = (context) => homeFromHostContext(context, options?.home);
11352
11658
  const stateFor = (context, runId) => states.get(runId) ?? (() => {
11353
11659
  const home = resolveHomeFromContext(context);
11354
- const sessionParent = sessionParentFromContext(context);
11660
+ const sessionParent = sessionParentFromHostContext(context);
11355
11661
  const pending = restoreState(context.cwd, runId, {
11356
11662
  ...home === void 0 ? {} : { home },
11357
11663
  ...sessionParent === void 0 ? {} : { sessionParent }
@@ -11361,7 +11667,7 @@ function createSubmissionLedgerHost(host, outputTools, failInfrastructure2 = (er
11361
11667
  })();
11362
11668
  const appendFor = (state, context, runId, attemptId, event) => {
11363
11669
  const home = resolveHomeFromContext(context);
11364
- const sessionParent = sessionParentFromContext(context);
11670
+ const sessionParent = sessionParentFromHostContext(context);
11365
11671
  const pointer = sitianReport({
11366
11672
  level: "event",
11367
11673
  kind: event.type,
@@ -13664,44 +13970,6 @@ var init_receipt_delivery_policy = __esm({
13664
13970
  }
13665
13971
  });
13666
13972
 
13667
- // src/public-command-renderer.ts
13668
- function isPublicCallableRole2(role) {
13669
- return PUBLIC_CALLABLE_ROLES3.has(role);
13670
- }
13671
- function renderPublicAkRoleCommand(target) {
13672
- if (!isPublicCallableRole2(target.role)) return void 0;
13673
- const role = target.role;
13674
- const metadata = packagedRoleMetadata(role);
13675
- if (metadata !== void 0 && "bareCommand" in metadata && metadata.bareCommand === false) {
13676
- return void 0;
13677
- }
13678
- if (target.phase === null || target.phase === void 0) {
13679
- return `ak-role ${role}`;
13680
- }
13681
- if (role === "coder" || role === "fixer") {
13682
- return `ak-role ${role} ${target.phase}`;
13683
- }
13684
- return `ak-role ${role}`;
13685
- }
13686
- var PUBLIC_CALLABLE_ROLES3;
13687
- var init_public_command_renderer = __esm({
13688
- "src/public-command-renderer.ts"() {
13689
- "use strict";
13690
- init_packaged_role_registry();
13691
- PUBLIC_CALLABLE_ROLES3 = new Set(
13692
- PACKAGED_ROLE_REGISTRY.map((entry) => entry.role)
13693
- );
13694
- }
13695
- });
13696
-
13697
- // src/public-cli/command-renderer.ts
13698
- var init_command_renderer = __esm({
13699
- "src/public-cli/command-renderer.ts"() {
13700
- "use strict";
13701
- init_public_command_renderer();
13702
- }
13703
- });
13704
-
13705
13973
  // src/public-cli/terminal.ts
13706
13974
  function encodeTerminalField(value) {
13707
13975
  return JSON.stringify(value);
@@ -13712,14 +13980,10 @@ function isLawfulTypedTerminalOutcome(outcome) {
13712
13980
  function exitCodeForTerminalOutcome(outcome) {
13713
13981
  return isLawfulTypedTerminalOutcome(outcome) ? 0 : 1;
13714
13982
  }
13715
- function recommendationNavigatorFact(input) {
13716
- const command = typeof input.modelCommand === "string" && input.modelCommand.trim() !== "" ? input.modelCommand : isPublicCallableRole2(input.next.role) ? renderPublicAkRoleCommand(input.next) : void 0;
13983
+ function adviceNavigatorFact(input) {
13717
13984
  return {
13718
- disposition: "recommendation",
13719
- next: input.next,
13720
- reason: input.reason,
13721
- ...command === void 0 ? {} : { command },
13722
- ...input.route === void 0 ? {} : { route: input.route },
13985
+ disposition: "advice",
13986
+ prose: input.prose,
13723
13987
  ...input.advisoryDiagnostic === void 0 ? {} : { advisoryDiagnostic: input.advisoryDiagnostic }
13724
13988
  };
13725
13989
  }
@@ -13747,14 +14011,8 @@ function formatTerminalResult(result) {
13747
14011
  if (result.navigator.advisoryDiagnostic !== void 0) {
13748
14012
  lines.push(`navigator-advisory ${encodeTerminalField(result.navigator.advisoryDiagnostic)}`);
13749
14013
  }
13750
- if (result.navigator.disposition === "recommendation") {
13751
- lines.push(
13752
- `next ${result.navigator.next.role} ${result.navigator.next.phase ?? "none"}`
13753
- );
13754
- lines.push(`reason ${encodeTerminalField(result.navigator.reason)}`);
13755
- if (result.navigator.command !== void 0) {
13756
- lines.push(`command ${encodeTerminalField(result.navigator.command)}`);
13757
- }
14014
+ if (result.navigator.disposition === "advice") {
14015
+ lines.push(`prose ${encodeTerminalField(result.navigator.prose)}`);
13758
14016
  } else if (result.navigator.disposition === "unavailable") {
13759
14017
  lines.push(
13760
14018
  `unavailable ${result.navigator.source} ${encodeTerminalField(result.navigator.reason)}`
@@ -13803,7 +14061,6 @@ function formatTerminalResult(result) {
13803
14061
  var init_terminal = __esm({
13804
14062
  "src/public-cli/terminal.ts"() {
13805
14063
  "use strict";
13806
- init_command_renderer();
13807
14064
  }
13808
14065
  });
13809
14066
 
@@ -14783,10 +15040,6 @@ async function appendRunAttemptHistory(source, outcome) {
14783
15040
  } catch {
14784
15041
  }
14785
15042
  }
14786
- function navigatorPhaseValue(value) {
14787
- if (value === "plan" || value === "apply") return value;
14788
- return null;
14789
- }
14790
15043
  function navigatorAttendanceCorrelatedWithBoundMarker(details, attendanceIndex, terminalIndex, marker) {
14791
15044
  if (attendanceIndex <= terminalIndex) return false;
14792
15045
  if (details.invocationId !== marker.invocationId) return false;
@@ -14795,29 +15048,33 @@ function navigatorAttendanceCorrelatedWithBoundMarker(details, attendanceIndex,
14795
15048
  function parseNavigatorAttendanceDetails(details) {
14796
15049
  const disposition = details.disposition;
14797
15050
  const advisoryDiagnostic = typeof details.routePlaybookReadFailure === "string" ? { advisoryDiagnostic: details.routePlaybookReadFailure } : {};
14798
- if (disposition === "recommendation") {
14799
- const next = details.next;
14800
- if (!isRecord11(next) || typeof next.role !== "string") {
15051
+ if (disposition === "advice" || disposition === "recommendation") {
15052
+ let prose;
15053
+ if (typeof details.prose === "string" && details.prose.trim() !== "") {
15054
+ prose = details.prose;
15055
+ } else {
15056
+ const next = isRecord11(details.next) && typeof details.next.role === "string" ? details.next.role : void 0;
15057
+ const reason = typeof details.reason === "string" && details.reason.trim() !== "" ? details.reason : void 0;
15058
+ const command = typeof details.command === "string" && details.command.trim() !== "" ? details.command : void 0;
15059
+ if (reason !== void 0 && next !== void 0) {
15060
+ prose = `${reason}\uFF08\u4E0B\u4E00\u6B65\uFF1A${next}\uFF09`;
15061
+ } else if (reason !== void 0) {
15062
+ prose = reason;
15063
+ } else if (next !== void 0) {
15064
+ prose = `\u4E0B\u4E00\u6B65\uFF1A${next}`;
15065
+ } else if (command !== void 0) {
15066
+ prose = command;
15067
+ }
15068
+ }
15069
+ if (prose === void 0 || prose.trim() === "") {
14801
15070
  return {
14802
- disposition: "unavailable",
14803
- source: "unknown",
14804
- reason: "navigator recommendation missing typed next role"
15071
+ disposition: "no-advice",
15072
+ ...advisoryDiagnostic
14805
15073
  };
14806
15074
  }
14807
- const reason = typeof details.reason === "string" ? details.reason : "";
14808
- const route = Array.isArray(details.route) ? details.route.filter(isRecord11).map((target) => ({
14809
- role: String(target.role),
14810
- phase: navigatorPhaseValue(target.phase)
14811
- })) : void 0;
14812
- return recommendationNavigatorFact({
14813
- ...advisoryDiagnostic,
14814
- next: {
14815
- role: next.role,
14816
- phase: navigatorPhaseValue(next.phase)
14817
- },
14818
- reason,
14819
- ...route === void 0 ? {} : { route },
14820
- ...typeof details.command === "string" ? { modelCommand: details.command } : {}
15075
+ return adviceNavigatorFact({
15076
+ prose,
15077
+ ...advisoryDiagnostic
14821
15078
  });
14822
15079
  }
14823
15080
  if (disposition === "unavailable") {
@@ -18444,7 +18701,7 @@ async function runPostAdmissionOneShot(input) {
18444
18701
  ...input.request,
18445
18702
  continuation: {
18446
18703
  kind: "resume",
18447
- prompt: buildResumeContinuationPrompt({
18704
+ prompt: buildAutoResumeContinuationPrompt({
18448
18705
  packageRoot: input.env.packageRoot,
18449
18706
  ...pickEngineAxis({
18450
18707
  engine: input.effectiveEngine ?? input.env.engine,
@@ -19316,7 +19573,7 @@ async function runPublicJudge(argv, env, io, parseJudgeArgv2) {
19316
19573
  ...admitted.correlationId === void 0 && env.correlationId === void 0 ? {} : { correlationId: admitted.correlationId ?? env.correlationId },
19317
19574
  continuation: {
19318
19575
  kind: "resume",
19319
- prompt: buildResumeContinuationPrompt({
19576
+ prompt: buildAutoResumeContinuationPrompt({
19320
19577
  packageRoot: env.packageRoot,
19321
19578
  ...pickEngineAxis(env)
19322
19579
  })
@@ -20699,14 +20956,32 @@ async function summonPublicRole(options) {
20699
20956
  case "navigator":
20700
20957
  case "gatekeeper": {
20701
20958
  const seat2 = options.role;
20702
- const [{ runPublicInstructionSeat: runPublicInstructionSeat2 }, invocation] = await Promise.all([
20959
+ const [{ runPublicInstructionSeat: runPublicInstructionSeat2, runPublicInstructionSeatResume: runPublicInstructionSeatResume2 }, invocation] = await Promise.all([
20703
20960
  Promise.resolve().then(() => (init_instruction_seat_run(), instruction_seat_run_exports)),
20704
20961
  Promise.resolve().then(() => (init_invocation(), invocation_exports))
20705
20962
  ]);
20706
20963
  const parse = seat2 === "auditor" ? invocation.parseAuditorArgv : seat2 === "navigator" ? invocation.parseNavigatorArgv : invocation.parseGatekeeperArgv;
20707
- const stepped = await runPrepared(parse, (env, once) => runPublicInstructionSeat2(options.argv, env, io, seat2, once));
20708
- if ("fail" in stepped) return stepped.fail;
20709
- result = stepped.ok;
20964
+ const resumeRunId = typeof options.resumeRunId === "string" && options.resumeRunId.trim() !== "" ? options.resumeRunId.trim() : void 0;
20965
+ if (resumeRunId !== void 0) {
20966
+ const instruction = options.argv[0] ?? "";
20967
+ const stepped = await runPrepared(parse, (env) => runPublicInstructionSeatResume2(
20968
+ {
20969
+ runId: resumeRunId,
20970
+ summons: {
20971
+ instruction,
20972
+ instructionEmpty: instruction.trim() === ""
20973
+ }
20974
+ },
20975
+ env,
20976
+ io
20977
+ ));
20978
+ if ("fail" in stepped) return stepped.fail;
20979
+ result = stepped.ok;
20980
+ } else {
20981
+ const stepped = await runPrepared(parse, (env, once) => runPublicInstructionSeat2(options.argv, env, io, seat2, once));
20982
+ if ("fail" in stepped) return stepped.fail;
20983
+ result = stepped.ok;
20984
+ }
20710
20985
  break;
20711
20986
  }
20712
20987
  case "judge": {
@@ -21653,7 +21928,7 @@ var init_archivist_record_entry = __esm({
21653
21928
  });
21654
21929
 
21655
21930
  // src/headless-host/production-host.ts
21656
- import { randomUUID as randomUUID10 } from "node:crypto";
21931
+ import { randomUUID as randomUUID11 } from "node:crypto";
21657
21932
 
21658
21933
  // src/role-runtime-dependencies.ts
21659
21934
  import { readFile as readFile22 } from "node:fs/promises";
@@ -21740,6 +22015,7 @@ import { Type as Type13 } from "typebox";
21740
22015
 
21741
22016
  // src/navigator-public-session.ts
21742
22017
  init_sitian_facade();
22018
+ import { basename as basename9 } from "node:path";
21743
22019
 
21744
22020
  // src/navigator-session-contracts.ts
21745
22021
  import { Type as Type12 } from "typebox";
@@ -21927,6 +22203,7 @@ async function resolveNavigatorSeatSelection(context) {
21927
22203
 
21928
22204
  // src/navigator-public-session.ts
21929
22205
  init_host_contracts();
22206
+ init_cli_errors();
21930
22207
  async function resolveNavigatorLedgerHome(context) {
21931
22208
  const { tryHomeFromAkRolesPath: tryHomeFromAkRolesPath2 } = await Promise.resolve().then(() => (init_activation_ledger_topology(), activation_ledger_topology_exports));
21932
22209
  const runDirectory = runDirectoryFromHostContext(context);
@@ -21941,7 +22218,42 @@ async function resolveNavigatorLedgerHome(context) {
21941
22218
  }
21942
22219
  return void 0;
21943
22220
  }
21944
- function createNativeNavigatorSessionFactory() {
22221
+ var NAVIGATOR_HOST_RUN_POINTER_ENTRY = "ak-navigator-host-run";
22222
+ function exactRecord2(value) {
22223
+ return typeof value === "object" && value !== null && !Array.isArray(value);
22224
+ }
22225
+ function runIdFromNavigatorDirectory(runDirectory) {
22226
+ const entry = basename9(runDirectory);
22227
+ const suffix = "@navigator";
22228
+ if (!entry.endsWith(suffix)) return void 0;
22229
+ const runId = entry.slice(0, entry.length - suffix.length);
22230
+ return runId.length > 0 ? runId : void 0;
22231
+ }
22232
+ function readNavigatorHostRunPointer(entries) {
22233
+ for (let index = entries.length - 1; index >= 0; index -= 1) {
22234
+ const entry = entries[index];
22235
+ if (!exactRecord2(entry)) continue;
22236
+ if (entry.type === "custom" && entry.customType === NAVIGATOR_HOST_RUN_POINTER_ENTRY) {
22237
+ const data = entry.data;
22238
+ if (exactRecord2(data) && typeof data.runId === "string" && data.runId.trim() !== "") {
22239
+ return data.runId.trim();
22240
+ }
22241
+ }
22242
+ }
22243
+ return void 0;
22244
+ }
22245
+ async function navigatorHostRunResumable(home, runId) {
22246
+ const { piDurablePrincipalAuthority: piDurablePrincipalAuthority2 } = await Promise.resolve().then(() => (init_durable_principal(), durable_principal_exports));
22247
+ const { loadResumableInstructionSeatRun: loadResumableInstructionSeatRun2 } = await Promise.resolve().then(() => (init_run_lifecycle(), run_lifecycle_exports));
22248
+ try {
22249
+ const loaded = await loadResumableInstructionSeatRun2(home, runId, piDurablePrincipalAuthority2);
22250
+ return loaded.admitted.role === "navigator";
22251
+ } catch (error) {
22252
+ if (error instanceof CliUsageError) return false;
22253
+ throw error;
22254
+ }
22255
+ }
22256
+ function createNativeNavigatorSessionFactory(deps) {
21945
22257
  return async ({ context, subject, tool }) => {
21946
22258
  let thinkingLevel;
21947
22259
  const { createRecordSession: createRecordSession2, NAVIGATOR_RECORD_KIND: NAVIGATOR_RECORD_KIND2 } = await Promise.resolve().then(() => (init_archivist_record_entry(), archivist_record_entry_exports));
@@ -21957,6 +22269,11 @@ function createNativeNavigatorSessionFactory() {
21957
22269
  let noReceipt;
21958
22270
  let disposed = false;
21959
22271
  let inFlightPrompt;
22272
+ let hostRunId = readNavigatorHostRunPointer(sessionManager.getEntries());
22273
+ const summon = deps?.summonPublicRole ?? (async (options) => {
22274
+ const { summonPublicRole: summonPublicRole2 } = await Promise.resolve().then(() => (init_public_role_summons(), public_role_summons_exports));
22275
+ return summonPublicRole2(options);
22276
+ });
21960
22277
  return {
21961
22278
  prompt: async (text) => {
21962
22279
  if (disposed) {
@@ -21966,14 +22283,24 @@ function createNativeNavigatorSessionFactory() {
21966
22283
  noReceipt = void 0;
21967
22284
  const run = (async () => {
21968
22285
  try {
21969
- const { summonPublicRole: summonPublicRole2 } = await Promise.resolve().then(() => (init_public_role_summons(), public_role_summons_exports));
21970
22286
  const summonHome = await resolveNavigatorLedgerHome(context);
21971
- const summoned = await summonPublicRole2({
22287
+ const resumeRunId = hostRunId;
22288
+ const baseSummon = {
21972
22289
  role: "navigator",
21973
22290
  argv: [text],
21974
22291
  cwd: context.cwd,
21975
22292
  ...summonHome === void 0 ? {} : { home: summonHome }
21976
- });
22293
+ };
22294
+ const resumable = deps?.hostRunResumable ?? navigatorHostRunResumable;
22295
+ let summoned;
22296
+ if (resumeRunId === void 0 || summonHome === void 0) {
22297
+ summoned = await summon(baseSummon);
22298
+ } else if (await resumable(summonHome, resumeRunId)) {
22299
+ summoned = await summon({ ...baseSummon, resumeRunId });
22300
+ } else {
22301
+ hostRunId = void 0;
22302
+ summoned = await summon(baseSummon);
22303
+ }
21977
22304
  const outcome = summoned.terminal?.roleOutcome;
21978
22305
  if (outcome === void 0) {
21979
22306
  const detail = summoned.stderr?.trim() || `exit ${summoned.exitCode}`;
@@ -21996,21 +22323,31 @@ function createNativeNavigatorSessionFactory() {
21996
22323
  noReceipt = outcome;
21997
22324
  return;
21998
22325
  }
22326
+ const runDirectory = summoned.runDirectory ?? (typeof summoned.admitted?.runDirectory === "string" ? summoned.admitted.runDirectory : void 0);
22327
+ if (typeof runDirectory === "string" && runDirectory.trim() !== "") {
22328
+ const nextRunId = runIdFromNavigatorDirectory(runDirectory);
22329
+ if (nextRunId !== void 0) {
22330
+ hostRunId = nextRunId;
22331
+ sessionManager.appendCustomEntry(NAVIGATOR_HOST_RUN_POINTER_ENTRY, { runId: nextRunId });
22332
+ }
22333
+ }
21999
22334
  if (outcome.kind !== "accepted") {
22000
22335
  return;
22001
22336
  }
22337
+ const { navigatorProseFromUnknown: navigatorProseFromUnknown2 } = await Promise.resolve().then(() => (init_navigator_output(), navigator_output_exports));
22338
+ const proseParts = [];
22002
22339
  for (const payload of outcome.payloads ?? []) {
22003
- if (typeof payload !== "object" || payload === null || Array.isArray(payload)) continue;
22004
- const candidates = payload.candidates;
22005
- if (!Array.isArray(candidates)) continue;
22006
- await tool.execute(
22007
- "navigator-public-prepare",
22008
- { candidates },
22009
- void 0,
22010
- void 0,
22011
- context
22012
- );
22340
+ const prose = navigatorProseFromUnknown2(payload);
22341
+ if (prose !== void 0) proseParts.push(prose);
22013
22342
  }
22343
+ if (proseParts.length === 0) return;
22344
+ await tool.execute(
22345
+ "navigator-public-prepare",
22346
+ { prose: proseParts.join("\n\n") },
22347
+ void 0,
22348
+ void 0,
22349
+ context
22350
+ );
22014
22351
  } catch (error) {
22015
22352
  if (error instanceof NavigatorUnavailableError) throw error;
22016
22353
  const fact = navigatorProviderFailureFromError(error);
@@ -22064,9 +22401,9 @@ function createNativeNavigatorSessionFactory() {
22064
22401
 
22065
22402
  // src/navigator-attendance.ts
22066
22403
  init_sitian_facade();
22067
- init_public_command_renderer();
22068
22404
  init_work_subject_identity();
22069
22405
  init_receipt_delivery_policy();
22406
+ init_navigator_output();
22070
22407
  var NAVIGATOR_EVENT_TYPE = "ak-navigator-attendance";
22071
22408
  var NAVIGATOR_PREPARE_ACCEPTED_TEXT = "\u6E38\u5955\u4F7F\u51C6\u5907\u5DF2\u63A5\u53D7";
22072
22409
  function resolveNavigatorAuthorityMaterial(roleInput, fileAuthority) {
@@ -22076,107 +22413,40 @@ function resolveNavigatorAuthorityMaterial(roleInput, fileAuthority) {
22076
22413
  }
22077
22414
  var NAVIGATOR_TARGETS = PACKAGED_ROLE_REGISTRY.map(({ role, phases }) => ({ role, phases }));
22078
22415
  var prepareSchema = Type13.Object({
22079
- candidates: Type13.Optional(Type13.Unknown({
22080
- 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"
22416
+ prose: Type13.Optional(Type13.Unknown({
22417
+ 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"
22081
22418
  }))
22082
22419
  }, { additionalProperties: true });
22083
- var ROUTE_ENTRY = "ak-navigator-route";
22084
22420
  var CONTEXT_ENTRY = "ak-navigator-context";
22085
22421
  var INVOCATION_ENTRY = NAVIGATOR_INVOCATION_ENTRY;
22086
22422
  var SETTLEMENT_ENTRY = "ak-navigator-settlement";
22087
- var targetRoles = new Set(NAVIGATOR_TARGETS.map(({ role }) => role));
22088
- function exactRecord2(value) {
22423
+ function exactRecord3(value) {
22089
22424
  return typeof value === "object" && value !== null && !Array.isArray(value);
22090
22425
  }
22091
22426
  function rejectedPrepareReason(entries, start) {
22092
22427
  const recent = entries.slice(start);
22093
22428
  const prepareCalls = /* @__PURE__ */ new Set();
22094
22429
  for (const entry of recent) {
22095
- if (!exactRecord2(entry) || entry.type !== "message" || !exactRecord2(entry.message) || entry.message.role !== "assistant" || !Array.isArray(entry.message.content)) continue;
22430
+ if (!exactRecord3(entry) || entry.type !== "message" || !exactRecord3(entry.message) || entry.message.role !== "assistant" || !Array.isArray(entry.message.content)) continue;
22096
22431
  for (const part of entry.message.content) {
22097
- if (exactRecord2(part) && part.type === "toolCall" && part.name === NAVIGATOR_PREPARE_TOOL_NAME && typeof part.id === "string") prepareCalls.add(part.id);
22432
+ if (exactRecord3(part) && part.type === "toolCall" && part.name === NAVIGATOR_PREPARE_TOOL_NAME && typeof part.id === "string") prepareCalls.add(part.id);
22098
22433
  }
22099
22434
  }
22100
22435
  let reason;
22101
22436
  for (const entry of recent) {
22102
- if (!exactRecord2(entry) || entry.type !== "message" || !exactRecord2(entry.message) || entry.message.role !== "toolResult" || entry.message.isError !== true) continue;
22437
+ if (!exactRecord3(entry) || entry.type !== "message" || !exactRecord3(entry.message) || entry.message.role !== "toolResult" || entry.message.isError !== true) continue;
22103
22438
  const callId = entry.message.toolCallId;
22104
22439
  if (entry.message.toolName !== NAVIGATOR_PREPARE_TOOL_NAME || typeof callId !== "string" || !prepareCalls.has(callId)) {
22105
22440
  return void 0;
22106
22441
  }
22107
22442
  const content = entry.message.content;
22108
- const text = Array.isArray(content) ? content.flatMap((part) => exactRecord2(part) && typeof part.text === "string" ? [part.text] : []).join("") : typeof content === "string" ? content : "";
22443
+ const text = Array.isArray(content) ? content.flatMap((part) => exactRecord3(part) && typeof part.text === "string" ? [part.text] : []).join("") : typeof content === "string" ? content : "";
22109
22444
  if (text.trim() !== "") reason = text.trim();
22110
22445
  }
22111
22446
  return reason;
22112
22447
  }
22113
- function targetIsValid(value) {
22114
- if (!exactRecord2(value) || !targetRoles.has(String(value.role))) return false;
22115
- const metadata = packagedRoleMetadata(String(value.role));
22116
- return metadata !== void 0 && metadata.phases.includes(value.phase);
22117
- }
22118
- function normalizeTarget(value) {
22119
- if (!exactRecord2(value)) return void 0;
22120
- const role = typeof value.role === "string" ? value.role.trim() : "";
22121
- if (role === "") return void 0;
22122
- if (value.phase === void 0 || value.phase === null) {
22123
- return { role, phase: null };
22124
- }
22125
- if (value.phase === "plan" || value.phase === "apply") {
22126
- return { role, phase: value.phase };
22127
- }
22128
- return { role, phase: null };
22129
- }
22130
- function normalizeMatches(value) {
22131
- if (!exactRecord2(value)) return void 0;
22132
- if (typeof value.role !== "string" || value.role.trim() === "") return void 0;
22133
- if (value.kind !== "accepted") return void 0;
22134
- let phase;
22135
- if (value.phase === void 0 || value.phase === null) phase = null;
22136
- else if (value.phase === "plan" || value.phase === "apply") phase = value.phase;
22137
- else return void 0;
22138
- if (value.statuses !== void 0) {
22139
- if (!Array.isArray(value.statuses) || value.statuses.some((status) => typeof status !== "string" || status.trim() === "")) {
22140
- return void 0;
22141
- }
22142
- return {
22143
- role: value.role,
22144
- phase,
22145
- kind: "accepted",
22146
- statuses: [...value.statuses]
22147
- };
22148
- }
22149
- return { role: value.role, phase, kind: "accepted" };
22150
- }
22151
- function normalizeCandidate(value) {
22152
- if (!exactRecord2(value)) return void 0;
22153
- const next = normalizeTarget(value.next);
22154
- const route = Array.isArray(value.route) ? value.route.map(normalizeTarget).filter((target) => target !== void 0) : void 0;
22155
- const matches = normalizeMatches(value.matches);
22156
- const id = typeof value.id === "string" && value.id.trim() !== "" ? value.id : void 0;
22157
- const reason = typeof value.reason === "string" && value.reason.trim() !== "" ? value.reason : void 0;
22158
- const command = typeof value.command === "string" ? value.command : void 0;
22159
- return {
22160
- ...id === void 0 ? {} : { id },
22161
- ...matches === void 0 ? {} : { matches },
22162
- ...route === void 0 || route.length === 0 ? {} : { route },
22163
- ...next === void 0 ? {} : { next },
22164
- ...reason === void 0 ? {} : { reason },
22165
- ...command === void 0 ? {} : { command }
22166
- };
22167
- }
22168
- function normalizePrepareOutput(value) {
22169
- if (!exactRecord2(value) || !Array.isArray(value.candidates)) return [];
22170
- return value.candidates.map(normalizeCandidate).filter((candidate) => candidate !== void 0);
22171
- }
22172
- function routeEqual(a, b) {
22173
- return a !== void 0 && a.length === b.length && a.every((target, index) => target.role === b[index].role && target.phase === b[index].phase);
22174
- }
22175
- function routeText(route) {
22176
- return route.map((target) => target.phase === null ? target.role : `${target.role} ${target.phase}`).join(" \u2192 ");
22177
- }
22178
- function targetText(target) {
22179
- return target.phase === null ? target.role : `${target.role} ${target.phase}`;
22448
+ function normalizePrepareProse(value) {
22449
+ return navigatorProseFromUnknown(value);
22180
22450
  }
22181
22451
  function navigatorSubjectKey(subjectRoot, subject, provenance = "role_input") {
22182
22452
  if (issueRoot(subjectRoot) !== void 0 || !subjectRoot.includes("/.ak/work/")) return subjectRoot;
@@ -22198,7 +22468,7 @@ function createNavigatorPrepareTool(onOutput) {
22198
22468
  return {
22199
22469
  name: NAVIGATOR_PREPARE_TOOL_NAME,
22200
22470
  label: "\u6E38\u5955\u4F7F\u51C6\u5907",
22201
- description: "\u63D0\u4EA4\u6E38\u5955\u4F7F\u65B9\u5411\u5EFA\u8BAE\u3002",
22471
+ description: "\u63D0\u4EA4\u6E38\u5955\u4F7F\u6563\u6587\u5EFA\u8BAE\u3002",
22202
22472
  parameters: prepareSchema,
22203
22473
  async execute(_id, value) {
22204
22474
  onOutput(value);
@@ -22206,34 +22476,6 @@ function createNavigatorPrepareTool(onOutput) {
22206
22476
  }
22207
22477
  };
22208
22478
  }
22209
- function selectNavigatorCandidate(candidates, settlement) {
22210
- if (settlement.kind !== "accepted") return void 0;
22211
- const usable = candidates.filter((candidate) => candidate.next !== void 0);
22212
- if (usable.length === 0) return void 0;
22213
- const rolePhaseMatched = usable.filter(
22214
- (candidate) => candidate.matches !== void 0 && candidate.matches.role === settlement.role && candidate.matches.phase === settlement.phase
22215
- );
22216
- if (rolePhaseMatched.length > 0) {
22217
- if (settlement.status !== void 0) {
22218
- const statusSpecific = rolePhaseMatched.find(
22219
- (candidate) => candidate.matches?.statuses !== void 0 && candidate.matches.statuses.includes(settlement.status)
22220
- );
22221
- if (statusSpecific !== void 0) {
22222
- return { candidate: statusSpecific, matchedToSettlement: true };
22223
- }
22224
- }
22225
- const rolePhaseGeneric = rolePhaseMatched.find(
22226
- (candidate) => candidate.matches?.statuses === void 0
22227
- );
22228
- if (rolePhaseGeneric !== void 0) {
22229
- return { candidate: rolePhaseGeneric, matchedToSettlement: true };
22230
- }
22231
- return void 0;
22232
- }
22233
- const unbound = usable.find((candidate) => candidate.matches === void 0);
22234
- if (unbound === void 0) return void 0;
22235
- return { candidate: unbound, matchedToSettlement: false };
22236
- }
22237
22479
  function formatNavigatorReport(report) {
22238
22480
  const playbookFailure = report.routePlaybookReadFailure === void 0 ? [] : [`\u8DEF\u4E66\u8BFB\u53D6\u5931\u8D25\uFF1A${report.routePlaybookReadFailure}`];
22239
22481
  if (report.disposition === "no-advice") return playbookFailure.join("\n");
@@ -22243,31 +22485,24 @@ function formatNavigatorReport(report) {
22243
22485
  if (report.disposition === "arrival") {
22244
22486
  return [...playbookFailure, ...report.arrivalMessage ? [report.arrivalMessage] : []].join("\n");
22245
22487
  }
22246
- return [
22247
- ...playbookFailure,
22248
- ...report.route === void 0 ? [] : [`\u8DEF\u7EBF\uFF1A${routeText(report.route)}`],
22249
- ...report.next === void 0 ? [] : [`\u4E0B\u4E00\u6B65\uFF1A${targetText(report.next)}`],
22250
- ...report.reason === void 0 || report.reason.trim() === "" ? [] : [`\u7406\u7531\uFF1A${report.reason}`],
22251
- ...report.command === void 0 || report.command.trim() === "" ? [] : [`\u547D\u4EE4\uFF1A${report.command}`]
22252
- ].join("\n");
22488
+ return [...playbookFailure, ...report.prose ? [report.prose] : []].join("\n");
22253
22489
  }
22254
22490
  function createNavigatorAttendance(options) {
22255
22491
  let preparation;
22492
+ let preparationInFlight = false;
22256
22493
  let sessionReady;
22257
22494
  let session;
22258
22495
  let subjectKey = options.subjectKey;
22259
22496
  let subject = options.subject;
22260
22497
  let authority = options.authority;
22261
22498
  let contextError = options.contextError;
22262
- let candidates;
22499
+ let preparedProse;
22263
22500
  const invocationPrincipal = options.invocationId ?? mintNavigatorInvocationId();
22264
22501
  let activeInvocationId = invocationPrincipal;
22265
- let previousRoute;
22266
22502
  let outputSink;
22267
22503
  let settlementTail = Promise.resolve();
22268
22504
  let settlementFailure;
22269
22505
  let preparationFailure;
22270
- let preparationNoReceipt = false;
22271
22506
  let routePlaybookReadFailure;
22272
22507
  let disposed = false;
22273
22508
  let warmedHelp;
@@ -22294,12 +22529,7 @@ function createNavigatorAttendance(options) {
22294
22529
  };
22295
22530
  let routePlaybookSettlement;
22296
22531
  let prepareBoundSettlement;
22297
- const prepare = async () => {
22298
- const boundSettlement = prepareBoundSettlement;
22299
- prepareBoundSettlement = void 0;
22300
- preparationNoReceipt = false;
22301
- const invocationId = invocationPrincipal;
22302
- activeInvocationId = invocationId;
22532
+ const loadMaterialsAndSession = async (invocationId) => {
22303
22533
  if (contextError !== void 0) throw navigatorUnavailableError("context", contextError);
22304
22534
  if (typeof authority !== "string" || authority.trim() === "") {
22305
22535
  throw navigatorUnavailableError(
@@ -22357,21 +22587,6 @@ function createNavigatorAttendance(options) {
22357
22587
  const helpContext = help.map(({ role, help: text }) => `<role_help role="${role}">
22358
22588
  ${text}
22359
22589
  </role_help>`).join("\n");
22360
- let output;
22361
- let prepareBatchRejected = false;
22362
- outputSink = (value) => {
22363
- if (output === void 0) {
22364
- output = value;
22365
- return;
22366
- }
22367
- const prior2 = output.candidates;
22368
- const next = value.candidates;
22369
- const merged = [
22370
- ...Array.isArray(prior2) ? prior2 : prior2 === void 0 ? [] : [prior2],
22371
- ...Array.isArray(next) ? next : next === void 0 ? [] : [next]
22372
- ];
22373
- output = { ...value, candidates: merged };
22374
- };
22375
22590
  const tool = createNavigatorPrepareTool((value) => {
22376
22591
  outputSink?.(value);
22377
22592
  });
@@ -22379,7 +22594,12 @@ ${text}
22379
22594
  sessionReady = (async () => {
22380
22595
  let created;
22381
22596
  try {
22382
- created = await options.createSession({ context: options.context, subject: subjectKey, ...options.modelSettingPath === void 0 ? {} : { modelSettingPath: options.modelSettingPath }, tool });
22597
+ created = await options.createSession({
22598
+ context: options.context,
22599
+ subject: subjectKey,
22600
+ ...options.modelSettingPath === void 0 ? {} : { modelSettingPath: options.modelSettingPath },
22601
+ tool
22602
+ });
22383
22603
  } catch (error) {
22384
22604
  throw navigatorUnavailableError("session", error);
22385
22605
  }
@@ -22410,26 +22630,40 @@ ${text}
22410
22630
  session.appendEntry(INVOCATION_ENTRY, { invocationId, role: options.role, phase: options.phase, subjectKey });
22411
22631
  }
22412
22632
  if (disposed) throw navigatorUnavailableError("session", new Error("Navigator attendance was disposed"));
22413
- const activeSession = session;
22414
- if (activeSession === void 0) throw new Error("Navigator session was not created");
22415
- 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;
22416
- if (exactRecord2(prior) && Array.isArray(prior.route) && prior.route.every((target) => targetIsValid(target))) {
22417
- previousRoute = prior.route.map((target) => ({ role: target.role, phase: target.phase }));
22418
- }
22419
- const publicSettlementHistory = activeSession.entries().filter((entry) => exactRecord2(entry) && entry.type === "custom" && entry.customType === SETTLEMENT_ENTRY && exactRecord2(entry.data)).map((entry) => entry.data);
22633
+ if (session === void 0) throw new Error("Navigator session was not created");
22634
+ return { soul, routePlaybook, helpContext, modelSetting, model, help, activeSession: session };
22635
+ };
22636
+ const prepare = async (materialsBundle) => {
22637
+ const boundSettlement = prepareBoundSettlement;
22638
+ prepareBoundSettlement = void 0;
22639
+ const invocationId = invocationPrincipal;
22640
+ activeInvocationId = invocationId;
22641
+ let output;
22642
+ let prepareBatchRejected = false;
22643
+ outputSink = (value) => {
22644
+ if (output === void 0) {
22645
+ output = value;
22646
+ return;
22647
+ }
22648
+ const prior = normalizePrepareProse(output) ?? "";
22649
+ const next = normalizePrepareProse(value) ?? "";
22650
+ const merged = [prior, next].filter((part) => part.trim() !== "").join("\n\n");
22651
+ output = { prose: merged };
22652
+ };
22653
+ const { soul, routePlaybook, helpContext, help, activeSession } = materialsBundle ?? await loadMaterialsAndSession(invocationId);
22654
+ const publicSettlementHistory = activeSession.entries().filter((entry) => exactRecord3(entry) && entry.type === "custom" && entry.customType === SETTLEMENT_ENTRY && exactRecord3(entry.data)).map((entry) => entry.data);
22420
22655
  const projection = {
22421
22656
  subjectKey,
22422
22657
  subject,
22423
22658
  authority,
22424
22659
  currentRole: { role: options.role, phase: options.phase },
22425
22660
  ...boundSettlement === void 0 ? {} : { currentSettlement: boundSettlement },
22426
- priorRoute: exactRecord2(prior) && Array.isArray(prior.route) && prior.route.every((target) => targetIsValid(target)) ? prior.route.map((target) => ({ role: target.role, phase: target.phase })) : null,
22427
22661
  publicSettlementHistory,
22428
22662
  liveRoleHelp: help
22429
22663
  };
22430
22664
  activeSession.appendEntry(CONTEXT_ENTRY, projection);
22431
- const request = [
22432
- "\u672C\u6B21\u5BFC\u822A\u6750\u6599\u5982\u4E0B\uFF1A",
22665
+ const request = boundSettlement === void 0 ? [
22666
+ "\u672C\u8F6E\u4E3A\u5F85\u547D\u8F6E\u3002",
22433
22667
  `<navigator_soul>
22434
22668
  ${soul}
22435
22669
  </navigator_soul>`,
@@ -22445,12 +22679,32 @@ ${authority}
22445
22679
  `<current_role>
22446
22680
  ${JSON.stringify({ role: options.role, phase: options.phase })}
22447
22681
  </current_role>`,
22448
- ...boundSettlement === void 0 ? [] : [`<current_settlement>
22682
+ `<public_settlement_history>
22683
+ ${JSON.stringify(projection.publicSettlementHistory)}
22684
+ </public_settlement_history>`,
22685
+ `<live_role_help>
22686
+ ${helpContext}
22687
+ </live_role_help>`
22688
+ ].join("\n\n") : [
22689
+ "\u672C\u8F6E\u4E3A\u7ED3\u7B97\u6295\u5582\u8F6E\u3002",
22690
+ `<navigator_soul>
22691
+ ${soul}
22692
+ </navigator_soul>`,
22693
+ ...routePlaybookReadFailure === void 0 ? [`<route_playbook>
22694
+ ${routePlaybook}
22695
+ </route_playbook>`] : ["\u53EF\u9009\u8DEF\u7EBF\u624B\u518C\u672A\u80FD\u8BFB\u53D6\u3002"],
22696
+ `<work_subject>
22697
+ ${subject}
22698
+ </work_subject>`,
22699
+ `<controlling_authority>
22700
+ ${authority}
22701
+ </controlling_authority>`,
22702
+ `<current_role>
22703
+ ${JSON.stringify({ role: options.role, phase: options.phase })}
22704
+ </current_role>`,
22705
+ `<current_settlement>
22449
22706
  ${JSON.stringify(boundSettlement)}
22450
- </current_settlement>`],
22451
- `<prior_route>
22452
- ${JSON.stringify(prior ?? null)}
22453
- </prior_route>`,
22707
+ </current_settlement>`,
22454
22708
  `<public_settlement_history>
22455
22709
  ${JSON.stringify(projection.publicSettlementHistory)}
22456
22710
  </public_settlement_history>`,
@@ -22491,33 +22745,47 @@ ${helpContext}
22491
22745
  if (deliveryRequest && output === void 0) delivery.recordDeliveryRequest();
22492
22746
  };
22493
22747
  await promptAllowingRejectedPrepare(request, false);
22494
- while (output === void 0 && delivery.nextAction() === "request-delivery") {
22495
- await promptAllowingRejectedPrepare(RECEIPT_DELIVERY_PROMPT, true);
22496
- }
22497
- if (output === void 0 && delivery.nextAction() === "no-receipt" && activeSession.providerFailure?.() === void 0) {
22498
- const facts = delivery.facts({ runPointer: activeSession.recordPointer(), attemptPointer: invocationId });
22499
- activeSession.appendEntry(NO_RECEIPT_LIFECYCLE_ENTRY_TYPE, facts);
22500
- preparationNoReceipt = true;
22501
- candidates = [];
22502
- return candidates;
22748
+ if (boundSettlement !== void 0) {
22749
+ while (output === void 0 && prepareBatchRejected && delivery.nextAction() === "request-delivery") {
22750
+ await promptAllowingRejectedPrepare(RECEIPT_DELIVERY_PROMPT, true);
22751
+ }
22752
+ if (output === void 0 && delivery.nextAction() === "request-delivery") {
22753
+ while (delivery.nextAction() === "request-delivery") {
22754
+ delivery.recordDeliveryRequest();
22755
+ }
22756
+ }
22757
+ if (output === void 0 && delivery.nextAction() === "no-receipt" && activeSession.providerFailure?.() === void 0) {
22758
+ const facts = delivery.facts({ runPointer: activeSession.recordPointer(), attemptPointer: invocationId });
22759
+ activeSession.appendEntry(NO_RECEIPT_LIFECYCLE_ENTRY_TYPE, facts);
22760
+ preparedProse = void 0;
22761
+ return void 0;
22762
+ }
22503
22763
  }
22504
22764
  } catch (error) {
22505
22765
  throw error instanceof NavigatorUnavailableError ? error : navigatorUnavailableError("transport", error);
22506
22766
  }
22507
22767
  if (output === void 0) {
22768
+ if (boundSettlement === void 0) {
22769
+ preparedProse = void 0;
22770
+ return void 0;
22771
+ }
22508
22772
  const nativeFailure = [...activeSession.entries()].reverse().find((entry) => {
22509
- if (!exactRecord2(entry) || entry.type !== "message" || !exactRecord2(entry.message)) return false;
22773
+ if (!exactRecord3(entry) || entry.type !== "message" || !exactRecord3(entry.message)) return false;
22510
22774
  return entry.message.role === "assistant" && typeof entry.message.errorMessage === "string" && entry.message.errorMessage.trim() !== "";
22511
22775
  });
22512
- const nativeMessage = exactRecord2(nativeFailure) && exactRecord2(nativeFailure.message) ? nativeFailure.message : void 0;
22776
+ const nativeMessage = exactRecord3(nativeFailure) && exactRecord3(nativeFailure.message) ? nativeFailure.message : void 0;
22513
22777
  const errorMessage = nativeMessage !== void 0 && typeof nativeMessage.errorMessage === "string" ? nativeMessage.errorMessage : "Navigator did not submit direction advice";
22514
22778
  const providerFailure = activeSession.providerFailure?.();
22515
22779
  const source = providerFailure?.source ?? "unknown";
22516
22780
  const cause = providerFailure?.cause ?? source;
22517
22781
  throw navigatorUnavailableError(source, errorMessage, cause);
22518
22782
  }
22519
- candidates = normalizePrepareOutput(output);
22520
- return candidates;
22783
+ if (boundSettlement === void 0) {
22784
+ preparedProse = void 0;
22785
+ return void 0;
22786
+ }
22787
+ preparedProse = normalizePrepareProse(output);
22788
+ return preparedProse;
22521
22789
  } finally {
22522
22790
  outputSink = void 0;
22523
22791
  }
@@ -22528,7 +22796,6 @@ ${helpContext}
22528
22796
  if (next.subjectKey !== subjectKey && session !== void 0) {
22529
22797
  const previous = session;
22530
22798
  session = void 0;
22531
- previousRoute = void 0;
22532
22799
  closing = previous.dispose();
22533
22800
  }
22534
22801
  subjectKey = next.subjectKey;
@@ -22550,13 +22817,16 @@ ${helpContext}
22550
22817
  prepare() {
22551
22818
  if (disposed || preparation !== void 0) return;
22552
22819
  preparationFailure = void 0;
22553
- preparation = prepare();
22820
+ preparationInFlight = true;
22821
+ preparation = prepare().finally(() => {
22822
+ preparationInFlight = false;
22823
+ });
22554
22824
  void preparation.catch((error) => {
22555
22825
  preparationFailure = error;
22556
22826
  });
22557
22827
  },
22558
22828
  isPreparing() {
22559
- return preparation !== void 0 || sessionReady !== void 0;
22829
+ return preparationInFlight;
22560
22830
  },
22561
22831
  knownRoutePlaybookReadFailure() {
22562
22832
  return routePlaybookReadFailure;
@@ -22580,81 +22850,70 @@ ${helpContext}
22580
22850
  if (disposed) return;
22581
22851
  const invocationId = activeInvocationId ?? invocationPrincipal;
22582
22852
  let report;
22583
- if (settlement.kind === "human_decision" || settlement.kind === "role_infrastructure_failure") {
22584
- if (sessionReady !== void 0) {
22585
- try {
22586
- await sessionReady;
22587
- } catch (error) {
22588
- preparationFailure ??= error;
22589
- }
22853
+ if (sessionReady !== void 0) {
22854
+ try {
22855
+ await sessionReady;
22856
+ } catch (error) {
22857
+ preparationFailure ??= error;
22590
22858
  }
22591
- if (preparation !== void 0) {
22592
- try {
22593
- await preparation;
22594
- } catch (error) {
22595
- preparationFailure ??= error;
22596
- }
22859
+ }
22860
+ if (preparation !== void 0) {
22861
+ try {
22862
+ await preparation;
22863
+ } catch (error) {
22864
+ preparationFailure ??= error;
22597
22865
  }
22598
- session?.appendEntry(SETTLEMENT_ENTRY, { invocationId, subjectKey, role: settlement.role, phase: settlement.phase, kind: settlement.kind, ...settlement.kind === "human_decision" ? { status: settlement.status } : {} });
22866
+ preparation = void 0;
22867
+ }
22868
+ const settlementFact = {
22869
+ invocationId,
22870
+ subjectKey,
22871
+ role: settlement.role,
22872
+ phase: settlement.phase,
22873
+ kind: settlement.kind,
22874
+ ..."status" in settlement && settlement.status !== void 0 ? { status: settlement.status } : {}
22875
+ };
22876
+ let drainedProse;
22877
+ if (settlement.kind === "arrival") {
22878
+ session?.appendEntry(SETTLEMENT_ENTRY, settlementFact);
22599
22879
  if (preparationFailure !== void 0) {
22600
22880
  report = unavailable(invocationId, preparationFailure);
22601
22881
  } else {
22602
- report = { disposition: "no-advice" };
22882
+ report = {
22883
+ disposition: "arrival",
22884
+ ...settlement.message === void 0 ? {} : { arrivalMessage: settlement.message }
22885
+ };
22603
22886
  }
22604
- } else if (settlement.kind === "arrival") {
22605
- if (sessionReady !== void 0) {
22887
+ } else {
22888
+ if (session !== void 0) preparationFailure = void 0;
22889
+ let coldMaterials;
22890
+ if (session === void 0 && preparationFailure === void 0) {
22606
22891
  try {
22607
- await sessionReady;
22892
+ coldMaterials = await loadMaterialsAndSession(invocationId);
22608
22893
  } catch (error) {
22609
- preparationFailure ??= error;
22894
+ preparationFailure = error;
22610
22895
  }
22611
22896
  }
22612
- if (preparation !== void 0) {
22897
+ session?.appendEntry(SETTLEMENT_ENTRY, settlementFact);
22898
+ if (preparationFailure === void 0) {
22899
+ prepareBoundSettlement = settlement;
22900
+ preparation = prepare(coldMaterials);
22901
+ void preparation.catch((error) => {
22902
+ preparationFailure = error;
22903
+ });
22613
22904
  try {
22614
- await preparation;
22905
+ drainedProse = await preparation;
22615
22906
  } catch (error) {
22616
22907
  preparationFailure ??= error;
22617
22908
  }
22909
+ preparation = void 0;
22618
22910
  }
22619
- report = preparationFailure === void 0 ? { disposition: "arrival", ...settlement.message === void 0 ? {} : { arrivalMessage: settlement.message } } : unavailable(invocationId, preparationFailure);
22620
- } else if (preparation === void 0) {
22621
- report = unavailable(invocationId, "Navigator preparation did not start");
22622
- } else {
22623
- try {
22624
- if (sessionReady !== void 0) await sessionReady;
22625
- let prepared = await preparation;
22626
- session?.appendEntry(SETTLEMENT_ENTRY, { invocationId, subjectKey, role: settlement.role, phase: settlement.phase, kind: settlement.kind, ...settlement.status === void 0 ? {} : { status: settlement.status } });
22627
- let selected = selectNavigatorCandidate(prepared, settlement);
22628
- if (selected?.candidate.next !== void 0 && !selected.matchedToSettlement) {
22629
- if (disposed) return;
22630
- prepareBoundSettlement = settlement;
22631
- prepared = await prepare();
22632
- if (disposed) return;
22633
- selected = selectNavigatorCandidate(prepared, settlement);
22634
- }
22635
- const selectedCandidate = selected?.candidate;
22636
- if (selectedCandidate?.next === void 0 && preparationNoReceipt) {
22637
- report = { disposition: "no-advice" };
22638
- } else if (selectedCandidate?.next === void 0) {
22639
- throw new Error("Navigator prepared no machine-usable next direction");
22640
- } else {
22641
- const selectedRoute = selectedCandidate.route;
22642
- const routeChanged = selectedRoute !== void 0 && !routeEqual(previousRoute, selectedRoute);
22643
- const command = typeof selectedCandidate.command === "string" && selectedCandidate.command.trim() !== "" ? selectedCandidate.command : renderPublicAkRoleCommand(selectedCandidate.next);
22644
- report = {
22645
- disposition: "recommendation",
22646
- ...routeChanged ? { route: selectedRoute } : {},
22647
- next: selectedCandidate.next,
22648
- ...selectedCandidate.reason === void 0 ? {} : { reason: selectedCandidate.reason },
22649
- ...command === void 0 ? {} : { command }
22650
- };
22651
- if (selectedRoute !== void 0) {
22652
- previousRoute = selectedRoute;
22653
- session?.appendEntry(ROUTE_ENTRY, { invocationId, subjectKey, route: selectedRoute });
22654
- }
22655
- }
22656
- } catch (error) {
22657
- report = unavailable(invocationId, error);
22911
+ if (preparationFailure !== void 0) {
22912
+ report = unavailable(invocationId, preparationFailure);
22913
+ } else if (typeof drainedProse === "string" && drainedProse.trim() !== "") {
22914
+ report = { disposition: "advice", prose: drainedProse };
22915
+ } else {
22916
+ report = { disposition: "no-advice" };
22658
22917
  }
22659
22918
  }
22660
22919
  await routePlaybookSettlement;
@@ -22668,10 +22927,7 @@ ${helpContext}
22668
22927
  role: options.role,
22669
22928
  phase: options.phase,
22670
22929
  subjectKey,
22671
- ...report.route === void 0 ? {} : { route: report.route },
22672
- ...report.next === void 0 ? {} : { next: report.next },
22673
- ...report.reason === void 0 ? {} : { reason: report.reason },
22674
- ...report.command === void 0 ? {} : { command: report.command },
22930
+ ...report.prose === void 0 ? {} : { prose: report.prose },
22675
22931
  ...report.unavailableReason === void 0 ? {} : { unavailableReason: report.unavailableReason },
22676
22932
  ...report.unavailableSource === void 0 ? {} : { unavailableSource: report.unavailableSource },
22677
22933
  ...report.unavailableCause === void 0 ? {} : { unavailableCause: report.unavailableCause },
@@ -22687,9 +22943,8 @@ ${helpContext}
22687
22943
  }
22688
22944
  preparation = void 0;
22689
22945
  sessionReady = void 0;
22690
- candidates = void 0;
22946
+ preparedProse = void 0;
22691
22947
  preparationFailure = void 0;
22692
- preparationNoReceipt = false;
22693
22948
  routePlaybookSettlement = void 0;
22694
22949
  routePlaybookReadFailure = void 0;
22695
22950
  }
@@ -22826,6 +23081,7 @@ init_host_contracts();
22826
23081
  init_sitian_facade();
22827
23082
  init_submission_ledger();
22828
23083
  init_collector_ledger();
23084
+ import { randomUUID as randomUUID8 } from "node:crypto";
22829
23085
  import { readFileSync as readFileSync6, writeSync as writeSync4 } from "node:fs";
22830
23086
  import { join as join39 } from "node:path";
22831
23087
  import { Value as Value4 } from "typebox/value";
@@ -24672,7 +24928,7 @@ init_navigator_output();
24672
24928
  var NAVIGATOR_TOOL_SPEC = {
24673
24929
  name: NAVIGATOR_OUTPUT_TOOL_NAME,
24674
24930
  label: "\u6E38\u5955\u4F7F\u5EFA\u8BAE",
24675
- description: "\u6E38\u5955\u4F7F\u7EC8\u5C40\u56DE\u6267\uFF1A\u6392\u597D\u5E8F\u7684\u4E0B\u4E00\u6B65\u89D2\u8272\u8DEF\u7EBF\u5EFA\u8BAE\u3002",
24931
+ description: "\u6E38\u5955\u4F7F\u7EC8\u5C40\u56DE\u6267\uFF1A\u6563\u6587\u5EFA\u8BAE\uFF0C\u539F\u6837\u5448\u73B0\u3002",
24676
24932
  promptSnippet: "\u6E38\u5955\u4F7F\u5EFA\u8BAE",
24677
24933
  parameters: navigatorOutputSchema
24678
24934
  };
@@ -26171,6 +26427,21 @@ function createCountersignRoleRuntime(roleHost, dependencies, hostActions) {
26171
26427
  dependencies
26172
26428
  );
26173
26429
  }
26430
+ function lastAssistantProse(messages) {
26431
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
26432
+ const message = messages[index];
26433
+ if (message?.role !== "assistant" || !Array.isArray(message.content)) continue;
26434
+ const texts = [];
26435
+ for (const part of message.content) {
26436
+ if (part.type === "text" && typeof part.text === "string" && part.text.length > 0) {
26437
+ texts.push(part.text);
26438
+ }
26439
+ }
26440
+ if (texts.length === 0) continue;
26441
+ return texts.join("");
26442
+ }
26443
+ return void 0;
26444
+ }
26174
26445
  function createRoleRuntimeExtension(dependencies) {
26175
26446
  return (envelopeHost) => {
26176
26447
  let projectClosedSubmission = async () => {
@@ -26229,10 +26500,6 @@ function createRoleRuntimeExtension(dependencies) {
26229
26500
  if (settlement === void 0 || attendance === void 0) return;
26230
26501
  const workContext = navigatorWorkContext;
26231
26502
  const pending = (async () => {
26232
- if (settlement.kind !== "accepted") {
26233
- await attendance.settle(settlement);
26234
- return;
26235
- }
26236
26503
  const settlePromise = attendance.settle(settlement);
26237
26504
  void settlePromise.catch(() => void 0);
26238
26505
  const raced = await raceNavigatorGrace(settlePromise, NAVIGATOR_POST_ROLE_GRACE_MS);
@@ -26433,10 +26700,8 @@ function createRoleRuntimeExtension(dependencies) {
26433
26700
  pendingSubmissionNonPassByToolCallId.delete(event.toolCallId);
26434
26701
  return { details: submissionNonPass, isError: true };
26435
26702
  }
26436
- if (event.isError) return;
26437
- return;
26438
26703
  });
26439
- roleHost.on("agent_end", (event, ctx) => {
26704
+ roleHost.on("agent_end", async (event, ctx) => {
26440
26705
  const lastMessage = event.messages.at(-1);
26441
26706
  if (lastMessage?.role === "assistant" && (lastMessage.stopReason === "error" || lastMessage.stopReason === "aborted")) {
26442
26707
  if (receiptDelivery.nextAction() !== "accepted") {
@@ -26444,6 +26709,47 @@ function createRoleRuntimeExtension(dependencies) {
26444
26709
  }
26445
26710
  return;
26446
26711
  }
26712
+ const role = selectedRole ?? roleHost.getFlag(ROLE_FLAG.name);
26713
+ if (role === "navigator" && receiptDelivery.nextAction() !== "accepted") {
26714
+ const prose = lastAssistantProse(event.messages);
26715
+ if (prose !== void 0 && prose.trim() !== "") {
26716
+ const accepted = { prose };
26717
+ await sealAcceptedSubmission({
26718
+ context: ctx,
26719
+ role: "navigator",
26720
+ accepted,
26721
+ toolCallId: `navigator-prose-exit:${randomUUID8()}`
26722
+ });
26723
+ await projectClosedSubmission(
26724
+ { role: "navigator", kind: "accepted", accepted },
26725
+ ctx
26726
+ );
26727
+ return;
26728
+ }
26729
+ if (!noReceiptRecorded) {
26730
+ const runPointer = runDirectoryFromHostContext(ctx);
26731
+ if (runPointer !== void 0) {
26732
+ noReceiptRecorded = true;
26733
+ while (receiptDelivery.nextAction() === "request-delivery") {
26734
+ receiptDelivery.recordDeliveryRequest();
26735
+ }
26736
+ const facts = receiptDelivery.facts({ runPointer, attemptPointer: `current:${runPointer}` });
26737
+ envelopeHost.appendEntry(NO_RECEIPT_LIFECYCLE_ENTRY_TYPE, facts);
26738
+ try {
26739
+ sitianReport({
26740
+ level: "event",
26741
+ kind: "no-receipt-lifecycle",
26742
+ cwd: ctx.cwd,
26743
+ sessionParent: ctx.sessionManager.getSessionFile(),
26744
+ payload: facts,
26745
+ source: "role-runtime"
26746
+ });
26747
+ } catch {
26748
+ }
26749
+ }
26750
+ }
26751
+ return;
26752
+ }
26447
26753
  if (receiptDelivery.nextAction() === "request-delivery") {
26448
26754
  receiptDelivery.recordDeliveryRequest();
26449
26755
  envelopeHost.appendEntry("ak-receipt-delivery-request");
@@ -27109,8 +27415,8 @@ function createRoleRuntimeDependencies(packageRoot) {
27109
27415
 
27110
27416
  // src/role-envelope.ts
27111
27417
  init_engine_detour();
27112
- import { randomUUID as randomUUID8 } from "node:crypto";
27113
- import { mkdir as mkdir7, writeFile as writeFile12 } from "node:fs/promises";
27418
+ import { randomUUID as randomUUID9 } from "node:crypto";
27419
+ import { appendFile as appendFile3, mkdir as mkdir7, writeFile as writeFile12 } from "node:fs/promises";
27114
27420
  import { createServer } from "node:net";
27115
27421
  import { dirname as dirname24, join as join42 } from "node:path";
27116
27422
  import { fileURLToPath as fileURLToPath2 } from "node:url";
@@ -27199,14 +27505,14 @@ async function requireGatekeeperPass(options) {
27199
27505
 
27200
27506
  // src/host-native-method.ts
27201
27507
  import { lstat as lstat7, mkdir as mkdir6, readlink, realpath as realpath8, symlink } from "node:fs/promises";
27202
- import { basename as basename9, dirname as dirname23, join as join41 } from "node:path";
27508
+ import { basename as basename10, dirname as dirname23, join as join41 } from "node:path";
27203
27509
  var HOST_METHOD_PLUGIN_NAME = "ak-methods";
27204
27510
  var packagedMethodsDir = (root) => join41(root, "resources", "methods");
27205
27511
  var packagedMethodPluginDir = (root) => join41(root, "dist", "method-host-plugin");
27206
27512
  function hostMethodSkills(methods) {
27207
27513
  return Object.freeze(methods.flatMap((method) => {
27208
27514
  if (method.kind !== "skill") return [];
27209
- const name = basename9(dirname23(method.path));
27515
+ const name = basename10(dirname23(method.path));
27210
27516
  return name ? [Object.freeze({ name })] : [];
27211
27517
  }));
27212
27518
  }
@@ -27297,7 +27603,7 @@ async function prepareRoleEnvelope(options) {
27297
27603
  let rejection;
27298
27604
  let infrastructureRoundFailure;
27299
27605
  const hostAbort = new AbortController();
27300
- const runId = request.runDirectory.split("/").filter(Boolean).at(-1) ?? randomUUID8();
27606
+ const runId = request.runDirectory.split("/").filter(Boolean).at(-1) ?? randomUUID9();
27301
27607
  await mkdir7(request.runDirectory, { recursive: true });
27302
27608
  let sessionFile = options.sessionFile ?? join42(request.runDirectory, "session", "session.jsonl");
27303
27609
  await mkdir7(dirname24(sessionFile), { recursive: true });
@@ -27319,6 +27625,25 @@ async function prepareRoleEnvelope(options) {
27319
27625
  if (error.code !== "EEXIST") throw error;
27320
27626
  }
27321
27627
  }
27628
+ let durableWriteChain = Promise.resolve();
27629
+ let armDurableWriteFailure;
27630
+ const persistPackageSessionEntry = (entry) => {
27631
+ const customType = typeof entry.customType === "string" ? entry.customType : "unknown";
27632
+ const line2 = `${JSON.stringify({
27633
+ ...entry,
27634
+ id: typeof entry.id === "string" ? entry.id : randomUUID9(),
27635
+ timestamp: typeof entry.timestamp === "string" ? entry.timestamp : (/* @__PURE__ */ new Date()).toISOString()
27636
+ })}
27637
+ `;
27638
+ durableWriteChain = durableWriteChain.then(async () => {
27639
+ try {
27640
+ await appendFile3(sessionFile, line2, "utf8");
27641
+ } catch (error) {
27642
+ const diagnostic = error instanceof Error ? error.message : String(error);
27643
+ armDurableWriteFailure?.(customType, diagnostic);
27644
+ }
27645
+ });
27646
+ };
27322
27647
  const context = {
27323
27648
  cwd: request.cwd,
27324
27649
  mode: "print",
@@ -27341,6 +27666,7 @@ async function prepareRoleEnvelope(options) {
27341
27666
  const entry = { type: "custom", customType, data };
27342
27667
  sessionEntries.push(entry);
27343
27668
  customEntries.push({ customType, data });
27669
+ persistPackageSessionEntry(entry);
27344
27670
  }
27345
27671
  },
27346
27672
  abort() {
@@ -27354,6 +27680,7 @@ async function prepareRoleEnvelope(options) {
27354
27680
  const entry = { type: "custom_message", customType, ...payload, message: payload };
27355
27681
  sessionEntries.push(entry);
27356
27682
  customEntries.push({ customType, data: message.details ?? message.content });
27683
+ persistPackageSessionEntry(entry);
27357
27684
  };
27358
27685
  const emit = async (event, value) => {
27359
27686
  const results = [];
@@ -27433,7 +27760,7 @@ async function prepareRoleEnvelope(options) {
27433
27760
  }
27434
27761
  };
27435
27762
  createRoleRuntimeExtension(options.dependencies)(envelope);
27436
- const token = randomUUID8();
27763
+ const token = randomUUID9();
27437
27764
  const server = createServer((socket) => serveSocket(socket));
27438
27765
  function rememberProjectedRejection(details, toolCallId, content) {
27439
27766
  if (typeof details !== "object" || details === null) return;
@@ -27469,6 +27796,17 @@ async function prepareRoleEnvelope(options) {
27469
27796
  };
27470
27797
  hostAbort.abort();
27471
27798
  }
27799
+ armDurableWriteFailure = (customType, diagnostic) => {
27800
+ rememberInfrastructureFailure(
27801
+ {
27802
+ cause: "infrastructure",
27803
+ kind: "role_infrastructure_failure",
27804
+ code: "durable-session-write-failed",
27805
+ customType
27806
+ },
27807
+ [{ type: "text", text: `ak-role: durable session entry flush failed (${customType}): ${diagnostic}` }]
27808
+ );
27809
+ };
27472
27810
  function declareRoundInfrastructureFailure(error) {
27473
27811
  const diagnostic = error instanceof Error ? error.message : String(error);
27474
27812
  const content = [{ type: "text", text: diagnostic }];
@@ -27514,7 +27852,7 @@ async function prepareRoleEnvelope(options) {
27514
27852
  async function invokeAkTool(name, args) {
27515
27853
  const tool = tools.get(name);
27516
27854
  if (tool === void 0) throw new Error(`Unknown AK tool: ${name}`);
27517
- const toolCallId = randomUUID8();
27855
+ const toolCallId = randomUUID9();
27518
27856
  calls.push({ toolCallId, toolName: name });
27519
27857
  sessionEntries.push({
27520
27858
  type: "message",
@@ -27630,6 +27968,15 @@ async function prepareRoleEnvelope(options) {
27630
27968
  const relay = fileURLToPath2(new URL("./mcp-relay.mjs", import.meta.url));
27631
27969
  await listen(server, options.socketPath);
27632
27970
  let disposed = false;
27971
+ let durableFailureHandedToCloseRound = false;
27972
+ const settleDurableWrites = async () => {
27973
+ await durableWriteChain;
27974
+ if (infrastructureRoundFailure !== void 0) {
27975
+ durableFailureHandedToCloseRound = true;
27976
+ return { accepted: false, failure: infrastructureRoundFailure };
27977
+ }
27978
+ return void 0;
27979
+ };
27633
27980
  const dispose = async () => {
27634
27981
  if (disposed) return;
27635
27982
  disposed = true;
@@ -27639,6 +27986,20 @@ async function prepareRoleEnvelope(options) {
27639
27986
  } catch (error) {
27640
27987
  cleanupFailures.push(error);
27641
27988
  }
27989
+ try {
27990
+ const alreadyHanded = durableFailureHandedToCloseRound;
27991
+ const durableFailure = await settleDurableWrites();
27992
+ if (durableFailure !== void 0 && !alreadyHanded) {
27993
+ cleanupFailures.push(
27994
+ Object.assign(
27995
+ new Error(durableFailure.failure.diagnostic ?? "durable session entry flush failed"),
27996
+ { code: durableFailure.failure.identity?.code ?? "durable-session-write-failed" }
27997
+ )
27998
+ );
27999
+ }
28000
+ } catch (error) {
28001
+ cleanupFailures.push(error);
28002
+ }
27642
28003
  try {
27643
28004
  const closeAll = server.closeAllConnections;
27644
28005
  if (typeof closeAll === "function") closeAll.call(server);
@@ -27660,6 +28021,7 @@ async function prepareRoleEnvelope(options) {
27660
28021
  if (calls.some((call) => call.toolName === terminatingToolName)) return;
27661
28022
  await invokeAkTool(terminatingToolName, params ?? {});
27662
28023
  }
28024
+ ;
27663
28025
  const closeRound = async () => {
27664
28026
  if (calls.length > 0) {
27665
28027
  const roundCalls = [...calls];
@@ -27667,6 +28029,7 @@ async function prepareRoleEnvelope(options) {
27667
28029
  await emit("turn_end", { turnIndex: 0, calls: roundCalls });
27668
28030
  }
27669
28031
  if (infrastructureRoundFailure !== void 0) {
28032
+ durableFailureHandedToCloseRound = true;
27670
28033
  return { accepted: false, failure: infrastructureRoundFailure };
27671
28034
  }
27672
28035
  let closure;
@@ -27678,6 +28041,8 @@ async function prepareRoleEnvelope(options) {
27678
28041
  }
27679
28042
  if (closure !== void 0) {
27680
28043
  await emit("agent_settled", {});
28044
+ const durableFailure2 = await settleDurableWrites();
28045
+ if (durableFailure2 !== void 0) return durableFailure2;
27681
28046
  return { accepted: true };
27682
28047
  }
27683
28048
  if (rejection !== void 0) {
@@ -27687,9 +28052,13 @@ async function prepareRoleEnvelope(options) {
27687
28052
  message: rejection.message
27688
28053
  };
27689
28054
  rejection = void 0;
28055
+ const durableFailure2 = await settleDurableWrites();
28056
+ if (durableFailure2 !== void 0) return durableFailure2;
27690
28057
  return { accepted: false, retry };
27691
28058
  }
27692
28059
  await emit("agent_settled", {});
28060
+ const durableFailure = await settleDurableWrites();
28061
+ if (durableFailure !== void 0) return durableFailure;
27693
28062
  return { accepted: true };
27694
28063
  };
27695
28064
  try {
@@ -27790,10 +28159,11 @@ function headlessTurnArgs(options) {
27790
28159
  description.promptFlag,
27791
28160
  ...description.fixedArgs,
27792
28161
  description.systemPromptFlag,
27793
- options.systemPromptPath,
27794
- description.jsonSchemaFlag,
27795
- JSON.stringify(options.jsonSchema)
28162
+ options.systemPromptPath
27796
28163
  ];
28164
+ if (options.jsonSchema !== void 0) {
28165
+ args.push(description.jsonSchemaFlag, JSON.stringify(options.jsonSchema));
28166
+ }
27797
28167
  if (options.pluginDir) args.push("--plugin-dir", options.pluginDir);
27798
28168
  if (options.mcpConfigPath !== void 0 && options.mcpConfigPath !== "") {
27799
28169
  args.push(description.mcpConfigFlag, options.mcpConfigPath);
@@ -28004,7 +28374,9 @@ function codexTurnArgs(options) {
28004
28374
  }
28005
28375
  }
28006
28376
  args.push("-c", `model_instructions_file=${codexTomlString(options.systemPromptPath)}`);
28007
- args.push("--output-schema", options.outputSchemaPath);
28377
+ if (options.outputSchemaPath !== void 0) {
28378
+ args.push("--output-schema", options.outputSchemaPath);
28379
+ }
28008
28380
  args.push(...codexMcpConfigArgs(options.mcpServers));
28009
28381
  if (options.model !== void 0 && options.model !== "") {
28010
28382
  args.push("-m", options.model);
@@ -28035,7 +28407,7 @@ function headlessMcpConfigDocument(mcpServers) {
28035
28407
 
28036
28408
  // src/headless-host/role-turn-host.ts
28037
28409
  import { spawn as spawn4, spawnSync } from "node:child_process";
28038
- import { randomUUID as randomUUID9 } from "node:crypto";
28410
+ import { randomUUID as randomUUID10 } from "node:crypto";
28039
28411
  import { existsSync as existsSync13 } from "node:fs";
28040
28412
  import { writeFile as writeFile13 } from "node:fs/promises";
28041
28413
  import { dirname as dirname25, isAbsolute as isAbsolute11, join as join44, resolve as resolve21 } from "node:path";
@@ -28157,6 +28529,7 @@ function reportHostSessionEvent(input) {
28157
28529
  }
28158
28530
 
28159
28531
  // src/headless-host/role-turn-host.ts
28532
+ init_navigator_output();
28160
28533
  function failure(cause, name, code, details, diagnostic) {
28161
28534
  return {
28162
28535
  code: null,
@@ -28425,10 +28798,9 @@ function buildTurnArgs(options) {
28425
28798
  if (options.sessionKind === "resume" && !options.sessionId) {
28426
28799
  throw new Error("codex resume requires a bound thread_id");
28427
28800
  }
28428
- if (options.outputSchemaPath === void 0) throw new Error("codex requires an output schema path");
28429
28801
  return codexTurnArgs({
28430
28802
  systemPromptPath: options.systemPromptPath,
28431
- outputSchemaPath: options.outputSchemaPath,
28803
+ ...options.outputSchemaPath === void 0 ? {} : { outputSchemaPath: options.outputSchemaPath },
28432
28804
  mcpServers: options.mcpServers,
28433
28805
  ...options.model === void 0 ? {} : { model: options.model },
28434
28806
  ...options.effort === void 0 ? {} : { effort: options.effort },
@@ -28443,7 +28815,8 @@ function buildTurnArgs(options) {
28443
28815
  return headlessTurnArgs({
28444
28816
  description: options.description,
28445
28817
  systemPromptPath: options.systemPromptPath,
28446
- jsonSchema: options.jsonSchema,
28818
+ // #959: navigator omits --json-schema so free-form prose is a lawful exit.
28819
+ ...options.jsonSchema === void 0 ? {} : { jsonSchema: options.jsonSchema },
28447
28820
  mcpConfigPath: options.mcpConfigPath,
28448
28821
  ...options.model === void 0 ? {} : { model: options.model },
28449
28822
  ...options.effort === void 0 ? {} : { effort: options.effort },
@@ -28461,7 +28834,7 @@ function createHeadlessRoleTurnHost(config) {
28461
28834
  let sessionId = await config.sessionIdentity.load(request.principal);
28462
28835
  let sessionKind = request.continuation.kind === "resume" && sessionId !== void 0 && sessionId !== "" ? "resume" : "new";
28463
28836
  if (sessionKind === "new" && !codex) {
28464
- sessionId = randomUUID9();
28837
+ sessionId = randomUUID10();
28465
28838
  await config.sessionIdentity.bind(request.principal, sessionId);
28466
28839
  }
28467
28840
  const env = { ...process.env, ...config.env ?? {} };
@@ -28472,13 +28845,15 @@ function createHeadlessRoleTurnHost(config) {
28472
28845
  let pluginDir;
28473
28846
  let applyMethodPrompt = codex ? (prompt) => applyCodexSkillInvocation(request.methods, prompt) : (prompt) => prompt;
28474
28847
  if (codex) {
28475
- outputSchemaPath = join44(request.runDirectory, "headless-output-schema.json");
28476
- await writeFile13(
28477
- outputSchemaPath,
28478
- `${JSON.stringify(closeJsonSchemaForCodex(prepared.jsonSchema), null, 2)}
28848
+ if (prepared.terminatingToolName !== NAVIGATOR_OUTPUT_TOOL_NAME) {
28849
+ outputSchemaPath = join44(request.runDirectory, "headless-output-schema.json");
28850
+ await writeFile13(
28851
+ outputSchemaPath,
28852
+ `${JSON.stringify(closeJsonSchemaForCodex(prepared.jsonSchema), null, 2)}
28479
28853
  `,
28480
- "utf8"
28481
- );
28854
+ "utf8"
28855
+ );
28856
+ }
28482
28857
  } else {
28483
28858
  mcpConfigPath = join44(request.runDirectory, "headless-mcp-config.json");
28484
28859
  await writeFile13(
@@ -28510,7 +28885,8 @@ function createHeadlessRoleTurnHost(config) {
28510
28885
  args = buildTurnArgs({
28511
28886
  description: config.description,
28512
28887
  systemPromptPath,
28513
- jsonSchema: prepared.jsonSchema,
28888
+ // #959: navigator prose exit — no closed JSON schema on claude either.
28889
+ ...prepared.terminatingToolName === NAVIGATOR_OUTPUT_TOOL_NAME ? {} : { jsonSchema: prepared.jsonSchema },
28514
28890
  mcpServers: prepared.mcpServers,
28515
28891
  ...mcpConfigPath === void 0 ? {} : { mcpConfigPath },
28516
28892
  ...outputSchemaPath === void 0 ? {} : { outputSchemaPath },
@@ -28634,6 +29010,18 @@ function createHeadlessRoleTurnHost(config) {
28634
29010
  details: { sessionId, exitCode: spawned.code }
28635
29011
  });
28636
29012
  }
29013
+ if (prepared.terminatingToolName === NAVIGATOR_OUTPUT_TOOL_NAME) {
29014
+ if (observation.finalMessage.trim() === "") {
29015
+ return terminalFromSpawned(spawned, {
29016
+ cause: "output",
29017
+ identity: { name: "HeadlessEmptyOutput", code: "empty-stdout" },
29018
+ diagnostic: spawned.stderr.trim() || "codex exec produced empty agent_message",
29019
+ details: { sessionId, exitCode: spawned.code }
29020
+ });
29021
+ }
29022
+ await prepared.ingestStructuredOutput({ prose: observation.finalMessage });
29023
+ return { status: "delivered", stderr: spawned.stderr };
29024
+ }
28637
29025
  let receipt;
28638
29026
  try {
28639
29027
  receipt = JSON.parse(observation.finalMessage);
@@ -28678,6 +29066,8 @@ function createHeadlessRoleTurnHost(config) {
28678
29066
  }
28679
29067
  if (envelope.structured_output !== void 0) {
28680
29068
  await prepared.ingestStructuredOutput(envelope.structured_output);
29069
+ } else if (prepared.terminatingToolName === NAVIGATOR_OUTPUT_TOOL_NAME && typeof envelope.result === "string" && envelope.result.trim() !== "") {
29070
+ await prepared.ingestStructuredOutput({ prose: envelope.result });
28681
29071
  }
28682
29072
  return { status: "delivered", stderr: spawned.stderr };
28683
29073
  }
@@ -28716,7 +29106,7 @@ function createProductionHeadlessRoleTurnHost(options) {
28716
29106
  sessionFile: sessionIdentity.resolveSessionFile(request.principal),
28717
29107
  // Same MCP relay as ACP so intermediate AK tools stay reachable;
28718
29108
  // headless adapter projects the row into --mcp-config.
28719
- socketPath: `/tmp/ak-headless-mcp-${randomUUID10()}.sock`,
29109
+ socketPath: `/tmp/ak-headless-mcp-${randomUUID11()}.sock`,
28720
29110
  // Schema channel owns the terminating receipt; hide it from MCP list.
28721
29111
  listTerminatingToolOnMcp: false
28722
29112
  })