@akagilnc/pi-workflow-roles 0.1.5845 → 0.1.5853

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 (66) hide show
  1. package/README.md +4 -4
  2. package/README.zh-CN.md +4 -4
  3. package/dist/acp-host/production-host.js +348 -1254
  4. package/dist/acp-host/role-turn-host.js +4 -98
  5. package/dist/headless-host/production-host.js +15731 -16582
  6. package/dist/headless-host/role-turn-host.js +6 -31
  7. package/dist/migrate-book-topology.js +31 -16
  8. package/dist/navigator-attendance.js +54 -404
  9. package/dist/navigator-invocation-identity.js +0 -2
  10. package/dist/navigator-lookup-host.js +41 -0
  11. package/dist/navigator-lookup.js +68 -0
  12. package/dist/navigator-route-table.js +42 -0
  13. package/dist/package-contracts/navigator-output.js +3 -11
  14. package/dist/packaged-role-registry.js +3 -27
  15. package/dist/public-cli/instruction-seat-run.js +4 -1
  16. package/dist/public-cli/invocation.js +13 -26
  17. package/dist/public-cli/main.js +286 -114
  18. package/dist/public-cli/option-definitions.js +24 -4
  19. package/dist/public-cli/post-admission.js +0 -9
  20. package/dist/public-cli/role-seat-runtime.js +14 -0
  21. package/dist/public-cli/settlement.js +14 -40
  22. package/dist/public-cli/terminal.js +1 -8
  23. package/dist/public-cli/turn-request.js +0 -3
  24. package/dist/public-role-summons.js +0 -1
  25. package/dist/receipt-delivery-policy.js +0 -23
  26. package/dist/role-runtime-dependencies.js +4 -11
  27. package/dist/role-runtime.js +18 -194
  28. package/dist/submission-ledger.js +19 -15
  29. package/dist/ticket-progress.js +23 -5
  30. package/extensions/role-runtime.ts +0 -16
  31. package/package.json +1 -1
  32. package/scripts/build-package.mjs +3 -7
  33. package/src/acp-host/role-turn-host.ts +8 -97
  34. package/src/headless-host/description.ts +0 -2
  35. package/src/headless-host/role-turn-host.ts +7 -32
  36. package/src/host-contracts.ts +5 -7
  37. package/src/navigator-attendance.ts +86 -549
  38. package/src/navigator-invocation-identity.ts +0 -2
  39. package/src/navigator-lookup-host.ts +45 -0
  40. package/src/navigator-lookup.ts +98 -0
  41. package/src/navigator-route-table.ts +92 -0
  42. package/src/package-contracts/navigator-output.ts +4 -15
  43. package/src/packaged-role-registry.ts +3 -32
  44. package/src/public-cli/instruction-seat-run.ts +3 -0
  45. package/src/public-cli/invocation.ts +18 -30
  46. package/src/public-cli/option-definitions.ts +25 -4
  47. package/src/public-cli/post-admission.ts +0 -11
  48. package/src/public-cli/role-seat-runtime.ts +14 -0
  49. package/src/public-cli/settlement.ts +23 -51
  50. package/src/public-cli/terminal.ts +3 -18
  51. package/src/public-cli/turn-request.ts +0 -5
  52. package/src/public-role-summons.ts +0 -8
  53. package/src/receipt-delivery-policy.ts +0 -21
  54. package/src/role-runtime-dependencies.ts +4 -11
  55. package/src/role-runtime.ts +19 -210
  56. package/src/submission-ledger.ts +23 -16
  57. package/src/ticket-progress.ts +32 -5
  58. package/dist/navigator-public-session.js +0 -205
  59. package/dist/navigator-role.js +0 -6
  60. package/dist/navigator-session-contracts.js +0 -227
  61. package/dist/navigator-work-context.js +0 -72
  62. package/resources/navigator-route-playbook.md +0 -33
  63. package/src/navigator-public-session.ts +0 -305
  64. package/src/navigator-role.ts +0 -15
  65. package/src/navigator-session-contracts.ts +0 -320
  66. package/src/navigator-work-context.ts +0 -97
@@ -1,4 +1,3 @@
1
- import { randomUUID } from "node:crypto";
2
1
  import { readPageSync, RUN_STATE_FILE } from "./run-dossier.js";
