@akagilnc/pi-workflow-roles 0.1.4321 → 0.1.4387

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 (71) hide show
  1. package/README.md +4 -1
  2. package/README.zh-CN.md +5 -1
  3. package/dist/acp-host/production-host.js +1308 -587
  4. package/dist/doctor-contracts.js +2 -2
  5. package/dist/engine-detour-tool.js +2 -8
  6. package/dist/gatekeeper-role.js +4 -19
  7. package/dist/headless-host/production-host.js +2613 -1892
  8. package/dist/merger-contracts.js +2 -2
  9. package/dist/migrate-book-topology.js +34 -9
  10. package/dist/notary-contracts.js +2 -2
  11. package/dist/package-contracts/auditor-output.js +2 -2
  12. package/dist/package-contracts/fixer-output.js +2 -2
  13. package/dist/package-contracts/gatekeeper-output.js +2 -2
  14. package/dist/package-contracts/navigator-output.js +2 -2
  15. package/dist/package-contracts/terminating-infrastructure.js +7 -2
  16. package/dist/package-contracts/terminating-tools.js +6 -0
  17. package/dist/packaged-role-registry.js +20 -1
  18. package/dist/public-cli/case-dossier-delivery.js +45 -28
  19. package/dist/public-cli/countersign-run.js +439 -0
  20. package/dist/public-cli/invocation.js +10 -0
  21. package/dist/public-cli/main.js +388 -101
  22. package/dist/public-cli/option-definitions.js +14 -0
  23. package/dist/public-cli/post-admission.js +44 -49
  24. package/dist/public-cli/run-lifecycle.js +13 -1
  25. package/dist/public-cli/settlement.js +14 -53
  26. package/dist/public-role-summons.js +14 -0
  27. package/dist/secretariat-contracts.js +8 -0
  28. package/dist/sitian-appender.js +21 -4
  29. package/extensions/role-runtime.ts +1 -0
  30. package/package.json +1 -1
  31. package/scripts/build-package.mjs +1 -0
  32. package/souls/secretariat.md +26 -0
  33. package/souls/ticket-law.md +9 -0
  34. package/src/collector-tool-schemas.ts +2 -2
  35. package/src/countersign-role.ts +2 -2
  36. package/src/diarist-role.ts +2 -2
  37. package/src/doctor-contracts.ts +2 -2
  38. package/src/engine-detour-tool.ts +3 -9
  39. package/src/gatekeeper-pass-envelope.ts +35 -2
  40. package/src/gatekeeper-role.ts +8 -31
  41. package/src/gleaner-left-role.ts +2 -2
  42. package/src/host-contracts.ts +2 -1
  43. package/src/inspector-role.ts +2 -2
  44. package/src/judge-role.ts +2 -2
  45. package/src/merger-contracts.ts +2 -2
  46. package/src/notary-contracts.ts +2 -2
  47. package/src/package-contracts/auditor-output.ts +2 -2
  48. package/src/package-contracts/fixer-output.ts +2 -2
  49. package/src/package-contracts/gatekeeper-output.ts +2 -2
  50. package/src/package-contracts/navigator-output.ts +2 -2
  51. package/src/package-contracts/terminating-infrastructure.ts +13 -3
  52. package/src/package-contracts/terminating-tools.ts +9 -1
  53. package/src/packaged-role-registry.ts +20 -1
  54. package/src/public-cli/case-dossier-delivery.ts +48 -29
  55. package/src/public-cli/cli.ts +10 -0
  56. package/src/public-cli/countersign-run.ts +29 -5
  57. package/src/public-cli/invocation.ts +28 -2
  58. package/src/public-cli/option-definitions.ts +17 -0
  59. package/src/public-cli/post-admission.ts +45 -58
  60. package/src/public-cli/run-lifecycle.ts +29 -2
  61. package/src/public-cli/secretariat-run.ts +266 -0
  62. package/src/public-cli/settlement.ts +31 -55
  63. package/src/public-cli/terminal.ts +2 -1
  64. package/src/public-role-summons.ts +23 -1
  65. package/src/reviewer-role.ts +2 -2
  66. package/src/role-runtime-dependencies.ts +1 -0
  67. package/src/role-runtime.ts +203 -18
  68. package/src/secretariat-contracts.ts +27 -0
  69. package/src/secretariat-role.ts +210 -0
  70. package/src/sitian-appender.ts +36 -3
  71. package/src/worker-role.ts +2 -2
