@akagilnc/pi-workflow-roles 0.1.5015 → 0.1.5063

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 (95) hide show
  1. package/README.md +2 -2
  2. package/README.zh-CN.md +2 -2
  3. package/THIRD_PARTY_NOTICES.md +8 -8
  4. package/dist/acp-host/production-host.js +525 -978
  5. package/dist/headless-host/description.js +0 -2
  6. package/dist/headless-host/production-host.js +528 -1014
  7. package/dist/host-descriptions.js +2 -3
  8. package/dist/migrate-book-topology.js +7 -12
  9. package/dist/packaged-role-registry.js +20 -18
  10. package/dist/pi/role-turn-host.js +3 -27
  11. package/dist/public-cli/cli.js +23 -2
  12. package/dist/public-cli/countersign-run.js +13 -8
  13. package/dist/public-cli/instruction-seat-run.js +75 -107
  14. package/dist/public-cli/invocation.js +13 -32
  15. package/dist/public-cli/machine-method-skills.js +150 -0
  16. package/dist/public-cli/main.js +549 -679
  17. package/dist/public-cli/post-admission.js +10 -5
  18. package/dist/public-cli/registry.js +2 -1
  19. package/dist/public-cli/run-lifecycle.js +12 -15
  20. package/dist/public-cli/seat-ticket-binding.js +5 -8
  21. package/dist/public-cli/settlement.js +12 -99
  22. package/dist/public-cli/turn-request.js +16 -8
  23. package/dist/public-role-summons.js +8 -3
  24. package/package.json +5 -1
  25. package/resources/countersign-ticket-issue.md +5 -0
  26. package/resources/diarist-collect.md +1 -0
  27. package/resources/secretariat-ticket-identity.md +15 -0
  28. package/scripts/build-package.mjs +1 -6
  29. package/src/headless-host/description.ts +0 -3
  30. package/src/headless-host/role-turn-host.ts +2 -23
  31. package/src/host-contracts.ts +2 -23
  32. package/src/host-descriptions.ts +2 -3
  33. package/src/packaged-role-registry.ts +17 -16
  34. package/src/pi/adapter.ts +0 -27
  35. package/src/pi/role-turn-host.ts +3 -31
  36. package/src/public-cli/cli.ts +24 -2
  37. package/src/public-cli/countersign-run.ts +17 -10
  38. package/src/public-cli/instruction-seat-run.ts +75 -105
  39. package/src/public-cli/invocation.ts +10 -38
  40. package/src/public-cli/machine-method-skills.ts +153 -0
  41. package/src/public-cli/post-admission.ts +12 -6
  42. package/src/public-cli/registry.ts +1 -0
  43. package/src/public-cli/run-lifecycle.ts +12 -13
  44. package/src/public-cli/seat-ticket-binding.ts +5 -8
  45. package/src/public-cli/settlement.ts +6 -138
  46. package/src/public-cli/turn-request.ts +24 -16
  47. package/src/public-role-summons.ts +16 -3
  48. package/src/reviewer-role.ts +1 -12
  49. package/src/role-envelope.ts +0 -13
  50. package/src/role-runtime-dependencies.ts +0 -13
  51. package/src/role-runtime.ts +4 -56
  52. package/src/worker-role.ts +1 -81
  53. package/dist/method-host-plugin/.claude-plugin/plugin.json +0 -5
  54. package/dist/method-host-plugin/skills/ak-cross-m-review/CONTEXT.md +0 -48
  55. package/dist/method-host-plugin/skills/ak-cross-m-review/LICENSE +0 -21
  56. package/dist/method-host-plugin/skills/ak-cross-m-review/SKILL.md +0 -170
  57. package/dist/method-host-plugin/skills/ak-cross-m-review/prompts/cmr-completeness.md +0 -118
  58. package/dist/method-host-plugin/skills/ak-cross-m-review/prompts/cmr-reviewer.md +0 -128
  59. package/dist/method-host-plugin/skills/ak-cross-m-review/provenance.json +0 -41
  60. package/dist/method-host-plugin/skills/diagnosing-bugs/SKILL.md +0 -134
  61. package/dist/method-host-plugin/skills/diagnosing-bugs/agents/openai.yaml +0 -3
  62. package/dist/method-host-plugin/skills/diagnosing-bugs/provenance.json +0 -31
  63. package/dist/method-host-plugin/skills/diagnosing-bugs/scripts/hitl-loop.template.sh +0 -41
  64. package/dist/method-host-plugin/skills/resolving-merge-conflicts/SKILL.md +0 -14
  65. package/dist/method-host-plugin/skills/resolving-merge-conflicts/agents/openai.yaml +0 -3
  66. package/dist/method-host-plugin/skills/resolving-merge-conflicts/provenance.json +0 -26
  67. package/dist/method-host-plugin/skills/tdd/SKILL.md +0 -38
  68. package/dist/method-host-plugin/skills/tdd/agents/openai.yaml +0 -3
  69. package/dist/method-host-plugin/skills/tdd/mocking.md +0 -59
  70. package/dist/method-host-plugin/skills/tdd/provenance.json +0 -36
  71. package/dist/method-host-plugin/skills/tdd/tests.md +0 -77
  72. package/dist/package-resources/method-skill.js +0 -259
  73. package/resources/method-host-plugin/.claude-plugin/plugin.json +0 -5
  74. package/resources/methods/ak-cross-m-review/CONTEXT.md +0 -48
  75. package/resources/methods/ak-cross-m-review/LICENSE +0 -21
  76. package/resources/methods/ak-cross-m-review/SKILL.md +0 -170
  77. package/resources/methods/ak-cross-m-review/prompts/cmr-completeness.md +0 -118
  78. package/resources/methods/ak-cross-m-review/prompts/cmr-reviewer.md +0 -128
  79. package/resources/methods/ak-cross-m-review/provenance.json +0 -41
  80. package/resources/methods/diagnosing-bugs/SKILL.md +0 -134
  81. package/resources/methods/diagnosing-bugs/agents/openai.yaml +0 -3
  82. package/resources/methods/diagnosing-bugs/provenance.json +0 -31
  83. package/resources/methods/diagnosing-bugs/scripts/hitl-loop.template.sh +0 -41
  84. package/resources/methods/resolving-merge-conflicts/SKILL.md +0 -14
  85. package/resources/methods/resolving-merge-conflicts/agents/openai.yaml +0 -3
  86. package/resources/methods/resolving-merge-conflicts/provenance.json +0 -26
  87. package/resources/methods/tdd/SKILL.md +0 -38
  88. package/resources/methods/tdd/agents/openai.yaml +0 -3
  89. package/resources/methods/tdd/mocking.md +0 -59
  90. package/resources/methods/tdd/provenance.json +0 -36
  91. package/resources/methods/tdd/tests.md +0 -77
  92. package/src/canonical-skill-binding.ts +0 -118
  93. package/src/host-native-method.ts +0 -185
  94. package/src/package-resources/method-skill-binding.ts +0 -60
  95. package/src/package-resources/method-skill.ts +0 -363