3
2
  import { admittedSourceRunPath } from "./public-cli/invocation.js";
4
3
  import { readFileSync, writeSync } from "node:fs";
@@ -7,14 +6,13 @@ import { ExplicitInternalActivationError, runDirectoryFromHostContext, } from ".
7
6
  import { Value } from "typebox/value";
8
7
  import { sitianReport } from "./sitian-facade.js";
9
8
  import { sitianReportSafe } from "./host-session-record.js";
10
- import { createSubmissionLedgerHost, sealAcceptedSubmission } from "./submission-ledger.js";
9
+ import { createSubmissionLedgerHost } from "./submission-ledger.js";
11
10
  import { registerFiledSubmissionTool } from "./filed-submission.js";
12
11
  import { registerReportTicketTool, reportTicketFromHostContext, REPORT_TICKET_TOOL_NAME, } from "./report-ticket-tool.js";
13
12
  import { activationTraceRecordSchema, namedActivationCause } from "./activation-trace.js";
14
13
  import { homeFromRunDirectory } from "./activation-ledger-topology.js";
15
14
  import { isSafePositiveTicketNumber, parseTicketNumber, } from "./run-ticket-number.js";
16
15
  import { durableSessionPointer, resolveBookKeyFromGit, } from "./activation-ledger.js";
17
- import { readPackageMaterial } from "./session-opening-materials.js";
18
16
  import { writeStderrJsonlRecord } from "./stderr-jsonl.js";
19
17
  import { ENGINE_DETOUR_TOOL_NAME, ENGINE_MODEL_FLAG_NAME, resolveEngineModel, resolveEngineName, } from "./engine-detour.js";
20
18
  import { engineSessionMaterialFromOptions, engineSessionReadingMaterial, } from "./package-resources/engine-material.js";
@@ -36,14 +34,13 @@ import { projectDiaristSessions, projectDiaristTicketSessions, } from "./diarist
36
34
  import { commitDiaristProjection } from "./diarist.js";
37
35
  import { TicketProvenanceInputError } from "./ticket-provenance.js";
38
36
  import { GATEKEEPER_TOOL_SPEC, } from "./gatekeeper-role.js";
39
- import { NAVIGATOR_TOOL_SPEC, } from "./navigator-role.js";
40
37
  import { AUDITOR_TOOL_SPEC, } from "./auditor-role.js";
41
38
  import { auditedRunIdentityFromDirectory, auditedRunIdentityMaterial, } from "./audited-run-identity.js";
42
- import { formatNavigatorReport, NAVIGATOR_EVENT_TYPE, NAVIGATOR_ROUTE_PLAYBOOK_FAILURE_ENTRY, navigatorSubjectKey, navigatorUnavailableError, subjectPath } from "./navigator-attendance.js";
39
+ import { formatNavigatorReport, NAVIGATOR_EVENT_TYPE, subjectPath } from "./navigator-attendance.js";
43
40
  import { AK_ROLE_AUDITOR_SOURCE_RUN_ENV } from "./auditor-soul.js";
44
41
  import { buildNavigatorInfrastructureFailureFact, classifyPackagedRoleTerminalResult, packagedRoleOutputRejectionReason, extractInfrastructureFailureEvidence, NAVIGATOR_INVOCATION_ENTRY, resolveLifecycleInvocationPrincipal, } from "./navigator-invocation-identity.js";
45
42
  import { NAVIGATOR_POST_ROLE_GRACE_MS, raceNavigatorGrace } from "./public-cli/settlement.js";
46
- import { PACKAGED_ROLE_REGISTRY, packagedRoleActivationFlags, packagedRoleInputFlag, packagedRoleMetadata, packagedRoleOutputTool, packagedRolePhaseFlag, } from "./packaged-role-registry.js";
43
+ import { PACKAGED_ROLE_REGISTRY, isNavigatorSeat, packagedRoleActivationFlags, packagedRoleMetadata, packagedRoleOutputTool, packagedRolePhaseFlag, } from "./packaged-role-registry.js";
47
44
  import { createJudgeRoleRuntime, } from "./judge-role.js";
48
45
  import { createReviewerRoleRuntime, } from "./reviewer-role.js";
