@akagilnc/pi-workflow-roles 0.1.5593 → 0.1.5614

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 (58) hide show
  1. package/README.md +1 -1
  2. package/README.zh-CN.md +1 -1
  3. package/dist/acp-host/production-host.js +521 -707
  4. package/dist/compliance-transport.js +2 -5
  5. package/dist/doctor-auditor.js +1 -1
  6. package/dist/gatekeeper-role.js +1 -1
  7. package/dist/headless-host/production-host.js +505 -691
  8. package/dist/merger-contracts.js +6 -2
  9. package/dist/migrate-book-topology.js +5142 -10735
  10. package/dist/navigator-public-session.js +4 -4
  11. package/dist/navigator-work-base.js +5 -30
  12. package/dist/package-contracts/worker-output.js +1 -6
  13. package/dist/packaged-role-registry.js +9 -6
  14. package/dist/pi/role-turn-host.js +10 -1
  15. package/dist/public-cli/instruction-seat-run.js +133 -38
  16. package/dist/public-cli/invocation.js +38 -74
  17. package/dist/public-cli/main.js +18155 -18235
  18. package/dist/public-cli/option-definitions.js +21 -2
  19. package/dist/public-cli/post-admission.js +25 -24
  20. package/dist/public-cli/run-lifecycle.js +4 -43
  21. package/dist/public-cli/turn-request.js +4 -9
  22. package/dist/public-role-summons.js +5 -3
  23. package/dist/role-run-placement.js +7 -1
  24. package/dist/role-run-relocation.js +3 -4
  25. package/package.json +1 -1
  26. package/scripts/build-package.mjs +2 -4
  27. package/src/audited-run-identity.ts +30 -0
  28. package/src/compliance-transport.ts +1 -4
  29. package/src/doctor-auditor.ts +1 -1
  30. package/src/gatekeeper-role.ts +1 -1
  31. package/src/host-contracts.ts +6 -4
  32. package/src/merger-contracts.ts +6 -2
  33. package/src/merger-role.ts +11 -1
  34. package/src/navigator-attendance.ts +2 -2
  35. package/src/navigator-public-session.ts +9 -5
  36. package/src/navigator-work-base.ts +19 -34
  37. package/src/notary-role.ts +12 -21
  38. package/src/package-contracts/worker-output.ts +0 -8
  39. package/src/packaged-role-registry.ts +8 -7
  40. package/src/pi/role-turn-host.ts +11 -1
  41. package/src/public-cli/instruction-seat-run.ts +162 -42
  42. package/src/public-cli/invocation.ts +55 -93
  43. package/src/public-cli/option-definitions.ts +22 -2
  44. package/src/public-cli/post-admission.ts +30 -24
  45. package/src/public-cli/run-lifecycle.ts +4 -56
  46. package/src/public-cli/turn-request.ts +9 -8
  47. package/src/public-role-summons.ts +17 -6
  48. package/src/role-envelope.ts +4 -0
  49. package/src/role-run-placement.ts +10 -1
  50. package/src/role-run-relocation.ts +3 -4
  51. package/src/role-runtime-dependencies.ts +0 -2
  52. package/src/role-runtime.ts +54 -47
  53. package/src/worker-role.ts +11 -78
  54. package/dist/auditor-dossier-tool.js +0 -47
  55. package/dist/package-contracts/fixer-packet.js +0 -77
  56. package/packets/fixer-prerequisites.json +0 -6
  57. package/src/auditor-dossier-tool.ts +0 -63
  58. package/src/package-contracts/fixer-packet.ts +0 -91
@@ -121,6 +121,11 @@ export type PublicSummonRequest = {
121
121
  * (#946 / ADR 0082).
122
122
  */
123
123
  readonly stationChild?: boolean;
124
+ /**
125
+ * Navigator nest work-context locator (#1166). Request-scoped internal path —
126
+ * never dialogue content; never shared parent process.env across await.
127
+ */
128
+ readonly navigatorWorkContextPath?: string;
124
129
  };
125
130
 
126
131
  const execFileAsync = promisify(execFile);
@@ -421,6 +426,10 @@ export async function summonPublicRole(
421
426
  ? {}
422
427
  : { correlationId: options.correlationId }),
423
428
  ...(options.createRunId === undefined ? {} : { createRunId: options.createRunId }),
429
+ ...(options.navigatorWorkContextPath === undefined
430
+ || options.navigatorWorkContextPath.trim() === ""
431
+ ? {}
432
+ : { navigatorWorkContextPath: options.navigatorWorkContextPath }),
424
433
  },
425
434
  };
