@akagilnc/pi-workflow-roles 0.1.3572 → 0.1.3621

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 (129) hide show
  1. package/dist/acp-host/production-host.js +20239 -10556
  2. package/dist/analyst-gate-cycles-read.js +387 -0
  3. package/dist/archivist-record-entry.js +22 -1
  4. package/dist/audit-escalation.js +6 -0
  5. package/dist/auditor-soul.js +74 -0
  6. package/dist/collector-config.js +86 -0
  7. package/dist/collector-evidence.js +316 -0
  8. package/dist/collector-github.js +527 -0
  9. package/dist/collector-ledger.js +853 -0
  10. package/dist/collector-tool-schemas.js +33 -0
  11. package/dist/compliance-transport.js +104 -52
  12. package/dist/diarist-mechanical.js +411 -0
  13. package/dist/diarist-ticket-resolution.js +177 -0
  14. package/dist/diarist.js +311 -0
  15. package/dist/doctor-auditor.js +25 -0
  16. package/dist/doctor-contracts.js +2 -0
  17. package/dist/doctor-evidence.js +142 -0
  18. package/dist/gatekeeper-role.js +104 -81
  19. package/dist/host-transition-prior-native.js +78 -0
  20. package/dist/institutional-resolution.js +1 -95
  21. package/dist/judge-auditor.js +26 -0
  22. package/dist/ledger-session-read.js +227 -0
  23. package/dist/merger-git-state.js +78 -0
  24. package/dist/navigator-attendance.js +15 -7
  25. package/dist/navigator-public-session.js +170 -0
  26. package/dist/navigator-session-contracts.js +36 -40
  27. package/dist/notary-source-run.js +122 -0
  28. package/dist/package-contracts/auditor-output.js +66 -0
  29. package/dist/package-contracts/evidence-child-output.js +34 -0
  30. package/dist/package-contracts/judge-output.js +2 -0
  31. package/dist/package-contracts/terminating-tools.js +25 -2
  32. package/dist/package-resources/method-skill.js +254 -0
  33. package/dist/packaged-role-registry.js +36 -0
  34. package/dist/pi/durable-principal.js +61 -0
  35. package/dist/pi/in-process-session.js +25 -6
  36. package/dist/pi/known-failure.js +52 -0
  37. package/dist/pi/role-turn-host.js +430 -0
  38. package/dist/public-cli/auto-resume.js +414 -0
  39. package/dist/public-cli/cli-errors.js +8 -0
  40. package/dist/public-cli/cli-io.js +1 -0
  41. package/dist/public-cli/command-renderer.js +5 -0
  42. package/dist/public-cli/doctor-run.js +84 -0
  43. package/dist/public-cli/inspector-run.js +136 -0
  44. package/dist/public-cli/instruction-seat-run.js +256 -0
  45. package/dist/public-cli/invocation.js +2225 -0
  46. package/dist/public-cli/judge-run.js +118 -0
  47. package/dist/public-cli/load-production-acp-host.js +40 -0
  48. package/dist/public-cli/main.js +1140 -652
  49. package/dist/public-cli/notary-run.js +161 -0
  50. package/dist/public-cli/option-definitions.js +1192 -0
  51. package/dist/public-cli/post-admission.js +667 -0
  52. package/dist/public-cli/public-run-credentials.js +49 -0
  53. package/dist/public-cli/registry.js +4 -1
  54. package/dist/public-cli/reviewer-dispatch-rejection.js +77 -0
  55. package/dist/public-cli/run-lifecycle.js +1344 -0
  56. package/dist/public-cli/seat-ticket-binding.js +113 -0
  57. package/dist/public-cli/settlement.js +3441 -0
  58. package/dist/public-cli/terminal.js +135 -0
  59. package/dist/public-cli/turn-request.js +25 -0
  60. package/dist/public-role-summons.js +301 -0
  61. package/dist/receipt-delivery-policy.js +10 -0
  62. package/dist/reviewer-child-executor.js +80 -8
  63. package/dist/reviewer-execution-ledger.js +2 -1
  64. package/dist/run-terminal-artifacts.js +195 -0
  65. package/dist/run-ticket-number.js +40 -0
  66. package/dist/session-assistant-usage.js +107 -0
  67. package/dist/shape-unreadable-failure.js +34 -0
  68. package/dist/submission-errors.js +3 -0
  69. package/dist/submission-ledger.js +388 -0
  70. package/dist/ticket-provenance-contracts.js +115 -0
  71. package/dist/ticket-provenance.js +340 -0
  72. package/extensions/role-runtime.ts +7 -0
  73. package/package.json +1 -1
  74. package/scripts/build-package.mjs +2 -1
  75. package/souls/doctor-auditor.md +1 -0
  76. package/souls/evidence-child.md +1 -0
  77. package/src/acp-host/production-host.ts +3 -0
  78. package/src/acp-host/role-envelope.ts +2 -2
  79. package/src/acp-host/role-turn-host.ts +9 -1
  80. package/src/analyst-gate-cycles-read.ts +37 -2
  81. package/src/archivist-record-entry.ts +45 -1
  82. package/src/audit-escalation.ts +17 -0
  83. package/src/auditor-role.ts +22 -0
  84. package/src/auditor-soul.ts +42 -0
  85. package/src/compliance-transport.ts +177 -66
  86. package/src/doctor-auditor.ts +10 -14
  87. package/src/doctor-contracts.ts +1 -0
  88. package/src/doctor-role.ts +2 -2
  89. package/src/evidence-child-role.ts +22 -0
  90. package/src/gatekeeper-pass-envelope.ts +109 -0
  91. package/src/gatekeeper-role.ts +145 -104
  92. package/src/host-contracts.ts +9 -1
  93. package/src/institutional-resolution.ts +8 -163
  94. package/src/judge-auditor.ts +10 -15
  95. package/src/judge-role.ts +8 -0
  96. package/src/navigator-attendance.ts +25 -9
  97. package/src/navigator-public-session.ts +217 -0
  98. package/src/navigator-session-contracts.ts +61 -54
  99. package/src/notary-source-run.ts +3 -1
  100. package/src/package-contracts/auditor-output.ts +82 -0
  101. package/src/package-contracts/evidence-child-output.ts +51 -0
  102. package/src/package-contracts/judge-output.ts +1 -0
  103. package/src/package-contracts/reviewer-output.ts +2 -2
  104. package/src/package-contracts/terminating-tools.ts +31 -1
  105. package/src/packaged-role-registry.ts +43 -0
  106. package/src/pi/adapter.ts +2 -1
  107. package/src/pi/in-process-session.ts +38 -12
  108. package/src/pi/role-turn-host.ts +34 -0
  109. package/src/public-cli/cli.ts +14 -6
  110. package/src/public-cli/instruction-seat-run.ts +289 -50
  111. package/src/public-cli/invocation.ts +66 -25
  112. package/src/public-cli/option-definitions.ts +61 -0
  113. package/src/public-cli/post-admission.ts +7 -1
  114. package/src/public-cli/registry.ts +4 -1
  115. package/src/public-cli/run-lifecycle.ts +22 -3
  116. package/src/public-cli/settlement.ts +120 -5
  117. package/src/public-cli/terminal.ts +2 -0
  118. package/src/public-role-summons.ts +431 -0
  119. package/src/receipt-delivery-policy.ts +10 -0
  120. package/src/reviewer-agent.ts +1 -1
  121. package/src/reviewer-child-executor.ts +114 -12
  122. package/src/reviewer-execution-ledger.ts +3 -2
  123. package/src/role-runtime.ts +158 -17
  124. package/src/session-assistant-usage.ts +119 -0
  125. package/src/session-opening-materials.ts +1 -1
  126. package/src/shape-unreadable-failure.ts +49 -0
  127. package/src/submission-errors.ts +3 -0
  128. package/dist/evidence-child-executor.js +0 -829
  129. package/src/evidence-child-executor.ts +0 -1140