49
46
  /**
@@ -398,52 +395,6 @@ export function createGatekeeperRoleRuntime(roleHost, dependencies) {
398
395
  soulTag: "gatekeeper",
399
396
  }, dependencies);
400
397
  }
401
- /** #639: direct Navigator public seat on the shared filed-officer envelope. */
402
- export function createNavigatorRoleRuntime(roleHost, dependencies) {
403
- const base = createFiledOfficerRuntime(roleHost, {
404
- role: "navigator",
405
- tool: NAVIGATOR_TOOL_SPEC,
406
- soulTag: "navigator",
407
- }, dependencies);
408
- let playbookBound = false;
409
- return {
410
- async activate() {
411
- await base.activate();
412
- if (playbookBound)
413
- return;
414
- playbookBound = true;
415
- // Standing system prompt, not a per-turn user message. Native read failure
416
- // is the explanation (ADR 0061); no code-written sentence.
417
- const loadRoutePlaybook = dependencies.loadRoutePlaybook
418
- ?? (() => readPackageMaterial("resources/navigator-route-playbook.md"));
419
- let playbookRead;
420
- roleHost.on("before_agent_start", async (event, ctx) => {
421
- const basePrompt = typeof event.systemPrompt === "string" ? event.systemPrompt : "";
422
- const parts = [];
423
- try {
424
- playbookRead ??= loadRoutePlaybook();
425
- const content = await playbookRead;
426
- dependencies.recordRoutePlaybookReadFailure?.(undefined);
427
- if (content.trim() !== "")
428
- parts.push(content);
429
- }
430
- catch (error) {
431
- const message = errorText(error);
432
- if (message.trim() !== "") {
433
- dependencies.recordRoutePlaybookReadFailure?.(message);
434
- parts.push(message);
435
- }
436
- }
437
- if (parts.length === 0)
438
- return;
439
- const text = parts.join("\n\n");
440
- return {
441
- systemPrompt: basePrompt.trim() === "" ? text : `${basePrompt}\n\n${text}`,
442
- };
443
- });
444
- },
445
- };
446
- }
447
398
  /** #675: public 审刑院 seat on the shared filed-officer envelope. */
448
399
  export function createAuditorRoleRuntime(roleHost, dependencies) {
449
400
  return createFiledOfficerRuntime(roleHost, {
@@ -641,27 +592,6 @@ export function createCountersignRoleRuntime(roleHost, dependencies) {
641
592
  soulTag: "countersign",
642
593
  }, dependencies);
643
594
  }
644
- /**
645
- * #959: last assistant text parts as navigator prose exit.
646
- * Tool-call-only messages yield undefined — those already ride the tool path.
647
- */
648
- function lastAssistantProse(messages) {
649
- for (let index = messages.length - 1; index >= 0; index -= 1) {
650
- const message = messages[index];
651
- if (message?.role !== "assistant" || !Array.isArray(message.content))
652
- continue;
653
- const texts = [];
654
- for (const part of message.content) {
655
- if (part.type === "text" && typeof part.text === "string" && part.text.length > 0) {
656
- texts.push(part.text);
657
- }
658
- }
659
- if (texts.length === 0)
660
- continue;
661
- return texts.join("");
662
- }
663
- return undefined;
664
- }
665
595
  export function createRoleRuntimeExtension(dependencies,
666
596
  /**
667
597
  * Effective ceiling already resolved for this turn (#1132). Absent only on
@@ -721,7 +651,7 @@ deliveryRequestLimit) {
721
651
  let navigatorActivation = 0;
722
652
  let navigatorDeliveryClosed = false;
723
653
  let pendingNavigatorSettlement;
724
- let navigatorWorkContext;
654
+ let navigatorSubjectKey;
725
655
  let navigatorSessionParent;
726
656
  let navigatorCwd;
727
657
  /** toolCallId → fact+evidence; one-shot projected onto durable tool_result (#475). */
@@ -776,7 +706,7 @@ deliveryRequestLimit) {
776
706
  const attendance = navigatorAttendance;
777
707
  if (settlement === undefined || attendance === undefined)
778
708
  return;
779
- const workContext = navigatorWorkContext;
709
+ const subjectKey = navigatorSubjectKey;
780
710
  const pending = (async () => {
781
711
  // ADR 0052 / #959 / #1160: every settlement that waits on parallel prepare
782
712
  // (accepted, human_decision, role_infrastructure_failure) shares one grace
@@ -795,7 +725,6 @@ deliveryRequestLimit) {
795
725
  disposition: "unavailable",
796
726
  unavailableReason: "Navigator exceeded post-role delivery grace",
797
727
  unavailableSource: "unknown",
798
- unavailableCause: "unknown",
799
728
  };
800
729
  const event = {
801
730
  version: 1,
@@ -803,10 +732,9 @@ deliveryRequestLimit) {
803
732
  invocationId: "post-role-grace-timeout",
804
733
  role: settlement.role,
805
734
  phase: settlement.phase,
806
- subjectKey: workContext?.subjectKey ?? "",
735
+ subjectKey: subjectKey ?? "",
807
736
  unavailableReason: "Navigator exceeded post-role delivery grace",
808
737
  unavailableSource: "unknown",
809
- unavailableCause: "unknown",
810
738
  };
811
739
  pendingNavigatorPresentation = { event, report };
812
740
  }
@@ -861,30 +789,6 @@ deliveryRequestLimit) {
861
789
  ctx.sessionManager.appendCustomEntry?.(NOTARY_SESSION_BOUND_ENTRY, bound);
862
790
  }
863
791
  }