426
435
  } catch (error) {
@@ -746,13 +755,13 @@ export async function summonGateOfficer(options: {
746
755
  /**
747
756
  * Plain-language re-ask when the prior officer reply was not three-state (#753 / #756).
748
757
  * Officers: reviewReask → same-ticket resume summons.instruction.
749
- * Never concatenated into argv (inspector parentRunPath is the pure 卷宗指针).
758
+ * Never concatenated into argv (binding stays on --source-run / parentRunPath).
750
759
  */
751
760
  readonly reask?: string;
752
761
  /**
753
762
  * In-flight parent 交卷 body (tool-call arguments). Relayed verbatim as officer
754
763
  * dialogue content when reask is absent (#879). Binding pointer stays on
755
- * --source-run / 卷宗指针 / ticket argv — never a content substitute.
764
+ * --source-run / parentRunPath — never a content substitute.
756
765
  */
757
766
  readonly submission?: unknown;
758
767
  /** Pi-adapter inject — forwarded to summonPublicRole (not a parent-host override). */
@@ -808,6 +817,7 @@ export async function summonGateOfficer(options: {
808
817
  if (gateSummon === "subject-source") {
809
818
  // #756: judge compliance path — same queue law as notary/inspector.
810
819
  // Binding pointer on argv; dialogue content rides gateReviewInstruction.
820
+ // #1166: no code-authored 卷宗指针 instruction — identity is startup material.
811
821
  return summonPublicRole({
812
822
  role: options.officer,
813
823
  argv: [
@@ -815,7 +825,8 @@ export async function summonGateOfficer(options: {
815
825
  "judge",
816
826
  "--source-run",
817
827
  options.sourceRunDirectory,
818
- `卷宗指针:${options.sourceRunDirectory}`,
828
+ "--project",
829
+ options.cwd,
819
830
  ],
820
831
  ...common,
821
832
  });
@@ -850,11 +861,11 @@ export async function summonGateOfficer(options: {
850
861
  ...(courtTicket === undefined ? {} : { boundTicketNumber: courtTicket }),
851
862
  });
852
863
  }
853
- // Inspector: argv stays pure 卷宗指针 (#747 parentRunPath lookup key).
854
- // Content (body/reask) rides env → summons.instruction / first-mint prompt.
864
+ // Inspector: bind via --source-run (same face as notary); dialogue rides env.
865
+ // #1166: no code-authored 卷宗指针 instruction — identity is startup material.
855
866
  return summonPublicRole({
856
867
  role: options.officer,
857
- argv: [`卷宗指针:${options.sourceRunDirectory}`],
868
+ argv: ["--source-run", options.sourceRunDirectory, "--project", options.cwd],
858
869
  ...common,
859
870
  });
860
871
  }
@@ -178,6 +178,10 @@ export async function prepareRoleEnvelope(options: {
178
178
  ...(request.courtAttemptId === undefined ? {} : { courtAttemptId: request.courtAttemptId }),
179
179
  ...(request.invocationScopeId === undefined ? {} : { invocationScopeId: request.invocationScopeId }),
180
180
  ...(request.host === undefined || request.host.trim() === "" ? {} : { host: request.host.trim() }),
181
+ ...(request.navigatorWorkContextPath === undefined
182
+ || request.navigatorWorkContextPath.trim() === ""
183
+ ? {}
184
+ : { navigatorWorkContextPath: request.navigatorWorkContextPath }),
181
185
  sessionManager: {
182
186
  getLeafEntry: () => sessionEntries.at(-1) as ReturnType<HostContext["sessionManager"]["getLeafEntry"]>,
183
187
  getLeafId: () => runId,
@@ -1,5 +1,5 @@
1
1
  import { readdir } from "node:fs/promises";
2
- import { basename, dirname, join } from "node:path";
2
+ import { basename, dirname, join, resolve } from "node:path";
3
3
 
4
4
  import {
5
5
  activationBookDirectory,
@@ -54,6 +54,15 @@ export function runDirectoryOfSessionFile(sessionFile: string): string {
54
54
  return dirname(dirname(sessionFile));
55
55
  }
56
56
 
57
+ /** Climb session/session.jsonl → run directory when the host exposes a session file. */
58
+ export function auditorRunDirectory(context: {
59
+ readonly sessionManager?: { getSessionFile?: () => string | undefined };
60
+ }): string | undefined {
61
+ const sessionFile = context.sessionManager?.getSessionFile?.();
62
+ if (sessionFile === undefined) return undefined;
63
+ return resolve(runDirectoryOfSessionFile(sessionFile));
64
+ }
65
+
57
66
  /** `<run>/session` → run directory. */
58
67
  export function runDirectoryFromSessionDirectory(sessionDirectory: string): string {
59
68
  return dirname(sessionDirectory);
@@ -23,10 +23,9 @@ const ADMITTED_PAGE_FIELDS = [
23
23
  "admittedRequestPath", // pre-#1161 pages only
24
24
  "sessionDirectory",
25
25
  "sessionFile",
26
- "taskPath",
27
- "packetPath",
28
- "prerequisitesPath",
29
- // #1165: requestManifestPath is a caller path — never rewrite.
26
+ // #1165/#1168: caller file-flag paths (requestManifestPath, prerequisitesPath)
27
+ // stay as given. Obsolete copy fields (taskPath/packetPath) are not rewritten —
28
+ // stock volumes keep their bytes; live relocate no longer maintains them.
30
29
  "mergerInputPath",
31
30
  "sourceRunPath",
32
31
  ] as const;
@@ -45,8 +45,6 @@ export function createRoleRuntimeDependencies(packageRoot: string): RoleRuntimeD
45
45
  packageRoot,
46
46
  loadRoleReferenceMaterials: loadPackagedRoleReferenceMaterials,
47
47
  loadRoleSoul: loadRegisteredRoleSoul,
48
- loadFixPacket: (path) => readFile(path, "utf8"),
49
- loadCoderTask: (path) => readFile(path, "utf8"),
50
48
  loadDoctorCase,
51
49
  loadNotarySourceRun: loadNotarySourceRunLocator,
52
50
  loadMergerInput: async (path) => JSON.parse(await readFile(path, "utf8")),
@@ -106,8 +106,13 @@ import {
106
106
  type AuditorRuntimeDependencies,
107
107
  } from "./auditor-role.ts";
108
108
 
109
+ import {
110
+ auditedRunIdentityFromDirectory,
111
+ auditedRunIdentityMaterial,
112
+ } from "./audited-run-identity.ts";
109
113
  import { formatNavigatorReport, NAVIGATOR_EVENT_TYPE, NAVIGATOR_ROUTE_PLAYBOOK_FAILURE_ENTRY, navigatorSubjectKey, navigatorUnavailableError, subjectPath, type NavigatorAttendance, type NavigatorAttendanceOptions, type NavigatorEvent, type NavigatorPhase, type NavigatorReport, type NavigatorSettlement, type NavigatorSubjectProvenance, type NavigatorWorkContext } from "./navigator-attendance.ts";
110
114
  import { loadNavigatorWorkBaseSuffix } from "./navigator-work-base.ts";
115
+ import { AK_ROLE_AUDITOR_SOURCE_RUN_ENV } from "./auditor-soul.ts";
111
116
  import {
112
117
  buildNavigatorInfrastructureFailureFact,
113
118
  classifyPackagedRoleTerminalResult,
@@ -346,8 +351,6 @@ export {
346
351
  } from "./worker-role.ts";
347
352
  export { fixerOutputSchema, validateFixerOutput } from "./package-contracts/fixer-output.ts";
348
353
  export type { FixerBlocker, FixerClassResult, FixerPhase, FixerTestEvidence } from "./package-contracts/fixer-output.ts";
349
- export { fixerPrerequisiteSchema, fixerPrerequisitesSchema, parseFixerPrerequisites, validateFixerPrerequisites } from "./package-contracts/fixer-packet.ts";
350
- export type { FixerInvocationInput, FixerPrerequisite } from "./package-contracts/fixer-packet.ts";
351
354
  export {
352
355
  AUDITOR_SOUL_ROLES,
353
356
  AK_ROLE_AUDITOR_SUBJECT_ENV,
@@ -460,8 +463,6 @@ export type RoleRuntimeDependencies = {
460
463
  loadRoleReferenceMaterials?(role: PackagedRole): Promise<string>;
461
464
  /** One soul loader. The role argument selects the registry record. */
462
465
  loadRoleSoul(role: PackagedRole): Promise<string>;
463
- loadFixPacket?(path: string): Promise<string>;
464
- loadCoderTask?(path: string): Promise<string>;
465
466
  loadNotarySourceRun?(path: string): Promise<import("./notary-contracts.ts").NotarySourceRunLocator>;
466
467
  loadDoctorCase?(path: string): Promise<import("./doctor-contracts.ts").DoctorCase>;
467
468
  loadMergerInput?(path: string): Promise<unknown>;
@@ -694,7 +695,7 @@ export function createNavigatorRoleRuntime(
694
695
  const loadRoutePlaybook = dependencies.loadRoutePlaybook
695
696
  ?? (() => readPackageMaterial("resources/navigator-route-playbook.md"));
696
697
  let playbookRead: Promise<string> | undefined;
697
- roleHost.on("before_agent_start", async (event) => {
698
+ roleHost.on("before_agent_start", async (event, ctx) => {
698
699
  const basePrompt = typeof event.systemPrompt === "string" ? event.systemPrompt : "";
699
700
  const parts: string[] = [];
700
701
  try {
@@ -709,8 +710,10 @@ export function createNavigatorRoleRuntime(
709
710
  parts.push(message);
710
711
  }
711
712
  }
712
- const prompt = typeof event.prompt === "string" ? event.prompt : "";
713
- const work = await loadNavigatorWorkBaseSuffix(prompt);
713
+ const work = await loadNavigatorWorkBaseSuffix(
714
+ ctx.sessionManager?.getSessionDir?.(),
715
+ ctx.navigatorWorkContextPath,
716
+ );
714
717
  if (work !== undefined && work.trim() !== "") parts.push(work);
715
718
  if (parts.length === 0) return;
716
719
  const text = parts.join("\n\n");
@@ -727,7 +730,7 @@ export function createAuditorRoleRuntime(
727
730
  roleHost: RoleHost,
728
731
  dependencies: AuditorRuntimeDependencies,
729
732
  ) {
730
- const base = createFiledOfficerRuntime(
733
+ return createFiledOfficerRuntime(
731
734
  roleHost,
732
735
  {
733
736
  role: "auditor",
@@ -736,24 +739,39 @@ export function createAuditorRoleRuntime(
736
739
  },
737
740
  dependencies,
738
741
  );
739
- return {
740
- async activate() {
741
- await base.activate();
742
- // Same tools whether nested or direct (#675): dossier tool always registered.
743
- // Source run: only the shared --source-run input face (never own-run fallback).
744
- const { createAuditorDossierTool, AUDITOR_DOSSIER_TOOL_NAME } =
745
- await import("./auditor-dossier-tool.ts");
746
- const { AK_ROLE_AUDITOR_SOURCE_RUN_ENV } = await import("./auditor-soul.ts");
747
- const already = roleHost.getAllTools().some((tool) => tool.name === AUDITOR_DOSSIER_TOOL_NAME);
748
- if (already) return;
749
- const sourceRun =
750
- typeof process.env[AK_ROLE_AUDITOR_SOURCE_RUN_ENV] === "string"
751
- && process.env[AK_ROLE_AUDITOR_SOURCE_RUN_ENV].trim() !== ""
752
- ? process.env[AK_ROLE_AUDITOR_SOURCE_RUN_ENV].trim()
753
- : undefined;
754
- roleHost.registerTool(createAuditorDossierTool(sourceRun) as never);
755
- },
756
- };
742
+ }
743
+
744
+ function isAuditedIdentitySeat(role: string): boolean {
745
+ return role === "notary" || role === "inspector" || role === "auditor" || role === "countersign";
746
+ }
747
+
748
+ /** Resolve audited-run directory for identity material — this-leg flags / admitted page first. */
749
+ function resolveAuditedSourceRunDirectory(
750
+ roleHost: RoleHost,
751
+ ctx: HostContext,
752
+ role: string,
753
+ ): string | undefined {
754
+ const notary = roleHost.getFlag(NOTARY_SOURCE_RUN_FLAG.name);
755
+ if (typeof notary === "string" && notary.trim() !== "") return notary.trim();
756
+ const inspector = roleHost.getFlag(INSPECTOR_SOURCE_RUN_FLAG.name);
757
+ if (typeof inspector === "string" && inspector.trim() !== "") return inspector.trim();
758
+ // This-leg admitted binding wins over shared auditor env (#1166 J3).
759
+ const runDirectory = runDirectoryFromHostContext(ctx);
760
+ if (runDirectory !== undefined) {
761
+ const admitted = readPageSync(runDirectory, "admitted");
762
+ if (typeof admitted?.sourceRunPath === "string" && admitted.sourceRunPath.trim() !== "") {
763
+ return admitted.sourceRunPath.trim();
764
+ }
765
+ }
766
+ // Auditor env is request-scoped soul binding for the auditor seat only.
767
+ if (role === "auditor") {
768
+ const auditor =
769
+ typeof process.env[AK_ROLE_AUDITOR_SOURCE_RUN_ENV] === "string"
770
+ ? process.env[AK_ROLE_AUDITOR_SOURCE_RUN_ENV].trim()
771
+ : "";
772
+ if (auditor !== "") return auditor;
773
+ }
774
+ return undefined;
757
775
  }
758
776
 
759
777
  /**
@@ -1224,15 +1242,16 @@ export function createRoleRuntimeExtension(
1224
1242
  if (reading === undefined) return;
1225
1243
  return { readingMaterial: reading };
1226
1244
  });
1227
- roleHost.on("before_agent_start", () => {
1228
- const path = roleHost.getFlag(INSPECTOR_SOURCE_RUN_FLAG.name);
1229
- if (typeof path !== "string" || path.trim() === "") return;
1230
- return {
1231
- readingMaterial: {
1232
- kind: "inspector-parent-binding" as const,
1233
- sourceRunPath: path,
1234
- },
1235
- };
1245
+ // #1166 / ADR 0087: four audit seats share one audited-run identity material.
1246
+ // Notary also emits identity from its own before_agent_start; skip double fold.
1247
+ roleHost.on("before_agent_start", (_event, ctx) => {
1248
+ const role = selectedRole ?? roleHost.getFlag(ROLE_FLAG.name);
1249
+ if (typeof role !== "string" || !isAuditedIdentitySeat(role) || role === "notary") return;
1250
+ const sourceDirectory = resolveAuditedSourceRunDirectory(roleHost, ctx, role);
1251
+ if (sourceDirectory === undefined) return;
1252
+ const identity = auditedRunIdentityFromDirectory(sourceDirectory);
1253
+ if (identity === undefined) return;
1254
+ return { readingMaterial: auditedRunIdentityMaterial(identity) };
1236
1255
  });
1237
1256
  roleHost.on("tool_result", async (event, ctx) => {
1238
1257
  const role = selectedRole;
@@ -1459,12 +1478,6 @@ export function createRoleRuntimeExtension(
1459
1478
  roleHost,
1460
1479
  {
1461
1480
  loadSoul: () => requireRoleSoul("fixer"),
1462
- async loadPacket(path) {
1463
- if (dependencies.loadFixPacket === undefined) {
1464
- throw new Error("Fixer packet loader is not configured");
1465
- }
1466
- return dependencies.loadFixPacket(path);
1467
- },
1468
1481
  },
1469
1482
  hostActions,
1470
1483
  { unfinishedReasonBounceLimit: deliveryLimit },
@@ -1473,12 +1486,6 @@ export function createRoleRuntimeExtension(
1473
1486
  roleHost,
1474
1487
  {
1475
1488
  loadSoul: () => requireRoleSoul("coder"),
1476
- async loadTask(path) {
1477
- if (dependencies.loadCoderTask === undefined) {
1478
- throw new Error("Coder task loader is not configured");
1479
- }
1480
- return dependencies.loadCoderTask(path);
1481
- },
1482
1489
  },
1483
1490
  hostActions,
1484
1491
  { unfinishedReasonBounceLimit: deliveryLimit },
@@ -10,11 +10,6 @@ import {
10
10
  import { validateFixerOutput, type FixerPhase } from "./package-contracts/fixer-output.ts";
11
11
  import { registerFiledSubmissionTool } from "./filed-submission.ts";
12
12
  import { roleSubmissionDeclaration } from "./role-submission-declarations.ts";
13
- import {
14
- FixerPacketValidationError,
15
- parseFixerPrerequisites,
16
- type FixerInvocationInput,
17
- } from "./package-contracts/fixer-packet.ts";
18
13
  import {
19
14
  createWorkerSubmissionGate,
20
15
  WorkerCommitReminderError,
@@ -37,21 +32,8 @@ export {
37
32
  validateAcceptedWorkerDetails,
38
33
  } from "./package-contracts/worker-output.ts";
39
34
  export type { WorkerOutput, FixerOutput, CoderOutput };
35
+ /** #1168: phase only — dispatch text is the first message, not a packet flag. */
40
36
  export const FIXER_FLAG_DEFINITIONS = {
41
- packet: {
42
- name: "ak-fix-packet",
43
- definition: {
44
- description: "Path to opaque prose instructions for the Fixer",
45
- type: "string" as const,
46
- },
47
- },
48
- prerequisites: {
49
- name: "ak-fixer-prerequisites",
50
- definition: {
51
- description: "Optional path to a JSON array of typed Fixer prerequisites",
52
- type: "string" as const,
53
- },
54
- },
55
37
  phase: {
56
38
  name: "ak-fixer-phase",
57
39
  definition: {
@@ -73,12 +55,10 @@ export type WorkerRoleHostActions = HostGatekeeperActions;
73
55
 
74
56
  export type FixerRoleDependencies = {
75
57
  loadSoul(): Promise<string>;
76
- loadPacket(path: string): Promise<string>;
77
58
  };
78
59
 
79
60
  export type CoderRoleDependencies = {
80
61
  loadSoul(): Promise<string>;
81
- loadTask(path: string): Promise<string>;
82
62
  };
83
63
 
84
64
  export type WorkerRoleRuntime = {
@@ -178,9 +158,6 @@ export function createFixerRoleRuntime(
178
158
  options?: { readonly unfinishedReasonBounceLimit?: number },
179
159
  ): WorkerRoleRuntime {
180
160
  let soul: string | undefined;
181
- let packet: FixerInvocationInput | undefined;
182
- let packetPath: string | undefined;
183
- let prerequisitesPath: string | undefined;
184
161
  let phase: WorkerPhase | undefined;
185
162
  let lifecycleRegistered = false;
186
163
  // #1132: ADR 0050 缺理由催全次数. The in-process seam passes the value it
@@ -190,14 +167,6 @@ export function createFixerRoleRuntime(
190
167
  ?? deliveryLimitFromEnv(process.env),
191
168
  });
192
169
 
193
- pi.registerFlag(
194
- FIXER_FLAG_DEFINITIONS.packet.name,
195
- FIXER_FLAG_DEFINITIONS.packet.definition,
196
- );
197
- pi.registerFlag(
198
- FIXER_FLAG_DEFINITIONS.prerequisites.name,
199
- FIXER_FLAG_DEFINITIONS.prerequisites.definition,
200
- );
201
170
  pi.registerFlag(
202
171
  FIXER_FLAG_DEFINITIONS.phase.name,
203
172
  FIXER_FLAG_DEFINITIONS.phase.definition,
@@ -214,33 +183,12 @@ export function createFixerRoleRuntime(
214
183
  );
215
184
  }
216
185
  phase = selectedPhase;
217
- const resolvedPacketPath = pi.getFlag(FIXER_FLAG_DEFINITIONS.packet.name);
218
- if (typeof resolvedPacketPath !== "string" || resolvedPacketPath.trim().length === 0) {
219
- throw new Error("Fixer role requires --ak-fix-packet");
220
- }
221
- packetPath = resolvedPacketPath;
222
- const instructions = await dependencies.loadPacket(packetPath);
223
- if (instructions.trim().length === 0) {
224
- throw new FixerPacketValidationError(
225
- new Error("Fixer instructions must be nonblank"),
226
- );
227
- }
228
- const resolvedPrerequisitesPath = pi.getFlag(FIXER_FLAG_DEFINITIONS.prerequisites.name);
229
- if (resolvedPrerequisitesPath !== undefined && (typeof resolvedPrerequisitesPath !== "string" || resolvedPrerequisitesPath.trim().length === 0)) {
230
- throw new Error("Fixer --ak-fixer-prerequisites path must be nonblank when supplied");
231
- }
232
- prerequisitesPath =
233
- typeof resolvedPrerequisitesPath === "string" ? resolvedPrerequisitesPath : undefined;
234
- const prerequisites = prerequisitesPath !== undefined
235
- ? parseFixerPrerequisites(await dependencies.loadPacket(prerequisitesPath))
236
- : Object.freeze([]);
237
- packet = Object.freeze({ instructions, prerequisites });
238
186
 
239
187
  if (!lifecycleRegistered) {
240
188
  lifecycleRegistered = true;
241
189
  registerWorkerSubmission(pi, "fixer", {
242
- notReady: "修内司修理包与阶段未装载",
243
- ready: () => packet !== undefined && phase !== undefined,
190
+ notReady: "修内司阶段未装载",
191
+ ready: () => phase !== undefined,
244
192
  phase: () => phase,
245
193
  project: (parameters, current) => deepFreeze(validateFixerOutput(parameters, current)),
246
194
  submissionGate,
@@ -257,17 +205,12 @@ export function createFixerRoleRuntime(
257
205
  reason: fixerBashSeatbeltDenyReason(matched),
258
206
  };
259
207
  });
208
+ // #1168: soul + phase only; dispatch text is the first message.
260
209
  pi.on("before_agent_start", (event) => {
261
210
  if (soul === undefined) throw new Error("修内司职分未装载");
262
- if (packetPath === undefined) throw new Error("修内司修理包路径未装载");
263
- // Path delivery only — body is self-fetched; no inline duplicate of flag bytes (#632).
264
- const prerequisitesBlock =
265
- prerequisitesPath === undefined
266
- ? ""
267
- : `\n\n<fixer_prerequisites_path>\n${prerequisitesPath}\n</fixer_prerequisites_path>`;
268
211
  return {
269
212
  systemPrompt:
270
- `${event.systemPrompt}\n\n<fixer_soul>\n${soul}\n</fixer_soul>\n\n<fixer_phase>\n${phase ?? ""}\n</fixer_phase>\n\n<fix_packet_path>\n${packetPath}\n</fix_packet_path>${prerequisitesBlock}`,
213
+ `${event.systemPrompt}\n\n<fixer_soul>\n${soul}\n</fixer_soul>\n\n<fixer_phase>\n${phase ?? ""}\n</fixer_phase>`,
271
214
  };
272
215
  });
273
216
  }
@@ -285,7 +228,6 @@ export function createCoderRoleRuntime(
285
228
  options?: { readonly unfinishedReasonBounceLimit?: number },
286
229
  ): WorkerRoleRuntime {
287
230
  let soul: string | undefined;
288
- let task: string | undefined;
289
231
  let phase: WorkerPhase | undefined;
290
232
  let lifecycleRegistered = false;
291
233
  // #1132: same resolved ceiling as the fixer gate. Absent = Pi child env.
@@ -294,10 +236,6 @@ export function createCoderRoleRuntime(
294
236
  ?? deliveryLimitFromEnv(process.env),
295
237
  });
296
238
 
297
- pi.registerFlag("ak-coder-task", {
298
- description: "Markdown task assigned to the coder role",
299
- type: "string",
300
- });
301
239
  pi.registerFlag("ak-coder-phase", {
302
240
  description:
303
241
  "Coder phase: plan (inspect and propose an implementation plan; no edits or commits) or apply (execute the approved plan and verify the first implementation)",
@@ -305,7 +243,7 @@ export function createCoderRoleRuntime(
305
243
  });
306
244
 
307
245
  return {
308
- async activate(ctx) {
246
+ async activate() {
309
247
  soul = (await dependencies.loadSoul()).trim();
310
248
  if (soul.length === 0) throw new Error("Coder soul is empty");
311
249
  const selectedPhase = pi.getFlag("ak-coder-phase");
@@ -315,28 +253,23 @@ export function createCoderRoleRuntime(
315
253
  );
316
254
  }
317
255
  phase = selectedPhase;
318
- const taskPath = pi.getFlag("ak-coder-task");
319
- if (typeof taskPath !== "string" || taskPath.trim().length === 0) {
320
- throw new Error("Coder role requires --ak-coder-task");
321
- }
322
- task = (await dependencies.loadTask(taskPath)).trim();
323
- if (task.length === 0) throw new Error("Coder task is empty");
324
256
 
325
257
  if (!lifecycleRegistered) {
326
258
  lifecycleRegistered = true;
327
259
  registerWorkerSubmission(pi, "coder", {
328
- notReady: "将作监任务与阶段未装载",
329
- ready: () => task !== undefined && phase !== undefined,
260
+ notReady: "将作监阶段未装载",
261
+ ready: () => phase !== undefined,
330
262
  phase: () => phase,
331
263
  project: (parameters, current) => validateWorkerOutput(parameters, current, "Coder"),
332
264
  submissionGate,
333
265
  hostActions,
334
266
  });
335
- pi.on("before_agent_start", (event, ctx) => {
267
+ // #1168: soul + phase only; dispatch text is the first message.
268
+ pi.on("before_agent_start", (event) => {
336
269
  if (soul === undefined) throw new Error("将作监职分未装载");
337
270
  return {
338
271
  systemPrompt:
339
- `${event.systemPrompt}\n\n<coder_soul>\n${soul}\n</coder_soul>\n\n<coder_phase>\n${phase ?? ""}\n</coder_phase>\n\n<coder_task>\n${task ?? ""}\n</coder_task>`,
272
+ `${event.systemPrompt}\n\n<coder_soul>\n${soul}\n</coder_soul>\n\n<coder_phase>\n${phase ?? ""}\n</coder_phase>`,
340
273
  };
341
274
  });
342
275
  }
@@ -1,47 +0,0 @@
1
- import { join, resolve } from "node:path";
2
- import { RUN_HISTORY_FILE, RUN_LOG_FILE, runCurrentPath } from "./run-dossier.js";
3
- import {
4
- runDirectoryOfSessionFile,
5
- sessionFileOf
6
- } from "./role-run-placement.js";
7
- import { Type } from "typebox";
8
- const AUDITOR_DOSSIER_TOOL_NAME = "ak_get_run_dossier";
9
- function auditorRunDirectory(context) {
10
- const sessionFile = context.sessionManager?.getSessionFile?.();
11
- if (sessionFile === void 0) return void 0;
12
- return resolve(runDirectoryOfSessionFile(sessionFile));
13
- }
14
- function createAuditorDossierTool(runDirectory) {
15
- return {
16
- name: AUDITOR_DOSSIER_TOOL_NAME,
17
- description: "\u5B9A\u4F4D\u672C\u5BA1\u8BA1\u5E2D\u7ED1\u5B9A\u7684 run \u5377\u5B97\u53CA\u5176\u8BC1\u636E\u5165\u53E3\u3002",
18
- // #836 r16 class 3: execute() ignores `_params` entirely — a closed root
19
- // only rejects the role for saying more.
20
- parameters: Type.Object({}, { additionalProperties: true }),
21
- async execute(_id, _params) {
22
- if (runDirectory === void 0) {
23
- return {
24
- content: [{ type: "text", text: "\u672C\u5BA1\u8BA1\u5E2D\u65E0\u7ED1\u5B9A run \u5377\u5B97\u8BB0\u5F55\u3002" }],
25
- details: void 0
26
- };
27
- }
28
- const details = {
29
- runDirectory,
30
- current: runCurrentPath(runDirectory),
31
- parentSessionCandidate: sessionFileOf(runDirectory),
32
- attachments: join(runDirectory, "attachments"),
33
- log: join(runDirectory, RUN_LOG_FILE),
34
- history: join(runDirectory, RUN_HISTORY_FILE)
35
- };
36
- return {
37
- content: [{ type: "text", text: JSON.stringify(details) }],
38
- details
39
- };
40
- }
41
- };
42
- }
43
- export {
44
- AUDITOR_DOSSIER_TOOL_NAME,
45
- auditorRunDirectory,
46
- createAuditorDossierTool
47
- };
@@ -1,77 +0,0 @@
1
- import { Type } from "typebox";
2
- import { Value } from "typebox/value";
3
- import { isRecord } from "../unknown-value.js";
4
- const FIXER_PREREQUISITE_ID_PATTERN = "^[A-Za-z0-9][A-Za-z0-9._-]*$";
5
- const fixerPrerequisiteSchema = Type.Object({
6
- id: Type.String({ pattern: FIXER_PREREQUISITE_ID_PATTERN }),
7
- requirement: Type.String({ pattern: "\\S" })
8
- });
9
- const fixerPrerequisitesSchema = Type.Array(fixerPrerequisiteSchema);
10
- function causeMessage(cause) {
11
- if (cause instanceof Error) return cause.message;
12
- if (typeof cause === "string") return cause;
13
- try {
14
- return JSON.stringify(cause) ?? String(cause);
15
- } catch {
16
- return String(cause);
17
- }
18
- }
19
- class FixerPacketValidationError extends Error {
20
- code = "AK_INVALID_FIX_PACKET";
21
- constructor(cause) {
22
- const prefix = "Fixer prerequisites or instructions violate the invocation contract";
23
- super(
24
- cause === void 0 ? prefix : `${prefix}: ${causeMessage(cause)}`,
25
- cause === void 0 ? void 0 : { cause }
26
- );
27
- this.name = "FixerPacketValidationError";
28
- }
29
- }
30
- function fail(cause) {
31
- throw new FixerPacketValidationError(cause);
32
- }
33
- function parseFailure(value) {
34
- if (!Array.isArray(value)) fail(new Error("Fixer prerequisites must be a JSON array"));
35
- for (const entry of value) {
36
- if (!isRecord(entry)) {
37
- fail(new Error("Fixer prerequisite entry must be an object with id and requirement fields"));
38
- }
39
- if (typeof entry.id !== "string" || !new RegExp(FIXER_PREREQUISITE_ID_PATTERN).test(entry.id)) {
40
- fail(new Error(`Fixer prerequisite id violates pattern ${FIXER_PREREQUISITE_ID_PATTERN}`));
41
- }
42
- if (typeof entry.requirement !== "string" || !/\S/.test(entry.requirement)) {
43
- fail(new Error("Fixer prerequisite requirement must be nonblank"));
44
- }
45
- }
46
- fail(new Error("Fixer prerequisites violate the attachment schema"));
47
- }
48
- function validateFixerPrerequisites(value) {
49
- if (!Value.Check(fixerPrerequisitesSchema, value)) parseFailure(value);
50
- const entries = value;
51
- const ids = /* @__PURE__ */ new Set();
52
- const prerequisites = entries.map((entry) => {
53
- if (ids.has(entry.id)) {
54
- fail(new Error(`Fixer prerequisites contain duplicate id: ${entry.id}`));
55
- }
56
- ids.add(entry.id);
57
- return Object.freeze({ id: entry.id, requirement: entry.requirement });
58
- });
59
- return Object.freeze(prerequisites);
60
- }
61
- function parseFixerPrerequisites(source) {
62
- let decoded;
63
- try {
64
- decoded = JSON.parse(source);
65
- } catch (error) {
66
- fail(error);
67
- }
68
- return validateFixerPrerequisites(decoded);
69
- }
70
- export {
71
- FIXER_PREREQUISITE_ID_PATTERN,
72
- FixerPacketValidationError,
73
- fixerPrerequisiteSchema,
74
- fixerPrerequisitesSchema,
75
- parseFixerPrerequisites,
76
- validateFixerPrerequisites
77
- };
@@ -1,6 +0,0 @@
1
- [
2
- {
3
- "id": "owner.choice",
4
- "requirement": "The controlling owner decision required before this repair exists."
5
- }
6
- ]