@@ -29,6 +29,8 @@ import { CorrectableSubmissionError } from "../submission-correctable-error.ts";
29
29
  import { DOCTOR_ACCEPTED_TEXT, DOCTOR_OUTPUT_TOOL_NAME, validateDoctorSubmissionShape, validateRecordedDoctorOutput, type DoctorOutput, type DoctorSubmission } from "../doctor-contracts.ts";
30
30
  import { GATEKEEPER_ACCEPTED_TEXT, GATEKEEPER_OUTPUT_TOOL_NAME, validateRecordedGatekeeperOutput, type GatekeeperDirectOutput } from "./gatekeeper-output.ts";
31
31
  import { NAVIGATOR_ACCEPTED_TEXT, NAVIGATOR_OUTPUT_TOOL_NAME, validateRecordedNavigatorOutput, type NavigatorAdvice } from "./navigator-output.ts";
32
+ import { AUDITOR_ACCEPTED_TEXT, AUDITOR_OUTPUT_TOOL_NAME, validateRecordedAuditorOutput, type AuditorOutput } from "./auditor-output.ts";
33
+ import { EVIDENCE_CHILD_ACCEPTED_TEXT, EVIDENCE_CHILD_OUTPUT_TOOL_NAME, validateRecordedEvidenceChildOutput, type EvidenceChildOutput } from "./evidence-child-output.ts";
32
34
  import { MERGER_ACCEPTED_TEXT, MERGER_OUTPUT_TOOL_NAME, validateMergerOutput, type MergerOutput } from "../merger-contracts.ts";