864
- if (navigatorAttendance !== undefined && navigatorWorkContext !== undefined && navigatorWorkContext.contextError === undefined) {
865
- // Flagged roles already have a concrete packet/task/case/review input.
866
- // A bare Judge (and other bare packaged entrypoint) gets its concrete
867
- // user task at this seam; do not copy the assembled system prompt.
868
- // Replacement is keyed by typed subject provenance, never prose prefixes.
869
- // Soft session_start placeholders (no materials yet) recover here; hard
870
- // contextError from true loader failures stays poisoned and honest.
871
- if (navigatorWorkContext.subjectProvenance === "placeholder") {
872
- // Navigator's own input bootstrap (#836): human prompt bytes key the
873
- // identity when nothing else has supplied a concrete subject yet.
874
- // Auto prepare stays identity-only — no subject/authority material copy.
875
- const subject = prompt.trim();
876
- if (subject !== "") {
877
- const root = subjectPath(ctx.sessionManager.getSessionDir(), ctx.cwd);
878
- const subjectProvenance = "user_prompt";
879
- navigatorWorkContext = {
880
- subjectKey: navigatorSubjectKey(root, subject, subjectProvenance),
881
- subjectProvenance,
882
- };
883
- await navigatorAttendance.setWorkContext(navigatorWorkContext);
884
- }
885
- }
886
- }
887
- navigatorAttendance?.prepare();
888
792
  // Reviewer parent prompt assembly.
889
793
  if (activeReviewerParent !== undefined && selectedRole === role) {
890
794
  return {
@@ -1006,49 +910,6 @@ deliveryRequestLimit) {
1006
910
  }
1007
911
  return;
1008
912
  }