@@ -105,7 +105,7 @@ export function buildCountersignTurnRequest(
105
105
  }
106
106
 
107
107
  /** 起居郎 identity outcome — escalate stays distinct from missing terminal. */
108
- type CourtDiaristIdentity =
108
+ export type CourtDiaristIdentity =
109
109
  | {
110
110
  readonly kind: "ticket";
111
111
  readonly ticketNumber: number;
@@ -119,11 +119,23 @@ type CourtDiaristIdentity =
119
119
  | { readonly kind: "unbound" }
120
120
  | { readonly kind: "escalate" };
121
121
 
122
- type CourtDiaristInvocationResult = {
122
+ export type CourtDiaristInvocationResult = {
123
123
  readonly identity: CourtDiaristIdentity;
124
124
  readonly failedWithoutEscalate?: { readonly diagnostic: string };
125
125
  };
126
126
 
127
+ /** Env slice shared by court diarist identity summons (countersign / secretariat). */
128
+ export type CourtDiaristSummonEnv = Pick<
129
+ CountersignRunEnv,
130
+ | "cwd"
131
+ | "home"
132
+ | "agentDir"
133
+ | "packageRoot"
134
+ | "credentials"
135
+ | "signal"
136
+ | "hostAdapters"
137
+ >;
138
+
127
139
  /**
128
140
  * Read #871 set from preserved diarist payloads.
129
141
  * - Field absent / null / non-array → undefined (no new set; resume keeps store).
@@ -191,13 +203,16 @@ function courtDiaristEscalated(roleOutcome: TerminalRoleOutcome | undefined): bo
191
203
  * When `boundTicketNumber` is set (typed handoff from countersign), diarist
192
204
  * binds under that key before the turn — never mechanical recognition from prose.
193
205
  */
194
- async function invokeCourtDiarist(input: {
206
+ export async function invokeCourtDiarist(input: {
195
207
  readonly instruction: string;
196
208
  readonly projectRoot: string;
197
209
  readonly failureLabel: string;
210
+ readonly attachmentPaths?: readonly string[];
211
+ /** Direct parent run id for durable child lineage (ADR 0010). */
212
+ readonly correlationId?: string;
198
213
  /** Already-verified typed key from countersign (refresh / post-assert handoff). */
199
214
  readonly boundTicketNumber?: number;
200
- }, env: CountersignRunEnv, io: CliIo): Promise<CourtDiaristInvocationResult> {
215
+ }, env: CourtDiaristSummonEnv, io: CliIo): Promise<CourtDiaristInvocationResult> {
201
216
  // Quiet face: the countersign caller must not see diarist CLI chatter.
202
217
  const quietIo: CliIo = {
203
218
  stdout() {},
@@ -210,7 +225,13 @@ async function invokeCourtDiarist(input: {
210
225
  const { summonPublicRole } = await import("../public-role-summons.ts");
211
226
  const result = await summonPublicRole({
212
227
  role: "diarist",
213
- argv: ["--project", input.projectRoot, input.instruction],
228
+ argv: [
229
+ "--project",
230
+ input.projectRoot,
231
+ ...(input.attachmentPaths ?? []).flatMap((path) => ["--attach", path]),
232
+ "--",
233
+ input.instruction,
234
+ ],
214
235
  cwd: env.cwd,
215
236
  home: env.home,
216
237
  agentDir: env.agentDir,
@@ -218,6 +239,7 @@ async function invokeCourtDiarist(input: {
218
239
  io: quietIo,
219
240
  ...(env.credentials === undefined ? {} : { credentials: env.credentials }),
220
241
  ...(env.signal === undefined ? {} : { signal: env.signal }),
242
+ ...(input.correlationId === undefined ? {} : { correlationId: input.correlationId }),
221
243
  ...(input.boundTicketNumber === undefined
222
244
  ? {}
223
245
  : { boundTicketNumber: input.boundTicketNumber }),
@@ -312,6 +334,7 @@ export async function runCountersignCourtDiaristStation(
312
334
  instruction: `整理 #${ticketNumber} 的本案依据。`,
313
335
  projectRoot: admitted.projectRoot,
314
336
  failureLabel: `ticket #${ticketNumber}`,
337
+ correlationId: admitted.runId,
315
338
  // Refresh holds a typed key — hand it off so identity is bound before turn.
316
339
  boundTicketNumber: ticketNumber,
317
340
  },
@@ -391,6 +414,7 @@ export async function runPublicCountersign(
391
414
  instruction: parsed.instruction,
392
415
  projectRoot: admitted.projectRoot,
393
416
  failureLabel: "unbound summons",
417
+ correlationId: admitted.runId,
394
418
  },
395
419
  env,
396
420
  io,
@@ -179,6 +179,10 @@ export type AdmittedDiaristInvocation = AdmittedRoleInvocationBase & {
179
179
  readonly role: "diarist";
180
180
  };
181
181
 
182
+ export type AdmittedSecretariatInvocation = AdmittedRoleInvocationBase & {
183
+ readonly role: "secretariat";
184
+ };
185
+
182
186
  export type CoderPhase = "plan" | "apply";
183
187
 
184
188
  export type AdmittedCoderInvocation = AdmittedRoleInvocationBase & {
@@ -266,6 +270,7 @@ export type AdmittedRoleInvocation =
266
270
  | AdmittedNavigatorInvocation
267
271
  | AdmittedAuditorInvocation
268
272
  | AdmittedDiaristInvocation
273
+ | AdmittedSecretariatInvocation
269
274
  | AdmittedCoderInvocation
270
275
  | AdmittedFixerInvocation
271
276
  | AdmittedCollectorInvocation
@@ -769,7 +774,7 @@ export function parsePositiveTicketNumber(
769
774
  /** 共享解析体:同形 owner 的 argv → instruction/attachments/project。 */
770
775
  function parseInstructionArgv(
771
776
  args: readonly string[],
772
- owner: "judge" | "countersign" | "inspector" | "gatekeeper" | "navigator" | "auditor" | "diarist",
777
+ owner: "judge" | "countersign" | "inspector" | "gatekeeper" | "navigator" | "auditor" | "diarist" | "secretariat",
773
778
  ): ParseInstructionArgvResult {
774
779
  const attachmentPaths: string[] = [];
775
780
  let project: string | undefined;
@@ -1033,6 +1038,12 @@ export function parseDiaristArgv(args: readonly string[]): ParseDiaristArgvResul
1033
1038
  return parseInstructionArgv(args, "diarist");
1034
1039
  }
1035
1040
 
1041
+ export type ParseSecretariatArgvResult = ParseInstructionArgvResult;
1042
+
1043
+ export function parseSecretariatArgv(args: readonly string[]): ParseSecretariatArgvResult {
1044
+ return parseInstructionArgv(args, "secretariat");
1045
+ }
1046
+
1036
1047
  /**
1037
1048
  * Parse Coder-specific argv after the `coder` token.
1038
1049
  * Phase defaults to apply; spellings from PUBLIC_OPTION_TABLE.coder (#342).
@@ -1241,6 +1252,7 @@ export type AdmitInspectorInvocationOptions = AdmitJudgeInvocationOptions & {
1241
1252
  export type AdmitGatekeeperInvocationOptions = AdmitInspectorInvocationOptions;
1242
1253
  export type AdmitNavigatorInvocationOptions = AdmitInspectorInvocationOptions;
1243
1254
  export type AdmitDiaristInvocationOptions = AdmitInspectorInvocationOptions;
1255
+ export type AdmitSecretariatInvocationOptions = AdmitInspectorInvocationOptions;
1244
1256
 
1245
1257
  /**
1246
1258
  * Shared instruction-seat admission for Judge and Inspector: project check,
@@ -1249,7 +1261,7 @@ export type AdmitDiaristInvocationOptions = AdmitInspectorInvocationOptions;
1249
1261
  * Ticket binding is post-admission via shared seat LLM path (#635).
1250
1262
  */
1251
1263
  async function admitStandardMaterialInvocation<
1252
- R extends "judge" | "inspector" | "gatekeeper" | "navigator" | "auditor" | "diarist",
1264
+ R extends "judge" | "inspector" | "gatekeeper" | "navigator" | "auditor" | "diarist" | "secretariat",
1253
1265
  >(
1254
1266
  role: R,
1255
1267
  options: AdmitInspectorInvocationOptions,
@@ -1393,6 +1405,13 @@ export async function admitDiaristInvocation(
1393
1405
  return admitStandardMaterialInvocation("diarist", options);
1394
1406
  }
1395
1407
 
1408
+ /** Admit a public Secretariat (中书省) run (#924). */
1409
+ export async function admitSecretariatInvocation(
1410
+ options: AdmitSecretariatInvocationOptions,
1411
+ ): Promise<AdmittedSecretariatInvocation> {
1412
+ return admitStandardMaterialInvocation("secretariat", options);
1413
+ }
1414
+
1396
1415
  /** Shared prompt transport for instruction-seat roles (judge/countersign/inspector). */
1397
1416
  export function buildInstructionTransportPrompt(
1398
1417
  admitted: { instruction: string; instructionEmpty: boolean; attachments: readonly { frozenPath: string }[] },
@@ -1417,6 +1436,13 @@ export function buildJudgeTransportPrompt(
1417
1436
  return buildInstructionTransportPrompt(admitted, engineMaterial);
1418
1437
  }
1419
1438
 
1439
+ export function buildSecretariatTransportPrompt(
1440
+ admitted: AdmittedSecretariatInvocation,
1441
+ engineMaterial?: EngineSessionMaterial,
1442
+ ): string {
1443
+ return buildInstructionTransportPrompt(admitted, engineMaterial);
1444
+ }
1445
+
1420
1446
  export function buildInspectorTransportPrompt(
1421
1447
  admitted: AdmittedInspectorInvocation,
1422
1448
  engineMaterial?: EngineSessionMaterial,
@@ -36,6 +36,7 @@ export type OptionOwner =
36
36
  | "navigator"
37
37
  | "auditor"
38
38
  | "diarist"
39
+ | "secretariat"
39
40
  | "analyst";
40
41
 
41
42
  /**
@@ -467,6 +468,11 @@ const DIARIST_OPTIONS = [
467
468
  bindOwner("diarist", SHARED_ATTACH_SEMANTICS),
468
469
  ] as const satisfies readonly PublicOptionDefinition[];
469
470
 
471
+ const SECRETARIAT_OPTIONS = [
472
+ bindOwner("secretariat", SHARED_PROJECT_SEMANTICS),
473
+ bindOwner("secretariat", SHARED_ATTACH_SEMANTICS),
474
+ ] as const satisfies readonly PublicOptionDefinition[];
475
+
470
476
  const CODER_OPTIONS = [
471
477
  {
472
478
  id: "phase",
@@ -841,6 +847,7 @@ export const PUBLIC_OPTION_TABLE = {
841
847
  navigator: NAVIGATOR_OPTIONS,
842
848
  auditor: AUDITOR_OPTIONS,
843
849
  diarist: DIARIST_OPTIONS,
850
+ secretariat: SECRETARIAT_OPTIONS,
844
851
  analyst: ANALYST_OPTIONS,
845
852
  } as const satisfies Record<OptionOwner, readonly PublicOptionDefinition[]>;
846
853
 
@@ -863,6 +870,7 @@ export const PUBLIC_ROLE_OPTION_OWNERS = [
863
870
  "navigator",
864
871
  "auditor",
865
872
  "diarist",
873
+ "secretariat",
866
874
  "analyst",
867
875
  ] as const satisfies readonly PublicRoleOptionOwner[];
868
876
 
@@ -1280,6 +1288,15 @@ const ROLE_COMMAND_HELP = {
1280
1288
  'ak-role diarist --attach ./design.md "补录本轮设计修订。"',
1281
1289
  ],
1282
1290
  },
1291
+ secretariat: {
1292
+ command: "secretariat",
1293
+ summary:
1294
+ "Secretariat (中书省): rewrite ticket per 票面法 and drive countersign to converged or escalate.",
1295
+ usage: ["ak-role secretariat [options] [instruction]"],
1296
+ examples: [
1297
+ 'ak-role secretariat "整理 #924 票面并送庭。"',
1298
+ ],
1299
+ },
1283
1300
  notary: {
1284
1301
  command: "notary",
1285
1302
  summary: "Direct Notary document check (quote fidelity + ticket alignment); zero prompt/attachment.",
@@ -18,9 +18,11 @@ import {
18
18
  import { CliUsageError } from "./cli-errors.ts";
19
19
  import type { RoleTurnRequestProjectionOptions } from "./turn-request.ts";
20
20
  import {
21
+ bindAdmittedTicketNumber,
21
22
  buildInstructionTransportPrompt,
22
23
  freezeAttachmentsIntoRun,
23
24
  } from "./invocation.ts";
25
+ import { readRecordedSubmissionRows } from "../submission-ledger.ts";
24
26
  import { pathContainedIn } from "../activation-ledger-topology.ts";
25
27
  import { pickEngineAxis } from "../package-resources/engine-material.ts";
26
28
  import { resolveHostAwareSessionAvailability } from "../session-identity.ts";
@@ -29,7 +31,6 @@ import type {
29
31
  ControlledFailureCause,
30
32
  DurablePrincipal,
31
33
  DurablePrincipalAuthority,
32
- RoleTurnContinuation,
33
34
  RoleTurnHost,
34
35
  RoleTurnKnownFailure,
35
36
  RoleTurnRequest,
@@ -37,10 +38,7 @@ import type {
37
38
  SessionCustomEntryAppender,
38
39
  } from "../host-contracts.ts";
39
40
  import { isOfficerReviewSeat } from "../host-contracts.ts";
40
- import {
41
- deliverCaseDossierAsAttachment,
42
- projectCaseDossierPointerSection,
43
- } from "./case-dossier-delivery.ts";
41
+ import { deliverCaseDossierAsAttachment } from "./case-dossier-delivery.ts";
44
42
 
45
43
  /** Original error bytes, never relabeled — a secondary fact riding beside a classified cause. */
46
44
  function describeCaughtError(error: unknown): { name?: string; message: string; code?: string | number } {
@@ -51,17 +49,6 @@ function describeCaughtError(error: unknown): { name?: string; message: string;
51
49
  return { message: String(error) };
52
50
  }
53
51
 
54
- /** Append one system section to a continuation prompt, keeping its kind. */
55
- function appendContinuationSection(
56
- continuation: RoleTurnContinuation,
57
- section: string,
58
- ): RoleTurnContinuation {
59
- const prompt = `${continuation.prompt}\n\n${section}`;
60
- return continuation.kind === "initial"
61
- ? { kind: "initial", prompt }
62
- : { kind: "resume", prompt };
63
- }
64
-
65
52
  /**
66
53
  * Nested gate summons (station child) on an officer seat: dialogue content is
67
54
  * peer words only (#879). ADR 0081 case dossier still hangs via the existing
@@ -592,10 +579,32 @@ export async function dispatchPostAdmissionTurn<
592
579
  */
593
580
  let afterDispatchApplied = false;
594
581
  const finishAfterTurn = async (result: DispatchOutcome): Promise<DispatchOutcome> => {
595
- if (adapters.afterDispatch === undefined || afterDispatchApplied) return result;
582
+ if (afterDispatchApplied) return result;
596
583
  afterDispatchApplied = true;
597
584
  try {
598
- await adapters.afterDispatch(admitted, lease);
585
+ // #858: an unbound seat may assert its ticket on the existing receipt.
586
+ // Read the original accepted payload; do not rewrite it, infer from prose,
587
+ // or reject missing/malformed declarations. An existing binding wins.
588
+ if (admitted.ticketNumber === undefined) {
589
+ const rows = await readRecordedSubmissionRows(
590
+ admitted.projectRoot,
591
+ admitted.runId,
592
+ { home: homeFromRunDirectory(admitted.runDirectory), sessionParent: join(admitted.runDirectory, "session", "session.jsonl") },
593
+ );
594
+ const asserted = rows
595
+ .filter((row) => row.kind === "accepted" && row.role === admitted.role)
596
+ .map((row) => row.accepted)
597
+ .find((payload) => {
598
+ if (payload === null || typeof payload !== "object" || Array.isArray(payload)) return false;
599
+ const value = (payload as { ticketNumber?: unknown }).ticketNumber;
600
+ return typeof value === "number" && Number.isSafeInteger(value) && value > 0;
601
+ });
602
+ const ticketNumber = asserted === undefined
603
+ ? undefined
604
+ : (asserted as { ticketNumber: number }).ticketNumber;
605
+ if (ticketNumber !== undefined) await bindAdmittedTicketNumber(admitted, ticketNumber);
606
+ }
607
+ if (adapters.afterDispatch !== undefined) await adapters.afterDispatch(admitted, lease);
599
608
  return result;
600
609
  } catch (error) {
601
610
  const primaryFailure =
@@ -728,10 +737,11 @@ export async function dispatchPostAdmissionTurn<
728
737
 
729
738
  // Turn request is assembled after beforeDispatch so this turn sees whatever it
730
739
  // settled — the seat's ticket bind re-projection and any court diarist station
731
- // writes (#742). Case dossier delivery (ADR 0081 / #709) rides here once for
732
- // every public entry. #879: station-child officer dialogue keeps peer body
733
- // intact — 起居录 hangs via existing attachments freeze (not prompt wrap,
734
- // not RoleTurnRequest.materials). Other entries keep the neutral prompt section.
740
+ // writes (#742). Case dossier delivery (ADR 0081 / #709 / #858) rides here once
741
+ // for every public entry on the existing attachments → readingMaterial face
742
+ // (station-child and ordinary share one seam). Dialogue continuation stays
743
+ // caller/peer opaque — never splice system path sections into user dialogue.
744
+ // No package-resume parallel face or typed resume identity.
735
745
  let turnRequest: RoleTurnRequest =
736
746
  env.signal === undefined ? request : { ...request, signal: env.signal };
737
747
  if (env.stationChild !== undefined) {
@@ -745,34 +755,16 @@ export async function dispatchPostAdmissionTurn<
745
755
  if (typeof liveHost === "string" && liveHost.trim() !== "") {
746
756
  turnRequest = { ...turnRequest, host: liveHost.trim() };
747
757
  }
748
- if (isStationChildOfficerDialogue(admitted.role, env)) {
749
- // 0081 non-body face: freeze pointer section under run/attachments/.
750
- // Peer dialogue continuation.prompt stays parent payload only — the seat
751
- // consumes the freeze via loadCaseDossierReadingMaterial → existing
752
- // agent-start readingMaterial / systemPrompt.materials fold (not prompt splice,
753
- // not RoleTurnRequest.materials).
754
- await deliverCaseDossierAsAttachment({
755
- ticketNumber: admitted.ticketNumber,
756
- projectRoot: admitted.projectRoot,
757
- home: env.home,
758
- runDirectory: admitted.runDirectory,
759
- });
760
- } else {
761
- const dossierSection = await projectCaseDossierPointerSection({
762
- ticketNumber: admitted.ticketNumber,
763
- projectRoot: admitted.projectRoot,
764
- home: env.home,
765
- });
766
- if (dossierSection !== undefined) {
767
- turnRequest = {
768
- ...turnRequest,
769
- continuation: appendContinuationSection(
770
- turnRequest.continuation,
771
- dossierSection,
772
- ),
773
- };
774
- }
775
- }
758
+ // 0081 non-dialogue face: freeze pointer section under run/attachments/.
759
+ // Seat consumes via loadCaseDossierReadingMaterial → existing agent-start
760
+ // readingMaterial / systemPrompt.materials fold. Caller instruction, empty
761
+ // request, and resume --message stay verbatim.
762
+ await deliverCaseDossierAsAttachment({
763
+ ticketNumber: admitted.ticketNumber,
764
+ projectRoot: admitted.projectRoot,
765
+ home: env.home,
766
+ runDirectory: admitted.runDirectory,
767
+ });
776
768
 
777
769
  // Authoritative host write happens here, at the real dispatch boundary —
778
770
  // immediately before the turn actually starts, after every retryable
@@ -1246,9 +1238,9 @@ export function resumeTurnRequestProjectionOptions(
1246
1238
  ...(env.model === undefined ? {} : { model: env.model }),
1247
1239
  ...pickEngineAxis(env),
1248
1240
  ...(env.timeoutMs === undefined ? {} : { timeoutMs: env.timeoutMs }),
1249
- ...(admitted.correlationId === undefined && env.correlationId === undefined
1241
+ ...(env.correlationId === undefined && admitted.correlationId === undefined
1250
1242
  ? {}
1251
- : { correlationId: admitted.correlationId ?? env.correlationId }),
1243
+ : { correlationId: env.correlationId ?? admitted.correlationId }),
1252
1244
  continuation: {
1253
1245
  kind: "resume",
1254
1246
  prompt,
@@ -1534,12 +1526,7 @@ export async function runPostAdmissionSeatResume<
1534
1526
  dispatch: async (turnRequest) => {
1535
1527
  const result = await dispatchPostAdmissionTurn({
1536
1528
  admitted: loaded.admitted,
1537
- env: {
1538
- ...input.env,
1539
- ...(loaded.admitted.correlationId === undefined
1540
- ? {}
1541
- : { correlationId: loaded.admitted.correlationId }),
1542
- },
1529
+ env: input.env,
1543
1530
  io: attemptIo,
1544
1531
  request: turnRequest,
1545
1532
  lease,
@@ -107,7 +107,8 @@ export type RoleRunRecord = {
107
107
  | "gatekeeper"
108
108
  | "navigator"
109
109
  | "auditor"
110
- | "diarist";
110
+ | "diarist"
111
+ | "secretariat";
111
112
  readonly state: RoleRunState;
112
113
  readonly bookKey: string;
113
114
  readonly projectRoot: string;
@@ -369,7 +370,8 @@ async function readRoleRunStateDisk(
369
370
  record.role !== "gatekeeper" &&
370
371
  record.role !== "navigator" &&
371
372
  record.role !== "auditor" &&
372
- record.role !== "diarist"
373
+ record.role !== "diarist" &&
374
+ record.role !== "secretariat"
373
375
  ) {
374
376
  return undefined;
375
377
  }
@@ -1692,6 +1694,12 @@ export type LoadedResumableDiaristRun = {
1692
1694
  readonly observation?: TypedHttp429Observation;
1693
1695
  };
1694
1696
 
1697
+ export type LoadedResumableSecretariatRun = {
1698
+ readonly admitted: import("./invocation.ts").AdmittedSecretariatInvocation;
1699
+ readonly run: RoleRunRecord;
1700
+ readonly observation?: TypedHttp429Observation;
1701
+ };
1702
+
1695
1703
  export type LoadedResumableInstructionSeatRun = {
1696
1704
  readonly admitted:
1697
1705
  | AdmittedGatekeeperInvocation
@@ -1990,6 +1998,24 @@ export async function loadResumableDiaristRun(
1990
1998
  return seatLoadedResult(loaded, admitted);
1991
1999
  }
1992
2000
 
2001
+ export async function loadResumableSecretariatRun(
2002
+ home: string,
2003
+ runId: string,
2004
+ authority: DurablePrincipalAuthority,
2005
+ ): Promise<LoadedResumableSecretariatRun> {
2006
+ const loaded = await loadResumableRunRecord(home, runId, authority);
2007
+ if (loaded.run.role !== "secretariat") {
2008
+ throw new CliUsageError(
2009
+ `role run ${runId} belongs to ${loaded.run.role}, not secretariat`,
2010
+ );
2011
+ }
2012
+ const admitted: import("./invocation.ts").AdmittedSecretariatInvocation = {
2013
+ role: "secretariat",
2014
+ ...resumedBaseAdmitted(loaded),
2015
+ };
2016
+ return seatLoadedResult(loaded, admitted);
2017
+ }
2018
+
1993
2019
  export type LoadedResumableMergerRun = {
1994
2020
  readonly admitted: AdmittedMergerInvocation;
1995
2021
  readonly run: RoleRunRecord;
@@ -2223,6 +2249,7 @@ export async function peekRoleRunRole(
2223
2249
  | "navigator"
2224
2250
  | "auditor"
2225
2251
  | "diarist"
2252
+ | "secretariat"
2226
2253
  | undefined
2227
2254
  > {
2228
2255
  const runDirectory = await findRunDirectoryById(home, runId);