@@ -41,9 +41,8 @@ export const HOST_DESCRIPTIONS = Object.freeze({
41
41
  * Headless CLI family (#645 / #646). Claude print-mode is the first row;
42
42
  * codex exec (#646) adds another. Protocol-specific argv/parse live in
43
43
  * headless-host helpers (#752 per-host impl).
44
- * Claude fixedArgs: print mode, full permissions. stream-json + verbose: live
45
- * host events for sitian records (#811); result is last line. Forced methods
46
- * ride `--plugin-dir` (#922); operator skill/setting surfaces stay open.
44
+ * Claude fixedArgs: print mode. stream-json + verbose: live
45
+ * host events for sitian records (#811); result is last line.
47
46
  */
48
47
  export const HEADLESS_HOST_DESCRIPTIONS = Object.freeze({
49
48
  "claude": Object.freeze({
@@ -14051,8 +14051,7 @@ var init_packaged_role_registry = __esm({
14051
14051
  { key: "packetPath" },
14052
14052
  { key: "prerequisitesPath", omitUndefined: true },
14053
14053
  { key: "prerequisites" }
14054
- ],
14055
- method: "observed"
14054
+ ]
14056
14055
  },
14057
14056
  boardPlacement: "marshal",
14058
14057
  activationFlags: [
@@ -14078,7 +14077,6 @@ var init_packaged_role_registry = __esm({
14078
14077
  worker: true,
14079
14078
  applyMethod: "tdd",
14080
14079
  /** Method-material load failure keeps the activation cause (not reviewer/fixer). */
14081
- methodLoadFailureCause: "activation",
14082
14080
  boardPlacement: "coder",
14083
14081
  phases: ["plan", "apply"],
14084
14082
  outputTool: CODER_OUTPUT_TOOL_NAME,
@@ -14089,8 +14087,7 @@ var init_packaged_role_registry = __esm({
14089
14087
  leaves: [
14090
14088
  { key: "phase" },
14091
14089
  { key: "taskPath" }
14092
- ],
14093
- method: "optional"
14090
+ ]
14094
14091
  },
14095
14092
  activationFlags: [
14096
14093
  { field: "taskPath", flag: "ak-coder-task", binds: "input" },
@@ -14131,8 +14128,7 @@ var init_packaged_role_registry = __esm({
14131
14128
  { key: "lens" },
14132
14129
  { key: "authorityRefs", copyArray: true },
14133
14130
  { key: "callerProvenance", callerProvenance: true }
14134
- ],
14135
- method: "observed"
14131
+ ]
14136
14132
  },
14137
14133
  /** Frozen base/lens/authority become the initial prompt; instruction follows. */
14138
14134
  transportPrompt: "skill-args",
@@ -14231,7 +14227,6 @@ var init_packaged_role_registry = __esm({
14231
14227
  methodSkills: ["resolving-merge-conflicts"],
14232
14228
  settleMethod: "resolving-merge-conflicts",
14233
14229
  /** Method-material load failure keeps the activation cause (not reviewer/fixer). */
14234
- methodLoadFailureCause: "activation",
14235
14230
  phases: [null],
14236
14231
  outputTool: MERGER_OUTPUT_TOOL_NAME,
14237
14232
  settlement: "residual",
@@ -14243,8 +14238,7 @@ var init_packaged_role_registry = __esm({
14243
14238
  leaves: [
14244
14239
  { key: "mergerInputPath" },
14245
14240
  { key: "derived" }
14246
- ],
14247
- method: "observed"
14241
+ ]
14248
14242
  },
14249
14243
  activationFlags: [
14250
14244
  { field: "inputPath", from: "mergerInputPath", flag: "ak-merger-input", binds: "input" }
@@ -14311,7 +14305,7 @@ var init_packaged_role_registry = __esm({
14311
14305
  activationStage: "load-and-install",
14312
14306
  receiptStatusKey: "status",
14313
14307
  // #924: 公用《票面法》三席同装
14314
- sessionMaterials: ["CLAUDE.md", "souls/countersign.md", "souls/ticket-law.md"]
14308
+ sessionMaterials: ["CLAUDE.md", "souls/countersign.md", "souls/ticket-law.md", "resources/countersign-ticket-issue.md"]
14315
14309
  },
14316
14310
  {
14317
14311
  role: "secretariat",
@@ -14319,7 +14313,7 @@ var init_packaged_role_registry = __esm({
14319
14313
  presentSettled: "always",
14320
14314
  summonResume: false,
14321
14315
  admission: "instruction",
14322
- sameParent: "court-diarist",
14316
+ sameParent: "none",
14323
14317
  phases: [null],
14324
14318
  outputTool: SECRETARIAT_OUTPUT_TOOL_NAME,
14325
14319
  settlement: "accepted",
@@ -14335,6 +14329,7 @@ var init_packaged_role_registry = __esm({
14335
14329
  "CLAUDE.md",
14336
14330
  "souls/secretariat.md",
14337
14331
  "souls/ticket-law.md",
14332
+ "resources/secretariat-ticket-identity.md",
14338
14333
  "souls/countersign.md",
14339
14334
  "souls/notary.md"
14340
14335
  ]
@@ -93,8 +93,7 @@ const PUBLIC_ROLE_RECORDS = [
93
93
  { key: "packetPath" },
94
94
  { key: "prerequisitesPath", omitUndefined: true },
95
95
  { key: "prerequisites" }
96
- ],
97
- method: "observed"
96
+ ]
98
97
  },
99
98
  boardPlacement: "marshal",
100
99
  activationFlags: [
@@ -120,7 +119,6 @@ const PUBLIC_ROLE_RECORDS = [
120
119
  worker: true,
121
120
  applyMethod: "tdd",
122
121
  /** Method-material load failure keeps the activation cause (not reviewer/fixer). */
123
- methodLoadFailureCause: "activation",
124
122
  boardPlacement: "coder",
125
123
  phases: ["plan", "apply"],
126
124
  outputTool: CODER_OUTPUT_TOOL_NAME,
@@ -131,8 +129,7 @@ const PUBLIC_ROLE_RECORDS = [
131
129
  leaves: [
132
130
  { key: "phase" },
133
131
  { key: "taskPath" }
134
- ],
135
- method: "optional"
132
+ ]
136
133
  },
137
134
  activationFlags: [
138
135
  { field: "taskPath", flag: "ak-coder-task", binds: "input" },
@@ -173,8 +170,7 @@ const PUBLIC_ROLE_RECORDS = [
173
170
  { key: "lens" },
174
171
  { key: "authorityRefs", copyArray: true },
175
172
  { key: "callerProvenance", callerProvenance: true }
176
- ],
177
- method: "observed"
173
+ ]
178
174
  },
179
175
  /** Frozen base/lens/authority become the initial prompt; instruction follows. */
180
176
  transportPrompt: "skill-args",
@@ -273,7 +269,6 @@ const PUBLIC_ROLE_RECORDS = [
273
269
  methodSkills: ["resolving-merge-conflicts"],
274
270
  settleMethod: "resolving-merge-conflicts",
275
271
  /** Method-material load failure keeps the activation cause (not reviewer/fixer). */
276
- methodLoadFailureCause: "activation",
277
272
  phases: [null],
278
273
  outputTool: MERGER_OUTPUT_TOOL_NAME,
279
274
  settlement: "residual",
@@ -285,8 +280,7 @@ const PUBLIC_ROLE_RECORDS = [
285
280
  leaves: [
286
281
  { key: "mergerInputPath" },
287
282
  { key: "derived" }
288
- ],
289
- method: "observed"
283
+ ]
290
284
  },
291
285
  activationFlags: [
292
286
  { field: "inputPath", from: "mergerInputPath", flag: "ak-merger-input", binds: "input" }
@@ -353,7 +347,7 @@ const PUBLIC_ROLE_RECORDS = [
353
347
  activationStage: "load-and-install",
354
348
  receiptStatusKey: "status",
355
349
  // #924: 公用《票面法》三席同装
356
- sessionMaterials: ["CLAUDE.md", "souls/countersign.md", "souls/ticket-law.md"]
350
+ sessionMaterials: ["CLAUDE.md", "souls/countersign.md", "souls/ticket-law.md", "resources/countersign-ticket-issue.md"]
357
351
  },
358
352
  {
359
353
  role: "secretariat",
@@ -361,7 +355,7 @@ const PUBLIC_ROLE_RECORDS = [
361
355
  presentSettled: "always",
362
356
  summonResume: false,
363
357
  admission: "instruction",
364
- sameParent: "court-diarist",
358
+ sameParent: "none",
365
359
  phases: [null],
366
360
  outputTool: SECRETARIAT_OUTPUT_TOOL_NAME,
367
361
  settlement: "accepted",
@@ -377,6 +371,7 @@ const PUBLIC_ROLE_RECORDS = [
377
371
  "CLAUDE.md",
378
372
  "souls/secretariat.md",
379
373
  "souls/ticket-law.md",
374
+ "resources/secretariat-ticket-identity.md",
380
375
  "souls/countersign.md",
381
376
  "souls/notary.md"
382
377
  ]
@@ -525,6 +520,18 @@ const PACKAGED_ROLE_REGISTRY = PUBLIC_ROLE_RECORDS.map(({ sessionMaterials: _omi
525
520
  function packagedRoleMetadata(role) {
526
521
  return PACKAGED_ROLE_REGISTRY.find((entry) => entry.role === role);
527
522
  }
523
+ function packagedMethodSkillNames() {
524
+ const names = [];
525
+ for (const record of PACKAGED_ROLE_REGISTRY) {
526
+ if ("methodSkills" in record && record.methodSkills !== void 0) {
527
+ for (const name of record.methodSkills) if (!names.includes(name)) names.push(name);
528
+ }
529
+ if ("applyMethod" in record && record.applyMethod !== void 0 && !names.includes(record.applyMethod)) {
530
+ names.push(record.applyMethod);
531
+ }
532
+ }
533
+ return names;
534
+ }
528
535
  function isOfficerReviewSeat(role) {
529
536
  const record = packagedRoleMetadata(role);
530
537
  return record !== void 0 && "reviewOfficer" in record && record.reviewOfficer === true;
@@ -559,11 +566,6 @@ function packagedRolePhaseFlag(role) {
559
566
  function packagedRoleOutputTool(role) {
560
567
  return packagedRoleMetadata(role)?.outputTool;
561
568
  }
562
- function packagedMethodLoadFailureCause(role) {
563
- const record = packagedRoleMetadata(role);
564
- if (record === void 0 || !("methodLoadFailureCause" in record)) return void 0;
565
- return record.methodLoadFailureCause;
566
- }
567
569
  function packagedBindsBoardTicket(role) {
568
570
  const record = packagedRoleMetadata(role);
569
571
  return record?.sameParent === "board-ticket";
@@ -689,7 +691,7 @@ export {
689
691
  packagedEmitsAuthorityRefs,
690
692
  packagedGateStageLabel,
691
693
  packagedGateSummon,
692
- packagedMethodLoadFailureCause,
694
+ packagedMethodSkillNames,
693
695
  packagedModelParent,
694
696
  packagedNavigatorSubject,
695
697
  packagedProjectsTargetBindRejection,
@@ -6,7 +6,7 @@
6
6
  import { execFile, spawn } from "node:child_process";
7
7
  import { constants } from "node:fs";
8
8
  import { access, appendFile, readFile, realpath } from "node:fs/promises";
9
- import { basename, delimiter, dirname, isAbsolute, join, resolve } from "node:path";
9
+ import { delimiter, dirname, isAbsolute, join, resolve } from "node:path";
10
10
  import { platform } from "node:process";
11
11
  import { promisify } from "node:util";
12
12
  import { randomUUID } from "node:crypto";
@@ -67,33 +67,11 @@ function buildMethodArgs(methods) {
67
67
  const skillArgs = [];
68
68
  for (const method of methods) {
69
69
  if (method.kind === "skill") {
70
- skillArgs.push("--skill", method.path);
70
+ skillArgs.push("--skill", dirname(method.path));
71
71
  }
72
72
  }
73
73
  return skillArgs;
74
74
  }
75
- /**
76
- * Pi-native `/skill:<name>` for a single forced method (ADR 0082: pi is one adapter
77
- * with no privilege; Pi-only seams stay inside the pi adapter).
78
- * Driven by typed RoleTurnRequest.methods — middle-layer decision, Pi-only syntax.
79
- * Zero/many methods leave the prompt alone (Fixer optional pair stays `--skill` only).
80
- */
81
- export function applyPiNativeSkillInvocation(methods, prompt) {
82
- const skills = methods.filter((method) => method.kind === "skill");
83
- if (skills.length !== 1)
84
- return prompt;
85
- const name = basename(dirname(skills[0].path));
86
- if (name.length === 0)
87
- return prompt;
88
- const token = `/skill:${name}`;
89
- const trimmed = prompt.trimStart();
90
- if (trimmed === token
91
- || trimmed.startsWith(`${token} `)
92
- || trimmed.startsWith(`${token}\n`)) {
93
- return prompt;
94
- }
95
- return prompt.length === 0 ? token : `${token} ${prompt}`;
96
- }
97
75
  /**
98
76
  * Pi last-hop argv after `--no-extensions -e entry` (#819).
99
77
  * Activation flag membership comes from middle-layer projectActivationFlags;
@@ -135,9 +113,7 @@ function piUserDialogueBody(request) {
135
113
  const _exhaustive = request.continuation;
136
114
  return _exhaustive;
137
115
  })();
138
- return request.continuation.kind === "resume"
139
- ? rawPrompt
140
- : applyPiNativeSkillInvocation(request.methods, rawPrompt);
116
+ return rawPrompt;
141
117
  }
142
118
  const execFileAsync = promisify(execFile);
143
119
  async function resolveSelectedPi(command, cwd, env) {
@@ -12,11 +12,13 @@ import { loadHostProvidersTable, projectHostFacingProvider, renderHostProvidersT
12
12
  import { packagedModelParent } from "../packaged-role-registry.js";
13
13
  import { seatModelOnly } from "./registry.js";
14
14
  import { CliUsageError } from "./cli-errors.js";
15
+ import { runMachineSkillSetup } from "./machine-method-skills.js";
15
16
  import { appendPiSessionCustomEntry } from "../pi/role-turn-host.js";
16
17
  import { composeRoleTurnHostAdapters, formatHostSelectionFailure, HostSelectionError, selectRoleTurnHost, } from "./role-turn-host-resolution.js";
17
18
  import { parseAnalystArgv, parsePublicSeatArgv, } from "./invocation.js";
18
19
  import { createTypedOptionConsumer, optionsForOwner, projectCommandHelp, projectOwnerOptions, PUBLIC_NAVIGATOR_HELP_NOTE, PUBLIC_ROLE_OPTION_OWNERS, renderHumanOwnerOptionLines, } from "./option-definitions.js";
19
- import { runPublicInstructionSeat, runPublicInstructionSeatResume } from "./instruction-seat-run.js";
20
+ import { continueParentAfterChild, runPublicInstructionSeat, runPublicInstructionSeatResume } from "./instruction-seat-run.js";
21
+ import { courtDiaristEscalated } from "./countersign-run.js";
20
22
  import { runPublicAnalyst } from "./analyst-run.js";
21
23
  import { AUTO_RESUME_LIMIT, peekRoleRunRole, } from "./run-lifecycle.js";
22
24
  import { INTERNAL_ROLE_ENTRYPOINT_RELATIVE, PUBLIC_CALLABLE_ROLES, isPublicCallableRole, isPublicCliSupportCommand, isPublicConfigurableSeat, listHelpCapabilities, } from "./registry.js";
@@ -792,6 +794,11 @@ export async function runAkRole(argv, env) {
792
794
  exitCode: await runConfigCommand(parsed.args, home, env.packageRoot, io),
793
795
  };
794
796
  }
797
+ if (parsed.command === "setup") {
798
+ if (parsed.args.length !== 0)
799
+ throw new CliUsageError("setup takes no arguments");
800
+ return { exitCode: await runMachineSkillSetup(home, io.stdout) };
801
+ }
795
802
  // #724 explicit fresh summons: `ak-role new <role> …` — same role argv, always mint.
796
803
  // Rewrites onto the role command with freshSummons; auto-resume and resume stay intact.
797
804
  if (parsed.command === "new") {
@@ -832,7 +839,21 @@ export async function runAkRole(argv, env) {
832
839
  seat,
833
840
  config,
834
841
  }), io);
835
- return cliResultFromRoleRun(result);
842
+ let current = result;
843
+ while (current.exitCode === 0 && current.admitted?.correlationId !== undefined
844
+ && current.terminal?.roleOutcome.kind === "accepted"
845
+ && !courtDiaristEscalated(current.terminal.roleOutcome)) {
846
+ const parentRunId = current.admitted.correlationId;
847
+ const parentRole = await peekRoleRunRole(home, parentRunId);
848
+ if (parentRole === undefined)
849
+ break;
850
+ const parentSeat = resolveEffectiveSeat(config, parentRole, credentials, invocationFromParsed(parsed));
851
+ const parentEnv = createRoleEnvironment(env, {
852
+ role: parentRole, home, agentDir, cwd, credentials, seat: parentSeat, config,
853
+ });
854
+ current = await continueParentAfterChild(parentRunId, current.admitted, parentEnv, io);
855
+ }
856
+ return cliResultFromRoleRun(current);
836
857
  }
837
858
  if (parsed.command !== undefined &&
838
859
  isPublicCliSupportCommand(parsed.command)) {
@@ -62,7 +62,7 @@ function courtDiaristEscalateDiagnostic(roleOutcome, submissions) {
62
62
  * - Multiple submissions: last qualifying set wins.
63
63
  * Live path never shape-rejects the role turn; durable damage is a separate seam.
64
64
  */
65
- function courtTicketNumbersFromOutcome(roleOutcome, principalTicket, submissions) {
65
+ export function courtTicketNumbersFromOutcome(roleOutcome, principalTicket, submissions) {
66
66
  if (roleOutcome === undefined)
67
67
  return undefined;
68
68
  const payloads = courtDiaristPayloadRows(roleOutcome, submissions);
@@ -97,7 +97,7 @@ function courtTicketNumbersFromOutcome(roleOutcome, principalTicket, submissions
97
97
  return latest;
98
98
  }
99
99
  /** Routing boolean over the child's own typed sequence — does not pick or rewrite a sole row. */
100
- function courtDiaristEscalated(roleOutcome) {
100
+ export function courtDiaristEscalated(roleOutcome) {
101
101
  if (roleOutcome === undefined)
102
102
  return false;
103
103
  if (roleOutcome.kind === "audit_escalation")
@@ -164,6 +164,7 @@ export async function invokeCourtDiarist(input, env, io) {
164
164
  diagnostic: courtDiaristEscalateDiagnostic(roleOutcome, submissions),
165
165
  },
166
166
  ...(result.admitted === undefined ? {} : { admitted: result.admitted }),
167
+ ...(result.terminal === undefined ? {} : { terminal: result.terminal }),
167
168
  };
168
169
  }
169
170
  if (result.exitCode !== 0) {
@@ -204,10 +205,10 @@ export async function invokeCourtDiarist(input, env, io) {
204
205
  * Missing ticketNumber (true-unbound / identity deferred) skips the refresh
205
206
  * station — no diary is minted for a true-unbound run. First-entry identity
206
207
  * lives on the shared countersign entry (typed 起居郎 key for bind). Bound refresh:
207
- * 起居郎 failure propagates (失败诚实).
208
+ * technical failure propagates; LLM escalation remains a recorded conclusion.
208
209
  * Path delivery onto materials is not this station's job — post-admission owns it.
209
210
  */
210
- export async function runCountersignCourtDiaristStation(admitted, env, io) {
211
+ export async function runCountersignCourtDiaristStation(admitted, env, io, afterTicketNumber) {
211
212
  if (env.runCourtDiaristStation !== undefined) {
212
213
  await env.runCourtDiaristStation(admitted);
213
214
  return;
@@ -230,7 +231,8 @@ export async function runCountersignCourtDiaristStation(admitted, env, io) {
230
231
  else {
231
232
  refreshTickets = [admitted.ticketNumber];
232
233
  }
233
- for (const ticketNumber of refreshTickets) {
234
+ const completedIndex = afterTicketNumber === undefined ? -1 : refreshTickets.indexOf(afterTicketNumber);
235
+ for (const ticketNumber of refreshTickets.slice(completedIndex + 1)) {
234
236
  const outcome = await invokeCourtDiarist({
235
237
  instruction: `整理 #${ticketNumber} 的本案依据。`,
236
238
  projectRoot: admitted.projectRoot,
@@ -239,11 +241,14 @@ export async function runCountersignCourtDiaristStation(admitted, env, io) {
239
241
  // Refresh holds a typed key — hand it off so identity is bound before turn.
240
242
  boundTicketNumber: ticketNumber,
241
243
  }, env, io);
242
- if (outcome.identity.kind === "escalate") {
243
- throw new StationChildExhaustedError(outcome.identity.diagnostic);
244
- }
245
244
  if (outcome.failedWithoutEscalate !== undefined) {
246
245
  throw new StationChildExhaustedError(outcome.failedWithoutEscalate.diagnostic);
247
246
  }
247
+ if (outcome.identity.kind === "escalate" && outcome.terminal !== undefined) {
248
+ return {
249
+ terminal: outcome.terminal,
250
+ ...(outcome.admitted === undefined ? {} : { childRunId: outcome.admitted.runId }),
251
+ };
252
+ }
248
253
  }
249
254
  }