1009
- const role = selectedRole ?? roleHost.getFlag(ROLE_FLAG.name);
1010
- // #959: navigator prose exit — final assistant text is the receipt.
1011
- // No typed-tool 催交; no JSON required. Tool path still wins when already accepted.
1012
- if (typeof role === "string"
1013
- && packagedRoleOutputTool(role) === NAVIGATOR_TOOL_SPEC.name
1014
- && receiptDelivery.nextAction() !== "accepted") {
1015
- const prose = lastAssistantProse(event.messages);
1016
- if (prose !== undefined && prose.trim() !== "") {
1017
- const accepted = { prose };
1018
- const toolCallId = `navigator-prose-exit:${randomUUID()}`;
1019
- await sealAcceptedSubmission({
1020
- context: ctx,
1021
- role: "navigator",
1022
- accepted,
1023
- toolCallId,
1024
- });
1025
- await projectClosedSubmission({ role: "navigator", kind: "accepted", accepted }, ctx, toolCallId);
1026
- return;
1027
- }
1028
- // Attended with neither tool nor prose → honest no_receipt (not typed 催交).
1029
- // Close the budget without sending prompts; the fact stays the real count.
1030
- if (!noReceiptRecorded) {
1031
- const runPointer = runDirectoryFromHostContext(ctx);
1032
- if (runPointer !== undefined) {
1033
- noReceiptRecorded = true;
1034
- receiptDelivery.closeBudget();
1035
- const facts = receiptDelivery.facts({
1036
- runPointer,
1037
- attemptPointer: receiptAttemptPointer(runPointer, ctx.invocationScopeId),
1038
- });
1039
- envelopeHost.appendEntry(NO_RECEIPT_LIFECYCLE_ENTRY_TYPE, facts);
1040
- sitianReportSafe({
1041
- level: "event",
1042
- kind: "no-receipt-lifecycle",
1043
- cwd: ctx.cwd,
1044
- sessionParent: ctx.sessionManager.getSessionFile(),
1045
- payload: facts,
1046
- source: "role-runtime",
1047
- });
1048
- }
1049
- }
1050
- return;
1051
- }
1052
913
  if (receiptDelivery.nextAction() === "request-delivery") {
1053
914
  receiptDelivery.recordDeliveryRequest();
1054
915
  // Keep the package-owned continuation off the public input lifecycle:
@@ -1196,14 +1057,6 @@ deliveryRequestLimit) {
1196
1057
  const gatekeeper = createGatekeeperRoleRuntime(roleHost, {
1197
1058
  loadSoul: () => requireRoleSoul("gatekeeper"),
1198
1059
  });
1199
- const navigator = createNavigatorRoleRuntime(roleHost, {
1200
- loadSoul: () => requireRoleSoul("navigator"),
1201
- recordRoutePlaybookReadFailure: (message) => {
1202
- envelopeHost.appendEntry(NAVIGATOR_ROUTE_PLAYBOOK_FAILURE_ENTRY, {
1203
- message: message ?? "",
1204
- });
1205
- },
1206
- });
1207
1060
  const auditor = createAuditorRoleRuntime(roleHost, {
1208
1061
  loadSoul: () => requireRoleSoul("auditor"),
1209
1062
  });
@@ -1301,7 +1154,7 @@ deliveryRequestLimit) {
1301
1154
  navigatorDeliveryClosed = false;
1302
1155
  pendingNavigatorSettlement = undefined;
1303
1156
  pendingInfrastructureFailures.clear();
1304
- navigatorWorkContext = undefined;
1157
+ navigatorSubjectKey = undefined;
1305
1158
  // #351: OAuth keepalive is orthogonal to --ak-role; start before role early-return
1306
1159
  // so role-less sessions (and reload after shutdown stop) still keep tokens alive.
1307
1160
  envelopeHost.startKeepalive(ctx);
@@ -1335,7 +1188,9 @@ deliveryRequestLimit) {
1335
1188
  "gleaner-left": () => gleanerLeft.activate(),
1336
1189
  inspector: () => inspector.activate(),
1337
1190
  gatekeeper: () => gatekeeper.activate(),
1338
- navigator: () => navigator.activate(),
1191
+ navigator: async () => {
1192
+ throw new Error("navigator is a table lookup (#1192); no host runtime serves it");
1193
+ },
1339
1194
  auditor: () => auditor.activate(),
1340
1195
  diarist: () => diarist.activate(),
1341
1196
  secretariat: () => secretariat.activate(),
@@ -1356,39 +1211,14 @@ deliveryRequestLimit) {
1356
1211
  }
1357
1212
  // Station children (court diarist, inner-gate summons) omit navigator sidecar (#840).
1358
1213
  // Top-level public entry legs still attend automatically.
1359
- // Navigator seat never re-attaches itself — prepare turns already ARE the navigator
1360
- // public activation (prevents summonPublicRole navigator ↔ attendance recursion).
1214
+ // The navigator seat never attends itself (summonPublicRole navigator ↔ attendance recursion).
1361
1215
  const isStationChild = roleHost.getFlag(STATION_CHILD_FLAG.name) === true;
