@akagilnc/pi-workflow-roles 0.1.5245 → 0.1.5270

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 (34) hide show
  1. package/dist/acp-host/production-host.js +125 -217
  2. package/dist/headless-host/production-host.js +381 -470
  3. package/dist/host-descriptions.js +0 -2
  4. package/dist/navigator-invocation-identity.js +0 -57
  5. package/dist/navigator-public-session.js +6 -1
  6. package/dist/pi/durable-principal.js +1 -12
  7. package/dist/public-cli/auto-resume.js +59 -87
  8. package/dist/public-cli/instruction-seat-run.js +3 -3
  9. package/dist/public-cli/main.js +86 -206
  10. package/dist/public-cli/post-admission.js +7 -15
  11. package/dist/public-cli/run-lifecycle.js +5 -15
  12. package/dist/public-cli/settlement.js +10 -59
  13. package/dist/public-cli/terminal.js +4 -2
  14. package/dist/session-identity.js +0 -18
  15. package/package.json +1 -1
  16. package/src/acp-host/description.ts +0 -2
  17. package/src/acp-host/production-host.ts +0 -1
  18. package/src/acp-host/role-turn-host.ts +12 -6
  19. package/src/headless-host/role-turn-host.ts +11 -3
  20. package/src/host-contracts.ts +0 -1
  21. package/src/host-descriptions.ts +0 -2
  22. package/src/navigator-invocation-identity.ts +4 -121
  23. package/src/navigator-public-session.ts +12 -1
  24. package/src/pi/durable-principal.ts +1 -11
  25. package/src/prepared-role-turn.ts +1 -1
  26. package/src/public-cli/auto-resume.ts +67 -109
  27. package/src/public-cli/instruction-seat-run.ts +3 -3
  28. package/src/public-cli/post-admission.ts +7 -21
  29. package/src/public-cli/run-lifecycle.ts +3 -21
  30. package/src/public-cli/settlement.ts +8 -75
  31. package/src/public-cli/terminal.ts +4 -2
  32. package/src/role-envelope.ts +3 -3
  33. package/src/role-runtime.ts +23 -5
  34. package/src/session-identity.ts +0 -22
@@ -2839,7 +2839,6 @@ var init_host_descriptions = __esm({
2839
2839
  modelFlag: "--model"
2840
2840
  }),
2841
2841
  modelPassing: "argv",
2842
- boundResume: "session/load",
2843
2842
  sessionBindingFile: "grok-acp-session.json"
2844
2843
  }),