33
35
  import { NOTARY_ACCEPTED_TEXT, NOTARY_OUTPUT_TOOL_NAME, validateRecordedNotaryOutput, type NotaryOutput } from "../notary-contracts.ts";
34
36
  import { COUNTERSIGN_ACCEPTED_TEXT, COUNTERSIGN_OUTPUT_TOOL_NAME, validateRecordedCountersignOutput, type CountersignVerdict } from "../countersign-contracts.ts";
@@ -72,6 +74,8 @@ export {
72
74
  validateRecordedInspectorOutput,
73
75
  validateRecordedGatekeeperOutput,
74
76
  validateRecordedNavigatorOutput,
77
+ validateRecordedAuditorOutput,
78
+ validateRecordedEvidenceChildOutput,
75
79
  validateRecordedDiaristOutput,
76
80
  };
77
81
  export type {
@@ -89,6 +93,8 @@ export type {
89
93
  InspectorOutput,
90
94
  GatekeeperDirectOutput,
91
95
  NavigatorAdvice,
96
+ AuditorOutput,
97
+ EvidenceChildOutput,
92
98
  DiaristOutput,
93
99
  };
94
100
 
@@ -106,6 +112,8 @@ export const TERMINATING_TOOL_NAMES = [
106
112
  INSPECTOR_OUTPUT_TOOL_NAME,
107
113
  GATEKEEPER_OUTPUT_TOOL_NAME,
108
114
  NAVIGATOR_OUTPUT_TOOL_NAME,
115
+ AUDITOR_OUTPUT_TOOL_NAME,
116
+ EVIDENCE_CHILD_OUTPUT_TOOL_NAME,
109
117
  DIARIST_OUTPUT_TOOL_NAME,
110
118
  ] as const;
111
119
 
@@ -124,6 +132,8 @@ export type AcceptedDetails =
124
132
  | InspectorOutput
125
133
  | GatekeeperDirectOutput
126
134
  | NavigatorAdvice
135
+ | AuditorOutput
136
+ | EvidenceChildOutput
127
137
  | DiaristOutput;
128
138
 
129
139
  export function isTerminatingToolName(
@@ -160,6 +170,10 @@ export function acceptedTextFor(toolName: TerminatingToolName): string {
160
170
  return GATEKEEPER_ACCEPTED_TEXT;
161
171
  case NAVIGATOR_OUTPUT_TOOL_NAME:
162
172
  return NAVIGATOR_ACCEPTED_TEXT;
173
+ case AUDITOR_OUTPUT_TOOL_NAME:
174
+ return AUDITOR_ACCEPTED_TEXT;
175
+ case EVIDENCE_CHILD_OUTPUT_TOOL_NAME:
176
+ return EVIDENCE_CHILD_ACCEPTED_TEXT;
163
177
  case DIARIST_OUTPUT_TOOL_NAME:
164
178
  return DIARIST_ACCEPTED_TEXT;
165
179
  }
@@ -220,16 +234,24 @@ export function validateAcceptedDetails(
220
234
  [INSPECTOR_OUTPUT_TOOL_NAME]: ["pass", "bounce"],
221
235
  [GATEKEEPER_OUTPUT_TOOL_NAME]: ["dispatch", "pass"],
222
236
  [NAVIGATOR_OUTPUT_TOOL_NAME]: ["advice"],
237
+ [AUDITOR_OUTPUT_TOOL_NAME]: ["pass", "revise", "escalate"],
238
+ [EVIDENCE_CHILD_OUTPUT_TOOL_NAME]: [],
223
239
  [DIARIST_OUTPUT_TOOL_NAME]: ["completed"],
224
240
  };
225
241
  const collectorDiscriminator = toolName === COLLECTOR_OUTPUT_TOOL && Array.isArray(candidate?.groups);
242
+ // Evidence-child: any object is a candidate body — no report-field presence gate (#675 / ADR 0055).
243
+ const evidenceChildDiscriminator =
244
+ toolName === EVIDENCE_CHILD_OUTPUT_TOOL_NAME
245
+ && candidate !== null
246
+ && typeof candidate === "object"
247
+ && !Array.isArray(candidate);
226
248
  const baseDiscriminator = discriminator;
227
249
  const runtimeBindingMissing =
228
250
  (toolName === DOCTOR_OUTPUT_TOOL_NAME && baseDiscriminator === "completed" && !(candidate?.cost !== null && typeof candidate?.cost === "object")) ||
229
251
  (toolName === REVIEWER_OUTPUT_TOOL_NAME && candidate?.version !== 2);
230
252
  if (
231
253
  runtimeBindingMissing ||
232
- (!collectorDiscriminator && (typeof discriminator !== "string" || !lawfulStatuses[toolName].includes(baseDiscriminator as string)))
254
+ (!collectorDiscriminator && !evidenceChildDiscriminator && (typeof discriminator !== "string" || !lawfulStatuses[toolName].includes(baseDiscriminator as string)))
233
255
  ) {
234
256
  throw new AcceptedDetailsContractError("terminating receipt has no recognized execution discriminator");
235
257
  }
@@ -261,6 +283,10 @@ export function validateAcceptedDetails(
261
283
  return validateRecordedGatekeeperOutput(details);
262
284
  case NAVIGATOR_OUTPUT_TOOL_NAME:
263
285
  return validateRecordedNavigatorOutput(details);
286
+ case AUDITOR_OUTPUT_TOOL_NAME:
287
+ return validateRecordedAuditorOutput(details);
288
+ case EVIDENCE_CHILD_OUTPUT_TOOL_NAME:
289
+ return validateRecordedEvidenceChildOutput(details);
264
290
  case DIARIST_OUTPUT_TOOL_NAME:
265
291
  return validateRecordedDiaristOutput(details);
266
292
  }
@@ -321,6 +347,10 @@ export function acceptedFacts(toolName: TerminatingToolName, details: AcceptedDe
321
347
  case INSPECTOR_OUTPUT_TOOL_NAME:
322
348
  case GATEKEEPER_OUTPUT_TOOL_NAME:
323
349
  case NAVIGATOR_OUTPUT_TOOL_NAME:
350
+ case AUDITOR_OUTPUT_TOOL_NAME:
351
+ return { status: (details as { status: string }).status };
352
+ case EVIDENCE_CHILD_OUTPUT_TOOL_NAME:
353
+ return { status: "report" };
324
354
  case DIARIST_OUTPUT_TOOL_NAME: return { status: (details as { status: string }).status };
325
355
  case JUDGE_OUTPUT_TOOL_NAME: return { status: (details as { judgeStatus: string }).judgeStatus };
326
356
  case COUNTERSIGN_OUTPUT_TOOL_NAME: return { status: (details as { countersignStatus: string }).countersignStatus };
@@ -11,6 +11,8 @@ import { NOTARY_OUTPUT_TOOL_NAME } from "./notary-contracts.ts";
11
11
  import { COUNTERSIGN_OUTPUT_TOOL_NAME } from "./countersign-contracts.ts";
12
12
  import { GLEANER_LEFT_OUTPUT_TOOL_NAME } from "./gleaner-left-contracts.ts";
13
13
  import { INSPECTOR_OUTPUT_TOOL_NAME } from "./inspector-contracts.ts";
14
+ import { AUDITOR_OUTPUT_TOOL_NAME } from "./package-contracts/auditor-output.ts";
15
+ import { EVIDENCE_CHILD_OUTPUT_TOOL_NAME } from "./package-contracts/evidence-child-output.ts";
14
16
  import {
15
17
  DIARIST_OUTPUT_TOOL_NAME,
16
18
  DIARIST_SOURCES_FLAG,
@@ -33,6 +35,28 @@ export const INSPECTOR_SESSION_MATERIALS = [
33
35
  "souls/gate-output-guide.md",
34
36
  ] as const;
35
37
 
38
+ /**
39
+ * Public 审刑院 shipping roster (#675 owner).
40
+ * Runtime assembly is subject-selected via AUDITOR_SESSION_MATERIALS
41
+ * (judge-auditor.md / doctor-auditor.md) — never a generic auditor.md.
42
+ * This list is the union of files that must ship; load path is loadAuditorSoul(subject).
43
+ */
44
+ export const AUDITOR_PUBLIC_SESSION_MATERIALS = [
45
+ "CLAUDE.md",
46
+ "souls/judge-auditor.md",
47
+ "souls/doctor-auditor.md",
48
+ "souls/audit-law.md",
49
+ "souls/quality-law.md",
50
+ ] as const;
51
+
52
+ /** Public evidence-child materials (#675). audit-law supplies lawful 取证授权; seat identity only in evidence-child.md. */
53
+ export const EVIDENCE_CHILD_SESSION_MATERIALS = [
54
+ "CLAUDE.md",
55
+ "souls/evidence-child.md",
56
+ "souls/audit-law.md",
57
+ "souls/quality-law.md",
58
+ ] as const;
59
+
36
60
  /**
37
61
  * One record per public callable role (#639: includes gatekeeper and navigator).
38
62
  */
@@ -189,6 +213,25 @@ export const PUBLIC_ROLE_RECORDS = [
189
213
  activationStage: "load-and-install",
190
214
  sessionMaterials: ["CLAUDE.md", "souls/navigator.md"],
191
215
  },
216
+ // #675: 审刑院 / evidence-child are roles like any other — public ak-role entries.
217
+ {
218
+ role: "auditor",
219
+ phases: [null],
220
+ outputTool: AUDITOR_OUTPUT_TOOL_NAME,
221
+ inputFlag: undefined,
222
+ phaseFlag: undefined,
223
+ activationStage: "load-and-install",
224
+ sessionMaterials: AUDITOR_PUBLIC_SESSION_MATERIALS,
225
+ },
226
+ {
227
+ role: "evidence-child",
228
+ phases: [null],
229
+ outputTool: EVIDENCE_CHILD_OUTPUT_TOOL_NAME,
230
+ inputFlag: undefined,
231
+ phaseFlag: undefined,
232
+ activationStage: "load-and-install",
233
+ sessionMaterials: EVIDENCE_CHILD_SESSION_MATERIALS,
234
+ },
192
235
  // #708 / ADR 0075 `diarist-is-role`: 起居郎 is a seat like any other. The
193
236
  // frozen source catalog rides the shared input-flag seam; it is absent for a
194
237
  // true-unbound summons (no ticket → no diary).
package/src/pi/adapter.ts CHANGED
@@ -7,7 +7,8 @@ import {
7
7
  type ToolDefinition,
8
8
  } from "@earendil-works/pi-coding-agent";
9
9
  import type { Static, TSchema } from "typebox";
10
- import { requireGatekeeperPass, type GatekeeperNonPassResult, type GatekeeperSubject } from "../gatekeeper-role.ts";
10
+ import type { GatekeeperNonPassResult, GatekeeperSubject } from "../gatekeeper-role.ts";
11
+ import { requireGatekeeperPass } from "../gatekeeper-pass-envelope.ts";
11
12
  import type {
12
13
  HostContext,
13
14
  HostEventRegistration,
@@ -207,7 +207,7 @@ export type OpenPiInstitutionalSessionResult = {
207
207
  readonly streamFailure: unknown;
208
208
  };
209
209
 
210
- export async function openPiInstitutionalSession(
210
+ export async function openPiInProcessSession(
211
211
  options: OpenPiInstitutionalSessionOptions,
212
212
  ): Promise<OpenPiInstitutionalSessionResult> {
213
213
  const label = options.label ?? "Institutional sub-session";
@@ -237,7 +237,7 @@ export async function openPiInstitutionalSession(
237
237
  ? childRegistry.find(selection.provider, selection.model)
238
238
  : undefined;
239
239
 
240
- const withTypedReason = (error: Error, reason: "auth" | "model"): Error =>
240
+ const withTypedReason = (error: Error, reason: "auth" | "model" | "thinking"): Error =>
241
241
  Object.assign(error, { reason });
242
242
 
243
243
  // Existing Navigator/model contract (pre-#590): unknown provider or model is
@@ -633,15 +633,26 @@ export async function openPiInstitutionalSession(
633
633
  }
634
634
  }
635
635
 
636
- // 7. Create AgentSession — thinking is opaque pass-through. Absent selection
637
- // omits thinkingLevel (Pi owns default). Pi clamps unsupported levels itself;
638
- // we do not re-check or invent package defaults.
636
+ // 7. Create AgentSession
637
+ // Thinking is opaque pass-through (#683 / #675 ⑥). Absent selection omits
638
+ // thinkingLevel (Pi owns default). Pi clamps unsupported levels itself;
639
+ // we do not re-check or invent package defaults. When reusing a session file,
640
+ // re-apply seat model after open so Pi cannot restore a stale model over
641
+ // selection (#675 ⑤ / #697).
642
+ const requestedThinking = selection.thinking;
643
+ const priorEntries =
644
+ typeof (sessionManager as { getEntries?: () => readonly unknown[] }).getEntries === "function"
645
+ ? (sessionManager as { getEntries: () => readonly unknown[] }).getEntries()
646
+ : [];
647
+ const reusedSession = priorEntries.some((entry) => {
648
+ if (typeof entry !== "object" || entry === null) return false;
649
+ const type = (entry as { type?: unknown }).type;
650
+ return type === "message" || type === "model_change" || type === "thinking_level_change";
651
+ });
639
652
  const { session } = await createAgentSession({
640
653
  cwd: options.cwd,
641
654
  model: effectiveModel,
642
- ...(options.selection.thinking === undefined
643
- ? {}
644
- : { thinkingLevel: options.selection.thinking as any }),
655
+ ...(requestedThinking === undefined ? {} : { thinkingLevel: requestedThinking as any }),
645
656
  modelRuntime: runtime,
646
657
  sessionManager,
647
658
  settingsManager: settings,
@@ -651,9 +662,23 @@ export async function openPiInstitutionalSession(
651
662
  ...(options.toolsAllowlist === undefined ? {} : { tools: options.toolsAllowlist as string[] }),
652
663
  ...(customTools.length === 0 ? {} : { customTools }),
653
664
  });
654
- await session.setModel(effectiveModel);
655
- if (options.selection.thinking !== undefined) {
656
- session.setThinkingLevel(options.selection.thinking as any);
665
+ if (reusedSession) {
666
+ try {
667
+ await session.setModel(effectiveModel);
668
+ if (requestedThinking !== undefined) {
669
+ session.setThinkingLevel(requestedThinking as any);
670
+ }
671
+ } catch (error) {
672
+ session.dispose();
673
+ throw withTypedReason(
674
+ error instanceof Error
675
+ ? error
676
+ : new Error(
677
+ `${label} failed to apply seat model/thinking for ${selection.provider}/${selection.model}`,
678
+ ),
679
+ requestedThinking !== undefined ? "thinking" : "model",
680
+ );
681
+ }
657
682
  }
658
683
 
659
684
  // 8. Event subscriptions
@@ -832,4 +857,5 @@ export async function openPiInstitutionalSession(
832
857
  }
833
858
  throw openError;
834
859
  }
835
- }
860
+ }
861
+
@@ -146,6 +146,10 @@ function buildActivationFlagArgs(activation: RoleTurnActivation): string[] {
146
146
  return ["--ak-role", "gatekeeper"];
147
147
  case "navigator":
148
148
  return ["--ak-role", "navigator"];
149
+ case "auditor":
150
+ return ["--ak-role", "auditor"];
151
+ case "evidence-child":
152
+ return ["--ak-role", "evidence-child"];
149
153
  case "diarist":
150
154
  return [
151
155
  "--ak-role",
@@ -213,6 +217,8 @@ export type PiSpawnRunner = (
213
217
  cwd: string;
214
218
  env: NodeJS.ProcessEnv;
215
219
  timeoutMs?: number;
220
+ /** Parent cancellation; the child gets the same graceful SIGTERM as a budget. */
221
+ signal?: AbortSignal;
216
222
  },
217
223
  ) => Promise<{
218
224
  code: number | null;
@@ -346,9 +352,17 @@ export function createDefaultPiSpawnRunner(options: {
346
352
  child.kill("SIGTERM");
347
353
  }, spawnOptions.timeoutMs);
348
354
  };
355
+ // Parent cancellation reaches the nested activation: same graceful SIGTERM,
356
+ // same single close settlement. SIGKILL stays forbidden (#675 / ADR 0010).
357
+ const parentSignal = spawnOptions.signal;
358
+ const terminateForParentAbort = (): void => {
359
+ child.kill("SIGTERM");
360
+ };
361
+ parentSignal?.addEventListener("abort", terminateForParentAbort, { once: true });
349
362
  let identityRecorded: Promise<void> = Promise.resolve();
350
363
  child.once("spawn", () => {
351
364
  hasSpawned = true;
365
+ if (parentSignal?.aborted === true) terminateForParentAbort();
352
366
  armTimeoutAfterChildReady();
353
367
  const runDirectory = spawnOptions.env.AK_ROLE_RUN_DIR;
354
368
  if (
@@ -371,11 +385,13 @@ export function createDefaultPiSpawnRunner(options: {
371
385
  return;
372
386
  }
373
387
  if (timer !== undefined) clearTimeout(timer);
388
+ parentSignal?.removeEventListener("abort", terminateForParentAbort);
374
389
  settled = true;
375
390
  reject(error);
376
391
  });
377
392
  child.on("close", (code) => {
378
393
  if (timer !== undefined) clearTimeout(timer);
394
+ parentSignal?.removeEventListener("abort", terminateForParentAbort);
379
395
  void identityRecorded.then(
380
396
  () => {
381
397
  if (settled) return;
@@ -447,10 +463,27 @@ export function createPiRoleTurnHost(config: PiRoleTurnHostConfig): RoleTurnHost
447
463
  HOME: request.home,
448
464
  PI_CODING_AGENT_DIR: request.agentDir,
449
465
  AK_ROLE_RUN_DIR: request.runDirectory,
466
+ // Nested public summons resolve package root without import.meta under jiti (#675).
467
+ // Child-process scoped only — not written back onto the parent process.env.
468
+ AK_ROLE_PACKAGE_ROOT: config.packageRoot,
450
469
  };
451
470
  if (request.courtAttemptId === undefined) delete env.AK_ROLE_COURT_ATTEMPT;
452
471
  else env.AK_ROLE_COURT_ATTEMPT = request.courtAttemptId;
453
472
  applyEngineChildEnv(env, request.engine);
473
+ // Nested auditor dossier tool binds the parent run pointer when published.
474
+ if (
475
+ typeof process.env.AK_ROLE_AUDITOR_SOURCE_RUN === "string"
476
+ && process.env.AK_ROLE_AUDITOR_SOURCE_RUN.trim() !== ""
477
+ ) {
478
+ env.AK_ROLE_AUDITOR_SOURCE_RUN = process.env.AK_ROLE_AUDITOR_SOURCE_RUN;
479
+ }
480
+ // Audited-subject input selects soul materials (same for nested and direct).
481
+ if (
482
+ typeof process.env.AK_ROLE_AUDITOR_SUBJECT === "string"
483
+ && process.env.AK_ROLE_AUDITOR_SUBJECT.trim() !== ""
484
+ ) {
485
+ env.AK_ROLE_AUDITOR_SUBJECT = process.env.AK_ROLE_AUDITOR_SUBJECT;
486
+ }
454
487
  if (request.correlationId !== undefined && request.correlationId.trim() !== "") {
455
488
  env.AK_CORRELATION_ID = request.correlationId;
456
489
  }
@@ -468,6 +501,7 @@ export function createPiRoleTurnHost(config: PiRoleTurnHostConfig): RoleTurnHost
468
501
  cwd: request.cwd,
469
502
  env,
470
503
  ...(timeoutMs === undefined ? {} : { timeoutMs }),
504
+ ...(request.signal === undefined ? {} : { signal: request.signal }),
471
505
  });
472
506
  },
473
507
  };
@@ -60,6 +60,8 @@ import {
60
60
  parseInspectorArgv,
61
61
  parseMergerArgv,
62
62
  parseNavigatorArgv,
63
+ parseAuditorArgv,
64
+ parseEvidenceChildArgv,
63
65
  parseNotaryArgv,
64
66
  parseReviewerArgv,
65
67
  recordLaunchedPiIdentity,
@@ -128,6 +130,8 @@ const RESUME_SEAT_DISPATCH: Record<
128
130
  inspector: { seat: "inspector", run: runPublicInspectorResume },
129
131
  gatekeeper: { seat: "gatekeeper", run: runPublicInstructionSeatResume },
130
132
  navigator: { seat: "navigator", run: runPublicInstructionSeatResume },
133
+ auditor: { seat: "auditor", run: runPublicInstructionSeatResume },
134
+ "evidence-child": { seat: "evidence-child", run: runPublicInstructionSeatResume },
131
135
  diarist: { seat: "diarist", run: runPublicDiaristResume },
132
136
  };
133
137
  import {
@@ -171,6 +175,8 @@ export const PUBLIC_ROLE_ARGV = {
171
175
  reviewer: { parse: parseReviewerArgv, options: optionsForOwner("reviewer") },
172
176
  gatekeeper: { parse: parseGatekeeperArgv, options: optionsForOwner("gatekeeper") },
173
177
  navigator: { parse: parseNavigatorArgv, options: optionsForOwner("navigator") },
178
+ auditor: { parse: parseAuditorArgv, options: optionsForOwner("auditor") },
179
+ "evidence-child": { parse: parseEvidenceChildArgv, options: optionsForOwner("evidence-child") },
174
180
  diarist: { parse: parseDiaristArgv, options: optionsForOwner("diarist") },
175
181
  /** Deterministic analysis seat (#336) — argv parse only; no LLM admission. */
176
182
  analyst: { parse: parseAnalystArgv, options: optionsForOwner("analyst") },
@@ -1539,9 +1545,13 @@ export async function runAkRole(
1539
1545
  };
1540
1546
  }
1541
1547
 
1542
- // Gatekeeper/Navigator direct public run paths (#639) — instruction seats,
1543
- // a role like any other; one parameterized branch for both.
1544
- if (parsed.command === "gatekeeper" || parsed.command === "navigator") {
1548
+ // Instruction seats (#639 / #675): gatekeeper / navigator / auditor / evidence-child.
1549
+ if (
1550
+ parsed.command === "gatekeeper"
1551
+ || parsed.command === "navigator"
1552
+ || parsed.command === "auditor"
1553
+ || parsed.command === "evidence-child"
1554
+ ) {
1545
1555
  const agentDir = resolveAgentDir(env, home);
1546
1556
  const cwd = env.cwd ?? process.cwd();
1547
1557
  const config = await loadAndValidateConfig(home, env.packageRoot);
@@ -1558,9 +1568,7 @@ export async function runAkRole(
1558
1568
  createRoleEnvironment(env, { role: parsed.command, home, agentDir, cwd, credentials, seat, config }),
1559
1569
  io,
1560
1570
  parsed.command,
1561
- parsed.command === "gatekeeper"
1562
- ? PUBLIC_ROLE_ARGV.gatekeeper.parse
1563
- : PUBLIC_ROLE_ARGV.navigator.parse,
1571
+ PUBLIC_ROLE_ARGV[parsed.command].parse,
1564
1572
  );
1565
1573
  return {
1566
1574
  exitCode: result.exitCode,