1362
1216
  if (dependencies.createNavigatorAttendance !== undefined
1363
- && entry.outputTool !== NAVIGATOR_TOOL_SPEC.name
1217
+ && !isNavigatorSeat(entry.role)
1364
1218
  && !isStationChild) {
1365
1219
  navigatorSessionParent = ctx.sessionManager.getSessionFile();
1366
1220
  navigatorCwd = ctx.cwd;
1367
- let work;
1368
- let contextError;
1369
- if (dependencies.loadNavigatorWorkContext === undefined) {
1370
- const fallbackSubjectKey = subjectPath(ctx.sessionManager.getSessionDir(), ctx.cwd);
1371
- contextError = new Error("Navigator work context loader is not configured");
1372
- work = { subjectKey: fallbackSubjectKey, subjectProvenance: "placeholder" };
1373
- }
1374
- else {
1375
- try {
1376
- work = await dependencies.loadNavigatorWorkContext({
1377
- context: ctx,
1378
- role: entry.role,
1379
- phase: navigatorPhase(roleHost, entry.role),
1380
- getFlag: (name) => roleHost.getFlag(name),
1381
- });
1382
- contextError = work.contextError;
1383
- }
1384
- catch (error) {
1385
- // Contract: README.md#Navigator-attendance — a failed context load continues with a typed placeholder work context; the original cause is retained in contextError for the typed unavailable report.
1386
- contextError = navigatorUnavailableError("context", error);
1387
- const fallbackSubjectKey = subjectPath(ctx.sessionManager.getSessionDir(), ctx.cwd);
1388
- work = { subjectKey: fallbackSubjectKey, subjectProvenance: "placeholder" };
1389
- }
1390
- }
1391
- navigatorWorkContext = { ...work, ...(contextError === undefined ? {} : { contextError }) };
1221
+ navigatorSubjectKey = subjectPath(ctx.sessionManager.getSessionDir(), ctx.cwd);
1392
1222
  // Shared envelope owns exact invocation principal from admitted session lifecycle.
1393
1223
  // session_start is process activation: resume unfinished principal only when marker
1394
1224
  // role/phase/subjectKey still match; mint for contradictory marker, malformed nearest,
@@ -1398,7 +1228,7 @@ deliveryRequestLimit) {
1398
1228
  const lifecyclePrincipal = resolveLifecycleInvocationPrincipal(sessionEntries, {
1399
1229
  role: entry.role,
1400
1230
  phase: invocationPhase,
1401
- subjectKey: work.subjectKey,
1231
+ subjectKey: navigatorSubjectKey,
1402
1232
  });
1403
1233
  const invocationId = lifecyclePrincipal.invocationId;
1404
1234
  if (!lifecyclePrincipal.resume) {
@@ -1406,7 +1236,7 @@ deliveryRequestLimit) {
1406
1236
  invocationId,
1407
1237
  role: entry.role,
1408
1238
  phase: invocationPhase,
1409
- subjectKey: work.subjectKey,
1239
+ subjectKey: navigatorSubjectKey,
1410
1240
  };
1411
1241
  envelopeHost.appendEntry(NAVIGATOR_INVOCATION_ENTRY, data);
1412
1242
  sitianReportSafe({
@@ -1423,22 +1253,16 @@ deliveryRequestLimit) {
1423
1253
  context: ctx,
1424
1254
  role: entry.role,
1425
1255
  phase: invocationPhase,
1426
- subjectKey: work.subjectKey,
1256
+ subjectKey: navigatorSubjectKey,
1427
1257
  invocationId,
1428
- deliveryRequestLimit: deliveryLimit,
1429
- ...(contextError === undefined ? {} : { contextError }),
1430
1258
  onEvent: (navigatorEvent, report) => {
1431
1259
  if (activation === navigatorActivation && !navigatorDeliveryClosed) {
1432
1260
  pendingNavigatorPresentation = { event: navigatorEvent, report };
1433
1261
  }
1434
1262
  },
1435
1263
  });
1436
- // Concrete work context starts parallel prepare (model runs now; #1160).
1437
- // Placeholder subjects wait for before_agent_start (user prompt may replace the subject key).
1438
- if (navigatorWorkContext.contextError === undefined &&
1439
- navigatorWorkContext.subjectProvenance !== "placeholder") {
1440
- navigatorAttendance.prepare();
1441
- }
1264
+ // The lookup starts with the parent role (#1160 / #1192).
1265
+ navigatorAttendance.prepare();
1442
1266
  }
1443
1267
  await executeActivationStage(entry.role, activationStage(entry.role, activateByRole), { clock, writeTrace });
1444
1268
  // #1171: same registration mouth as submission tools; when-to-call is on the tool itself.
@@ -7,7 +7,7 @@ import { findRunDirectoryById } from "./public-cli/run-lifecycle.js";
7
7
  import { isCorrectableExecuteError } from "./submission-correctable-error.js";