2845
2844
  /**
@@ -2857,7 +2856,6 @@ var init_host_descriptions = __esm({
2857
2856
  thinkingFlag: "--reasoning"
2858
2857
  }),
2859
2858
  modelPassing: "set_model",
2860
- boundResume: "session/load",
2861
2859
  sessionBindingFile: "hermes-acp-session.json",
2862
2860
  seatProfileSoul: Object.freeze({
2863
2861
  flag: "-p",
@@ -3764,7 +3762,6 @@ __export(durable_principal_exports, {
3764
3762
  issuePiDurablePrincipalCoordinates: () => issuePiDurablePrincipalCoordinates,
3765
3763
  piDurablePrincipalAuthority: () => piDurablePrincipalAuthority
3766
3764
  });
3767
- import { lstat } from "node:fs/promises";
3768
3765
  import { join as join9 } from "node:path";
3769
3766
  function encode(coordinates) {
3770
3767
  return coordinates;
@@ -3817,15 +3814,6 @@ var init_durable_principal = __esm({
3817
3814
  sessionDirectory: record4.sessionDirectory,
3818
3815
  sessionFile: typeof record4.sessionFile === "string" && record4.sessionFile.trim() !== "" ? record4.sessionFile : join9(record4.sessionDirectory, "session.jsonl")
3819
3816
  };
3820
- },
3821
- async isAvailable(principal) {
3822
- const { sessionFile } = this.decode(principal);
3823
- try {
3824
- const stat2 = await lstat(sessionFile);
3825
- return stat2.isFile() && !stat2.isSymbolicLink();
3826
- } catch {
3827
- return false;
3828
- }
3829
3817
  }
3830
3818
  };
3831
3819
  }
@@ -4427,8 +4415,8 @@ function formatTerminalResult(result) {
4427
4415
  `diagnostic ${encodeTerminalField(result.roleOutcome.diagnostic)}`
4428
4416
  );
4429
4417
  }
4430
- if (result.roleOutcome.kind === "failure" || result.roleOutcome.kind === "no_receipt" || result.roleOutcome.kind === "audit_escalation") {
4431
- const facts = result.roleOutcome.decisiveFacts ?? {};
4418
+ if (result.roleOutcome.kind === "failure" || result.roleOutcome.kind === "no_receipt" || result.roleOutcome.kind === "audit_escalation" || result.roleOutcome.decisiveFacts?.failedAttempts !== void 0) {
4419
+ const facts = result.roleOutcome.kind === "accepted" ? { failedAttempts: result.roleOutcome.decisiveFacts?.failedAttempts } : result.roleOutcome.decisiveFacts ?? {};
4432
4420
  for (const [key, value] of Object.entries(facts)) {
4433
4421
  if (value === void 0) continue;
4434
4422
  const rendered = typeof value === "string" ? value : JSON.stringify(value);
@@ -5841,7 +5829,7 @@ var init_ticket_provenance = __esm({
5841
5829
 
5842
5830
  // src/notary-source-run.ts
5843
5831
  import { dirname as dirname12, isAbsolute as isAbsolute5, join as join17, resolve as resolve10, basename as basename6 } from "node:path";
5844
- import { lstat as lstat2, realpath as realpath3 } from "node:fs/promises";
5832
+ import { lstat, realpath as realpath3 } from "node:fs/promises";
5845
5833
  async function readRetainedIdentity(runDirectory) {
5846
5834
  try {
5847
5835
  return await readRoleRunIdentity(runDirectory);
@@ -5869,7 +5857,7 @@ async function requireRunDirectory(candidate, display) {
5869
5857
  }
5870
5858
  let stat2;
5871
5859
  try {
5872
- stat2 = await lstat2(real);
5860
+ stat2 = await lstat(real);
5873
5861
  } catch (error) {
5874
5862
  throw new NotarySourceRunError(
5875
5863
  `notary --source-run is not a readable run directory: ${display}`,
@@ -7033,7 +7021,7 @@ var init_option_definitions = __esm({
7033
7021
  import { execFileSync as execFileSync2 } from "node:child_process";
7034
7022
  import { existsSync as existsSync4 } from "node:fs";
7035
7023
  import {
7036
- lstat as lstat3,
7024
+ lstat as lstat2,
7037
7025
  mkdtemp as mkdtemp2,
7038
7026
  readFile as readFile13,
7039
7027
  realpath as realpath4,
@@ -7595,7 +7583,7 @@ async function readRegularFileAttachment(sourcePath) {
7595
7583
  const absolute = isAbsolute6(sourcePath) ? sourcePath : resolve11(sourcePath);
7596
7584
  let st;
7597
7585
  try {
7598
- st = await lstat3(absolute);
7586
+ st = await lstat2(absolute);
7599
7587
  } catch (error) {
7600
7588
  throw new CliUsageError(
7601
7589
  `attachment is not a readable regular file: ${sourcePath}`,
@@ -11314,11 +11302,6 @@ async function appendRunAttemptHistory(source, outcome) {
11314
11302
  } catch {
11315
11303
  }
11316
11304
  }
11317
- function navigatorAttendanceCorrelatedWithBoundMarker(details, attendanceIndex, terminalIndex, marker) {
11318
- if (attendanceIndex <= terminalIndex) return false;
11319
- if (details.invocationId !== marker.invocationId) return false;
11320
- return true;
11321
- }
11322
11305
  function parseNavigatorAttendanceDetails(details) {
11323
11306
  const disposition = details.disposition;
11324
11307
  const advisoryDiagnostic = typeof details.routePlaybookReadFailure === "string" ? { advisoryDiagnostic: details.routePlaybookReadFailure } : {};
@@ -11469,54 +11452,12 @@ function extractNavigatorAttendanceFact(entries) {
11469
11452
  reason: "Navigator attendance has no durable packaged role terminal"
11470
11453
  };
11471
11454
  }
11472
- let markerIndex = -1;
11473
- for (let i = terminal.index - 1; i >= 0; i -= 1) {
11474
- const entry = entries[i];
11475
- if (entry?.type === "custom" && entry.customType === NAVIGATOR_INVOCATION_ENTRY) {
11476
- markerIndex = i;
11477
- break;
11478
- }
11479
- }
11480
- if (markerIndex < 0) {
11481
- return {
11482
- disposition: "unavailable",
11483
- source: "unknown",
11484
- reason: "Navigator attendance is uncorrelated with session invocation facts"
11485
- };
11486
- }
11487
- const marker = parseInvocationMarkerIdentity(entries[markerIndex]?.data);
11488
- if (marker === void 0) {
11489
- return {
11490
- disposition: "unavailable",
11491
- source: "unknown",
11492
- reason: "Navigator attendance is uncorrelated with session invocation facts"
11493
- };
11494
- }
11495
- for (let i = entries.length - 1; i >= 0; i -= 1) {
11455
+ for (let i = terminal.index; i < entries.length; i += 1) {
11496
11456
  const entry = entries[i];
11497
- if (entry?.type === "custom_message" && entry.customType === "ak-navigator-attendance") {
11498
- const details = entry.message?.details ?? entry.details;
11499
- if (!isRecord10(details)) {
11500
- return {
11501
- disposition: "unavailable",
11502
- source: "unknown",
11503
- reason: "Navigator attendance is unparseable"
11504
- };
11505
- }
11506
- if (!navigatorAttendanceCorrelatedWithBoundMarker(
11507
- details,
11508
- i,
11509
- terminal.index,
11510
- marker
11511
- )) {
11512
- return {
11513
- disposition: "unavailable",
11514
- source: "unknown",
11515
- reason: "Navigator attendance is uncorrelated with session invocation facts"
11516
- };
11517
- }
11518
- return parseNavigatorAttendanceDetails(details);
11519
- }
11457
+ if (entry?.type !== "custom" || entry.customType !== "ak-role-submission-closure") continue;
11458
+ const details = isRecord10(entry.data) ? entry.data.navigator : void 0;
11459
+ if (!isRecord10(details)) break;
11460
+ return parseNavigatorAttendanceDetails(details);
11520
11461
  }
11521
11462
  return {
11522
11463
  disposition: "unavailable",
@@ -12625,12 +12566,6 @@ function createSessionIdentityAuthority(authority, sessionBindingFile) {
12625
12566
  }
12626
12567
  };
12627
12568
  }
12628
- function resolveHostAwareSessionAvailability(host, principalAuthority) {
12629
- if (host === void 0 || host === DEFAULT_ROLE_TURN_HOST) {
12630
- return (principal) => principalAuthority.isAvailable(principal);
12631
- }
12632
- return async (principal) => await readStoredHostSessionId(host, principalAuthority, principal) !== void 0;
12633
- }
12634
12569
  async function readStoredHostSessionId(host, authority, principal) {
12635
12570
  if (host === void 0 || host === DEFAULT_ROLE_TURN_HOST) return void 0;
12636
12571
  const description = lookupHostDescription(host) ?? lookupHeadlessHostDescription(host);
@@ -12930,9 +12865,9 @@ var init_host_session_record = __esm({
12930
12865
  // src/public-cli/auto-resume.ts
12931
12866
  import { constants as fsConstants2 } from "node:fs";
12932
12867
  import { randomUUID as randomUUID6 } from "node:crypto";
12933
- import { lstat as lstat5, mkdir as mkdir3, open } from "node:fs/promises";
12868
+ import { lstat as lstat4, mkdir as mkdir3, open } from "node:fs/promises";
12934
12869
  import { join as join31 } from "node:path";
12935
- async function persistReturnedRunState(admitted, authority, options) {
12870
+ async function persistReturnedRunState(admitted, options) {
12936
12871
  if (options?.lawful === true) {
12937
12872
  await markRunTerminal(admitted.runDirectory);
12938
12873
  return;
@@ -12942,10 +12877,8 @@ async function persistReturnedRunState(admitted, authority, options) {
12942
12877
  });
12943
12878
  const typedHttp429 = resumeObservation.typedHttp429;
12944
12879
  if (admitted.principal !== void 0 && typedHttp429 !== void 0) {
12945
- if (await authority.isAvailable(admitted.principal)) {
12946
- await markRunResumable(admitted.runDirectory, typedHttp429);
12947
- return;
12948
- }
12880
+ await markRunResumable(admitted.runDirectory, typedHttp429);
12881
+ return;
12949
12882
  }
12950
12883
  await markRunTerminal(admitted.runDirectory);
12951
12884
  }
@@ -12967,20 +12900,20 @@ async function finalizeExceptionRunBestEffort(runDirectory, io) {
12967
12900
  }
12968
12901
  }
12969
12902
  async function ensureRealArtifactsDirectory(runDirectory) {
12970
- const runStat = await lstat5(runDirectory);
12903
+ const runStat = await lstat4(runDirectory);
12971
12904
  if (runStat.isSymbolicLink() || !runStat.isDirectory()) {
12972
12905
  throw new Error("run artifact retention: run directory is not a real directory");
12973
12906
  }
12974
12907
  const artifactsDir = roleRunArtifactsDirectory(runDirectory);
12975
12908
  try {
12976
- const existing = await lstat5(artifactsDir);
12909
+ const existing = await lstat4(artifactsDir);
12977
12910
  if (existing.isSymbolicLink() || !existing.isDirectory()) {
12978
12911
  throw new Error("run artifact retention: artifacts path is not a real directory");
12979
12912
  }
12980
12913
  } catch (error) {
12981
12914
  if (!isMissingPathError5(error)) throw error;
12982
12915
  await mkdir3(artifactsDir, { recursive: true });
12983
- const created = await lstat5(artifactsDir);
12916
+ const created = await lstat4(artifactsDir);
12984
12917
  if (created.isSymbolicLink() || !created.isDirectory()) {
12985
12918
  throw new Error("run artifact retention: artifacts directory is not a real directory");
12986
12919
  }
@@ -13111,7 +13044,6 @@ function dispatchExceptionFailureTerminal(input) {
13111
13044
  async function runWithAutoResumeLoop(options) {
13112
13045
  const limit = options.autoResumeLimit ?? AUTO_RESUME_LIMIT;
13113
13046
  parseAutoResumeLimit(limit);
13114
- const isPrincipalAvailable = options.isPrincipalAvailable ?? ((principal) => options.principalAuthority.isAvailable(principal));
13115
13047
  let autoResumeAttempts = 0;
13116
13048
  let isFirst = true;
13117
13049
  let currentPayload = options.buildInitialPayload();
@@ -13119,6 +13051,9 @@ async function runWithAutoResumeLoop(options) {
13119
13051
  let lastThrownError;
13120
13052
  let everyAttemptThrew = true;
13121
13053
  const retainedErrorFiles = [];
13054
+ const failedAttempts = [];
13055
+ let stoppedResult;
13056
+ let endReason;
13122
13057
  while (true) {
13123
13058
  let result;
13124
13059
  let turnStartedBeforeThrow = false;
@@ -13127,6 +13062,11 @@ async function runWithAutoResumeLoop(options) {
13127
13062
  result = await options.dispatch(currentPayload, lease, isFirst, dummyIo);
13128
13063
  } catch (error) {
13129
13064
  lastThrownError = error;
13065
+ const failedAttempt = {
13066
+ attempt: dispatchOrdinal,
13067
+ diagnostic: describeErrorIdentity(unwrapTurnDispatchedFailure(error))
13068
+ };
13069
+ failedAttempts.push(failedAttempt);
13130
13070
  turnStartedBeforeThrow = error instanceof TurnDispatchedFailure;
13131
13071
  const attempt = dispatchOrdinal;
13132
13072
  try {
@@ -13138,6 +13078,7 @@ async function runWithAutoResumeLoop(options) {
13138
13078
  error
13139
13079
  );
13140
13080
  retainedErrorFiles.push(file);
13081
+ failedAttempt.errorFile = file;
13141
13082
  options.io.stderr(
13142
13083
  `dispatch attempt ${attempt} threw (${describeErrorIdentity(error)}); full error retained at ${file}
13143
13084
  `
@@ -13158,100 +13099,30 @@ async function runWithAutoResumeLoop(options) {
13158
13099
  dispatchOrdinal += 1;
13159
13100
  if (result !== void 0) {
13160
13101
  everyAttemptThrew = false;
13161
- const terminal = result.terminal;
13162
- if (terminal !== void 0) {
13163
- terminal.autoResumeCount = autoResumeAttempts;
13164
- }
13165
- const lawful = terminal !== void 0 && isLawfulTypedTerminalOutcome(terminal.roleOutcome);
13166
- if (lawful) {
13167
- if (terminal !== void 0) {
13168
- options.io.stdout(formatTerminalResult(terminal));
13102
+ const terminal2 = result.terminal;
13103
+ if (terminal2 !== void 0) {
13104
+ terminal2.autoResumeCount = autoResumeAttempts;
13105
+ if (terminal2.roleOutcome.kind === "failure") {
13106
+ failedAttempts.push({
13107
+ attempt: dispatchOrdinal - 1,
13108
+ diagnostic: terminal2.roleOutcome.diagnostic,
13109
+ decisiveFacts: terminal2.roleOutcome.decisiveFacts
13110
+ });
13169
13111
  }
13170
- return result;
13171
- }
13172
- if (result.skipAutoResume === true) {
13173
- if (terminal !== void 0) presentTerminal(terminal, options.io);
13174
- return result;
13175
13112
  }
13176
- if (processCancelSignalName(options.signal) !== void 0) {
13177
- if (terminal !== void 0) presentTerminal(terminal, options.io);
13178
- return result;
13179
- }
13180
- }
13181
- if (result !== void 0) {
13182
- const terminal = result.terminal;
13183
- if (autoResumeAttempts >= limit) {
13184
- if (terminal !== void 0) presentTerminal(terminal, options.io);
13185
- return result;
13186
- }
13187
- if (result.turnDispatched === true && !await isPrincipalAvailable(options.admitted.principal)) {
13188
- if (terminal !== void 0) presentTerminal(terminal, options.io);
13189
- return result;
13113
+ if (terminal2 !== void 0 && isLawfulTypedTerminalOutcome(terminal2.roleOutcome) || result.skipAutoResume === true || autoResumeAttempts >= limit || processCancelSignalName(options.signal) !== void 0) {
13114
+ stoppedResult = result;
13115
+ break;
13190
13116
  }
13191
13117
  } else {
13192
13118
  if (autoResumeAttempts >= limit) {
13193
- const terminal = await attachDispatchExceptionTerminal(
13194
- options.admitted,
13195
- dispatchExceptionFailureTerminal({
13196
- role: options.admitted.role,
13197
- runId: options.admitted.runId,
13198
- causeError: lastThrownError,
13199
- errorFiles: retainedErrorFiles,
13200
- autoResumeAttempts,
13201
- endReason: "auto-resume budget exhausted",
13202
- everyAttemptThrew
13203
- }),
13204
- options.io
13205
- );
13206
- await finalizeExceptionRunBestEffort(options.admitted.runDirectory, options.io);
13207
- presentTerminal(terminal, options.io);
13208
- return {
13209
- exitCode: 1,
13210
- terminal
13211
- };
13119
+ endReason = "auto-resume budget exhausted";
13120
+ break;
13212
13121
  }
13213
13122
  const cancelName = processCancelSignalName(options.signal);
13214
13123
  if (cancelName !== void 0) {
13215
- const terminal = await attachDispatchExceptionTerminal(
13216
- options.admitted,
13217
- dispatchExceptionFailureTerminal({
13218
- role: options.admitted.role,
13219
- runId: options.admitted.runId,
13220
- causeError: lastThrownError,
13221
- errorFiles: retainedErrorFiles,
13222
- autoResumeAttempts,
13223
- endReason: `ak-role terminated by ${cancelName}`,
13224
- everyAttemptThrew
13225
- }),
13226
- options.io
13227
- );
13228
- await finalizeExceptionRunBestEffort(options.admitted.runDirectory, options.io);
13229
- presentTerminal(terminal, options.io);
13230
- return {
13231
- exitCode: 1,
13232
- terminal
13233
- };
13234
- }
13235
- if (!await isPrincipalAvailable(options.admitted.principal)) {
13236
- const terminal = await attachDispatchExceptionTerminal(
13237
- options.admitted,
13238
- dispatchExceptionFailureTerminal({
13239
- role: options.admitted.role,
13240
- runId: options.admitted.runId,
13241
- causeError: lastThrownError,
13242
- errorFiles: retainedErrorFiles,
13243
- autoResumeAttempts,
13244
- endReason: "session principal unavailable before further resume",
13245
- everyAttemptThrew
13246
- }),
13247
- options.io
13248
- );
13249
- await finalizeExceptionRunBestEffort(options.admitted.runDirectory, options.io);
13250
- presentTerminal(terminal, options.io);
13251
- return {
13252
- exitCode: 1,
13253
- terminal
13254
- };
13124
+ endReason = `ak-role terminated by ${cancelName}`;
13125
+ break;
13255
13126
  }
13256
13127
  }
13257
13128
  autoResumeAttempts++;
@@ -13260,6 +13131,34 @@ async function runWithAutoResumeLoop(options) {
13260
13131
  isFirst = false;
13261
13132
  }
13262
13133
  }
13134
+ const terminal = stoppedResult === void 0 ? await attachDispatchExceptionTerminal(
13135
+ options.admitted,
13136
+ dispatchExceptionFailureTerminal({
13137
+ role: options.admitted.role,
13138
+ runId: options.admitted.runId,
13139
+ causeError: lastThrownError,
13140
+ errorFiles: retainedErrorFiles,
13141
+ autoResumeAttempts,
13142
+ endReason,
13143
+ everyAttemptThrew
13144
+ }),
13145
+ options.io
13146
+ ) : stoppedResult.terminal;
13147
+ if (stoppedResult === void 0) {
13148
+ await finalizeExceptionRunBestEffort(options.admitted.runDirectory, options.io);
13149
+ }
13150
+ const complete = terminal !== void 0 && failedAttempts.length > 0 ? { ...terminal, roleOutcome: {
13151
+ ...terminal.roleOutcome,
13152
+ decisiveFacts: { ...terminal.roleOutcome.decisiveFacts, failedAttempts }
13153
+ } } : terminal;
13154
+ if (complete !== void 0) {
13155
+ if (isLawfulTypedTerminalOutcome(complete.roleOutcome)) {
13156
+ options.io.stdout(formatTerminalResult(complete));
13157
+ } else {
13158
+ presentTerminal(complete, options.io);
13159
+ }
13160
+ }
13161
+ return stoppedResult === void 0 ? { exitCode: 1, terminal: complete } : { ...stoppedResult, ...complete === void 0 ? {} : { terminal: complete } };
13263
13162
  }
13264
13163
  var dummyIo, TurnDispatchedFailure, DISPATCH_ERROR_RETENTION_ENTRY_TYPE;
13265
13164
  var init_auto_resume = __esm({
@@ -13428,14 +13327,9 @@ async function presentControlledFailure2(admitted, failureInput, adapters, autho
13428
13327
  ...failureInput.knownDiagnostic === void 0 ? {} : { knownDiagnostic: failureInput.knownDiagnostic },
13429
13328
  ...session === void 0 ? {} : { session }
13430
13329
  });
13431
- let resumable = false;
13432
- const typedHttp429 = resumeObservation.typedHttp429;
13433
- if (admitted.principal !== void 0) {
13434
- const sessionPrincipalAvailable = await authority.isAvailable(admitted.principal);
13435
- resumable = sessionPrincipalAvailable && typedHttp429 !== void 0;
13436
- }
13330
+ const resumable = admitted.principal !== void 0 && resumeObservation.typedHttp429 !== void 0;
13437
13331
  if (persistRunState && !failureInput.skipRunStateWrite) {
13438
- await persistReturnedRunState(admitted, authority);
13332
+ await persistReturnedRunState(admitted);
13439
13333
  }
13440
13334
  let publishedErrorPath;
13441
13335
  let terminal;
@@ -13480,7 +13374,7 @@ async function settleDeferredPersist(admitted, authority, adapters, io, result)
13480
13374
  const { needsPersist: _needsPersist, ...settledResult } = result;
13481
13375
  const lawful = isLawfulTypedTerminalOutcome(result.terminal.roleOutcome);
13482
13376
  try {
13483
- await persistReturnedRunState(admitted, authority, lawful ? { lawful: true } : void 0);
13377
+ await persistReturnedRunState(admitted, lawful ? { lawful: true } : void 0);
13484
13378
  return settledResult;
13485
13379
  } catch (error) {
13486
13380
  const failed = await settleAfterTurnStarted(
@@ -13758,7 +13652,7 @@ async function dispatchPostAdmissionTurn(input) {
13758
13652
  }
13759
13653
  if (persistRunState) {
13760
13654
  try {
13761
- await persistReturnedRunState(admitted, env.principalAuthority, { lawful: true });
13655
+ await persistReturnedRunState(admitted, { lawful: true });
13762
13656
  } catch (error) {
13763
13657
  await recordBestEffortPostDispatchDiagnostic(
13764
13658
  admitted,
@@ -13843,7 +13737,7 @@ async function dispatchPostAdmissionTurn(input) {
13843
13737
  }
13844
13738
  if (persistRunState) {
13845
13739
  try {
13846
- await persistReturnedRunState(admitted, env.principalAuthority, { lawful: true });
13740
+ await persistReturnedRunState(admitted, { lawful: true });
13847
13741
  } catch (error) {
13848
13742
  await recordBestEffortPostDispatchDiagnostic(
13849
13743
  admitted,
@@ -14060,10 +13954,6 @@ async function runPostAdmissionSeatResume(input) {
14060
13954
  return await runWithAutoResumeLoop({
14061
13955
  admitted: loaded.admitted,
14062
13956
  principalAuthority: env.principalAuthority,
14063
- isPrincipalAvailable: resolveHostAwareSessionAvailability(
14064
- env.host,
14065
- env.principalAuthority
14066
- ),
14067
13957
  io: input.io,
14068
13958
  sessionAppender: env.sessionAppender,
14069
13959
  autoResumeLimit: env.autoResumeLimit,
@@ -14251,7 +14141,6 @@ async function runPostAdmissionResumable(input) {
14251
14141
  return runWithAutoResumeLoop({
14252
14142
  admitted,
14253
14143
  principalAuthority: env.principalAuthority,
14254
- isPrincipalAvailable: resolveHostAwareSessionAvailability(env.host, env.principalAuthority),
14255
14144
  io,
14256
14145
  sessionAppender: env.sessionAppender,
14257
14146
  autoResumeLimit: env.autoResumeLimit,
@@ -14373,7 +14262,7 @@ var init_seat_ticket_binding = __esm({
14373
14262
 
14374
14263
  // src/public-cli/machine-method-skills.ts
14375
14264
  import { accessSync, constants as constants2, statSync as statSync4 } from "node:fs";
14376
- import { lstat as lstat6, mkdir as mkdir4, symlink } from "node:fs/promises";
14265
+ import { lstat as lstat5, mkdir as mkdir4, symlink } from "node:fs/promises";
14377
14266
  import { join as join33 } from "node:path";
14378
14267
  import { spawnSync as spawnSync2 } from "node:child_process";
14379
14268
  function skillRoot(home) {
@@ -14403,7 +14292,7 @@ function linkedSkillRoot(home, host) {
14403
14292
  }
14404
14293
  async function occupied(path) {
14405
14294
  try {
14406
- await lstat6(path);
14295
+ await lstat5(path);
14407
14296
  return true;
14408
14297
  } catch (error) {
14409
14298
  if (error.code !== "ENOENT") throw error;
@@ -15488,7 +15377,7 @@ async function runPublicInstructionSeatResume(request, env, io) {
15488
15377
  };
15489
15378
  let binding;
15490
15379
  try {
15491
- const loaded = await loadResumablePublicRole(env.home, request.runId, env.principalAuthority, true);
15380
+ const loaded = await loadResumablePublicRole(env.home, request.runId, env.principalAuthority);
15492
15381
  binding = loaded.admitted.role === "auditor" ? await readAuditorResumeBinding(loaded.admitted.runDirectory) : void 0;
15493
15382
  } catch (error) {
15494
15383
  if (!(error instanceof CliUsageError)) throw error;
@@ -15531,7 +15420,7 @@ async function queueConclusionFromChild(child, env, io) {
15531
15420
  }
15532
15421
  }
15533
15422
  async function continueParentAfterChild(parentRunId, child, env, io) {
15534
- const loaded = await loadResumablePublicRole(env.home, parentRunId, env.principalAuthority, true);
15423
+ const loaded = await loadResumablePublicRole(env.home, parentRunId, env.principalAuthority);
15535
15424
  if (loaded.run.state !== "admitted" && !AUDITED_ROLES.has(loaded.admitted.role)) {
15536
15425
  return runPublicInstructionSeatResume({ runId: parentRunId }, env, io);
15537
15426
  }
@@ -15726,7 +15615,7 @@ async function auditSubmittedRole(turn, env, io, passedOfficer, passedReceipt, p
15726
15615
  const escalation = chain.passes.at(-1);
15727
15616
  const escalatedRunId = escalation?.runId ?? (escalation?.runDirectory === void 0 ? void 0 : runIdFromRunDirectory(escalation.runDirectory));
15728
15617
  if (escalatedRunId === void 0) throw new Error("escalated audit has no resumable run identity");
15729
- const officer = await loadResumablePublicRole(env.home, escalatedRunId, env.principalAuthority, true);
15618
+ const officer = await loadResumablePublicRole(env.home, escalatedRunId, env.principalAuthority);
15730
15619
  const terminal2 = await trySettlePublicSeat(officer.admitted, env.principalAuthority, void 0);
15731
15620
  if (terminal2 === void 0) throw new Error("escalated audit has no terminal result");
15732
15621
  io.stdout(formatTerminalResult(terminal2));
@@ -19650,7 +19539,6 @@ __export(run_lifecycle_exports, {
19650
19539
  describeErrorIdentity: () => describeErrorIdentity,
19651
19540
  findLatestRunIdForSeatTicket: () => findLatestRunIdForSeatTicket,
19652
19541
  findRunDirectoryById: () => findRunDirectoryById,
19653
- isDurablePrincipalAvailable: () => isDurablePrincipalAvailable,
19654
19542
  isV1ResumableProvider: () => isV1ResumableProvider,
19655
19543
  loadResumablePublicRole: () => loadResumablePublicRole,
19656
19544
  markRunAdmitted: () => markRunAdmitted,
@@ -19670,7 +19558,7 @@ __export(run_lifecycle_exports, {
19670
19558
  renderResumeCommand: () => renderResumeCommand,
19671
19559
  writeRoleRunState: () => writeRoleRunState
19672
19560
  });
19673
- import { chmod, lstat as lstat7, open as open3, readdir as readdir7, readFile as readFile22, unlink as unlink5, writeFile as writeFile9 } from "node:fs/promises";
19561
+ import { chmod, lstat as lstat6, open as open3, readdir as readdir7, readFile as readFile22, unlink as unlink5, writeFile as writeFile9 } from "node:fs/promises";
19674
19562
  import { basename as basename10, join as join40 } from "node:path";
19675
19563
  function buildAutoResumeContinuationPrompt(options) {
19676
19564
  return appendEngineSessionMaterial(
@@ -19984,9 +19872,6 @@ async function clearCurrentCourt(runDirectory, expectedCourtAttemptId) {
19984
19872
  ...current.resumable === void 0 ? {} : { resumable: current.resumable }
19985
19873
  });
19986
19874
  }
19987
- async function isDurablePrincipalAvailable(principal, authority) {
19988
- return authority.isAvailable(principal);
19989
- }
19990
19875
  function describeErrorIdentity(error) {
19991
19876
  const candidate = error;
19992
19877
  const name = typeof candidate?.name === "string" && candidate.name !== "" ? candidate.name : typeof error;
@@ -20228,7 +20113,7 @@ async function runHasFormedSessionPrincipal(runDirectory) {
20228
20113
  if (disk === void 0) return false;
20229
20114
  const sessionFile = typeof disk.principalWire.sessionFile === "string" && disk.principalWire.sessionFile.trim() !== "" ? disk.principalWire.sessionFile : join40(disk.principalWire.sessionDirectory, "session.jsonl");
20230
20115
  try {
20231
- const stat2 = await lstat7(sessionFile);
20116
+ const stat2 = await lstat6(sessionFile);
20232
20117
  return stat2.isFile() && !stat2.isSymbolicLink();
20233
20118
  } catch (error) {
20234
20119
  if (errorCodeOf(error) === "ENOENT") return false;
@@ -20320,7 +20205,7 @@ function restoredTicketFields(fields) {
20320
20205
  ...fields.courtTicketNumbers === void 0 ? {} : { courtTicketNumbers: fields.courtTicketNumbers }
20321
20206
  };
20322
20207
  }
20323
- async function loadResumableRunRecord(home, runId, authority, allowUnformedAdmitted = false) {
20208
+ async function loadResumableRunRecord(home, runId, authority) {
20324
20209
  const runDirectory = await findRunDirectoryById(home, runId);
20325
20210
  if (runDirectory === void 0) {
20326
20211
  throw new CliUsageError(`unknown role run id: ${runId}`);
@@ -20334,11 +20219,6 @@ async function loadResumableRunRecord(home, runId, authority, allowUnformedAdmit
20334
20219
  throw new CliUsageError(`unknown role run id: ${runId}`);
20335
20220
  }
20336
20221
  const { run, principal } = materialized;
20337
- if (!(allowUnformedAdmitted && run.state === "admitted") && !await isDurablePrincipalAvailable(principal, authority)) {
20338
- throw new CliUsageError(
20339
- `role run Pi session principal is unavailable: ${runId}`
20340
- );
20341
- }
20342
20222
  let instruction = "";
20343
20223
  let instructionEmpty = true;
20344
20224
  let attachments = [];
@@ -20615,8 +20495,8 @@ async function peekRoleRunRole(home, runId) {
20615
20495
  const run = await readRoleRunIdentity(runDirectory);
20616
20496
  return run?.role;
20617
20497
  }
20618
- async function loadResumablePublicRole(home, runId, authority, allowUnformedAdmitted = false) {
20619
- const loaded = await loadResumableRunRecord(home, runId, authority, allowUnformedAdmitted);
20498
+ async function loadResumablePublicRole(home, runId, authority) {
20499
+ const loaded = await loadResumableRunRecord(home, runId, authority);
20620
20500
  return seatLoadedResult(loaded, admitResumedRole(loaded));
20621
20501
  }
20622
20502
  function admitResumedRole(loaded) {
@@ -21696,9 +21576,14 @@ function createNativeNavigatorSessionFactory(deps) {
21696
21576
  }
21697
21577
  if (outcome.kind === "failure") {
21698
21578
  providerFailure = navigatorProviderFailureFromPublicTerminal(outcome);
21579
+ const failedAttempts = outcome.decisiveFacts.failedAttempts;
21580
+ const attemptReasons = Array.isArray(failedAttempts) ? failedAttempts.map((entry, index) => {
21581
+ const fact = entry !== null && typeof entry === "object" ? entry : void 0;
21582
+ return `${typeof fact?.attempt === "number" ? fact.attempt + 1 : index + 1}: ${typeof fact?.diagnostic === "string" ? fact.diagnostic : outcome.diagnostic}`;
21583
+ }) : [];
21699
21584
  throw navigatorUnavailableError(
21700
21585
  providerFailure.source,
21701
- new Error(outcome.diagnostic),
21586
+ new Error(attemptReasons.length > 0 ? attemptReasons.join("\n") : outcome.diagnostic),
21702
21587
  providerFailure.cause
21703
21588
  );
21704
21589
  }
@@ -24121,8 +24006,15 @@ async function projectClosedSubmissionLifecycle(closed, context, phase, recordAc
24121
24006
  isError: false,
24122
24007
  details: closed.accepted
24123
24008
  };
24124
- context.sessionManager.appendCustomEntry?.("ak-role-submission-closure", closure);
24125
- await settle(publicNavigatorSettlement(closed.role, phase, closure));
24009
+ let navigator;
24010
+ try {
24011
+ navigator = await settle(publicNavigatorSettlement(closed.role, phase, closure));
24012
+ } finally {
24013
+ context.sessionManager.appendCustomEntry?.("ak-role-submission-closure", {
24014
+ ...closure,
24015
+ ...navigator === void 0 ? {} : { navigator }
24016
+ });
24017
+ }
24126
24018
  }
24127
24019
  function createFiledOfficerRuntime(roleHost, spec, dependencies) {
24128
24020
  let soul;
@@ -24481,6 +24373,8 @@ function createRoleRuntimeExtension(dependencies) {
24481
24373
  let activeReviewerParent;
24482
24374
  let navigatorAttendance;
24483
24375
  let pendingNavigatorPresentation;
24376
+ let navigatorActivation = 0;
24377
+ let navigatorDeliveryClosed = false;
24484
24378
  let pendingNavigatorSettlement;
24485
24379
  let navigatorWorkContext;
24486
24380
  let navigatorSessionParent;
@@ -24533,6 +24427,7 @@ function createRoleRuntimeExtension(dependencies) {
24533
24427
  void settlePromise.catch(() => void 0);
24534
24428
  const raced = await raceNavigatorGrace(settlePromise, NAVIGATOR_POST_ROLE_GRACE_MS);
24535
24429
  if (raced.status !== "timeout") return;
24430
+ navigatorDeliveryClosed = true;
24536
24431
  if (pendingNavigatorPresentation === void 0) {
24537
24432
  const report = {
24538
24433
  disposition: "unavailable",
@@ -24557,6 +24452,7 @@ function createRoleRuntimeExtension(dependencies) {
24557
24452
  })();
24558
24453
  pendingNavigatorSettlement = pending;
24559
24454
  await pending;
24455
+ return pendingNavigatorPresentation?.event;
24560
24456
  };
24561
24457
  projectClosedSubmission = async (closed, context) => projectClosedSubmissionLifecycle(
24562
24458
  closed,
@@ -25036,6 +24932,8 @@ function createRoleRuntimeExtension(dependencies) {
25036
24932
  receiptDelivery = createReceiptDeliveryPolicy();
25037
24933
  noReceiptRecorded = false;
25038
24934
  pendingNavigatorPresentation = void 0;
24935
+ navigatorActivation += 1;
24936
+ navigatorDeliveryClosed = false;
25039
24937
  pendingNavigatorSettlement = void 0;
25040
24938
  pendingInfrastructureFailures.clear();
25041
24939
  pendingSubmissionNonPassByToolCallId.clear();
@@ -25131,6 +25029,7 @@ function createRoleRuntimeExtension(dependencies) {
25131
25029
  } catch {
25132
25030
  }
25133
25031
  }
25032
+ const activation = navigatorActivation;
25134
25033
  navigatorAttendance = await dependencies.createNavigatorAttendance({
25135
25034
  context: ctx,
25136
25035
  role: entry.role,
@@ -25141,7 +25040,9 @@ function createRoleRuntimeExtension(dependencies) {
25141
25040
  invocationId,
25142
25041
  ...contextError === void 0 ? {} : { contextError },
25143
25042
  onEvent: (navigatorEvent, report) => {
25144
- pendingNavigatorPresentation = { event: navigatorEvent, report };
25043
+ if (activation === navigatorActivation && !navigatorDeliveryClosed) {
25044
+ pendingNavigatorPresentation = { event: navigatorEvent, report };
25045
+ }
25145
25046
  }
25146
25047
  });
25147
25048
  if (navigatorWorkContext.contextError === void 0 && navigatorWorkContext.subjectProvenance !== "placeholder") {
@@ -26455,297 +26356,307 @@ function createHeadlessRoleTurnHost(config) {
26455
26356
  try {
26456
26357
  const explicitHostSessionId = request.continuation.kind === "resume" ? request.continuation.hostSessionId : void 0;
26457
26358
  let sessionId = explicitHostSessionId !== void 0 && explicitHostSessionId !== "" ? explicitHostSessionId : await config.sessionIdentity.load(request.principal);
26458
- let sessionKind = request.continuation.kind === "resume" && sessionId !== void 0 && sessionId !== "" ? "resume" : "new";
26459
- if (sessionKind === "new" && !codex) {
26460
- sessionId = randomUUID10();
26461
- await config.sessionIdentity.bind(request.principal, sessionId);
26462
- }
26463
- const env = { ...process.env, ...config.env ?? {} };
26464
- const systemPromptPath = join47(request.runDirectory, "headless-system-prompt.txt");
26465
- await writeFile11(systemPromptPath, systemPrompt, "utf8");
26466
- let mcpConfigPath;
26467
- let outputSchemaPath;
26468
- if (codex) {
26469
- if (prepared.terminatingToolName !== NAVIGATOR_OUTPUT_TOOL_NAME) {
26470
- outputSchemaPath = join47(request.runDirectory, "headless-output-schema.json");
26359
+ if (request.continuation.kind === "resume" && (sessionId === void 0 || sessionId === "")) {
26360
+ outcome = failure(
26361
+ "session",
26362
+ "HeadlessSessionFailure",
26363
+ "session-id-missing",
26364
+ void 0,
26365
+ "resume requires a bound session id"
26366
+ );
26367
+ } else {
26368
+ let sessionKind = request.continuation.kind === "resume" ? "resume" : "new";
26369
+ if (sessionKind === "new" && !codex) {
26370
+ sessionId = randomUUID10();
26371
+ await config.sessionIdentity.bind(request.principal, sessionId);
26372
+ }
26373
+ const env = { ...process.env, ...config.env ?? {} };
26374
+ const systemPromptPath = join47(request.runDirectory, "headless-system-prompt.txt");
26375
+ await writeFile11(systemPromptPath, systemPrompt, "utf8");
26376
+ let mcpConfigPath;
26377
+ let outputSchemaPath;
26378
+ if (codex) {
26379
+ if (prepared.terminatingToolName !== NAVIGATOR_OUTPUT_TOOL_NAME) {
26380
+ outputSchemaPath = join47(request.runDirectory, "headless-output-schema.json");
26381
+ await writeFile11(
26382
+ outputSchemaPath,
26383
+ `${JSON.stringify(closeJsonSchemaForCodex(prepared.jsonSchema), null, 2)}
26384
+ `,
26385
+ "utf8"
26386
+ );
26387
+ }
26388
+ } else {
26389
+ mcpConfigPath = join47(request.runDirectory, "headless-mcp-config.json");
26471
26390
  await writeFile11(
26472
- outputSchemaPath,
26473
- `${JSON.stringify(closeJsonSchemaForCodex(prepared.jsonSchema), null, 2)}
26391
+ mcpConfigPath,
26392
+ `${JSON.stringify(headlessMcpConfigDocument(prepared.mcpServers), null, 2)}
26474
26393
  `,
26475
26394
  "utf8"
26476
26395
  );
26477
26396
  }
26478
- } else {
26479
- mcpConfigPath = join47(request.runDirectory, "headless-mcp-config.json");
26480
- await writeFile11(
26481
- mcpConfigPath,
26482
- `${JSON.stringify(headlessMcpConfigDocument(prepared.mcpServers), null, 2)}
26483
- `,
26484
- "utf8"
26485
- );
26486
- }
26487
- const sessionParent = config.sessionIdentity.resolveSessionFile(request.principal);
26488
- let exitedSessionId;
26489
- try {
26490
- outcome = await driveExternalRoleTurnRounds(prepared, request, {
26491
- roundLimitName: "HeadlessRoundLimit",
26492
- currentSessionId: () => sessionId,
26493
- afterRetry() {
26494
- sessionKind = "resume";
26495
- },
26496
- async runRound({ prompt, abortSignal }) {
26497
- let args;
26498
- try {
26499
- const gitCommonDir = codex ? resolveGitCommonDir(request.cwd) : void 0;
26500
- args = buildTurnArgs({
26501
- description: config.description,
26502
- systemPromptPath,
26503
- // #959: navigator prose exit — no closed JSON schema on claude either.
26504
- ...prepared.terminatingToolName === NAVIGATOR_OUTPUT_TOOL_NAME ? {} : { jsonSchema: prepared.jsonSchema },
26505
- mcpServers: prepared.mcpServers,
26506
- ...mcpConfigPath === void 0 ? {} : { mcpConfigPath },
26507
- ...outputSchemaPath === void 0 ? {} : { outputSchemaPath },
26508
- ...request.model?.model !== void 0 ? { model: request.model.model } : {},
26509
- ...request.model?.thinking !== void 0 ? { effort: request.model.thinking } : {},
26510
- sessionId,
26511
- sessionKind,
26512
- cwd: request.cwd,
26513
- ...gitCommonDir === void 0 ? {} : { writableRoots: [gitCommonDir] }
26514
- });
26515
- } catch (error) {
26516
- const message = error instanceof Error ? error.message : String(error);
26517
- return {
26518
- status: "terminal",
26519
- result: failure("session", "HeadlessArgvFailure", "argv-failed", { diagnostic: message }, message)
26520
- };
26521
- }
26522
- const codexObserver = codex ? createCodexExecTurnObserver() : void 0;
26523
- let pointerRecorded = false;
26524
- let codexIdObserved = false;
26525
- if (sessionId !== void 0 && sessionId !== "") {
26526
- pointerRecorded = recordNativeSessionPointer({
26527
- host: config.hostName,
26528
- sessionId,
26529
- cwd: request.cwd,
26530
- sessionParent,
26531
- home: request.home
26532
- }) !== void 0;
26533
- }
26534
- let spawned;
26535
- let childExited = false;
26536
- try {
26537
- spawned = await spawnHeadlessTurn({
26538
- onClose() {
26539
- childExited = true;
26540
- },
26541
- binary: config.binary,
26542
- args,
26543
- cwd: request.cwd,
26544
- env,
26545
- stdin: prompt,
26546
- ...abortSignal === void 0 ? {} : { signal: abortSignal },
26547
- ...request.timeoutMs === void 0 ? {} : { timeoutMs: request.timeoutMs },
26548
- onStdoutLine(line2) {
26549
- const trimmed = line2.trim();
26550
- if (trimmed === "") return;
26551
- let event;
26552
- try {
26553
- event = JSON.parse(trimmed);
26554
- } catch {
26555
- return;
26556
- }
26557
- codexObserver?.observe(event);
26558
- if (!codex && typeof event === "object" && event !== null && "session_id" in event && typeof event.session_id === "string" && event.session_id !== "" && event.session_id !== sessionId) {
26559
- sessionId = event.session_id;
26560
- recordNativeSessionPointer({ host: config.hostName, sessionId, cwd: request.cwd, sessionParent, home: request.home });
26561
- }
26562
- if (codex && !codexIdObserved) {
26563
- const tid = codexObserver?.result().threadId;
26564
- if (tid !== void 0 && tid !== "") {
26565
- codexIdObserved = true;
26566
- pointerRecorded = recordNativeSessionPointer({
26567
- host: config.hostName,
26568
- sessionId: tid,
26569
- cwd: request.cwd,
26570
- sessionParent,
26571
- home: request.home
26572
- }) !== void 0;
26573
- }
26574
- }
26575
- }
26576
- });
26577
- const roundSessionId = (codex ? codexObserver?.result().threadId : void 0) ?? sessionId;
26578
- exitedSessionId = roundSessionId;
26579
- if (codex && roundSessionId !== void 0 && roundSessionId !== "" && !pointerRecorded) {
26580
- recordNativeSessionPointer({ host: config.hostName, sessionId: roundSessionId, cwd: request.cwd, sessionParent, home: request.home });
26581
- }
26582
- } catch (error) {
26583
- if (childExited) exitedSessionId = (codex ? codexObserver?.result().threadId : void 0) ?? sessionId;
26584
- if (isHostAbortedError(error)) throw error;
26585
- const message = error instanceof Error ? error.message : String(error);
26586
- const observedHostFailure = codexObserver?.result().failureDiagnostic;
26587
- if (observedHostFailure !== void 0) {
26397
+ const sessionParent = config.sessionIdentity.resolveSessionFile(request.principal);
26398
+ let exitedSessionId;
26399
+ try {
26400
+ outcome = await driveExternalRoleTurnRounds(prepared, request, {
26401
+ roundLimitName: "HeadlessRoundLimit",
26402
+ currentSessionId: () => sessionId,
26403
+ afterRetry() {
26404
+ sessionKind = "resume";
26405
+ },
26406
+ async runRound({ prompt, abortSignal }) {
26407
+ let args;
26408
+ try {
26409
+ const gitCommonDir = codex ? resolveGitCommonDir(request.cwd) : void 0;
26410
+ args = buildTurnArgs({
26411
+ description: config.description,
26412
+ systemPromptPath,
26413
+ // #959: navigator prose exit — no closed JSON schema on claude either.
26414
+ ...prepared.terminatingToolName === NAVIGATOR_OUTPUT_TOOL_NAME ? {} : { jsonSchema: prepared.jsonSchema },
26415
+ mcpServers: prepared.mcpServers,
26416
+ ...mcpConfigPath === void 0 ? {} : { mcpConfigPath },
26417
+ ...outputSchemaPath === void 0 ? {} : { outputSchemaPath },
26418
+ ...request.model?.model !== void 0 ? { model: request.model.model } : {},
26419
+ ...request.model?.thinking !== void 0 ? { effort: request.model.thinking } : {},
26420
+ sessionId,
26421
+ sessionKind,
26422
+ cwd: request.cwd,
26423
+ ...gitCommonDir === void 0 ? {} : { writableRoots: [gitCommonDir] }
26424
+ });
26425
+ } catch (error) {
26426
+ const message = error instanceof Error ? error.message : String(error);
26588
26427
  return {
26589
26428
  status: "terminal",
26590
- result: failure("output", "HeadlessCliError", "codex-turn-failed", {
26591
- diagnostic: observedHostFailure,
26592
- sessionRecordDiagnostic: message,
26593
- sessionId
26594
- }, observedHostFailure)
26429
+ result: failure("session", "HeadlessArgvFailure", "argv-failed", { diagnostic: message }, message)
26595
26430
  };
26596
26431
  }
26597
- return {
26598
- status: "terminal",
26599
- result: failure("activation", "HeadlessSpawnFailure", "spawn-failed", {
26600
- diagnostic: message,
26601
- binary: config.binary
26602
- }, message)
26603
- };
26604
- }
26605
- if (spawned.timedOut) {
26606
- return terminalFromSpawned(spawned, {
26607
- cause: "timeout",
26608
- identity: { name: "HeadlessTimeout", code: "timeout" },
26609
- details: { sessionId }
26610
- });
26611
- }
26612
- if (codex) {
26613
- const observation = codexObserver.result();
26614
- if (observation.threadId !== void 0 && observation.threadId !== "") {
26615
- sessionId = observation.threadId;
26616
- }
26617
- let sessionBindingDiagnostic;
26618
- const hostFailed = observation.failureDiagnostic !== void 0 || spawned.code !== 0 && spawned.code !== null;
26619
- if (hostFailed && observation.threadId !== void 0 && observation.threadId !== "") {
26620
- try {
26621
- await config.sessionIdentity.bind(request.principal, observation.threadId);
26622
- } catch (error) {
26623
- sessionBindingDiagnostic = error instanceof Error ? error.message : String(error);
26624
- }
26625
- }
26626
- if (observation.failureDiagnostic !== void 0) {
26627
- return terminalFromSpawned(spawned, {
26628
- cause: "output",
26629
- identity: { name: "HeadlessCliError", code: "codex-turn-failed" },
26630
- diagnostic: observation.failureDiagnostic,
26631
- details: {
26632
- sessionId,
26633
- exitCode: spawned.code,
26634
- ...sessionBindingDiagnostic === void 0 ? {} : { sessionBindingDiagnostic }
26635
- }
26636
- });
26432
+ const codexObserver = codex ? createCodexExecTurnObserver() : void 0;
26433
+ let pointerRecorded = false;
26434
+ let codexIdObserved = false;
26435
+ if (sessionId !== void 0 && sessionId !== "") {
26436
+ pointerRecorded = recordNativeSessionPointer({
26437
+ host: config.hostName,
26438
+ sessionId,
26439
+ cwd: request.cwd,
26440
+ sessionParent,
26441
+ home: request.home
26442
+ }) !== void 0;
26637
26443
  }
26638
- if (spawned.code !== 0 && spawned.code !== null) {
26639
- return terminalFromSpawned(spawned, {
26640
- cause: "output",
26641
- identity: { name: "HeadlessCliError", code: "codex-nonzero-exit" },
26642
- diagnostic: spawned.stderr.trim() || `codex exec exited ${String(spawned.code)}`,
26643
- details: {
26644
- sessionId,
26645
- exitCode: spawned.code,
26646
- ...sessionBindingDiagnostic === void 0 ? {} : { sessionBindingDiagnostic }
26444
+ let spawned;
26445
+ let childExited = false;
26446
+ try {
26447
+ spawned = await spawnHeadlessTurn({
26448
+ onClose() {
26449
+ childExited = true;
26450
+ },
26451
+ binary: config.binary,
26452
+ args,
26453
+ cwd: request.cwd,
26454
+ env,
26455
+ stdin: prompt,
26456
+ ...abortSignal === void 0 ? {} : { signal: abortSignal },
26457
+ ...request.timeoutMs === void 0 ? {} : { timeoutMs: request.timeoutMs },
26458
+ onStdoutLine(line2) {
26459
+ const trimmed = line2.trim();
26460
+ if (trimmed === "") return;
26461
+ let event;
26462
+ try {
26463
+ event = JSON.parse(trimmed);
26464
+ } catch {
26465
+ return;
26466
+ }
26467
+ codexObserver?.observe(event);
26468
+ if (!codex && typeof event === "object" && event !== null && "session_id" in event && typeof event.session_id === "string" && event.session_id !== "" && event.session_id !== sessionId) {
26469
+ sessionId = event.session_id;
26470
+ recordNativeSessionPointer({ host: config.hostName, sessionId, cwd: request.cwd, sessionParent, home: request.home });
26471
+ }
26472
+ if (codex && !codexIdObserved) {
26473
+ const tid = codexObserver?.result().threadId;
26474
+ if (tid !== void 0 && tid !== "") {
26475
+ codexIdObserved = true;
26476
+ pointerRecorded = recordNativeSessionPointer({
26477
+ host: config.hostName,
26478
+ sessionId: tid,
26479
+ cwd: request.cwd,
26480
+ sessionParent,
26481
+ home: request.home
26482
+ }) !== void 0;
26483
+ }
26484
+ }
26647
26485
  }
26648
26486
  });
26487
+ const roundSessionId = (codex ? codexObserver?.result().threadId : void 0) ?? sessionId;
26488
+ exitedSessionId = roundSessionId;
26489
+ if (codex && roundSessionId !== void 0 && roundSessionId !== "" && !pointerRecorded) {
26490
+ recordNativeSessionPointer({ host: config.hostName, sessionId: roundSessionId, cwd: request.cwd, sessionParent, home: request.home });
26491
+ }
26492
+ } catch (error) {
26493
+ if (childExited) exitedSessionId = (codex ? codexObserver?.result().threadId : void 0) ?? sessionId;
26494
+ if (isHostAbortedError(error)) throw error;
26495
+ const message = error instanceof Error ? error.message : String(error);
26496
+ const observedHostFailure = codexObserver?.result().failureDiagnostic;
26497
+ if (observedHostFailure !== void 0) {
26498
+ return {
26499
+ status: "terminal",
26500
+ result: failure("output", "HeadlessCliError", "codex-turn-failed", {
26501
+ diagnostic: observedHostFailure,
26502
+ sessionRecordDiagnostic: message,
26503
+ sessionId
26504
+ }, observedHostFailure)
26505
+ };
26506
+ }
26507
+ return {
26508
+ status: "terminal",
26509
+ result: failure("activation", "HeadlessSpawnFailure", "spawn-failed", {
26510
+ diagnostic: message,
26511
+ binary: config.binary
26512
+ }, message)
26513
+ };
26649
26514
  }
26650
- if (observation.threadId === void 0 || observation.threadId === "") {
26651
- return terminalFromSpawned(spawned, {
26652
- cause: "session",
26653
- identity: { name: "HeadlessMissingThreadId", code: "missing-thread-id" },
26654
- diagnostic: "codex exec emitted no thread.started thread_id",
26655
- details: { sessionId, exitCode: spawned.code }
26656
- });
26657
- }
26658
- sessionId = observation.threadId;
26659
- await config.sessionIdentity.bind(request.principal, sessionId);
26660
- if (!observation.turnCompleted) {
26661
- return terminalFromSpawned(spawned, {
26662
- cause: "output",
26663
- identity: { name: "HeadlessCliError", code: "codex-missing-terminal-event" },
26664
- diagnostic: "codex exec exited without turn.completed",
26665
- details: { sessionId, exitCode: spawned.code }
26666
- });
26667
- }
26668
- if (observation.finalMessage === void 0) {
26515
+ if (spawned.timedOut) {
26669
26516
  return terminalFromSpawned(spawned, {
26670
- cause: "output",
26671
- identity: { name: "HeadlessEmptyOutput", code: "empty-stdout" },
26672
- diagnostic: spawned.stderr.trim() || "codex exec produced no agent_message",
26673
- details: { sessionId, exitCode: spawned.code }
26517
+ cause: "timeout",
26518
+ identity: { name: "HeadlessTimeout", code: "timeout" },
26519
+ details: { sessionId }
26674
26520
  });
26675
26521
  }
26676
- if (prepared.terminatingToolName === NAVIGATOR_OUTPUT_TOOL_NAME) {
26677
- if (observation.finalMessage.trim() === "") {
26522
+ if (codex) {
26523
+ const observation = codexObserver.result();
26524
+ if (observation.threadId !== void 0 && observation.threadId !== "") {
26525
+ sessionId = observation.threadId;
26526
+ }
26527
+ let sessionBindingDiagnostic;
26528
+ const hostFailed = observation.failureDiagnostic !== void 0 || spawned.code !== 0 && spawned.code !== null;
26529
+ if (hostFailed && observation.threadId !== void 0 && observation.threadId !== "") {
26530
+ try {
26531
+ await config.sessionIdentity.bind(request.principal, observation.threadId);
26532
+ } catch (error) {
26533
+ sessionBindingDiagnostic = error instanceof Error ? error.message : String(error);
26534
+ }
26535
+ }
26536
+ if (observation.failureDiagnostic !== void 0) {
26537
+ return terminalFromSpawned(spawned, {
26538
+ cause: "output",
26539
+ identity: { name: "HeadlessCliError", code: "codex-turn-failed" },
26540
+ diagnostic: observation.failureDiagnostic,
26541
+ details: {
26542
+ sessionId,
26543
+ exitCode: spawned.code,
26544
+ ...sessionBindingDiagnostic === void 0 ? {} : { sessionBindingDiagnostic }
26545
+ }
26546
+ });
26547
+ }
26548
+ if (spawned.code !== 0 && spawned.code !== null) {
26549
+ return terminalFromSpawned(spawned, {
26550
+ cause: "output",
26551
+ identity: { name: "HeadlessCliError", code: "codex-nonzero-exit" },
26552
+ diagnostic: spawned.stderr.trim() || `codex exec exited ${String(spawned.code)}`,
26553
+ details: {
26554
+ sessionId,
26555
+ exitCode: spawned.code,
26556
+ ...sessionBindingDiagnostic === void 0 ? {} : { sessionBindingDiagnostic }
26557
+ }
26558
+ });
26559
+ }
26560
+ if (observation.threadId === void 0 || observation.threadId === "") {
26561
+ return terminalFromSpawned(spawned, {
26562
+ cause: "session",
26563
+ identity: { name: "HeadlessMissingThreadId", code: "missing-thread-id" },
26564
+ diagnostic: "codex exec emitted no thread.started thread_id",
26565
+ details: { sessionId, exitCode: spawned.code }
26566
+ });
26567
+ }
26568
+ sessionId = observation.threadId;
26569
+ await config.sessionIdentity.bind(request.principal, sessionId);
26570
+ if (!observation.turnCompleted) {
26571
+ return terminalFromSpawned(spawned, {
26572
+ cause: "output",
26573
+ identity: { name: "HeadlessCliError", code: "codex-missing-terminal-event" },
26574
+ diagnostic: "codex exec exited without turn.completed",
26575
+ details: { sessionId, exitCode: spawned.code }
26576
+ });
26577
+ }
26578
+ if (observation.finalMessage === void 0) {
26678
26579
  return terminalFromSpawned(spawned, {
26679
26580
  cause: "output",
26680
26581
  identity: { name: "HeadlessEmptyOutput", code: "empty-stdout" },
26681
- diagnostic: spawned.stderr.trim() || "codex exec produced empty agent_message",
26582
+ diagnostic: spawned.stderr.trim() || "codex exec produced no agent_message",
26583
+ details: { sessionId, exitCode: spawned.code }
26584
+ });
26585
+ }
26586
+ if (prepared.terminatingToolName === NAVIGATOR_OUTPUT_TOOL_NAME) {
26587
+ if (observation.finalMessage.trim() === "") {
26588
+ return terminalFromSpawned(spawned, {
26589
+ cause: "output",
26590
+ identity: { name: "HeadlessEmptyOutput", code: "empty-stdout" },
26591
+ diagnostic: spawned.stderr.trim() || "codex exec produced empty agent_message",
26592
+ details: { sessionId, exitCode: spawned.code }
26593
+ });
26594
+ }
26595
+ await prepared.ingestStructuredOutput({ prose: observation.finalMessage });
26596
+ return { status: "delivered", stderr: spawned.stderr };
26597
+ }
26598
+ let receipt;
26599
+ try {
26600
+ receipt = JSON.parse(observation.finalMessage);
26601
+ } catch {
26602
+ return terminalFromSpawned(spawned, {
26603
+ cause: "output",
26604
+ identity: { name: "HeadlessEmptyOutput", code: "unparseable-final-message" },
26605
+ diagnostic: "codex final agent_message was not JSON",
26682
26606
  details: { sessionId, exitCode: spawned.code }
26683
26607
  });
26684
26608
  }
26685
- await prepared.ingestStructuredOutput({ prose: observation.finalMessage });
26609
+ await prepared.ingestStructuredOutput(receipt);
26686
26610
  return { status: "delivered", stderr: spawned.stderr };
26687
26611
  }
26688
- let receipt;
26689
- try {
26690
- receipt = JSON.parse(observation.finalMessage);
26691
- } catch {
26612
+ const envelope = parseHeadlessCliStdout(spawned.stdout);
26613
+ if (envelope === void 0) {
26692
26614
  return terminalFromSpawned(spawned, {
26693
26615
  cause: "output",
26694
- identity: { name: "HeadlessEmptyOutput", code: "unparseable-final-message" },
26695
- diagnostic: "codex final agent_message was not JSON",
26616
+ identity: { name: "HeadlessEmptyOutput", code: "empty-stdout" },
26617
+ diagnostic: spawned.stderr.length > 0 ? spawned.stderr : "headless CLI produced no parseable result",
26696
26618
  details: { sessionId, exitCode: spawned.code }
26697
26619
  });
26698
26620
  }
26699
- await prepared.ingestStructuredOutput(receipt);
26621
+ if (typeof envelope.session_id === "string" && envelope.session_id !== "") {
26622
+ sessionId = envelope.session_id;
26623
+ await config.sessionIdentity.bind(request.principal, sessionId);
26624
+ }
26625
+ if (envelope.is_error === true || typeof envelope.subtype === "string" && envelope.subtype.startsWith("error_")) {
26626
+ const errorCode = typeof envelope.subtype === "string" && envelope.subtype.startsWith("error_") ? envelope.subtype : envelope.is_error === true ? "is_error" : "cli-error";
26627
+ const diagnostic = typeof envelope.result === "string" ? envelope.result : Array.isArray(envelope.errors) ? envelope.errors.map(String).join("\n") : spawned.stderr.length > 0 ? spawned.stderr : "headless CLI reported is_error";
26628
+ return terminalFromSpawned(spawned, {
26629
+ cause: "output",
26630
+ identity: { name: "HeadlessCliError", code: errorCode },
26631
+ diagnostic,
26632
+ details: {
26633
+ sessionId,
26634
+ subtype: envelope.subtype,
26635
+ errors: envelope.errors,
26636
+ exitCode: spawned.code
26637
+ }
26638
+ });
26639
+ }
26640
+ if (envelope.structured_output !== void 0) {
26641
+ await prepared.ingestStructuredOutput(envelope.structured_output);
26642
+ } else if (prepared.terminatingToolName === NAVIGATOR_OUTPUT_TOOL_NAME && typeof envelope.result === "string" && envelope.result.trim() !== "") {
26643
+ await prepared.ingestStructuredOutput({ prose: envelope.result });
26644
+ }
26700
26645
  return { status: "delivered", stderr: spawned.stderr };
26701
26646
  }
26702
- const envelope = parseHeadlessCliStdout(spawned.stdout);
26703
- if (envelope === void 0) {
26704
- return terminalFromSpawned(spawned, {
26705
- cause: "output",
26706
- identity: { name: "HeadlessEmptyOutput", code: "empty-stdout" },
26707
- diagnostic: spawned.stderr.length > 0 ? spawned.stderr : "headless CLI produced no parseable result",
26708
- details: { sessionId, exitCode: spawned.code }
26709
- });
26710
- }
26711
- if (typeof envelope.session_id === "string" && envelope.session_id !== "") {
26712
- sessionId = envelope.session_id;
26713
- await config.sessionIdentity.bind(request.principal, sessionId);
26714
- }
26715
- if (envelope.is_error === true || typeof envelope.subtype === "string" && envelope.subtype.startsWith("error_")) {
26716
- const errorCode = typeof envelope.subtype === "string" && envelope.subtype.startsWith("error_") ? envelope.subtype : envelope.is_error === true ? "is_error" : "cli-error";
26717
- const diagnostic = typeof envelope.result === "string" ? envelope.result : Array.isArray(envelope.errors) ? envelope.errors.map(String).join("\n") : spawned.stderr.length > 0 ? spawned.stderr : "headless CLI reported is_error";
26718
- return terminalFromSpawned(spawned, {
26719
- cause: "output",
26720
- identity: { name: "HeadlessCliError", code: errorCode },
26721
- diagnostic,
26722
- details: {
26723
- sessionId,
26724
- subtype: envelope.subtype,
26725
- errors: envelope.errors,
26726
- exitCode: spawned.code
26727
- }
26728
- });
26729
- }
26730
- if (envelope.structured_output !== void 0) {
26731
- await prepared.ingestStructuredOutput(envelope.structured_output);
26732
- } else if (prepared.terminatingToolName === NAVIGATOR_OUTPUT_TOOL_NAME && typeof envelope.result === "string" && envelope.result.trim() !== "") {
26733
- await prepared.ingestStructuredOutput({ prose: envelope.result });
26734
- }
26735
- return { status: "delivered", stderr: spawned.stderr };
26736
- }
26737
- });
26738
- } finally {
26739
- if (exitedSessionId !== void 0 && exitedSessionId !== "") copyAndRecordHostDossier({
26740
- host: config.hostName,
26741
- sessionId: exitedSessionId,
26742
- cwd: request.cwd,
26743
- sessionDirectory: join47(request.runDirectory, "session"),
26744
- sessionParent,
26745
- continuation: request.continuation,
26746
- ...request.model !== void 0 ? { model: request.model } : {},
26747
- ...request.home !== void 0 ? { home: request.home } : {}
26748
- });
26647
+ });
26648
+ } finally {
26649
+ if (exitedSessionId !== void 0 && exitedSessionId !== "") copyAndRecordHostDossier({
26650
+ host: config.hostName,
26651
+ sessionId: exitedSessionId,
26652
+ cwd: request.cwd,
26653
+ sessionDirectory: join47(request.runDirectory, "session"),
26654
+ sessionParent,
26655
+ continuation: request.continuation,
26656
+ ...request.model !== void 0 ? { model: request.model } : {},
26657
+ ...request.home !== void 0 ? { home: request.home } : {}
26658
+ });
26659
+ }
26749
26660
  }
26750
26661
  } finally {
26751
26662
  try {