8
8
  import { reportTicketFromHostContext } from "./report-ticket-tool.js";
9
9
  import { readDeclaredTicketNumber } from "./run-ticket-number.js";
10
- import { captureWorktreeHead, landTicketProgressForSealedSubmission, } from "./ticket-progress.js";
10
+ import { captureWorktreeHead, landTicketProgress, landTicketProgressForSealedSubmission, } from "./ticket-progress.js";
11
11
  import { isRecord, errorText } from "./unknown-value.js";
12
12
  /**
13
13
  * Admitted run identity for the ledger subject.
@@ -293,17 +293,19 @@ function homeFromHostContext(context, home) {
293
293
  return sessionParent !== undefined ? tryHomeFromAkRolesPath(sessionParent) : undefined;
294
294
  }
295
295
  /**
296
- * #959: seal one accepted submission without a model tool call.
297
- * Same ledger row shape as the terminating-tool wrap.
298
- * Used when a prose-exit seat (navigator) harvests the final assistant text.
296
+ * #1192: seal one accepted submission without a model tool call or host session
297
+ * (the navigator lookup run). Same sealed ledger event and the same original
298
+ * receipt / progress landing as the terminating-tool wrap; the progress line
299
+ * names no session because the run has none.
299
300
  */
300
- export async function sealAcceptedSubmission(options) {
301
- const runId = runIdentity(options.context);
302
- const attemptId = attemptIdentity(options.context, runId);
303
- const sessionParent = sessionParentFromHostContext(options.context);
304
- const home = homeFromHostContext(options.context, options.home);
305
- // #1199: same seal-time HEAD + progress landing as the terminating-tool wrap.
306
- const sealHead = captureWorktreeHead(options.context.cwd);
301
+ export function sealAcceptedSubmission(options) {
302
+ const runId = runIdFromRunDirectory(options.runDirectory);
303
+ if (runId === undefined)
304
+ throw new Error("提交账需要已受理的 run 身份");
305
+ const attemptId = options.courtAttemptId ?? `${runId}:initial`;
306
+ const sealHead = captureWorktreeHead(options.cwd);
307
+ const sessionParent = sessionFileOf(options.runDirectory);
308
+ const home = options.home ?? tryHomeFromAkRolesPath(sessionParent);
307
309
  sitianReport({
308
310
  level: "event",
309
311
  kind: "sealed",
@@ -316,15 +318,17 @@ export async function sealAcceptedSubmission(options) {
316
318
  accepted: options.accepted,
317
319
  },
318
320
  source: "role-runtime",
319
- cwd: options.context.cwd,
321
+ cwd: options.cwd,
320
322
  ...(home !== undefined ? { home } : {}),
321
- ...(sessionParent === undefined ? {} : { sessionParent }),
323
+ sessionParent,
322
324
  });
323
- landTicketProgressForSealedSubmission({
324
- context: options.context,
325
+ landTicketProgress({
326
+ runDirectory: options.runDirectory,
325
327
  role: options.role,
326
328
  accepted: options.accepted,
327
329
  sealHead,
330
+ sessionFile: undefined,
331
+ instruction: options.instruction ?? "",
328
332
  });
329
333
  }
330
334
  /**
@@ -197,6 +197,25 @@ export function landTicketProgressForSealedSubmission(input) {
197
197
  const runDirectory = runDirectoryFromHostContext(input.context);
198
198
  if (runDirectory === undefined)
199
199
  return undefined;
200
+ return landTicketProgress({
201
+ runDirectory,
202
+ role: input.role,
203
+ accepted: input.accepted,
204
+ sealHead: input.sealHead,
205
+ ...(input.lens === undefined ? {} : { lens: input.lens }),
206
+ sessionFile: progressSessionAbsolute(runDirectory, input.context),
207
+ instruction: typeof input.context.summonsInstruction === "string"
208
+ ? input.context.summonsInstruction
209
+ : "",
210
+ });
211
+ }
212
+ /**
213
+ * Original receipt plus progress line for one sealed submission.
214
+ * `sessionFile` is absent for a run that never had a host session (the
215
+ * navigator lookup, #1192): the line then names no session.
216
+ */
217
+ export function landTicketProgress(input) {
218
+ const { runDirectory } = input;
200
219
  const subjectDirectory = subjectDirectoryOfRun(runDirectory);
201
220
  if (subjectDirectory === undefined)
202
221
  return undefined;
@@ -225,12 +244,11 @@ export function landTicketProgressForSealedSubmission(input) {
225
244
  : readTicketProgressLines(subjectDirectory);
226
245
  // Unbound: round stays empty until whole-leg bind publishes into ticket current.
227
246
  const round = unbound ? "" : nextRoundFromLines(existing, input.role, lens);
228
- const sessionFile = progressSessionAbsolute(runDirectory, input.context);
229
- const sessionRelative = relative(subjectDirectory, sessionFile).split(sep).join("/");
247
+ const sessionRelative = input.sessionFile === undefined
248
+ ? ""
249
+ : relative(subjectDirectory, input.sessionFile).split(sep).join("/");
230
250
  const { status, summary } = statusAndSummaryFromPayload(input.role, input.accepted);
231
- const instruction = typeof input.context.summonsInstruction === "string"
232
- ? input.context.summonsInstruction
233
- : "";
251
+ const instruction = input.instruction;
234
252
  const line = {
235
253
  at: new Date().toISOString(),
236
254
  seat: input.role,
@@ -11,10 +11,6 @@ import {
11
11
  } from "@earendil-works/pi-coding-agent";
12
12
  import type { Message } from "@earendil-works/pi-ai";
13
13
 
14
- import {
15
- registerNavigatorModelCommand,
16
- } from "../src/navigator-attendance.ts";
17
- import { loadNavigatorWorkContext as loadHostNeutralNavigatorWorkContext } from "../src/navigator-work-context.ts";
18
14
  import { JUDGE_OUTPUT_TOOL_NAME } from "../src/package-contracts/judge-output.ts";
19
15
  import { readOAuthKeepaliveProviders } from "../src/oauth-keepalive.ts";
20
16
  import {
@@ -53,17 +49,6 @@ export function transcriptFromContext(ctx: ExtensionContext): string {
53
49
  );
54
50
  }
55
51
 
56
- export async function loadNavigatorWorkContext(
57
- pi: Pick<ExtensionAPI, "getFlag">,
58
- options: { context: ExtensionContext | import("../src/host-contracts.ts").HostContext; role: string },
59
- ) {
60
- return loadHostNeutralNavigatorWorkContext({
61
- context: options.context as import("../src/host-contracts.ts").HostContext,
62
- role: options.role,
63
- getFlag: (name) => pi.getFlag(name),
64
- });
65
- }
66
-
67
52
  /** Pi extension deps are the shared packaged factory. Host flags stay on the envelope. */
68
53
  export function createPiRoleRuntimeDependencies(
69
54
  _pi: ExtensionAPI,
@@ -73,7 +58,6 @@ export function createPiRoleRuntimeDependencies(
73
58
 
74
59
  export default function roleRuntime(pi: ExtensionAPI): void {
75
60
  const oauthKeepaliveProviders = readOAuthKeepaliveProviders();
76
- registerNavigatorModelCommand(pi);
77
61
  createPiRoleRuntimeExtension(createPiRoleRuntimeDependencies(pi), {
78
62
  transcriptFromContext,
79
63
  oauthKeepalive: { providers: oauthKeepaliveProviders },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akagilnc/pi-workflow-roles",
3
- "version": "0.1.5845",
3
+ "version": "0.1.5853",
4
4
  "description": "Soul-bound workflow roles for Pi",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -10,14 +10,10 @@ const entries = [
10
10
  // Static import of navigator-invocation-identity (#603: non-bundle graph closure).
11
11
  "uuidv7",
12
12
  "navigator-attendance",
13
- // Navigator package-graph dependencies used by attendance settlement.
14
- // navigator-session-contracts is a static import of the published attendance root
15
- // (#590: published non-bundle graph must stay closed under its own relative edges).
16
- "navigator-public-session",
17
- // Static import of navigator-public-session (sitianReportSafe).
13
+ // Static import of navigator-attendance: the lookup (summons the navigator run)
14
+ // and the package-relative modules it reaches (#590 closure).
15
+ "navigator-lookup",
18
16
  "host-session-record",
19
- "navigator-session-contracts",
20
- // Static import of navigator-attendance and navigator-public-session.
21
17
  "atomic-write",
22
18
  "public-role-summons",
23
19
  "activation-ledger-git",