@akagilnc/pi-workflow-roles 0.1.3771 → 0.1.3789

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 (40) hide show
  1. package/README.md +1 -1
  2. package/README.zh-CN.md +1 -1
  3. package/dist/acp-host/production-host.js +793 -393
  4. package/dist/atomic-write.js +23 -0
  5. package/dist/collector-handbook.js +142 -0
  6. package/dist/collector-ledger.js +39 -47
  7. package/dist/collector-role.js +103 -14
  8. package/dist/collector-tool-schemas.js +25 -1
  9. package/dist/headless-host/description.js +77 -0
  10. package/dist/headless-host/mcp-relay.mjs +119 -0
  11. package/dist/headless-host/production-host.js +26841 -0
  12. package/dist/host-descriptions.js +44 -3
  13. package/dist/public-cli/load-production-external-host.js +19 -0
  14. package/dist/public-cli/load-production-headless-host.js +36 -0
  15. package/dist/public-cli/main.js +244 -234
  16. package/dist/public-cli/option-definitions.js +2 -2
  17. package/dist/public-role-summons.js +40 -5
  18. package/dist/role-runtime.js +3 -0
  19. package/extensions/role-runtime.ts +2 -0
  20. package/package.json +1 -1
  21. package/resources/collector-bot-handbook.md +33 -0
  22. package/scripts/build-package.mjs +28 -0
  23. package/src/acp-host/production-host.ts +4 -0
  24. package/src/acp-host/role-envelope.ts +141 -84
  25. package/src/acp-host/role-turn-host.ts +12 -0
  26. package/src/collector-handbook.ts +194 -0
  27. package/src/collector-ledger.ts +42 -62
  28. package/src/collector-role.ts +117 -11
  29. package/src/collector-tool-schemas.ts +25 -1
  30. package/src/headless-host/description.ts +123 -0
  31. package/src/headless-host/production-host.ts +75 -0
  32. package/src/headless-host/role-turn-host.ts +424 -0
  33. package/src/host-descriptions.ts +53 -6
  34. package/src/public-cli/cli.ts +2 -2
  35. package/src/public-cli/load-production-external-host.ts +29 -0
  36. package/src/public-cli/load-production-headless-host.ts +48 -0
  37. package/src/public-cli/main.ts +5 -0
  38. package/src/public-cli/option-definitions.ts +2 -2
  39. package/src/public-role-summons.ts +62 -9
  40. package/src/role-runtime.ts +5 -0
@@ -883,10 +883,10 @@ __export(session_assistant_usage_exports, {
883
883
  });
884
884
  import { join as join2 } from "node:path";
885
885
  async function readAssistantUsageFromSessionFile(sessionFile) {
886
- const { readFile: readFile21 } = await import("node:fs/promises");
886
+ const { readFile: readFile22 } = await import("node:fs/promises");
887
887
  let text;
888
888
  try {
889
- text = await readFile21(sessionFile, "utf8");
889
+ text = await readFile22(sessionFile, "utf8");
890
890
  } catch (error) {
891
891
  if (error?.code === "ENOENT") return void 0;
892
892
  throw error;
@@ -6085,8 +6085,8 @@ var init_option_definitions = __esm({
6085
6085
  repeatable: false,
6086
6086
  form: "option",
6087
6087
  description: {
6088
- en: "Optional request manifest JSON path ({requests:[{id,body}]}).",
6089
- zh: "\u53EF\u9009 request manifest JSON \u8DEF\u5F84\uFF08{requests:[{id,body}]}\uFF09\u3002"
6088
+ en: "Optional request manifest JSON path ({requests:[{id,body}]}). Role may also decide request bodies from handbook/field activity without this file.",
6089
+ zh: "\u53EF\u9009 request manifest JSON \u8DEF\u5F84\uFF08{requests:[{id,body}]}\uFF09\u3002\u89D2\u8272\u4EA6\u53EF\u4F9D\u624B\u518C/\u73B0\u573A\u81EA\u884C\u5224\u5B9A\u8BF7\u6C42\u6B63\u6587\uFF0C\u4E0D\u5FC5\u4F9D\u8D56\u672C\u6587\u4EF6\u3002"
6090
6090
  }
6091
6091
  }
6092
6092
  ];
@@ -8518,11 +8518,11 @@ function parseAnalystCohortIssueToken(raw, flag) {
8518
8518
  `${flag} requires a comma-separated list of N or book:N`
8519
8519
  );
8520
8520
  }
8521
- const sep4 = trimmed.lastIndexOf(":");
8522
- if (sep4 > 0) {
8523
- const rhs = trimmed.slice(sep4 + 1);
8521
+ const sep5 = trimmed.lastIndexOf(":");
8522
+ if (sep5 > 0) {
8523
+ const rhs = trimmed.slice(sep5 + 1);
8524
8524
  if (ANALYST_TICKET_NUMBER_PATTERN.test(rhs)) {
8525
- const bookKey = trimmed.slice(0, sep4);
8525
+ const bookKey = trimmed.slice(0, sep5);
8526
8526
  if (bookKey.trim() === "") {
8527
8527
  throw new CliUsageError(
8528
8528
  `${flag} book:N requires a non-empty book key, got ${raw}`
@@ -8756,24 +8756,35 @@ var init_invocation = __esm({
8756
8756
  var host_descriptions_exports = {};
8757
8757
  __export(host_descriptions_exports, {
8758
8758
  DEFAULT_ROLE_TURN_HOST: () => DEFAULT_ROLE_TURN_HOST,
8759
+ HEADLESS_HOST_DESCRIPTIONS: () => HEADLESS_HOST_DESCRIPTIONS,
8759
8760
  HOST_DESCRIPTIONS: () => HOST_DESCRIPTIONS,
8760
8761
  assertRegisteredHostName: () => assertRegisteredHostName,
8762
+ lookupHeadlessHostDescription: () => lookupHeadlessHostDescription,
8761
8763
  lookupHostDescription: () => lookupHostDescription,
8764
+ lookupHostFamily: () => lookupHostFamily,
8762
8765
  packagedExternalHostNames: () => packagedExternalHostNames
8763
8766
  });
8764
8767
  function lookupHostDescription(host) {
8765
8768
  return Object.hasOwn(HOST_DESCRIPTIONS, host) ? HOST_DESCRIPTIONS[host] : void 0;
8766
8769
  }
8770
+ function lookupHeadlessHostDescription(host) {
8771
+ return Object.hasOwn(HEADLESS_HOST_DESCRIPTIONS, host) ? HEADLESS_HOST_DESCRIPTIONS[host] : void 0;
8772
+ }
8773
+ function lookupHostFamily(host) {
8774
+ if (lookupHostDescription(host) !== void 0) return "acp";
8775
+ if (lookupHeadlessHostDescription(host) !== void 0) return "headless";
8776
+ return void 0;
8777
+ }
8767
8778
  function packagedExternalHostNames() {
8768
- return Object.keys(HOST_DESCRIPTIONS);
8779
+ return [...Object.keys(HOST_DESCRIPTIONS), ...Object.keys(HEADLESS_HOST_DESCRIPTIONS)];
8769
8780
  }
8770
8781
  function assertRegisteredHostName(host) {
8771
- if (host === DEFAULT_ROLE_TURN_HOST || lookupHostDescription(host) !== void 0) {
8782
+ if (host === DEFAULT_ROLE_TURN_HOST || lookupHostFamily(host) !== void 0) {
8772
8783
  return host;
8773
8784
  }
8774
8785
  throw new Error(`unregistered host: ${host}`);
8775
8786
  }
8776
- var PRIVATE_COMPAT_ENV, DEFAULT_ROLE_TURN_HOST, HOST_DESCRIPTIONS;
8787
+ var PRIVATE_COMPAT_ENV, DEFAULT_ROLE_TURN_HOST, HOST_DESCRIPTIONS, HEADLESS_HOST_DESCRIPTIONS;
8777
8788
  var init_host_descriptions = __esm({
8778
8789
  "src/host-descriptions.ts"() {
8779
8790
  "use strict";
@@ -8825,14 +8836,37 @@ var init_host_descriptions = __esm({
8825
8836
  })
8826
8837
  })
8827
8838
  });
8839
+ HEADLESS_HOST_DESCRIPTIONS = Object.freeze({
8840
+ "claude": Object.freeze({
8841
+ binaryFromHome: Object.freeze([".local", "bin", "claude"]),
8842
+ sessionBindingFile: "claude-headless-session.json",
8843
+ fixedArgs: Object.freeze([
8844
+ // One result envelope (not stream-json): typed receipt only; no event-stream copy.
8845
+ "--output-format",
8846
+ "json",
8847
+ "--permission-mode",
8848
+ "bypassPermissions",
8849
+ // Empty sources: no user/project/local operator surface (envelope owns materials).
8850
+ "--setting-sources",
8851
+ "",
8852
+ // With adapter-supplied --mcp-config only (AK relay); drops operator + claude.ai MCP.
8853
+ "--strict-mcp-config"
8854
+ ]),
8855
+ promptFlag: "-p",
8856
+ modelFlag: "--model",
8857
+ effortFlag: "--effort",
8858
+ // File path keeps large role envelopes off ARG_MAX.
8859
+ systemPromptFlag: "--system-prompt-file",
8860
+ jsonSchemaFlag: "--json-schema",
8861
+ mcpConfigFlag: "--mcp-config",
8862
+ sessionIdFlag: "--session-id",
8863
+ resumeFlag: "--resume"
8864
+ })
8865
+ });
8828
8866
  }
8829
8867
  });
8830
8868
 
8831
8869
  // src/public-cli/load-production-acp-host.ts
8832
- var load_production_acp_host_exports = {};
8833
- __export(load_production_acp_host_exports, {
8834
- loadProductionAcpHostFactory: () => loadProductionAcpHostFactory
8835
- });
8836
8870
  import { existsSync as existsSync5 } from "node:fs";
8837
8871
  import { join as join14 } from "node:path";
8838
8872
  import { pathToFileURL } from "node:url";
@@ -8856,6 +8890,54 @@ var init_load_production_acp_host = __esm({
8856
8890
  }
8857
8891
  });
8858
8892
 
8893
+ // src/public-cli/load-production-headless-host.ts
8894
+ import { existsSync as existsSync6 } from "node:fs";
8895
+ import { join as join15 } from "node:path";
8896
+ import { pathToFileURL as pathToFileURL2 } from "node:url";
8897
+ async function loadProductionHeadlessHostFactory(packageRoot, host) {
8898
+ const description = lookupHeadlessHostDescription(host);
8899
+ if (description === void 0) {
8900
+ throw new Error(`unregistered headless host: ${host}`);
8901
+ }
8902
+ const built = join15(packageRoot, "dist/headless-host/production-host.js");
8903
+ const source = join15(packageRoot, "src/headless-host/production-host.ts");
8904
+ const target = existsSync6(built) ? built : source;
8905
+ const href = pathToFileURL2(target).href;
8906
+ const mod = await import(href);
8907
+ const create = mod.createProductionHeadlessRoleTurnHost;
8908
+ return (options) => create({ ...options, description });
8909
+ }
8910
+ var init_load_production_headless_host = __esm({
8911
+ "src/public-cli/load-production-headless-host.ts"() {
8912
+ "use strict";
8913
+ init_host_descriptions();
8914
+ }
8915
+ });
8916
+
8917
+ // src/public-cli/load-production-external-host.ts
8918
+ var load_production_external_host_exports = {};
8919
+ __export(load_production_external_host_exports, {
8920
+ loadProductionExternalHostFactory: () => loadProductionExternalHostFactory
8921
+ });
8922
+ async function loadProductionExternalHostFactory(packageRoot, host) {
8923
+ const family = lookupHostFamily(host);
8924
+ if (family === "acp") {
8925
+ return loadProductionAcpHostFactory(packageRoot, host);
8926
+ }
8927
+ if (family === "headless") {
8928
+ return loadProductionHeadlessHostFactory(packageRoot, host);
8929
+ }
8930
+ throw new Error(`unregistered host: ${host}`);
8931
+ }
8932
+ var init_load_production_external_host = __esm({
8933
+ "src/public-cli/load-production-external-host.ts"() {
8934
+ "use strict";
8935
+ init_host_descriptions();
8936
+ init_load_production_acp_host();
8937
+ init_load_production_headless_host();
8938
+ }
8939
+ });
8940
+
8859
8941
  // src/public-cli/host-providers.ts
8860
8942
  var host_providers_exports = {};
8861
8943
  __export(host_providers_exports, {
@@ -8870,15 +8952,15 @@ __export(host_providers_exports, {
8870
8952
  renderHostProvidersTable: () => renderHostProvidersTable
8871
8953
  });
8872
8954
  import { readFileSync as readFileSync2 } from "node:fs";
8873
- import { join as join15 } from "node:path";
8955
+ import { join as join16 } from "node:path";
8874
8956
  function hostProvidersPath(home) {
8875
8957
  if (typeof home !== "string" || home.trim() === "") {
8876
8958
  throw new Error("home must be explicitly provided");
8877
8959
  }
8878
- return join15(home, ".ak-roles", "host-providers.json");
8960
+ return join16(home, ".ak-roles", "host-providers.json");
8879
8961
  }
8880
8962
  function hermesProviderModelsCachePath(home) {
8881
- return join15(home, ".hermes", "provider_models_cache.json");
8963
+ return join16(home, ".hermes", "provider_models_cache.json");
8882
8964
  }
8883
8965
  function parseHostProvidersTable(value) {
8884
8966
  if (value === null || typeof value !== "object" || Array.isArray(value)) {
@@ -9445,7 +9527,7 @@ __export(config_exports, {
9445
9527
  validatePublicCliConfigAxes: () => validatePublicCliConfigAxes
9446
9528
  });
9447
9529
  import { mkdir as mkdir2, readFile as readFile10, writeFile as writeFile5 } from "node:fs/promises";
9448
- import { dirname as dirname8, join as join16 } from "node:path";
9530
+ import { dirname as dirname8, join as join17 } from "node:path";
9449
9531
  function isGateOfficerSeat(value) {
9450
9532
  return GATE_OFFICER_SEATS.includes(value);
9451
9533
  }
@@ -9453,7 +9535,7 @@ function publicCliConfigPath(home) {
9453
9535
  if (typeof home !== "string" || home.trim() === "") {
9454
9536
  throw new Error("home must be explicitly provided");
9455
9537
  }
9456
- return join16(home, ".ak-roles", "public-cli.json");
9538
+ return join17(home, ".ak-roles", "public-cli.json");
9457
9539
  }
9458
9540
  async function loadPublicCliConfig(home) {
9459
9541
  const path = publicCliConfigPath(home);
@@ -9862,7 +9944,7 @@ function credentialProvidersFromAuthData(data) {
9862
9944
  }
9863
9945
  async function loadCredentialProviders(agentDir) {
9864
9946
  try {
9865
- const raw = await readFile10(join16(agentDir, "auth.json"), "utf8");
9947
+ const raw = await readFile10(join17(agentDir, "auth.json"), "utf8");
9866
9948
  return credentialProvidersFromAuthData(JSON.parse(raw));
9867
9949
  } catch (error) {
9868
9950
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
@@ -10004,7 +10086,7 @@ var init_ticket_provenance_contracts = __esm({
10004
10086
  // src/ticket-provenance.ts
10005
10087
  import { createHash as createHash5 } from "node:crypto";
10006
10088
  import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync3, writeFileSync as writeFileSync3 } from "node:fs";
10007
- import { join as join17 } from "node:path";
10089
+ import { join as join18 } from "node:path";
10008
10090
  function ticketProvenanceSubject(ticketNumber) {
10009
10091
  if (!Number.isSafeInteger(ticketNumber) || ticketNumber < 1) {
10010
10092
  throw new Error(`ticket-provenance subject requires a positive ticket number, got ${String(ticketNumber)}`);
@@ -10062,7 +10144,7 @@ function resolveTicketProvenanceVolume(ticketNumber, cwd, home) {
10062
10144
  return {
10063
10145
  recordFile: path.recordFile,
10064
10146
  volumeDir: path.sessionDir,
10065
- humanViewFile: join17(path.sessionDir, TICKET_PROVENANCE_HUMAN_VIEW)
10147
+ humanViewFile: join18(path.sessionDir, TICKET_PROVENANCE_HUMAN_VIEW)
10066
10148
  };
10067
10149
  }
10068
10150
  async function readTicketProvenance(ticketNumber, cwd, home) {
@@ -10206,7 +10288,7 @@ var init_case_dossier_delivery = __esm({
10206
10288
 
10207
10289
  // src/host-transition-prior-native.ts
10208
10290
  import { access as access2, readdir as readdir3 } from "node:fs/promises";
10209
- import { dirname as dirname9, join as join18 } from "node:path";
10291
+ import { dirname as dirname9, join as join19 } from "node:path";
10210
10292
  function isEnoent2(error) {
10211
10293
  return typeof error === "object" && error !== null && error.code === "ENOENT";
10212
10294
  }
@@ -10231,7 +10313,7 @@ async function listSitianRecordPaths(sessionParent) {
10231
10313
  const recordPaths = [];
10232
10314
  for (const entry of entries) {
10233
10315
  if (!entry.isDirectory()) continue;
10234
- const recordFile = join18(sessionRoot, entry.name, "records.jsonl");
10316
+ const recordFile = join19(sessionRoot, entry.name, "records.jsonl");
10235
10317
  try {
10236
10318
  await access2(recordFile);
10237
10319
  recordPaths.push(recordFile);
@@ -10298,7 +10380,7 @@ var init_public_run_credentials = __esm({
10298
10380
  });
10299
10381
 
10300
10382
  // src/run-terminal-artifacts.ts
10301
- import { basename as basename6, dirname as dirname10, join as join19 } from "node:path";
10383
+ import { basename as basename6, dirname as dirname10, join as join20 } from "node:path";
10302
10384
  function runIdFromRunDirectory(runDirectory) {
10303
10385
  const name = basename6(runDirectory);
10304
10386
  const at = name.lastIndexOf("@");
@@ -10702,7 +10784,7 @@ var init_ledger_session_read = __esm({
10702
10784
 
10703
10785
  // src/analyst-gate-cycles-read.ts
10704
10786
  import { readdir as readdir4 } from "node:fs/promises";
10705
- import { join as join20 } from "node:path";
10787
+ import { join as join21 } from "node:path";
10706
10788
  function isRecord13(value) {
10707
10789
  return typeof value === "object" && value !== null && !Array.isArray(value);
10708
10790
  }
@@ -10929,10 +11011,10 @@ function pairGateRounds(volumes) {
10929
11011
  return rounds.sort((a, b) => a.officerStartedAt.localeCompare(b.officerStartedAt)).map((round, index) => ({ ...round, roundIndex: index + 1 }));
10930
11012
  }
10931
11013
  async function resolveOfficerSessionFromPointerFile(pointerPath) {
10932
- const { readFile: readFile21 } = await import("node:fs/promises");
11014
+ const { readFile: readFile22 } = await import("node:fs/promises");
10933
11015
  let raw;
10934
11016
  try {
10935
- raw = JSON.parse(await readFile21(pointerPath, "utf8"));
11017
+ raw = JSON.parse(await readFile22(pointerPath, "utf8"));
10936
11018
  } catch (error) {
10937
11019
  throw new Error(
10938
11020
  `direct officer run pointer unreadable in ${pointerPath}: ${error instanceof Error ? error.message : String(error)}`,
@@ -10964,7 +11046,7 @@ async function readAnalystGateCyclesFromAuditorRoles(auditorRolesDirectory, opti
10964
11046
  throw error;
10965
11047
  }
10966
11048
  for (const name of names) {
10967
- const path = join20(directory, name);
11049
+ const path = join21(directory, name);
10968
11050
  const fromPointer = name.endsWith(".pointer.json");
10969
11051
  const sessionPath = fromPointer ? await resolveOfficerSessionFromPointerFile(path) : path;
10970
11052
  if (sessionPath === void 0) continue;
@@ -11006,14 +11088,14 @@ var init_analyst_gate_cycles_read = __esm({
11006
11088
  });
11007
11089
 
11008
11090
  // src/session-opening-materials.ts
11009
- import { existsSync as existsSync6 } from "node:fs";
11091
+ import { existsSync as existsSync7 } from "node:fs";
11010
11092
  import { readFile as readFile12 } from "node:fs/promises";
11011
- import { dirname as dirname11, join as join21 } from "node:path";
11012
- import { fileURLToPath, pathToFileURL as pathToFileURL2 } from "node:url";
11093
+ import { dirname as dirname11, join as join22 } from "node:path";
11094
+ import { fileURLToPath, pathToFileURL as pathToFileURL3 } from "node:url";
11013
11095
  function resolvePackageRootDir(moduleUrl = import.meta.url) {
11014
11096
  let dir = dirname11(fileURLToPath(moduleUrl));
11015
11097
  for (let i = 0; i < 8; i += 1) {
11016
- if (existsSync6(join21(dir, "package.json")) && existsSync6(join21(dir, "souls"))) {
11098
+ if (existsSync7(join22(dir, "package.json")) && existsSync7(join22(dir, "souls"))) {
11017
11099
  return dir;
11018
11100
  }
11019
11101
  const parent = dirname11(dir);
@@ -11043,7 +11125,7 @@ var init_session_opening_materials = __esm({
11043
11125
  "src/session-opening-materials.ts"() {
11044
11126
  "use strict";
11045
11127
  init_packaged_role_registry();
11046
- packageRootUrl = pathToFileURL2(resolvePackageRootDir() + "/").href;
11128
+ packageRootUrl = pathToFileURL3(resolvePackageRootDir() + "/").href;
11047
11129
  MAIN_ROLE_SESSION_MATERIALS = {
11048
11130
  ...Object.fromEntries(
11049
11131
  PUBLIC_ROLE_RECORDS.map((record4) => [record4.role, record4.sessionMaterials])
@@ -11885,12 +11967,12 @@ var init_reviewer_dispatch = __esm({
11885
11967
  // src/public-cli/reviewer-dispatch-rejection.ts
11886
11968
  import { writeFileSync as writeFileSync4 } from "node:fs";
11887
11969
  import { readFile as readFile13, unlink as unlink3 } from "node:fs/promises";
11888
- import { join as join22 } from "node:path";
11970
+ import { join as join23 } from "node:path";
11889
11971
  function isReviewerPreflightViolation(value) {
11890
11972
  return typeof value === "string" && REVIEWER_PREFLIGHT_VIOLATIONS.includes(value);
11891
11973
  }
11892
11974
  function reviewerDispatchRejectionPath(runDirectory) {
11893
- return join22(runDirectory, REVIEWER_DISPATCH_REJECTION_FILE);
11975
+ return join23(runDirectory, REVIEWER_DISPATCH_REJECTION_FILE);
11894
11976
  }
11895
11977
  function recordReviewerDispatchRejectionSync(runDirectory, rejection) {
11896
11978
  writeFileSync4(
@@ -12422,76 +12504,7 @@ var init_collector_identity = __esm({
12422
12504
  }
12423
12505
  });
12424
12506
 
12425
- // src/collector-tool-schemas.ts
12426
- import { Type as Type13 } from "typebox";
12427
- var collectorObserveArgsSchema, collectorRequestArgsSchema, collectorReadArgsSchema, collectorWaitArgsSchema, collectorBindTargetArgsSchema, collectorFindingItemDeclaration, collectorOutputBaseSchema, collectorOutputArgsSchema;
12428
- var init_collector_tool_schemas = __esm({
12429
- "src/collector-tool-schemas.ts"() {
12430
- "use strict";
12431
- init_collector_evidence();
12432
- init_open_tool_schema();
12433
- init_terminating_infrastructure();
12434
- collectorObserveArgsSchema = Type13.Object({}, { additionalProperties: false });
12435
- collectorRequestArgsSchema = Type13.Object({
12436
- requestId: Type13.String({ minLength: 1, description: "\u914D\u7F6E\u8BF7\u6C42\u8EAB\u4EFD" }),
12437
- snapshotId: Type13.String({ minLength: 1, description: "\u6700\u65B0\u7559\u5B58\u89C2\u5BDF\u5FEB\u7167" })
12438
- }, { additionalProperties: false });
12439
- collectorReadArgsSchema = Type13.Object({
12440
- evidenceId: Type13.String({ minLength: 1, description: "observe \u8FD4\u56DE\u7684\u6750\u6599\u8BC1\u636E id\uFF08evidenceId\uFF09" })
12441
- }, { additionalProperties: false });
12442
- collectorWaitArgsSchema = Type13.Object({
12443
- durationMs: Type13.Integer({ minimum: 1, maximum: COLLECTOR_ELIGIBILITY_MS, description: "\u7B49\u5F85\u6BEB\u79D2\uFF1B\u5355\u6B21\u4E0A\u9650\u4E94\u5206\u949F\u4E14\u4E0D\u8D85\u5269\u4F59\u8D44\u683C" })
12444
- }, { additionalProperties: false });
12445
- collectorBindTargetArgsSchema = Type13.Object({
12446
- prNumber: Type13.Optional(Type13.Unknown({
12447
- description: "\u89D2\u8272\u5224\u5B9A\u7684\u672C\u4ED3 PR \u53F7\uFF08\u6B63\u6574\u6570\uFF09\u3002\u4E0E issueNumber \u4E8C\u9009\u4E00\u6216\u540C\u6307\u552F\u4E00\u76EE\u6807\u3002\u5F62\u72B6\u6307\u5F15\uFF0C\u975E schema \u95F8\u3002"
12448
- })),
12449
- issueNumber: Type13.Optional(Type13.Unknown({
12450
- description: "\u89D2\u8272\u5224\u5B9A\u7684\u672C\u4ED3 issue \u53F7\uFF08\u6B63\u6574\u6570\uFF09\uFF1Bruntime \u7ECF\u7EBF\u4E0A\u5173\u8054\u89E3\u6790\u552F\u4E00 PR\u3002\u5F62\u72B6\u6307\u5F15\uFF0C\u975E schema \u95F8\u3002"
12451
- }))
12452
- }, { additionalProperties: true });
12453
- collectorFindingItemDeclaration = (() => {
12454
- const item = Type13.Object(
12455
- {
12456
- evidenceId: Type13.Unknown({
12457
- description: "observe \u8FD4\u56DE\u7684\u6750\u6599\u6307\u9488\uFF08\u5FC5\u586B\u8BED\u4E49\uFF09"
12458
- }),
12459
- category: Type13.Unknown({
12460
- description: "\u7B80\u77ED\u5F52\u7C7B\u6807\u7B7E\uFF0C\u4E0D\u662F\u6458\u8981"
12461
- }),
12462
- summary: Type13.Unknown({
12463
- description: "\u54EA\u4E2A bot\u3001\u4EC0\u4E48\u95EE\u9898\u7684\u6458\u8981\uFF1B\u4E0D\u8A8A\u6284\u6B63\u6587"
12464
- })
12465
- },
12466
- {
12467
- additionalProperties: true,
12468
- description: "\u5355\u6761 finding \u6307\u9488\uFF1AevidenceId + \u53EF\u9009 category/summary\u3002\u5F62\u72B6\u6307\u5F15\uFF0C\u975E schema \u95F8\u3002"
12469
- }
12470
- );
12471
- item.required = [];
12472
- return item;
12473
- })();
12474
- collectorOutputBaseSchema = openToolObject(
12475
- Type13.Object({
12476
- // No root type:array — host must not shape-reject non-array findings (#676 C).
12477
- // Nested item declarations ride `items` for registration preservation (ADR 0057).
12478
- findings: Type13.Unsafe({
12479
- description: "\u672C\u6B21\u6536\u96C6\u5230\u7684\u9010\u6761 findings\uFF08\u6307\u9488\u6570\u7EC4\u4E3A\u89C4\u8303\u5F62\uFF09\u3002\u96F6 finding \u7684\u6A21\u677F\u901A\u77E5\u4E0D\u5F97\u8FDB\u5165\uFF1B\u6B63\u5E38\u5B8C\u5DE5\u65E0 finding \u65F6\u7701\u7565\u3002\u5F62\u72B6\u6307\u5F15\uFF0C\u975E schema \u95F8\u3002",
12480
- items: collectorFindingItemDeclaration
12481
- }),
12482
- unfinishedReasons: Type13.Unknown({
12483
- description: "\u672A\u5B8C\u6210\u539F\u56E0\u5B57\u7B26\u4E32\u6570\u7EC4\uFF08\u989D\u5EA6/\u6545\u969C/\u7B49\u5F85\u5C4A\u6EE1\u7B49\u73B0\u573A\u4F9D\u636E\uFF09\uFF1B\u4E0D\u5F97\u628A\u672A\u5B8C\u6210\u8868\u8FF0\u4E3A\u65E0\u95EE\u9898\u3002\u65E0\u53EF\u62A5\u544A\u65F6\u7701\u7565\u3002\u5F62\u72B6\u6307\u5F15\uFF0C\u975E schema \u95F8\u3002"
12484
- })
12485
- })
12486
- );
12487
- collectorOutputArgsSchema = withInfrastructureFailureDeclaration(
12488
- collectorOutputBaseSchema
12489
- );
12490
- }
12491
- });
12492
-
12493
12507
  // src/collector-ledger.ts
12494
- import Value2 from "typebox/value";
12495
12508
  function utf8SafePrefix(text, maxBytes) {
12496
12509
  if (Buffer.byteLength(text, "utf8") <= maxBytes) return text;
12497
12510
  const bytes = Buffer.from(text, "utf8");
@@ -12564,9 +12577,7 @@ function createCollectorLedger(config, options) {
12564
12577
  const prIdentity = (pr) => `${pr.state}|${pr.headOid}|${pr.updatedAt ?? ""}`;
12565
12578
  const requireBoundPr = () => {
12566
12579
  if (config.prNumber === void 0) {
12567
- throw new Error(
12568
- "Collector PR target is unbound; call ak_collector_bind_target with the role-decided issue/PR or pass --pr"
12569
- );
12580
+ throw new Error("\u901A\u8FDB\u53F8 PR \u76EE\u6807\u672A\u7ED1\u5B9A");
12570
12581
  }
12571
12582
  return config.prNumber;
12572
12583
  };
@@ -12848,11 +12859,11 @@ function createCollectorLedger(config, options) {
12848
12859
  throw new Error("\u901A\u8FDB\u53F8\u5DF2\u4EA7\u51FA\u8F93\u51FA\u5019\u9009\uFF0C\u672C\u5C40\u4E0D\u518D\u53D7\u7406\u76EE\u6807\u7ED1\u5B9A");
12849
12860
  }
12850
12861
  if (!Number.isSafeInteger(prNumber) || prNumber < 1) {
12851
- throw new Error("Collector bind target requires a positive safe-integer PR number");
12862
+ throw new Error("\u901A\u8FDB\u53F8\u7ED1\u5B9A\u76EE\u6807\u8981\u6C42\u6B63\u5B89\u5168\u6574\u6570 PR \u53F7");
12852
12863
  }
12853
12864
  if (config.prNumber !== void 0 && config.prNumber !== prNumber) {
12854
12865
  throw new Error(
12855
- `Collector target already bound to PR ${config.prNumber}; cannot rebind to ${prNumber}`
12866
+ `\u901A\u8FDB\u53F8\u76EE\u6807\u5DF2\u7ED1\u5B9A PR ${config.prNumber}\uFF0C\u4E0D\u53EF\u6539\u7ED1\u4E3A ${prNumber}`
12856
12867
  );
12857
12868
  }
12858
12869
  config.prNumber = prNumber;
@@ -13049,9 +13060,21 @@ function createCollectorLedger(config, options) {
13049
13060
  if (ledger.unresolvedTransportFailure) {
13050
13061
  throw latchFatal("\u901A\u8FDB\u53F8\u8BF7\u6C42\u65F6\u5B58\u5728\u672A\u6062\u590D\u7684\u4F20\u8F93\u5931\u8D25");
13051
13062
  }
13052
- const request = config.manifest.requests.find((item) => item.id === input.requestId);
13053
- if (request === void 0) {
13054
- throw new Error(`\u672A\u77E5\u901A\u8FDB\u53F8 requestId "${input.requestId}"`);
13063
+ if (typeof input.requestId !== "string") {
13064
+ throw new Error("\u901A\u8FDB\u53F8 requestId \u987B\u4E3A\u5B57\u7B26\u4E32");
13065
+ }
13066
+ const requestId = input.requestId.trim();
13067
+ if (requestId.length === 0) {
13068
+ throw new Error("\u901A\u8FDB\u53F8 requestId \u987B\u4E3A\u975E\u7A7A\uFF08\u9996\u5C3E\u7A7A\u767D\u4E0D\u6784\u6210\u8EAB\u4EFD\uFF09");
13069
+ }
13070
+ const configured = config.manifest.requests.find((item) => item.id === requestId);
13071
+ const roleBody = typeof input.body === "string" ? input.body : void 0;
13072
+ if (configured === void 0) {
13073
+ if (roleBody === void 0 || roleBody.trim().length === 0) {
13074
+ throw new Error(
13075
+ `\u672A\u77E5\u901A\u8FDB\u53F8 requestId "${requestId}" \u4E14\u672A\u63D0\u4F9B body\uFF1B\u8BF7\u63D0\u4EA4\u89D2\u8272\u5224\u5B9A\u7684\u8BF7\u6C42\u6B63\u6587\u6216\u4F7F\u7528 request-manifest`
13076
+ );
13077
+ }
13055
13078
  }
13056
13079
  const snapshot = snapshots.find((item) => item.snapshotId === input.snapshotId);
13057
13080
  if (snapshot === void 0) {
@@ -13067,10 +13090,11 @@ function createCollectorLedger(config, options) {
13067
13090
  finalObservationRequired = true;
13068
13091
  throw latchFatal("\u901A\u8FDB\u53F8\u8BF7\u6C42\u4E0D\u5728\u8D44\u683C\u622A\u6B62\u524D");
13069
13092
  }
13093
+ const configuredBody = configured?.requestBody ?? roleBody;
13070
13094
  const { body, marker } = buildCollectorRequestBody({
13071
- configuredBody: request.requestBody,
13095
+ configuredBody,
13072
13096
  manifestDigest: config.manifest.digest,
13073
- requestId: request.id,
13097
+ requestId,
13074
13098
  headOid: snapshot.headOid
13075
13099
  });
13076
13100
  const existingMarker = snapshot.evidenceIds.some((id) => {
@@ -13079,7 +13103,7 @@ function createCollectorLedger(config, options) {
13079
13103
  });
13080
13104
  if (existingMarker) {
13081
13105
  throw new Error(
13082
- `\u901A\u8FDB\u53F8\u5728\u6B64 HEAD \u5DF2\u6709\u540C marker \u7684\u5DF2\u8BA4\u8BC1\u8BF7\u6C42 "${input.requestId}"`
13106
+ `\u901A\u8FDB\u53F8\u5728\u6B64 HEAD \u5DF2\u6709\u540C marker \u7684\u5DF2\u8BA4\u8BC1\u8BF7\u6C42 "${requestId}"`
13083
13107
  );
13084
13108
  }
13085
13109
  const boundPr = requireBoundPr();
@@ -13087,18 +13111,18 @@ function createCollectorLedger(config, options) {
13087
13111
  config.repository.canonical,
13088
13112
  String(boundPr),
13089
13113
  snapshot.headOid,
13090
- request.id
13114
+ requestId
13091
13115
  ].join("|");
13092
13116
  if (attemptKeys.has(attemptKey)) {
13093
13117
  throw new Error(
13094
- `\u901A\u8FDB\u53F8\u8FDB\u7A0B\u5185\u8BF7\u6C42 "${request.id}" \u5728 HEAD ${snapshot.headOid} \u7684 attempt \u5DF2\u7528`
13118
+ `\u901A\u8FDB\u53F8\u8FDB\u7A0B\u5185\u8BF7\u6C42 "${requestId}" \u5728 HEAD ${snapshot.headOid} \u7684 attempt \u5DF2\u7528`
13095
13119
  );
13096
13120
  }
13097
13121
  const startedAt = clock2.wallNow().toISOString();
13098
13122
  const attemptId = sha256Text(`${attemptKey}:${startedAt}`).slice(0, 16);
13099
13123
  const attempt = {
13100
13124
  attemptId,
13101
- requestId: request.id,
13125
+ requestId,
13102
13126
  observedHead: snapshot.headOid,
13103
13127
  snapshotId: snapshot.snapshotId,
13104
13128
  marker,
@@ -13140,7 +13164,7 @@ function createCollectorLedger(config, options) {
13140
13164
  return {
13141
13165
  status: "succeeded",
13142
13166
  attemptId,
13143
- requestId: request.id,
13167
+ requestId,
13144
13168
  observedHead: snapshot.headOid,
13145
13169
  marker,
13146
13170
  commentEvidenceId: record4.evidenceId
@@ -13154,7 +13178,7 @@ function createCollectorLedger(config, options) {
13154
13178
  return {
13155
13179
  status: "ambiguous_loss",
13156
13180
  attemptId,
13157
- requestId: request.id,
13181
+ requestId,
13158
13182
  observedHead: snapshot.headOid,
13159
13183
  marker,
13160
13184
  diagnostics: result.diagnostics
@@ -13171,14 +13195,6 @@ function createCollectorLedger(config, options) {
13171
13195
  if (activationTime === void 0) {
13172
13196
  throw latchFatal("\u901A\u8FDB\u53F8\u7B49\u5F85\u9700\u8981\u6FC0\u6D3B");
13173
13197
  }
13174
- if (!Number.isSafeInteger(input.durationMs) || input.durationMs < 1) {
13175
- throw new Error("\u901A\u8FDB\u53F8\u7B49\u5F85 durationMs \u987B\u4E3A\u6B63\u5B89\u5168\u6574\u6570");
13176
- }
13177
- if (input.durationMs > COLLECTOR_ELIGIBILITY_MS) {
13178
- throw new Error(
13179
- `\u901A\u8FDB\u53F8\u7B49\u5F85 durationMs \u81F3\u591A\u4E3A ${COLLECTOR_ELIGIBILITY_MS}`
13180
- );
13181
- }
13182
13198
  if (pastCutoff(clock2)) {
13183
13199
  finalObservationRequired = true;
13184
13200
  throw latchFatal("\u901A\u8FDB\u53F8\u7B49\u5F85\u4E0D\u5728\u8D44\u683C\u622A\u6B62\u524D");
@@ -13280,26 +13296,27 @@ function buildObserveModelView(input) {
13280
13296
  }))
13281
13297
  };
13282
13298
  }
13283
- var COLLECTOR_OBSERVE_TOOL, COLLECTOR_READ_TOOL, COLLECTOR_REQUEST_TOOL, COLLECTOR_WAIT_TOOL, COLLECTOR_BIND_TARGET_TOOL, COLLECTOR_OPERATIONAL_TOOLS, COLLECTOR_OBSERVE_BODY_HEAD_BYTES, COLLECTOR_ACTIVATION_ENTRY_TYPE, COLLECTOR_SNAPSHOT_ENTRY_TYPE, COLLECTOR_REQUEST_ENTRY_TYPE, COLLECTOR_WAIT_ENTRY_TYPE;
13299
+ var COLLECTOR_OBSERVE_TOOL, COLLECTOR_READ_TOOL, COLLECTOR_REQUEST_TOOL, COLLECTOR_WAIT_TOOL, COLLECTOR_BIND_TARGET_TOOL, COLLECTOR_HANDBOOK_WRITE_TOOL, COLLECTOR_OPERATIONAL_TOOLS, COLLECTOR_OBSERVE_BODY_HEAD_BYTES, COLLECTOR_ACTIVATION_ENTRY_TYPE, COLLECTOR_SNAPSHOT_ENTRY_TYPE, COLLECTOR_REQUEST_ENTRY_TYPE, COLLECTOR_WAIT_ENTRY_TYPE;
13284
13300
  var init_collector_ledger = __esm({
13285
13301
  "src/collector-ledger.ts"() {
13286
13302
  "use strict";
13287
13303
  init_collector_evidence();
13288
13304
  init_collector_github();
13289
13305
  init_collector_identity();
13290
- init_collector_tool_schemas();
13291
13306
  init_collector_output();
13292
13307
  COLLECTOR_OBSERVE_TOOL = "ak_collector_observe";
13293
13308
  COLLECTOR_READ_TOOL = "ak_collector_read";
13294
13309
  COLLECTOR_REQUEST_TOOL = "ak_collector_request";
13295
13310
  COLLECTOR_WAIT_TOOL = "ak_collector_wait";
13296
13311
  COLLECTOR_BIND_TARGET_TOOL = "ak_collector_bind_target";
13312
+ COLLECTOR_HANDBOOK_WRITE_TOOL = "ak_collector_handbook_write";
13297
13313
  COLLECTOR_OPERATIONAL_TOOLS = [
13298
13314
  COLLECTOR_BIND_TARGET_TOOL,
13299
13315
  COLLECTOR_OBSERVE_TOOL,
13300
13316
  COLLECTOR_READ_TOOL,
13301
13317
  COLLECTOR_REQUEST_TOOL,
13302
- COLLECTOR_WAIT_TOOL
13318
+ COLLECTOR_WAIT_TOOL,
13319
+ COLLECTOR_HANDBOOK_WRITE_TOOL
13303
13320
  ];
13304
13321
  COLLECTOR_OBSERVE_BODY_HEAD_BYTES = 512;
13305
13322
  COLLECTOR_ACTIVATION_ENTRY_TYPE = "ak-collector-activation";
@@ -13312,7 +13329,7 @@ var init_collector_ledger = __esm({
13312
13329
  // src/package-resources/method-skill.ts
13313
13330
  import { createHash as createHash7 } from "node:crypto";
13314
13331
  import { readFile as readFile14, realpath as realpath7 } from "node:fs/promises";
13315
- import { join as join23 } from "node:path";
13332
+ import { join as join24 } from "node:path";
13316
13333
  function gitBlobOid(bytes) {
13317
13334
  const body = typeof bytes === "string" ? Buffer.from(bytes, "utf8") : Buffer.from(bytes);
13318
13335
  const header = Buffer.from(`blob ${body.byteLength}\0`, "utf8");
@@ -13329,10 +13346,10 @@ function packagedMethodSkillRelativeDirectory(name) {
13329
13346
  return `${METHOD_SKILL_RELATIVE_ROOT}/${name}`;
13330
13347
  }
13331
13348
  function resolvePackagedMethodSkillRoot(packageRoot, name) {
13332
- return join23(packageRoot, packagedMethodSkillRelativeDirectory(name));
13349
+ return join24(packageRoot, packagedMethodSkillRelativeDirectory(name));
13333
13350
  }
13334
13351
  function resolvePackagedMethodSkillPath(packageRoot, name) {
13335
- return join23(resolvePackagedMethodSkillRoot(packageRoot, name), "SKILL.md");
13352
+ return join24(resolvePackagedMethodSkillRoot(packageRoot, name), "SKILL.md");
13336
13353
  }
13337
13354
  function isRecord14(value) {
13338
13355
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -13426,8 +13443,8 @@ function parseProvenance(raw, expectedName) {
13426
13443
  }
13427
13444
  async function loadPackagedMethodSkillMaterial(packageRoot, name) {
13428
13445
  const rootDirectory = resolvePackagedMethodSkillRoot(packageRoot, name);
13429
- const skillPathConfigured = join23(rootDirectory, "SKILL.md");
13430
- const provenancePath = join23(rootDirectory, "provenance.json");
13446
+ const skillPathConfigured = join24(rootDirectory, "SKILL.md");
13447
+ const provenancePath = join24(rootDirectory, "provenance.json");
13431
13448
  let provenanceRaw;
13432
13449
  try {
13433
13450
  provenanceRaw = await readFile14(provenancePath, "utf8");
@@ -13444,7 +13461,7 @@ async function loadPackagedMethodSkillMaterial(packageRoot, name) {
13444
13461
  }
13445
13462
  const provenance = parseProvenance(provenanceJson, name);
13446
13463
  for (const [rel, expected] of Object.entries(provenance.files)) {
13447
- const absolute = join23(rootDirectory, rel);
13464
+ const absolute = join24(rootDirectory, rel);
13448
13465
  let bytes;
13449
13466
  try {
13450
13467
  bytes = await readFile14(absolute);
@@ -13960,7 +13977,7 @@ var init_terminal = __esm({
13960
13977
  // src/public-cli/settlement.ts
13961
13978
  import { randomUUID as randomUUID3 } from "node:crypto";
13962
13979
  import { appendFile as appendFile2, readFile as readFile15, readdir as readdir5, writeFile as writeFile6 } from "node:fs/promises";
13963
- import { dirname as dirname12, join as join24 } from "node:path";
13980
+ import { dirname as dirname12, join as join25 } from "node:path";
13964
13981
  function sealedLedgerHome(admitted) {
13965
13982
  return homeFromRunDirectory(admitted.runDirectory);
13966
13983
  }
@@ -14375,7 +14392,7 @@ async function readSessionProviderStop(sessionFile) {
14375
14392
  }
14376
14393
  }
14377
14394
  async function readBoundEvidenceChildKnownFailure(sessionFile) {
14378
- const childDirectory = join24(dirname12(sessionFile), "evidence-children");
14395
+ const childDirectory = join25(dirname12(sessionFile), "evidence-children");
14379
14396
  let names;
14380
14397
  try {
14381
14398
  names = await readdir5(childDirectory);
@@ -14386,7 +14403,7 @@ async function readBoundEvidenceChildKnownFailure(sessionFile) {
14386
14403
  for (const file of names.filter((name) => name.endsWith(".jsonl")).sort().reverse()) {
14387
14404
  let entries;
14388
14405
  try {
14389
- entries = await readBoundSessionEntries(join24(childDirectory, file));
14406
+ entries = await readBoundSessionEntries(join25(childDirectory, file));
14390
14407
  } catch (error) {
14391
14408
  throw sessionReadFailure(error, "failed to read discovered evidence-child session");
14392
14409
  }
@@ -14440,7 +14457,7 @@ async function loadBoundAuditorVolumes(sessionFile) {
14440
14457
  latestParentUserIndex = i;
14441
14458
  break;
14442
14459
  }
14443
- const childDirectories = [join24(dirname12(sessionFile), "auditor-roles")];
14460
+ const childDirectories = [join25(dirname12(sessionFile), "auditor-roles")];
14444
14461
  const valid = [];
14445
14462
  let sawAnyDirectory = false;
14446
14463
  for (const childDirectory of childDirectories) {
@@ -14455,7 +14472,7 @@ async function loadBoundAuditorVolumes(sessionFile) {
14455
14472
  for (const file of names.filter((name) => name.endsWith(".jsonl")).sort().reverse()) {
14456
14473
  let entries;
14457
14474
  try {
14458
- entries = await readBoundSessionEntries(join24(childDirectory, file));
14475
+ entries = await readBoundSessionEntries(join25(childDirectory, file));
14459
14476
  } catch (error) {
14460
14477
  throw sessionReadFailure(error, "failed to read discovered auditor session");
14461
14478
  }
@@ -14971,8 +14988,8 @@ function projectTerminalGateFact(rounds) {
14971
14988
  };
14972
14989
  }
14973
14990
  async function extractGateFactFromSessionDirectory(sessionDirectory, options = {}) {
14974
- const directories = [join24(sessionDirectory, "auditor-roles")];
14975
- const parentSessionFile = options.parentSessionFile ?? join24(sessionDirectory, "session.jsonl");
14991
+ const directories = [join25(sessionDirectory, "auditor-roles")];
14992
+ const parentSessionFile = options.parentSessionFile ?? join25(sessionDirectory, "session.jsonl");
14976
14993
  const rounds = await readAnalystGateCyclesFromAuditorRoles(directories, {
14977
14994
  parentSessionFile
14978
14995
  });
@@ -15070,8 +15087,8 @@ async function extractNavigatorFactFromAdmittedSession(sessionFile) {
15070
15087
  async function publishJudgeArtifacts(admitted, roleOutcome, coordinates) {
15071
15088
  await appendRunAttemptHistory({ role: admitted.role, runId: admitted.runId, sessionFile: coordinates.sessionFile }, roleOutcome);
15072
15089
  const artifactsDir = await ensureRunArtifactsDir(admitted.runDirectory);
15073
- const reportPath = join24(artifactsDir, "report.json");
15074
- const evidencePath = join24(artifactsDir, "evidence.json");
15090
+ const reportPath = join25(artifactsDir, "report.json");
15091
+ const evidencePath = join25(artifactsDir, "evidence.json");
15075
15092
  await writeFile6(
15076
15093
  reportPath,
15077
15094
  `${JSON.stringify(
@@ -15161,8 +15178,8 @@ async function trySettleJudgeTerminalResult(admitted, authority) {
15161
15178
  async function publishDoctorArtifacts(admitted, roleOutcome, coordinates, options = {}) {
15162
15179
  await appendRunAttemptHistory({ role: admitted.role, runId: admitted.runId, sessionFile: coordinates.sessionFile }, roleOutcome);
15163
15180
  const artifactsDir = await ensureRunArtifactsDir(admitted.runDirectory);
15164
- const reportPath = join24(artifactsDir, "report.json");
15165
- const evidencePath = join24(artifactsDir, "evidence.json");
15181
+ const reportPath = join25(artifactsDir, "report.json");
15182
+ const evidencePath = join25(artifactsDir, "evidence.json");
15166
15183
  await writeFile6(
15167
15184
  reportPath,
15168
15185
  `${JSON.stringify(
@@ -15395,7 +15412,7 @@ function uniqueFailureFallbackDirs(runDirectory, baseDir) {
15395
15412
  return dirs;
15396
15413
  }
15397
15414
  async function resolveFailureArtifactsBase(runDirectory) {
15398
- const artifactsDir = join24(runDirectory, "artifacts");
15415
+ const artifactsDir = join25(runDirectory, "artifacts");
15399
15416
  try {
15400
15417
  await ensureRunArtifactsDir(runDirectory);
15401
15418
  return { baseDir: artifactsDir };
@@ -15411,7 +15428,7 @@ async function writeFailureJsonRetainingCause(preferredCandidates, uniqueFallbac
15411
15428
  const candidates = [
15412
15429
  ...preferredCandidates,
15413
15430
  // One unique name per fallback dir — collisions on fixed names cannot exhaust this.
15414
- ...uniqueFallbackDirs.map((dir) => join24(dir, `${stem}.${randomUUID3()}.json`))
15431
+ ...uniqueFallbackDirs.map((dir) => join25(dir, `${stem}.${randomUUID3()}.json`))
15415
15432
  ];
15416
15433
  for (let i = 0; i < candidates.length; i += 1) {
15417
15434
  const path = candidates[i];
@@ -15456,26 +15473,26 @@ async function publishFailureArtifacts(admitted, failure2, authority) {
15456
15473
  } catch (error) {
15457
15474
  priorIssues.push(publicationAttemptFromError(sessionFile, error));
15458
15475
  }
15459
- const underArtifacts = baseDir === join24(admitted.runDirectory, "artifacts");
15476
+ const underArtifacts = baseDir === join25(admitted.runDirectory, "artifacts");
15460
15477
  const uniqueFallbackDirs = uniqueFailureFallbackDirs(
15461
15478
  admitted.runDirectory,
15462
15479
  baseDir
15463
15480
  );
15464
15481
  const errorCandidates = underArtifacts ? [
15465
- join24(baseDir, "error.json"),
15466
- join24(baseDir, "error.settlement.json"),
15467
- join24(admitted.runDirectory, "error.settlement.json")
15482
+ join25(baseDir, "error.json"),
15483
+ join25(baseDir, "error.settlement.json"),
15484
+ join25(admitted.runDirectory, "error.settlement.json")
15468
15485
  ] : [
15469
- join24(baseDir, "error.settlement.json"),
15470
- join24(baseDir, "error.json")
15486
+ join25(baseDir, "error.settlement.json"),
15487
+ join25(baseDir, "error.json")
15471
15488
  ];
15472
15489
  const evidenceCandidates = underArtifacts ? [
15473
- join24(baseDir, "evidence.json"),
15474
- join24(baseDir, "evidence.settlement.json"),
15475
- join24(admitted.runDirectory, "evidence.settlement.json")
15490
+ join25(baseDir, "evidence.json"),
15491
+ join25(baseDir, "evidence.settlement.json"),
15492
+ join25(admitted.runDirectory, "evidence.settlement.json")
15476
15493
  ] : [
15477
- join24(baseDir, "evidence.settlement.json"),
15478
- join24(baseDir, "evidence.json")
15494
+ join25(baseDir, "evidence.settlement.json"),
15495
+ join25(baseDir, "evidence.json")
15479
15496
  ];
15480
15497
  const errorPayloadBase = {
15481
15498
  kind: "error",
@@ -15765,7 +15782,7 @@ var init_settlement = __esm({
15765
15782
  import { constants as fsConstants } from "node:fs";
15766
15783
  import { randomUUID as randomUUID4 } from "node:crypto";
15767
15784
  import { lstat as lstat5, mkdir as mkdir4, open as open2 } from "node:fs/promises";
15768
- import { join as join25 } from "node:path";
15785
+ import { join as join26 } from "node:path";
15769
15786
  function presentTerminal(terminal, io) {
15770
15787
  if (terminal.roleOutcome.kind === "failure" || terminal.roleOutcome.kind === "no_receipt") {
15771
15788
  presentFailureTerminal(terminal, io);
@@ -15784,7 +15801,7 @@ async function finalizeExceptionRunBestEffort(runDirectory, io) {
15784
15801
  }
15785
15802
  }
15786
15803
  function runArtifactsDirectory(runDirectory) {
15787
- return join25(runDirectory, "artifacts");
15804
+ return join26(runDirectory, "artifacts");
15788
15805
  }
15789
15806
  async function ensureRealArtifactsDirectory(runDirectory) {
15790
15807
  const runStat = await lstat5(runDirectory);
@@ -15867,7 +15884,7 @@ function jsonSafeReplacer() {
15867
15884
  }
15868
15885
  async function retainDispatchError(admitted, principalAuthority, sessionAppender, attempt, error) {
15869
15886
  const artifactsDir = await ensureRealArtifactsDirectory(admitted.runDirectory);
15870
- const filePath = join25(
15887
+ const filePath = join26(
15871
15888
  artifactsDir,
15872
15889
  `dispatch-error-attempt-${attempt}-${randomUUID4()}.json`
15873
15890
  );
@@ -16116,7 +16133,7 @@ var init_auto_resume = __esm({
16116
16133
  // src/public-cli/post-admission.ts
16117
16134
  import { randomUUID as randomUUID5 } from "node:crypto";
16118
16135
  import { readFile as readFile16, writeFile as writeFile7 } from "node:fs/promises";
16119
- import { isAbsolute as isAbsolute7, join as join26, resolve as resolve11 } from "node:path";
16136
+ import { isAbsolute as isAbsolute7, join as join27, resolve as resolve11 } from "node:path";
16120
16137
  function appendContinuationSection(continuation, section) {
16121
16138
  const prompt = `${continuation.prompt}
16122
16139
 
@@ -16125,7 +16142,7 @@ ${section}`;
16125
16142
  }
16126
16143
  async function readInvocationHost(runDirectory) {
16127
16144
  try {
16128
- const raw = JSON.parse(await readFile16(join26(runDirectory, "invocation.json"), "utf8"));
16145
+ const raw = JSON.parse(await readFile16(join27(runDirectory, "invocation.json"), "utf8"));
16129
16146
  return typeof raw.host === "string" && raw.host.trim() !== "" ? raw.host : void 0;
16130
16147
  } catch (error) {
16131
16148
  if (error.code === "ENOENT") return void 0;
@@ -16279,7 +16296,7 @@ async function dispatchPostAdmissionTurn(input) {
16279
16296
  }
16280
16297
  try {
16281
16298
  await writeFile7(
16282
- join26(admitted.runDirectory, "stderr.log"),
16299
+ join27(admitted.runDirectory, "stderr.log"),
16283
16300
  result.stderr,
16284
16301
  "utf8"
16285
16302
  );
@@ -16388,7 +16405,7 @@ function resumeTurnRequestProjectionOptions(admitted, request, env, summonsPrepa
16388
16405
  }
16389
16406
  function isAlreadyFrozenSummonsAttachment(runDirectory, attachmentPath) {
16390
16407
  const absolute = isAbsolute7(attachmentPath) ? attachmentPath : resolve11(attachmentPath);
16391
- return pathContainedIn(join26(runDirectory, "attachments"), absolute);
16408
+ return pathContainedIn(join27(runDirectory, "attachments"), absolute);
16392
16409
  }
16393
16410
  async function prepareSummonsResumeMaterials(runDirectory, summons) {
16394
16411
  if (summons === void 0) return void 0;
@@ -17573,8 +17590,8 @@ __export(public_role_summons_exports, {
17573
17590
  summonGateOfficer: () => summonGateOfficer,
17574
17591
  summonPublicRole: () => summonPublicRole
17575
17592
  });
17576
- import { existsSync as existsSync7 } from "node:fs";
17577
- import { join as join27 } from "node:path";
17593
+ import { existsSync as existsSync8 } from "node:fs";
17594
+ import { join as join28 } from "node:path";
17578
17595
  function createCapturingIo() {
17579
17596
  const chunks = [];
17580
17597
  return {
@@ -17597,7 +17614,7 @@ function parentDir(path) {
17597
17614
  function walkPackageRoot(start) {
17598
17615
  let dir = start;
17599
17616
  for (let i = 0; i < 12; i += 1) {
17600
- if (existsSync7(join27(dir, "package.json")) && existsSync7(join27(dir, "souls"))) {
17617
+ if (existsSync8(join28(dir, "package.json")) && existsSync8(join28(dir, "souls"))) {
17601
17618
  return dir;
17602
17619
  }
17603
17620
  const parent = parentDir(dir);
@@ -17673,9 +17690,9 @@ async function createSummonEnv(options) {
17673
17690
  const hostName = options.seat.host ?? "pi";
17674
17691
  let roleTurnHost = piHost;
17675
17692
  if (hostName !== "pi") {
17676
- const { lookupHostDescription: lookupHostDescription2 } = await Promise.resolve().then(() => (init_host_descriptions(), host_descriptions_exports));
17677
- const { loadProductionAcpHostFactory: loadProductionAcpHostFactory2 } = await Promise.resolve().then(() => (init_load_production_acp_host(), load_production_acp_host_exports));
17678
- if (lookupHostDescription2(hostName) === void 0) {
17693
+ const { lookupHostFamily: lookupHostFamily2 } = await Promise.resolve().then(() => (init_host_descriptions(), host_descriptions_exports));
17694
+ const { loadProductionExternalHostFactory: loadProductionExternalHostFactory2 } = await Promise.resolve().then(() => (init_load_production_external_host(), load_production_external_host_exports));
17695
+ if (lookupHostFamily2(hostName) === void 0) {
17679
17696
  throw new Error(
17680
17697
  `public role summons host unregistered: host=${hostName} seat=${options.role}`
17681
17698
  );
@@ -17683,7 +17700,7 @@ async function createSummonEnv(options) {
17683
17700
  let hostPromise;
17684
17701
  roleTurnHost = {
17685
17702
  executeTurn: async (request) => {
17686
- hostPromise ??= loadProductionAcpHostFactory2(options.packageRoot, hostName).then(
17703
+ hostPromise ??= loadProductionExternalHostFactory2(options.packageRoot, hostName).then(
17687
17704
  (create) => create({
17688
17705
  packageRoot: options.packageRoot,
17689
17706
  principalAuthority
@@ -17717,7 +17734,7 @@ async function createSummonEnv(options) {
17717
17734
  async function summonPublicRole(options) {
17718
17735
  const packageRoot = resolveSummonsPackageRoot(options.packageRoot);
17719
17736
  const home = await resolveSummonHome(options);
17720
- const agentDir = options.agentDir ?? process.env.PI_CODING_AGENT_DIR ?? join27(home, ".pi", "agent");
17737
+ const agentDir = options.agentDir ?? process.env.PI_CODING_AGENT_DIR ?? join28(home, ".pi", "agent");
17721
17738
  const {
17722
17739
  loadCredentialProviders: loadCredentialProviders2,
17723
17740
  loadPublicCliConfig: loadPublicCliConfig2,
@@ -17725,7 +17742,8 @@ async function summonPublicRole(options) {
17725
17742
  } = await Promise.resolve().then(() => (init_config(), config_exports));
17726
17743
  const credentials = options.credentials ?? await loadCredentialProviders2(agentDir);
17727
17744
  const config = await loadPublicCliConfig2(home);
17728
- const seat = resolveEffectiveSeat2(config, options.role, credentials);
17745
+ const invocation = options.host === void 0 ? void 0 : { host: options.host };
17746
+ const seat = resolveEffectiveSeat2(config, options.role, credentials, invocation);
17729
17747
  const env = {
17730
17748
  ...await createSummonEnv({
17731
17749
  role: options.role,
@@ -17837,6 +17855,38 @@ async function summonPublicRole(options) {
17837
17855
  ...stderr === void 0 || stderr === "" ? {} : { stderr }
17838
17856
  };
17839
17857
  }
17858
+ async function parentInvocationHost(sourceRunDirectory) {
17859
+ const { readFile: readFile22 } = await import("node:fs/promises");
17860
+ const path = join28(sourceRunDirectory, "invocation.json");
17861
+ let text;
17862
+ try {
17863
+ text = await readFile22(path, "utf8");
17864
+ } catch (error) {
17865
+ const code = error instanceof Error && "code" in error ? error.code : void 0;
17866
+ throw new Error(
17867
+ `parent invocation.json required for gate source run at ${path}: ${code ?? (error instanceof Error ? error.message : String(error))}`,
17868
+ { cause: error }
17869
+ );
17870
+ }
17871
+ let raw;
17872
+ try {
17873
+ raw = JSON.parse(text);
17874
+ } catch (error) {
17875
+ throw new Error(
17876
+ `parent invocation.json unreadable at ${path}: ${error instanceof Error ? error.message : String(error)}`,
17877
+ { cause: error }
17878
+ );
17879
+ }
17880
+ if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
17881
+ throw new Error(`parent invocation.json has non-object shape at ${path}`);
17882
+ }
17883
+ const host = raw.host;
17884
+ if (host === void 0) return void 0;
17885
+ if (typeof host !== "string" || host.trim() === "") {
17886
+ throw new Error(`parent invocation.json host must be a non-empty string at ${path}`);
17887
+ }
17888
+ return host;
17889
+ }
17840
17890
  async function summonGateOfficer(options) {
17841
17891
  let home = options.home;
17842
17892
  if (home === void 0) {
@@ -17850,6 +17900,7 @@ async function summonGateOfficer(options) {
17850
17900
  submission: options.submission
17851
17901
  });
17852
17902
  }
17903
+ const parentHost = await parentInvocationHost(options.sourceRunDirectory);
17853
17904
  const common = {
17854
17905
  cwd: options.cwd,
17855
17906
  ...home === void 0 ? {} : { home },
@@ -17858,6 +17909,7 @@ async function summonGateOfficer(options) {
17858
17909
  ...options.signal === void 0 ? {} : { signal: options.signal },
17859
17910
  ...options.reask === void 0 ? {} : { reviewReask: options.reask },
17860
17911
  ...gateReviewInstruction === void 0 ? {} : { gateReviewInstruction },
17912
+ ...parentHost === void 0 ? {} : { host: parentHost },
17861
17913
  ...options.roleTurnHost === void 0 ? {} : { roleTurnHost: options.roleTurnHost },
17862
17914
  ...options.createRunId === void 0 ? {} : { createRunId: options.createRunId }
17863
17915
  };
@@ -17909,7 +17961,7 @@ __export(compliance_transport_exports, {
17909
17961
  runComplianceAudit: () => runComplianceAudit,
17910
17962
  tryReadComplianceCandidate: () => tryReadComplianceCandidate
17911
17963
  });
17912
- import { Type as Type14 } from "typebox";
17964
+ import { Type as Type13 } from "typebox";
17913
17965
  function readListField(value) {
17914
17966
  return Array.isArray(value) ? value : value === void 0 ? [] : [value];
17915
17967
  }
@@ -18007,9 +18059,9 @@ var init_compliance_transport = __esm({
18007
18059
  "use strict";
18008
18060
  init_auditor_dossier_tool();
18009
18061
  AUDITOR_DOSSIER_PROMPT = "\u672C run \u5377\u5B97\u5DF2\u5C31\u7EEA\u3002";
18010
- nonblank2 = Type14.String({ minLength: 1, pattern: "\\S" });
18011
- decisionGateSchema = Type14.Object({ question: nonblank2, options: Type14.Array(nonblank2, { minItems: 1 }) }, { additionalProperties: false });
18012
- complianceDecisionSchema = Type14.Object({ status: Type14.Unknown({ description: "pass | bounce | escalate \u2014 \u5F62\u72B6\u6307\u5F15\uFF0C\u975E schema \u95F8" }), violations: Type14.Array(nonblank2, { description: "\u89C2\u5BDF\u5230\u7684\u5408\u89C4\u8FDD\u89C4" }), conflicts: Type14.Array(nonblank2, { description: "\u672A\u51B3\u6743\u5A01\u6216\u6267\u884C\u51B2\u7A81" }), decisionGate: Type14.Union([decisionGateSchema, Type14.Null()], { description: "\u5347\u7EA7\u95EE\u9898\u4E0E\u53EF\u9009\u9009\u9879" }) }, { additionalProperties: true, required: [] });
18062
+ nonblank2 = Type13.String({ minLength: 1, pattern: "\\S" });
18063
+ decisionGateSchema = Type13.Object({ question: nonblank2, options: Type13.Array(nonblank2, { minItems: 1 }) }, { additionalProperties: false });
18064
+ complianceDecisionSchema = Type13.Object({ status: Type13.Unknown({ description: "pass | bounce | escalate \u2014 \u5F62\u72B6\u6307\u5F15\uFF0C\u975E schema \u95F8" }), violations: Type13.Array(nonblank2, { description: "\u89C2\u5BDF\u5230\u7684\u5408\u89C4\u8FDD\u89C4" }), conflicts: Type13.Array(nonblank2, { description: "\u672A\u51B3\u6743\u5A01\u6216\u6267\u884C\u51B2\u7A81" }), decisionGate: Type13.Union([decisionGateSchema, Type13.Null()], { description: "\u5347\u7EA7\u95EE\u9898\u4E0E\u53EF\u9009\u9009\u9879" }) }, { additionalProperties: true, required: [] });
18013
18065
  COMPLIANCE_RESPONSE_ENTRY_TYPE = "ak_compliance_response";
18014
18066
  AUDITOR_PARENT_ATTEMPT_BINDING_ENTRY_TYPE = "ak_auditor_parent_attempt_binding";
18015
18067
  AUDITOR_COMPLIANCE_FAILURE_ENTRY_TYPE = "ak_auditor_compliance_failure";
@@ -18023,7 +18075,7 @@ var init_compliance_transport = __esm({
18023
18075
  });
18024
18076
 
18025
18077
  // src/dossier-resolution.ts
18026
- import { existsSync as existsSync8, statSync as statSync2 } from "node:fs";
18078
+ import { existsSync as existsSync9, statSync as statSync2 } from "node:fs";
18027
18079
  import { resolve as resolve12 } from "node:path";
18028
18080
  function resolveAuditDossier(env = process.env) {
18029
18081
  const raw = env[AUDIT_RUN_DIR_ENV];
@@ -18032,7 +18084,7 @@ function resolveAuditDossier(env = process.env) {
18032
18084
  }
18033
18085
  const runDirectory = resolve12(raw);
18034
18086
  try {
18035
- if (!existsSync8(runDirectory) || !statSync2(runDirectory).isDirectory()) {
18087
+ if (!existsSync9(runDirectory) || !statSync2(runDirectory).isDirectory()) {
18036
18088
  return { status: "incomplete", observation: { kind: "missing-dossier" } };
18037
18089
  }
18038
18090
  } catch {
@@ -18103,8 +18155,8 @@ var init_doctor_auditor = __esm({
18103
18155
  });
18104
18156
 
18105
18157
  // src/navigator-session-contracts.ts
18106
- import { Type as Type15 } from "typebox";
18107
- import { Value as Value3 } from "typebox/value";
18158
+ import { Type as Type14 } from "typebox";
18159
+ import { Value as Value2 } from "typebox/value";
18108
18160
  function navigatorUnavailableKey(value) {
18109
18161
  return typeof value === "string" && NAVIGATOR_UNAVAILABLE_KEYS.has(value) ? value : void 0;
18110
18162
  }
@@ -18255,26 +18307,26 @@ var init_navigator_session_contracts = __esm({
18255
18307
  this.originalCause = originalCause;
18256
18308
  }
18257
18309
  };
18258
- navigatorProviderFailureSchema = Type15.Object({
18259
- source: Type15.Union([
18260
- Type15.Literal("context"),
18261
- Type15.Literal("session"),
18262
- Type15.Literal("model"),
18263
- Type15.Literal("thinking"),
18264
- Type15.Literal("auth"),
18265
- Type15.Literal("quota"),
18266
- Type15.Literal("transport"),
18267
- Type15.Literal("unknown")
18310
+ navigatorProviderFailureSchema = Type14.Object({
18311
+ source: Type14.Union([
18312
+ Type14.Literal("context"),
18313
+ Type14.Literal("session"),
18314
+ Type14.Literal("model"),
18315
+ Type14.Literal("thinking"),
18316
+ Type14.Literal("auth"),
18317
+ Type14.Literal("quota"),
18318
+ Type14.Literal("transport"),
18319
+ Type14.Literal("unknown")
18268
18320
  ]),
18269
- cause: Type15.Union([
18270
- Type15.Literal("context"),
18271
- Type15.Literal("session"),
18272
- Type15.Literal("model"),
18273
- Type15.Literal("thinking"),
18274
- Type15.Literal("auth"),
18275
- Type15.Literal("quota"),
18276
- Type15.Literal("transport"),
18277
- Type15.Literal("unknown")
18321
+ cause: Type14.Union([
18322
+ Type14.Literal("context"),
18323
+ Type14.Literal("session"),
18324
+ Type14.Literal("model"),
18325
+ Type14.Literal("thinking"),
18326
+ Type14.Literal("auth"),
18327
+ Type14.Literal("quota"),
18328
+ Type14.Literal("transport"),
18329
+ Type14.Literal("unknown")
18278
18330
  ])
18279
18331
  }, { additionalProperties: false });
18280
18332
  }
@@ -18282,11 +18334,11 @@ var init_navigator_session_contracts = __esm({
18282
18334
 
18283
18335
  // src/archivist-record-topology.ts
18284
18336
  import { createHash as createHash8 } from "node:crypto";
18285
- import { join as join28 } from "node:path";
18337
+ import { join as join29 } from "node:path";
18286
18338
  function subjectKeyedRecordDirectory(input) {
18287
18339
  const ledgerHome = input.parentSessionFile !== void 0 && input.parentSessionFile.length > 0 ? resolveActivationLedgerHomeForPath(input.parentSessionFile) : resolveActivationLedgerHome(input.home);
18288
18340
  const digest = createHash8("sha256").update(input.subject).digest("hex").slice(0, 32);
18289
- return join28(
18341
+ return join29(
18290
18342
  activationBookDirectory(ledgerHome, resolveBookKeyFromGit(input.cwd)),
18291
18343
  input.kind,
18292
18344
  digest
@@ -18310,11 +18362,11 @@ __export(archivist_record_entry_exports, {
18310
18362
  createRecordSessionOpen: () => createRecordSessionOpen,
18311
18363
  subjectKeyedRecordDirectory: () => subjectKeyedRecordDirectory
18312
18364
  });
18313
- import { existsSync as existsSync9, mkdirSync as mkdirSync4, readFileSync as readFileSync3, realpathSync as realpathSync2, writeFileSync as writeFileSync5 } from "node:fs";
18314
- import { dirname as dirname13, resolve as resolve13, join as join29 } from "node:path";
18365
+ import { existsSync as existsSync10, mkdirSync as mkdirSync4, readFileSync as readFileSync3, realpathSync as realpathSync2, writeFileSync as writeFileSync5 } from "node:fs";
18366
+ import { dirname as dirname13, resolve as resolve13, join as join30 } from "node:path";
18315
18367
  import { SessionManager } from "@earendil-works/pi-coding-agent";
18316
18368
  function readCurrentSession(sessionDir) {
18317
- const ledger = join29(sessionDir, CURRENT_SESSION_LEDGER);
18369
+ const ledger = join30(sessionDir, CURRENT_SESSION_LEDGER);
18318
18370
  try {
18319
18371
  const value = JSON.parse(readFileSync3(ledger, "utf8"));
18320
18372
  if (typeof value !== "object" || value === null || typeof value.sessionFile !== "string" || value.sessionFile.length === 0) {
@@ -18329,7 +18381,7 @@ function readCurrentSession(sessionDir) {
18329
18381
  }
18330
18382
  }
18331
18383
  function writeCurrentSession(sessionDir, sessionFile) {
18332
- const ledger = join29(sessionDir, CURRENT_SESSION_LEDGER);
18384
+ const ledger = join30(sessionDir, CURRENT_SESSION_LEDGER);
18333
18385
  try {
18334
18386
  writeFileSync5(ledger, `${JSON.stringify({ sessionFile })}
18335
18387
  `, { flag: "wx" });
@@ -18390,10 +18442,10 @@ function createRecordSessionOpen(options) {
18390
18442
  return { session: SessionManager.inMemory(cwd), resumed: false };
18391
18443
  } else {
18392
18444
  const parentResolved = resolve13(parentFile);
18393
- sessionDir = physicallyContainedIn(ledgerHome, parentResolved) ? join29(dirname13(parentResolved), options.kind) : join29(activationBookDirectory(ledgerHome, resolveBookKeyFromGit(cwd)), options.kind);
18445
+ sessionDir = physicallyContainedIn(ledgerHome, parentResolved) ? join30(dirname13(parentResolved), options.kind) : join30(activationBookDirectory(ledgerHome, resolveBookKeyFromGit(cwd)), options.kind);
18394
18446
  parentSession = parentFile;
18395
18447
  }
18396
- const nestAlreadyExists = existsSync9(sessionDir);
18448
+ const nestAlreadyExists = existsSync10(sessionDir);
18397
18449
  ensureRealDirectoryTree(ledgerHome, sessionDir);
18398
18450
  const mayResumeSameNest = options.subject !== void 0 || options.kind === WORKER_SUBMISSION_GATE_KIND;
18399
18451
  if (mayResumeSameNest && nestAlreadyExists) {
@@ -18411,7 +18463,7 @@ function createRecordSessionOpen(options) {
18411
18463
  );
18412
18464
  if (session.isPersisted()) {
18413
18465
  const file = session.getSessionFile();
18414
- if (file !== void 0 && !existsSync9(file)) {
18466
+ if (file !== void 0 && !existsSync10(file)) {
18415
18467
  const header = session.getHeader();
18416
18468
  if (header !== null && header.type === "session") {
18417
18469
  writeFileSync5(file, `${JSON.stringify(header)}
@@ -18429,7 +18481,7 @@ function createRecordSession(options) {
18429
18481
  return createRecordSessionOpen(options).session;
18430
18482
  }
18431
18483
  function bookDirectOfficerRunPointer(options) {
18432
- const nest = join29(dirname13(options.parentSessionFile), "auditor-roles");
18484
+ const nest = join30(dirname13(options.parentSessionFile), "auditor-roles");
18433
18485
  mkdirSync4(nest, { recursive: true });
18434
18486
  const pointer = {
18435
18487
  version: 1,
@@ -18439,7 +18491,7 @@ function bookDirectOfficerRunPointer(options) {
18439
18491
  ...options.runDirectory !== void 0 && options.runDirectory.trim() !== "" ? { runDirectory: options.runDirectory } : {}
18440
18492
  };
18441
18493
  writeFileSync5(
18442
- join29(nest, `${options.officer}.pointer.json`),
18494
+ join30(nest, `${options.officer}.pointer.json`),
18443
18495
  `${JSON.stringify(pointer)}
18444
18496
  `,
18445
18497
  "utf8"
@@ -18626,7 +18678,7 @@ var init_navigator_public_session = __esm({
18626
18678
  import { createHash as createHash9 } from "node:crypto";
18627
18679
  import { resolve as resolve14 } from "node:path";
18628
18680
  import "@earendil-works/pi-coding-agent";
18629
- import { Type as Type16 } from "typebox";
18681
+ import { Type as Type15 } from "typebox";
18630
18682
  function resolveNavigatorAuthorityMaterial(roleInput, fileAuthority) {
18631
18683
  if (roleInput !== void 0 && roleInput.trim() !== "") return roleInput;
18632
18684
  if (fileAuthority !== void 0 && fileAuthority.trim() !== "") return fileAuthority;
@@ -19289,8 +19341,8 @@ var init_navigator_attendance = __esm({
19289
19341
  NAVIGATOR_EVENT_TYPE = "ak-navigator-attendance";
19290
19342
  NAVIGATOR_PREPARE_ACCEPTED_TEXT = "\u6E38\u5955\u4F7F\u51C6\u5907\u5DF2\u63A5\u53D7";
19291
19343
  NAVIGATOR_TARGETS = PACKAGED_ROLE_REGISTRY.map(({ role, phases }) => ({ role, phases }));
19292
- prepareSchema = Type16.Object({
19293
- candidates: Type16.Optional(Type16.Unknown({
19344
+ prepareSchema = Type15.Object({
19345
+ candidates: Type15.Optional(Type15.Unknown({
19294
19346
  description: "\u65B9\u5411\u5019\u9009\uFF1Bcandidates[].next.role \u5FC5\u586B\uFF0Cphase \u53EF\u9009\uFF0Croute/matches/reason/command \u53EF\u9009\u4E0A\u4E0B\u6587\uFF0C\u975E\u53D7\u7406\u95F8"
19295
19347
  }))
19296
19348
  }, { additionalProperties: true });
@@ -19303,7 +19355,7 @@ var init_navigator_attendance = __esm({
19303
19355
  });
19304
19356
 
19305
19357
  // src/engine-detour-tool.ts
19306
- import { Type as Type17 } from "typebox";
19358
+ import { Type as Type16 } from "typebox";
19307
19359
  function isCallerCancellation(error, signal) {
19308
19360
  if (signal?.aborted === true) return true;
19309
19361
  if (typeof error === "object" && error !== null && error.name === "AbortError") {
@@ -19378,9 +19430,9 @@ var init_engine_detour_tool = __esm({
19378
19430
  "src/engine-detour-tool.ts"() {
19379
19431
  "use strict";
19380
19432
  init_engine_detour();
19381
- engineDetourArgsSchema = Type17.Object(
19433
+ engineDetourArgsSchema = Type16.Object(
19382
19434
  {
19383
- argv: Type17.Array(Type17.String({ minLength: 1 }), {
19435
+ argv: Type16.Array(Type16.String({ minLength: 1 }), {
19384
19436
  minItems: 1,
19385
19437
  description: "\u9996\u9879\u4E3A PATH \u4E2D\u7684\u53EF\u6267\u884C\u6587\u4EF6\uFF0C\u5176\u4F59\u9879\u4E3A\u53C2\u6570\u3002"
19386
19438
  })
@@ -19707,7 +19759,7 @@ var init_oauth_keepalive = __esm({
19707
19759
  });
19708
19760
 
19709
19761
  // src/activation-trace.ts
19710
- import { Type as Type18 } from "typebox";
19762
+ import { Type as Type17 } from "typebox";
19711
19763
  function namedActivationCause(error) {
19712
19764
  const evidenceId = `activation-cause-${++activationCauseEvidence}`;
19713
19765
  retainedActivationCauses.set(evidenceId, error);
@@ -19728,17 +19780,17 @@ var causeSchema, activationTraceRecordSchema, activationCauseEvidence, retainedA
19728
19780
  var init_activation_trace = __esm({
19729
19781
  "src/activation-trace.ts"() {
19730
19782
  "use strict";
19731
- causeSchema = Type18.Object({
19732
- identity: Type18.String({ minLength: 1 }),
19733
- name: Type18.String({ minLength: 1 }),
19734
- message: Type18.String(),
19735
- evidenceId: Type18.Optional(Type18.String({ minLength: 1 }))
19783
+ causeSchema = Type17.Object({
19784
+ identity: Type17.String({ minLength: 1 }),
19785
+ name: Type17.String({ minLength: 1 }),
19786
+ message: Type17.String(),
19787
+ evidenceId: Type17.Optional(Type17.String({ minLength: 1 }))
19736
19788
  }, { additionalProperties: false });
19737
- activationTraceRecordSchema = Type18.Object({
19738
- role: Type18.String({ minLength: 1 }),
19739
- stageId: Type18.String({ pattern: "^[a-z][a-z0-9-]*$" }),
19740
- status: Type18.Literal("failed"),
19741
- timestamp: Type18.String({ format: "date-time" }),
19789
+ activationTraceRecordSchema = Type17.Object({
19790
+ role: Type17.String({ minLength: 1 }),
19791
+ stageId: Type17.String({ pattern: "^[a-z][a-z0-9-]*$" }),
19792
+ status: Type17.Literal("failed"),
19793
+ timestamp: Type17.String({ format: "date-time" }),
19742
19794
  cause: causeSchema
19743
19795
  }, { additionalProperties: false });
19744
19796
  activationCauseEvidence = 0;
@@ -20020,10 +20072,10 @@ var init_stderr_jsonl = __esm({
20020
20072
 
20021
20073
  // src/tool-execution-observation.ts
20022
20074
  import { writeSync as writeSync3 } from "node:fs";
20023
- import { Type as Type19 } from "typebox";
20024
- import { Value as Value4 } from "typebox/value";
20075
+ import { Type as Type18 } from "typebox";
20076
+ import { Value as Value3 } from "typebox/value";
20025
20077
  function validateToolExecutionObservationRecord(record4) {
20026
- if (!Value4.Check(toolExecutionObservationRecordSchema, record4)) {
20078
+ if (!Value3.Check(toolExecutionObservationRecordSchema, record4)) {
20027
20079
  throw new TypeError("Tool execution observation record does not match its contract");
20028
20080
  }
20029
20081
  return record4;
@@ -20114,29 +20166,266 @@ var init_tool_execution_observation = __esm({
20114
20166
  init_stderr_jsonl();
20115
20167
  TOOL_EXECUTION_UPDATE_THROTTLE_MS = 3e4;
20116
20168
  observationBase = {
20117
- role: Type19.String({ minLength: 1 }),
20118
- toolCallId: Type19.String({ minLength: 1 }),
20119
- toolName: Type19.String({ minLength: 1 }),
20120
- timestamp: Type19.String({ format: "date-time" })
20169
+ role: Type18.String({ minLength: 1 }),
20170
+ toolCallId: Type18.String({ minLength: 1 }),
20171
+ toolName: Type18.String({ minLength: 1 }),
20172
+ timestamp: Type18.String({ format: "date-time" })
20121
20173
  };
20122
- toolExecutionObservationRecordSchema = Type19.Union([
20123
- Type19.Object({
20174
+ toolExecutionObservationRecordSchema = Type18.Union([
20175
+ Type18.Object({
20124
20176
  ...observationBase,
20125
- event: Type19.Literal("tool_execution_start")
20177
+ event: Type18.Literal("tool_execution_start")
20126
20178
  }, { additionalProperties: true }),
20127
- Type19.Object({
20179
+ Type18.Object({
20128
20180
  ...observationBase,
20129
- event: Type19.Literal("tool_execution_update")
20181
+ event: Type18.Literal("tool_execution_update")
20130
20182
  }, { additionalProperties: true }),
20131
- Type19.Object({
20183
+ Type18.Object({
20132
20184
  ...observationBase,
20133
- event: Type19.Literal("tool_execution_end"),
20134
- isError: Type19.Boolean()
20185
+ event: Type18.Literal("tool_execution_end"),
20186
+ isError: Type18.Boolean()
20135
20187
  }, { additionalProperties: true })
20136
20188
  ]);
20137
20189
  }
20138
20190
  });
20139
20191
 
20192
+ // src/atomic-write.ts
20193
+ import { randomUUID as randomUUID6 } from "node:crypto";
20194
+ import { rename, rm as rm2, writeFile as writeFile8 } from "node:fs/promises";
20195
+ import { dirname as dirname17, join as join32 } from "node:path";
20196
+ async function writeFileAtomically(destination, contents) {
20197
+ const parent = dirname17(destination);
20198
+ const temporary = join32(parent, `.atomic-write-${randomUUID6()}.tmp`);
20199
+ try {
20200
+ await writeFile8(temporary, contents);
20201
+ await rename(temporary, destination);
20202
+ } catch (error) {
20203
+ await rm2(temporary, { force: true }).catch(() => void 0);
20204
+ throw error;
20205
+ }
20206
+ }
20207
+ var init_atomic_write = __esm({
20208
+ "src/atomic-write.ts"() {
20209
+ "use strict";
20210
+ }
20211
+ });
20212
+
20213
+ // src/collector-tool-schemas.ts
20214
+ import { Type as Type19 } from "typebox";
20215
+ var collectorObserveArgsSchema, COLLECTOR_REQUEST_ID_PATTERN, collectorRequestArgsSchema, COLLECTOR_HANDBOOK_MAX_BYTES, collectorHandbookWriteArgsSchema, collectorReadArgsSchema, collectorWaitArgsSchema, collectorBindTargetArgsSchema, collectorFindingItemDeclaration, collectorOutputBaseSchema, collectorOutputArgsSchema;
20216
+ var init_collector_tool_schemas = __esm({
20217
+ "src/collector-tool-schemas.ts"() {
20218
+ "use strict";
20219
+ init_collector_evidence();
20220
+ init_open_tool_schema();
20221
+ init_terminating_infrastructure();
20222
+ collectorObserveArgsSchema = Type19.Object({}, { additionalProperties: false });
20223
+ COLLECTOR_REQUEST_ID_PATTERN = /^\S(?:.*\S)?$/;
20224
+ collectorRequestArgsSchema = Type19.Object({
20225
+ requestId: Type19.String({
20226
+ minLength: 1,
20227
+ pattern: COLLECTOR_REQUEST_ID_PATTERN.source,
20228
+ description: "\u8BF7\u6C42\u8EAB\u4EFD\uFF08\u914D\u7F6E id \u6216\u89D2\u8272\u5224\u5B9A\u7684\u7A33\u5B9A id\uFF1B\u9996\u5C3E\u65E0\u7A7A\u767D\uFF09"
20229
+ }),
20230
+ snapshotId: Type19.String({ minLength: 1, description: "\u6700\u65B0\u7559\u5B58\u89C2\u5BDF\u5FEB\u7167" }),
20231
+ body: Type19.Optional(Type19.String({
20232
+ minLength: 1,
20233
+ description: "\u89D2\u8272\u5224\u5B9A\u7684\u8BF7\u6C42\u6B63\u6587\uFF1Brequest-manifest \u672A\u6536\u5F55\u8BE5 requestId \u65F6\u5FC5\u586B"
20234
+ }))
20235
+ }, { additionalProperties: false });
20236
+ COLLECTOR_HANDBOOK_MAX_BYTES = 64 * 1024;
20237
+ collectorHandbookWriteArgsSchema = Type19.Object({
20238
+ scope: Type19.Union([
20239
+ Type19.Literal("general"),
20240
+ Type19.Literal("repo")
20241
+ ], { description: "general\uFF1D\u901A\u7528\u624B\u518C\uFF1Brepo\uFF1D\u5F53\u524D\u4ED3\u5E93\u5DEE\u5F02" }),
20242
+ body: Type19.String({
20243
+ description: `\u624B\u518C\u5168\u6587\uFF08opaque \u5DE5\u4F5C\u8BB0\u5FC6\uFF1B\u6574\u4EFD\u66FF\u6362\uFF1BUTF-8 \u81F3\u591A ${COLLECTOR_HANDBOOK_MAX_BYTES} \u5B57\u8282\uFF09`
20244
+ })
20245
+ }, { additionalProperties: false });
20246
+ collectorReadArgsSchema = Type19.Object({
20247
+ evidenceId: Type19.String({ minLength: 1, description: "observe \u8FD4\u56DE\u7684\u6750\u6599\u8BC1\u636E id\uFF08evidenceId\uFF09" })
20248
+ }, { additionalProperties: false });
20249
+ collectorWaitArgsSchema = Type19.Object({
20250
+ durationMs: Type19.Integer({ minimum: 1, maximum: COLLECTOR_ELIGIBILITY_MS, description: "\u7B49\u5F85\u6BEB\u79D2\uFF1B\u5355\u6B21\u4E0A\u9650\u4E94\u5206\u949F\u4E14\u4E0D\u8D85\u5269\u4F59\u8D44\u683C" })
20251
+ }, { additionalProperties: false });
20252
+ collectorBindTargetArgsSchema = Type19.Object({
20253
+ prNumber: Type19.Optional(Type19.Unknown({
20254
+ description: "\u89D2\u8272\u5224\u5B9A\u7684\u672C\u4ED3 PR \u53F7\uFF08\u6B63\u6574\u6570\uFF09\u3002\u4E0E issueNumber \u4E8C\u9009\u4E00\u6216\u540C\u6307\u552F\u4E00\u76EE\u6807\u3002\u5F62\u72B6\u6307\u5F15\uFF0C\u975E schema \u95F8\u3002"
20255
+ })),
20256
+ issueNumber: Type19.Optional(Type19.Unknown({
20257
+ description: "\u89D2\u8272\u5224\u5B9A\u7684\u672C\u4ED3 issue \u53F7\uFF08\u6B63\u6574\u6570\uFF09\uFF1Bruntime \u7ECF\u7EBF\u4E0A\u5173\u8054\u89E3\u6790\u552F\u4E00 PR\u3002\u5F62\u72B6\u6307\u5F15\uFF0C\u975E schema \u95F8\u3002"
20258
+ }))
20259
+ }, { additionalProperties: true });
20260
+ collectorFindingItemDeclaration = (() => {
20261
+ const item = Type19.Object(
20262
+ {
20263
+ evidenceId: Type19.Unknown({
20264
+ description: "observe \u8FD4\u56DE\u7684\u6750\u6599\u6307\u9488\uFF08\u5FC5\u586B\u8BED\u4E49\uFF09"
20265
+ }),
20266
+ category: Type19.Unknown({
20267
+ description: "\u7B80\u77ED\u5F52\u7C7B\u6807\u7B7E\uFF0C\u4E0D\u662F\u6458\u8981"
20268
+ }),
20269
+ summary: Type19.Unknown({
20270
+ description: "\u54EA\u4E2A bot\u3001\u4EC0\u4E48\u95EE\u9898\u7684\u6458\u8981\uFF1B\u4E0D\u8A8A\u6284\u6B63\u6587"
20271
+ })
20272
+ },
20273
+ {
20274
+ additionalProperties: true,
20275
+ description: "\u5355\u6761 finding \u6307\u9488\uFF1AevidenceId + \u53EF\u9009 category/summary\u3002\u5F62\u72B6\u6307\u5F15\uFF0C\u975E schema \u95F8\u3002"
20276
+ }
20277
+ );
20278
+ item.required = [];
20279
+ return item;
20280
+ })();
20281
+ collectorOutputBaseSchema = openToolObject(
20282
+ Type19.Object({
20283
+ // No root type:array — host must not shape-reject non-array findings (#676 C).
20284
+ // Nested item declarations ride `items` for registration preservation (ADR 0057).
20285
+ findings: Type19.Unsafe({
20286
+ description: "\u672C\u6B21\u6536\u96C6\u5230\u7684\u9010\u6761 findings\uFF08\u6307\u9488\u6570\u7EC4\u4E3A\u89C4\u8303\u5F62\uFF09\u3002\u96F6 finding \u7684\u6A21\u677F\u901A\u77E5\u4E0D\u5F97\u8FDB\u5165\uFF1B\u6B63\u5E38\u5B8C\u5DE5\u65E0 finding \u65F6\u7701\u7565\u3002\u5F62\u72B6\u6307\u5F15\uFF0C\u975E schema \u95F8\u3002",
20287
+ items: collectorFindingItemDeclaration
20288
+ }),
20289
+ unfinishedReasons: Type19.Unknown({
20290
+ description: "\u672A\u5B8C\u6210\u539F\u56E0\u5B57\u7B26\u4E32\u6570\u7EC4\uFF08\u989D\u5EA6/\u6545\u969C/\u7B49\u5F85\u5C4A\u6EE1\u7B49\u73B0\u573A\u4F9D\u636E\uFF09\uFF1B\u4E0D\u5F97\u628A\u672A\u5B8C\u6210\u8868\u8FF0\u4E3A\u65E0\u95EE\u9898\u3002\u65E0\u53EF\u62A5\u544A\u65F6\u7701\u7565\u3002\u5F62\u72B6\u6307\u5F15\uFF0C\u975E schema \u95F8\u3002"
20291
+ })
20292
+ })
20293
+ );
20294
+ collectorOutputArgsSchema = withInfrastructureFailureDeclaration(
20295
+ collectorOutputBaseSchema
20296
+ );
20297
+ }
20298
+ });
20299
+
20300
+ // src/collector-handbook.ts
20301
+ import { readFile as readFile18 } from "node:fs/promises";
20302
+ import { join as join33, sep as sep4 } from "node:path";
20303
+ function resolveCollectorHandbookRoot(sessionPath) {
20304
+ if (typeof sessionPath !== "string" || sessionPath.trim().length === 0) {
20305
+ throw new Error("\u901A\u8FDB\u53F8\u624B\u518C\u8981\u6C42\u975E\u7A7A session \u8DEF\u5F84\uFF0C\u4E14\u4F4D\u4E8E books/<bookKey>/");
20306
+ }
20307
+ const segments = sessionPath.split(sep4);
20308
+ let bookKey;
20309
+ for (let i = 0; i + 3 < segments.length; i += 1) {
20310
+ if (segments[i] === ".ak-roles" && segments[i + 1] === "books") {
20311
+ const candidate = segments[i + 2];
20312
+ if (candidate.length > 0) {
20313
+ bookKey = candidate;
20314
+ break;
20315
+ }
20316
+ }
20317
+ }
20318
+ if (bookKey === void 0) {
20319
+ throw new Error(
20320
+ `\u901A\u8FDB\u53F8\u624B\u518C\u8981\u6C42 session \u4F4D\u4E8E books/<bookKey>/\uFF1B\u6536\u5230 ${sessionPath}`
20321
+ );
20322
+ }
20323
+ if (bookKey === "." || bookKey === "..") {
20324
+ throw new Error(`\u901A\u8FDB\u53F8\u624B\u518C\u62D2\u7EDD\u4E0D\u5B89\u5168 bookKey ${JSON.stringify(bookKey)}`);
20325
+ }
20326
+ const ledgerHome = resolveActivationLedgerHomeForPath(sessionPath);
20327
+ const root = join33(activationBookDirectory(ledgerHome, bookKey), "collector-handbook");
20328
+ return { ledgerHome, bookKey, root };
20329
+ }
20330
+ function collectorHandbookRepoFileName(repositoryCanonical) {
20331
+ if (!/^[a-z0-9][a-z0-9._-]*\/[a-z0-9][a-z0-9._-]*$/.test(repositoryCanonical)) {
20332
+ throw new Error(
20333
+ `\u901A\u8FDB\u53F8\u624B\u518C\u4ED3\u5E93\u6587\u4EF6\u8981\u6C42\u89C4\u8303 owner/repo\uFF0C\u6536\u5230 ${JSON.stringify(repositoryCanonical)}`
20334
+ );
20335
+ }
20336
+ return `${repositoryCanonical.replaceAll("/", "__")}.md`;
20337
+ }
20338
+ function createCollectorHandbookStore(input) {
20339
+ const generalPath = join33(input.handbookRoot, "general.md");
20340
+ const repoDir = join33(input.handbookRoot, "repos");
20341
+ const repoPath = join33(repoDir, collectorHandbookRepoFileName(input.repositoryCanonical));
20342
+ const assertHandbookBudget = (body, label) => {
20343
+ const byteLength = Buffer.byteLength(body, "utf8");
20344
+ if (byteLength > COLLECTOR_HANDBOOK_MAX_BYTES) {
20345
+ throw new Error(
20346
+ `\u901A\u8FDB\u53F8\u624B\u518C${label} UTF-8 \u81F3\u591A ${COLLECTOR_HANDBOOK_MAX_BYTES} \u5B57\u8282\uFF0C\u6536\u5230 ${byteLength}`
20347
+ );
20348
+ }
20349
+ return byteLength;
20350
+ };
20351
+ const readOptional = async (path, parentDir2) => {
20352
+ ensureRealDirectoryTree(input.ledgerHome, parentDir2);
20353
+ assertLedgerFileInsideHome(path, input.ledgerHome);
20354
+ try {
20355
+ const body = await readFile18(path, "utf8");
20356
+ assertHandbookBudget(body, "\u6B63\u6587");
20357
+ return body;
20358
+ } catch (error) {
20359
+ if (isNotFound(error)) return void 0;
20360
+ throw error;
20361
+ }
20362
+ };
20363
+ return {
20364
+ root: input.handbookRoot,
20365
+ repositoryCanonical: input.repositoryCanonical,
20366
+ async read() {
20367
+ const bookGeneral = await readOptional(generalPath, input.handbookRoot);
20368
+ const bookRepo = await readOptional(repoPath, repoDir);
20369
+ if (bookGeneral !== void 0) {
20370
+ return {
20371
+ general: bookGeneral,
20372
+ repo: bookRepo ?? "",
20373
+ generalSource: "book",
20374
+ repoSource: bookRepo === void 0 ? "empty" : "book",
20375
+ generalPath,
20376
+ repoPath
20377
+ };
20378
+ }
20379
+ const seed = input.seedGeneral;
20380
+ if (typeof seed === "string" && seed.length > 0) {
20381
+ assertHandbookBudget(seed, "\u6B63\u6587");
20382
+ return {
20383
+ general: seed,
20384
+ repo: bookRepo ?? "",
20385
+ generalSource: "seed",
20386
+ repoSource: bookRepo === void 0 ? "empty" : "book",
20387
+ generalPath,
20388
+ repoPath
20389
+ };
20390
+ }
20391
+ return {
20392
+ general: "",
20393
+ repo: bookRepo ?? "",
20394
+ generalSource: "empty",
20395
+ repoSource: bookRepo === void 0 ? "empty" : "book",
20396
+ generalPath,
20397
+ repoPath
20398
+ };
20399
+ },
20400
+ async write(scope, body) {
20401
+ const byteLength = assertHandbookBudget(body, "\u6B63\u6587");
20402
+ ensureRealDirectoryTree(input.ledgerHome, input.handbookRoot);
20403
+ const path = scope === "general" ? generalPath : repoPath;
20404
+ if (scope === "repo") {
20405
+ ensureRealDirectoryTree(input.ledgerHome, repoDir);
20406
+ }
20407
+ assertLedgerFileInsideHome(path, input.ledgerHome);
20408
+ await writeFileAtomically(path, body);
20409
+ return {
20410
+ scope,
20411
+ path,
20412
+ byteLength
20413
+ };
20414
+ }
20415
+ };
20416
+ }
20417
+ function isNotFound(error) {
20418
+ return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
20419
+ }
20420
+ var init_collector_handbook = __esm({
20421
+ "src/collector-handbook.ts"() {
20422
+ "use strict";
20423
+ init_atomic_write();
20424
+ init_activation_ledger_topology();
20425
+ init_collector_tool_schemas();
20426
+ }
20427
+ });
20428
+
20140
20429
  // src/collector-receipt.ts
20141
20430
  function fail4(message) {
20142
20431
  throw new Error(message);
@@ -20236,20 +20525,34 @@ var init_collector_receipt = __esm({
20236
20525
  // src/collector-role.ts
20237
20526
  function buildMethodContext(activation) {
20238
20527
  const pr = activation.ledger.config.prNumber;
20239
- return [
20528
+ const handbook = activation.handbookView;
20529
+ const lines = [
20240
20530
  "<collector_method>",
20241
20531
  `host: github.com`,
20242
20532
  `repository: ${activation.repository.canonical}`,
20243
- `prNumber: ${pr === void 0 ? "unbound \u2014 call ak_collector_bind_target with the role-decided issue/PR before observe" : String(pr)}`,
20533
+ `prNumber: ${pr === void 0 ? "\u672A\u7ED1\u5B9A" : String(pr)}`,
20244
20534
  `requests: ${JSON.stringify(activation.manifest.requests.map((request) => ({ id: request.id })))}`,
20535
+ `handbookGeneralSource: ${handbook.generalSource}`,
20536
+ `handbookRepoSource: ${handbook.repoSource}`,
20245
20537
  "</collector_method>"
20246
- ].join("\n");
20538
+ ];
20539
+ if (handbook.general.length > 0 || handbook.repo.length > 0) {
20540
+ const payload = JSON.stringify({
20541
+ general: handbook.general,
20542
+ repo: handbook.repo,
20543
+ generalSource: handbook.generalSource,
20544
+ repoSource: handbook.repoSource,
20545
+ repository: activation.repository.canonical
20546
+ }).replaceAll("<", "\\u003c");
20547
+ lines.push("", "<collector_handbook>", payload, "</collector_handbook>");
20548
+ }
20549
+ return lines.join("\n");
20247
20550
  }
20248
20551
  function parsePositiveTicket(raw, label) {
20249
20552
  if (raw === void 0 || raw === null) return void 0;
20250
20553
  if (typeof raw === "number" && Number.isSafeInteger(raw) && raw >= 1) return raw;
20251
20554
  if (typeof raw === "string" && /^[1-9]\d*$/.test(raw.trim())) return Number(raw.trim());
20252
- throw new CollectorTargetBindError(`ak_collector_bind_target ${label} must be a positive safe integer`);
20555
+ throw new CollectorTargetBindError(`\u901A\u8FDB\u53F8\u7ED1\u5B9A ${label} \u987B\u4E3A\u6B63\u5B89\u5168\u6574\u6570`);
20253
20556
  }
20254
20557
  function createCollectorRoleRuntime(pi, dependencies, hostActions) {
20255
20558
  let toolsRegistered = false;
@@ -20278,13 +20581,28 @@ function createCollectorRoleRuntime(pi, dependencies, hostActions) {
20278
20581
  clock,
20279
20582
  ctx
20280
20583
  );
20584
+ const sessionPath = ctx.sessionManager?.getSessionFile?.() ?? ctx.sessionManager?.getSessionDir?.();
20585
+ if (typeof sessionPath !== "string" || sessionPath.length === 0) {
20586
+ throw new Error("\u901A\u8FDB\u53F8\u624B\u518C\u8981\u6C42 session \u8DEF\u5F84\u4F4D\u4E8E books/<bookKey>/");
20587
+ }
20588
+ const placement = resolveCollectorHandbookRoot(sessionPath);
20589
+ const seedGeneral = dependencies.loadHandbookSeed === void 0 ? void 0 : (await dependencies.loadHandbookSeed()).trim();
20590
+ const handbook = createCollectorHandbookStore({
20591
+ ledgerHome: placement.ledgerHome,
20592
+ handbookRoot: placement.root,
20593
+ repositoryCanonical: repository.canonical,
20594
+ ...seedGeneral === void 0 || seedGeneral.length === 0 ? {} : { seedGeneral }
20595
+ });
20596
+ const handbookView = await handbook.read();
20281
20597
  return {
20282
20598
  soul,
20283
20599
  repository,
20284
20600
  manifest,
20285
20601
  ledger,
20286
20602
  transport,
20287
- clock
20603
+ clock,
20604
+ handbook,
20605
+ handbookView
20288
20606
  };
20289
20607
  },
20290
20608
  assembleMaterials(activation, baseSystemPrompt) {
@@ -20337,7 +20655,7 @@ function createCollectorRoleRuntime(pi, dependencies, hostActions) {
20337
20655
  const issueNumber = parsePositiveTicket(params.issueNumber, "issueNumber");
20338
20656
  if (prNumber === void 0 && issueNumber === void 0) {
20339
20657
  throw new CollectorTargetBindError(
20340
- "ak_collector_bind_target requires role-decided prNumber and/or issueNumber"
20658
+ "\u901A\u8FDB\u53F8\u7ED1\u5B9A\u987B\u7531\u89D2\u8272\u5224\u5B9A prNumber \u4E0E/\u6216 issueNumber"
20341
20659
  );
20342
20660
  }
20343
20661
  let bound = prNumber;
@@ -20349,18 +20667,18 @@ function createCollectorRoleRuntime(pi, dependencies, hostActions) {
20349
20667
  });
20350
20668
  if (associated.length === 0) {
20351
20669
  throw new CollectorTargetBindError(
20352
- `no PR associated with issue #${issueNumber} in ${activation.repository.canonical}; pass an explicit --pr or a different issueNumber`
20670
+ `${activation.repository.canonical} \u7684 issue #${issueNumber} \u65E0\u5173\u8054 PR\uFF1B\u8BF7\u6539\u7528\u660E\u786E --pr \u6216\u5176\u4ED6 issueNumber`
20353
20671
  );
20354
20672
  }
20355
20673
  if (associated.length > 1) {
20356
20674
  throw new CollectorTargetBindError(
20357
- `multiple PRs associated with issue #${issueNumber}: ${associated.join(", ")}; pass an explicit prNumber or --pr`
20675
+ `issue #${issueNumber} \u5173\u8054\u591A\u4E2A PR\uFF1A${associated.join("\u3001")}\uFF1B\u8BF7\u6539\u7528\u660E\u786E prNumber \u6216 --pr`
20358
20676
  );
20359
20677
  }
20360
20678
  const fromIssue = associated[0];
20361
20679
  if (prNumber !== void 0 && prNumber !== fromIssue) {
20362
20680
  throw new CollectorTargetBindError(
20363
- `prNumber ${prNumber} conflicts with issue #${issueNumber} association PR ${fromIssue}`
20681
+ `prNumber ${prNumber} \u4E0E issue #${issueNumber} \u5173\u8054 PR ${fromIssue} \u51B2\u7A81`
20364
20682
  );
20365
20683
  }
20366
20684
  bound = fromIssue;
@@ -20452,8 +20770,8 @@ function createCollectorRoleRuntime(pi, dependencies, hostActions) {
20452
20770
  pi.registerTool({
20453
20771
  name: COLLECTOR_REQUEST_TOOL,
20454
20772
  label: "\u901A\u8FDB\u53F8\u8BF7\u6C42",
20455
- description: "\u6309\u914D\u7F6E\u8BF7\u6C42\u4F53\u4E0E\u5173\u8054\u6807\u8BB0\uFF0C\u5728\u6240\u5F15\u6700\u65B0\u5FEB\u7167 HEAD \u53D1\u4E00\u6B21\u8BF7\u6C42\u3002",
20456
- promptSnippet: "\u6309\u914D\u7F6E\u53D1\u4E00\u6B21\u8BF7\u6C42",
20773
+ description: "\u5728\u6240\u5F15\u6700\u65B0\u5FEB\u7167 HEAD \u53D1\u4E00\u6B21\u8BF7\u6C42\u3002requestId \u53EF\u53D6\u914D\u7F6E\u6E05\u5355\uFF0C\u6216\u89D2\u8272\u4F9D\u624B\u518C/\u73B0\u573A\u5224\u5B9A\u7684\u7A33\u5B9A id\uFF1B\u540E\u8005\u987B\u540C\u65F6\u63D0\u4F9B body\u3002",
20774
+ promptSnippet: "\u53D1\u4E00\u6B21\u8BC4\u5BA1\u8BF7\u6C42",
20457
20775
  parameters: requestSchema,
20458
20776
  async execute(toolCallId, params, signal, _onUpdate, ctx) {
20459
20777
  const activation = getActivation();
@@ -20461,7 +20779,11 @@ function createCollectorRoleRuntime(pi, dependencies, hostActions) {
20461
20779
  try {
20462
20780
  activation.ledger.beginOperational(COLLECTOR_REQUEST_TOOL, toolCallId);
20463
20781
  const details = await activation.ledger.request(
20464
- params,
20782
+ {
20783
+ requestId: params.requestId,
20784
+ snapshotId: params.snapshotId,
20785
+ ...typeof params.body === "string" ? { body: params.body } : {}
20786
+ },
20465
20787
  activation.transport,
20466
20788
  activation.clock,
20467
20789
  signal
@@ -20480,6 +20802,44 @@ function createCollectorRoleRuntime(pi, dependencies, hostActions) {
20480
20802
  }
20481
20803
  }
20482
20804
  });
20805
+ pi.registerTool({
20806
+ name: COLLECTOR_HANDBOOK_WRITE_TOOL,
20807
+ label: "\u901A\u8FDB\u53F8\u624B\u518C\u5199\u5165",
20808
+ description: "\u5199\u5165\u901A\u7528\u624B\u518C\u6216\u5F53\u524D\u4ED3\u5E93\u5DEE\u5F02\u5168\u6587\uFF08\u6574\u4EFD\u66FF\u6362\uFF09\u3002",
20809
+ promptSnippet: "\u66F4\u65B0 bot \u624B\u518C",
20810
+ parameters: handbookWriteSchema,
20811
+ async execute(toolCallId, params, _signal, _onUpdate, ctx) {
20812
+ const activation = getActivation();
20813
+ if (activation === void 0) throw new Error("\u901A\u8FDB\u53F8\u672A\u6FC0\u6D3B");
20814
+ try {
20815
+ activation.ledger.beginOperational(COLLECTOR_HANDBOOK_WRITE_TOOL, toolCallId);
20816
+ const details = await activation.handbook.write(params.scope, params.body);
20817
+ activation.handbookView = await activation.handbook.read();
20818
+ activation.ledger.completeOperational(toolCallId);
20819
+ return {
20820
+ content: [{
20821
+ type: "text",
20822
+ text: `\u624B\u518C\u5DF2\u5199\u5165\uFF1A${details.scope}`
20823
+ }],
20824
+ details: {
20825
+ scope: details.scope,
20826
+ path: details.path,
20827
+ byteLength: details.byteLength,
20828
+ generalSource: activation.handbookView.generalSource,
20829
+ repoSource: activation.handbookView.repoSource
20830
+ }
20831
+ };
20832
+ } catch (error) {
20833
+ if (isCorrectableExecuteError(error)) throw error;
20834
+ hostActions.failInfrastructure(error, ctx, toolCallId);
20835
+ } finally {
20836
+ try {
20837
+ activation.ledger.completeOperational(toolCallId);
20838
+ } catch {
20839
+ }
20840
+ }
20841
+ }
20842
+ });
20483
20843
  pi.registerTool({
20484
20844
  name: COLLECTOR_WAIT_TOOL,
20485
20845
  label: "\u901A\u8FDB\u53F8\u7B49\u5F85",
@@ -20557,13 +20917,14 @@ function createCollectorRoleRuntime(pi, dependencies, hostActions) {
20557
20917
  }
20558
20918
  };
20559
20919
  }
20560
- var CollectorNormalCompletionDeclarationError, CollectorTargetBindError, COLLECTOR_REQUIRED_TOOLS, COLLECTOR_TRANSPORT_FLAGS, observeSchema, readSchema, requestSchema, waitSchema, bindSchema, outputSchema;
20920
+ var CollectorNormalCompletionDeclarationError, CollectorTargetBindError, COLLECTOR_REQUIRED_TOOLS, COLLECTOR_TRANSPORT_FLAGS, observeSchema, readSchema, requestSchema, waitSchema, bindSchema, handbookWriteSchema, outputSchema;
20561
20921
  var init_collector_role = __esm({
20562
20922
  "src/collector-role.ts"() {
20563
20923
  "use strict";
20564
20924
  init_collector_config();
20565
20925
  init_collector_evidence();
20566
20926
  init_collector_github();
20927
+ init_collector_handbook();
20567
20928
  init_collector_ledger();
20568
20929
  init_collector_receipt();
20569
20930
  init_collector_tool_schemas();
@@ -20589,6 +20950,7 @@ var init_collector_role = __esm({
20589
20950
  COLLECTOR_READ_TOOL,
20590
20951
  COLLECTOR_REQUEST_TOOL,
20591
20952
  COLLECTOR_WAIT_TOOL,
20953
+ COLLECTOR_HANDBOOK_WRITE_TOOL,
20592
20954
  COLLECTOR_OUTPUT_TOOL
20593
20955
  ];
20594
20956
  COLLECTOR_TRANSPORT_FLAGS = Object.freeze([
@@ -20619,6 +20981,7 @@ var init_collector_role = __esm({
20619
20981
  requestSchema = collectorRequestArgsSchema;
20620
20982
  waitSchema = collectorWaitArgsSchema;
20621
20983
  bindSchema = collectorBindTargetArgsSchema;
20984
+ handbookWriteSchema = collectorHandbookWriteArgsSchema;
20622
20985
  outputSchema = collectorOutputArgsSchema;
20623
20986
  }
20624
20987
  });
@@ -21600,7 +21963,7 @@ var init_reviewer_role = __esm({
21600
21963
 
21601
21964
  // src/worker-submission-gates.ts
21602
21965
  import { execFileSync as execFileSync4 } from "node:child_process";
21603
- import { existsSync as existsSync10, lstatSync as lstatSync3, readdirSync as readdirSync2, readFileSync as readFileSync4, rmdirSync, rmSync } from "node:fs";
21966
+ import { existsSync as existsSync11, lstatSync as lstatSync3, readdirSync as readdirSync2, readFileSync as readFileSync4, rmdirSync, rmSync } from "node:fs";
21604
21967
  import { resolve as resolve18 } from "node:path";
21605
21968
  function git2(cwd, args) {
21606
21969
  return execFileSync4("git", args, {
@@ -21621,7 +21984,7 @@ function statusOf(error) {
21621
21984
  return typeof error === "object" && error !== null && "status" in error ? error.status : void 0;
21622
21985
  }
21623
21986
  function tryGetAll(file, key) {
21624
- if (!existsSync10(file)) return [];
21987
+ if (!existsSync11(file)) return [];
21625
21988
  try {
21626
21989
  const out = gitFile(file, ["--get-all", key]);
21627
21990
  return out.length === 0 ? [] : out.split("\n");
@@ -21631,7 +21994,7 @@ function tryGetAll(file, key) {
21631
21994
  }
21632
21995
  }
21633
21996
  function ownedHook(path) {
21634
- if (!existsSync10(path)) return false;
21997
+ if (!existsSync11(path)) return false;
21635
21998
  return readFileSync4(path, "utf8").includes(HOOK_MARKER);
21636
21999
  }
21637
22000
  function escapeGitConfigValueRegex(value) {
@@ -21658,11 +22021,11 @@ function rmOwnedDir(dir) {
21658
22021
  const hookPath = resolve18(dir, HOOK_FILE);
21659
22022
  if (!ownedHook(hookPath)) return;
21660
22023
  rmSync(hookPath, { force: true });
21661
- if (existsSync10(dir) && readdirSync2(dir).length === 0) rmdirSync(dir);
22024
+ if (existsSync11(dir) && readdirSync2(dir).length === 0) rmdirSync(dir);
21662
22025
  }
21663
22026
  function linkedGitDirs(commonDir) {
21664
22027
  const root = resolve18(commonDir, "worktrees");
21665
- if (!existsSync10(root)) return [];
22028
+ if (!existsSync11(root)) return [];
21666
22029
  return readdirSync2(root).map((name) => resolve18(root, name)).filter((dir) => lstatSync3(dir).isDirectory());
21667
22030
  }
21668
22031
  function uninstallPackageWorkerHooks(cwd) {
@@ -21729,11 +22092,11 @@ function reliableWindow(cwd, baseline, head) {
21729
22092
  const raw = git2(cwd, ["log", "--format=%P%x1e%s", range]);
21730
22093
  if (raw.length === 0) return [];
21731
22094
  return raw.split("\n").flatMap((line2) => {
21732
- const sep4 = line2.indexOf("");
21733
- if (sep4 < 0) return [];
22095
+ const sep5 = line2.indexOf("");
22096
+ if (sep5 < 0) return [];
21734
22097
  return [{
21735
- subject: line2.slice(sep4 + 1),
21736
- merge: line2.slice(0, sep4).trim().includes(" ")
22098
+ subject: line2.slice(sep5 + 1),
22099
+ merge: line2.slice(0, sep5).trim().includes(" ")
21737
22100
  }];
21738
22101
  });
21739
22102
  }
@@ -22351,8 +22714,8 @@ var init_activation_reconciliation = __esm({
22351
22714
 
22352
22715
  // src/role-runtime.ts
22353
22716
  import { readFileSync as readFileSync5, writeSync as writeSync4 } from "node:fs";
22354
- import { join as join31 } from "node:path";
22355
- import { Value as Value5 } from "typebox/value";
22717
+ import { join as join34 } from "node:path";
22718
+ import { Value as Value4 } from "typebox/value";
22356
22719
  function decodeReviewerAdmittedInputs(getFlag) {
22357
22720
  let reviewScopeKeys;
22358
22721
  const rawScopeKeys = getFlag("ak-review-scope-keys");
@@ -22479,7 +22842,7 @@ function activationStage(role, runtime) {
22479
22842
  }
22480
22843
  }
22481
22844
  function validateActivationTraceRecord(record4) {
22482
- if (!Value5.Check(activationTraceRecordSchema, record4)) {
22845
+ if (!Value4.Check(activationTraceRecordSchema, record4)) {
22483
22846
  throw new TypeError("Activation trace record does not match its closed contract");
22484
22847
  }
22485
22848
  return record4;
@@ -22723,7 +23086,7 @@ function readDiaristRunCoordinates() {
22723
23086
  if (typeof runDirectory !== "string" || runDirectory.trim() === "") {
22724
23087
  throw new Error("diarist accept requires AK_ROLE_RUN_DIR");
22725
23088
  }
22726
- const admittedPath = join31(runDirectory, "admitted-request.json");
23089
+ const admittedPath = join34(runDirectory, "admitted-request.json");
22727
23090
  const admitted = JSON.parse(readFileSync5(admittedPath, "utf8"));
22728
23091
  if (typeof admitted.projectRoot !== "string" || admitted.projectRoot.trim() === "") {
22729
23092
  throw new Error(`diarist admitted-request missing projectRoot (${admittedPath})`);
@@ -23341,7 +23704,8 @@ function createRoleRuntimeExtension(dependencies) {
23341
23704
  dossierEntries: context.sessionManager?.getEntries?.() ?? []
23342
23705
  });
23343
23706
  },
23344
- ...dependencies.createCollectorClock === void 0 ? {} : { createClock: dependencies.createCollectorClock }
23707
+ ...dependencies.createCollectorClock === void 0 ? {} : { createClock: dependencies.createCollectorClock },
23708
+ ...dependencies.loadCollectorHandbookSeed === void 0 ? {} : { loadHandbookSeed: dependencies.loadCollectorHandbookSeed }
23345
23709
  },
23346
23710
  hostActions
23347
23711
  );
@@ -24082,9 +24446,9 @@ __export(in_process_session_exports, {
24082
24446
  DEFAULT_COMPLIANCE_IDLE_MAX_RETRIES: () => DEFAULT_COMPLIANCE_IDLE_MAX_RETRIES,
24083
24447
  openPiInProcessSession: () => openPiInProcessSession
24084
24448
  });
24085
- import { mkdtemp as mkdtemp2, rm as rm2 } from "node:fs/promises";
24449
+ import { mkdtemp as mkdtemp2, rm as rm3 } from "node:fs/promises";
24086
24450
  import { tmpdir as tmpdir2 } from "node:os";
24087
- import { join as join32 } from "node:path";
24451
+ import { join as join35 } from "node:path";
24088
24452
  import {
24089
24453
  createAgentSession,
24090
24454
  DefaultResourceLoader,
@@ -24207,7 +24571,7 @@ async function openPiInProcessSession(options) {
24207
24571
  let scratchDir;
24208
24572
  let resolvedAgentDir = options.agentDir;
24209
24573
  if (resolvedAgentDir === void 0) {
24210
- scratchDir = await mkdtemp2(join32(options.credentialScratchParent ?? tmpdir2(), "ak-institutional-"));
24574
+ scratchDir = await mkdtemp2(join35(options.credentialScratchParent ?? tmpdir2(), "ak-institutional-"));
24211
24575
  resolvedAgentDir = scratchDir;
24212
24576
  }
24213
24577
  try {
@@ -24689,7 +25053,7 @@ async function openPiInProcessSession(options) {
24689
25053
  }
24690
25054
  if (scratchDir !== void 0) {
24691
25055
  try {
24692
- await rm2(scratchDir, { recursive: true, force: true });
25056
+ await rm3(scratchDir, { recursive: true, force: true });
24693
25057
  } catch (error) {
24694
25058
  cleanupFailures.push(error);
24695
25059
  }
@@ -24714,7 +25078,7 @@ async function openPiInProcessSession(options) {
24714
25078
  } catch (openError) {
24715
25079
  if (scratchDir !== void 0) {
24716
25080
  try {
24717
- await rm2(scratchDir, { recursive: true, force: true });
25081
+ await rm3(scratchDir, { recursive: true, force: true });
24718
25082
  } catch (cleanupFailure) {
24719
25083
  throw new AggregateError(
24720
25084
  [openError, cleanupFailure],
@@ -24901,9 +25265,9 @@ var init_reviewer_child_executor = __esm({
24901
25265
 
24902
25266
  // src/reviewer-workspace.ts
24903
25267
  import { spawn as spawn4 } from "node:child_process";
24904
- import { mkdtemp as mkdtemp3, rm as rm3 } from "node:fs/promises";
25268
+ import { mkdtemp as mkdtemp3, rm as rm4 } from "node:fs/promises";
24905
25269
  import { tmpdir as tmpdir3 } from "node:os";
24906
- import { join as join33 } from "node:path";
25270
+ import { join as join36 } from "node:path";
24907
25271
  async function runCommand(command, args, options = {}) {
24908
25272
  return await new Promise((resolve20, reject) => {
24909
25273
  const child = spawn4(command, args, { ...options.cwd === void 0 ? {} : { cwd: options.cwd }, stdio: ["ignore", "pipe", "pipe"], signal: options.signal });
@@ -24952,8 +25316,8 @@ async function prepareSnapshot(accepted, signal, dependencies) {
24952
25316
  if (!sameReviewerPinnedTarget({ repositoryRoot: accepted.repositoryRoot, objectFormat, targetHead }, accepted)) throw new Error("Accepted Reviewer target identity no longer matches the repository");
24953
25317
  await git3(accepted.repositoryRoot, ["cat-file", "-e", `${targetHead}^{commit}`], signal);
24954
25318
  dependencies.fault?.("mirror.before-create");
24955
- mirrorRoot = await mkdtemp3(join33(tmpdir3(), "ak-reviewer-snapshot-"));
24956
- const mirrorPath = join33(mirrorRoot, "repository.git");
25319
+ mirrorRoot = await mkdtemp3(join36(tmpdir3(), "ak-reviewer-snapshot-"));
25320
+ const mirrorPath = join36(mirrorRoot, "repository.git");
24957
25321
  dependencies.fault?.("mirror.create");
24958
25322
  await runCommand("git", ["init", "--bare", `--object-format=${accepted.objectFormat}`, mirrorPath], signal === void 0 ? {} : { signal });
24959
25323
  await git3(mirrorPath, ["fetch", "--no-tags", accepted.repositoryRoot, targetHead], signal);
@@ -24970,7 +25334,7 @@ async function prepareClone(snapshot, signal, dependencies) {
24970
25334
  const target = { repositoryRoot: snapshot.repositoryRoot, objectFormat: snapshot.objectFormat, targetHead: snapshot.targetHead, refs: { ...snapshot.refs } };
24971
25335
  try {
24972
25336
  dependencies.fault?.("workspace.before-create");
24973
- workspace = await mkdtemp3(join33(tmpdir3(), "ak-reviewer-leg-"));
25337
+ workspace = await mkdtemp3(join36(tmpdir3(), "ak-reviewer-leg-"));
24974
25338
  dependencies.fault?.("workspace.init");
24975
25339
  await git3(workspace, ["init", `--object-format=${snapshot.objectFormat}`, "--initial-branch=ak-reviewer-unborn"], signal);
24976
25340
  dependencies.fault?.("workspace.fetch");
@@ -25004,12 +25368,12 @@ function createReviewerWorkspaceOwner(dependencies = {}) {
25004
25368
  return Object.freeze({ target: frozenTarget, workspaces: Object.freeze(workspaces) });
25005
25369
  },
25006
25370
  async dispose(workspace) {
25007
- await rm3(workspace.path, { recursive: true, force: false });
25371
+ await rm4(workspace.path, { recursive: true, force: false });
25008
25372
  return "deleted";
25009
25373
  },
25010
25374
  async shutdown() {
25011
25375
  if (ownedSnapshot === void 0) return;
25012
- cleanupPromise ??= rm3(ownedSnapshot.mirrorRoot, { recursive: true, force: false });
25376
+ cleanupPromise ??= rm4(ownedSnapshot.mirrorRoot, { recursive: true, force: false });
25013
25377
  await cleanupPromise;
25014
25378
  }
25015
25379
  };
@@ -25171,7 +25535,7 @@ var init_reviewer_agent = __esm({
25171
25535
  });
25172
25536
 
25173
25537
  // src/acp-host/production-host.ts
25174
- import { readFile as readFile20 } from "node:fs/promises";
25538
+ import { readFile as readFile21 } from "node:fs/promises";
25175
25539
  import { fileURLToPath as fileURLToPath3 } from "node:url";
25176
25540
 
25177
25541
  // src/canonical-skill-binding.ts
@@ -25385,9 +25749,9 @@ init_auditor_soul();
25385
25749
  init_session_opening_materials();
25386
25750
 
25387
25751
  // src/acp-host/description.ts
25388
- import { join as join34 } from "node:path";
25752
+ import { join as join37 } from "node:path";
25389
25753
  function resolveAcpBinary(description, operatorHome) {
25390
- return join34(operatorHome, ...description.binaryFromHome);
25754
+ return join37(operatorHome, ...description.binaryFromHome);
25391
25755
  }
25392
25756
  function acpStdioArgs(description, model, seat) {
25393
25757
  const { prefix, suffix, modelFlag, thinkingFlag } = description.argv;
@@ -25410,10 +25774,10 @@ init_gatekeeper_pass_envelope();
25410
25774
  init_packaged_role_registry();
25411
25775
  init_method_skill();
25412
25776
  init_role_runtime();
25413
- import { randomUUID as randomUUID6 } from "node:crypto";
25414
- import { mkdir as mkdir5, readFile as readFile18, writeFile as writeFile8 } from "node:fs/promises";
25777
+ import { randomUUID as randomUUID7 } from "node:crypto";
25778
+ import { mkdir as mkdir5, readFile as readFile19, writeFile as writeFile9 } from "node:fs/promises";
25415
25779
  import { createServer } from "node:net";
25416
- import { basename as basename7, dirname as dirname17, join as join35 } from "node:path";
25780
+ import { basename as basename7, dirname as dirname18, join as join38 } from "node:path";
25417
25781
  import { fileURLToPath as fileURLToPath2 } from "node:url";
25418
25782
 
25419
25783
  // src/acp-host/role-turn-host.ts
@@ -25712,7 +26076,7 @@ function buildAcpSkillExpansion(methodSkills, prompt) {
25712
26076
  return Object.freeze({
25713
26077
  name: parsed.name,
25714
26078
  location: method.path,
25715
- content: `References are relative to ${dirname17(method.path)}.
26079
+ content: `References are relative to ${dirname18(method.path)}.
25716
26080
 
25717
26081
  ${method.body}`,
25718
26082
  userMessage: parsed.userMessage
@@ -25764,12 +26128,27 @@ function createComposedAcpRoleTurnHost(config) {
25764
26128
  dependencies: config.roleRuntimeDependencies,
25765
26129
  // Same durable-principal path settlement uses for isAvailable (#617 DK-4 layout).
25766
26130
  sessionFile: config.sessionIdentity.resolveSessionFile(request.principal),
25767
- socketPath: config.socketPath?.(request) ?? `/tmp/ak-acp-mcp-${randomUUID6()}.sock`
26131
+ socketPath: config.socketPath?.(request) ?? `/tmp/ak-acp-mcp-${randomUUID7()}.sock`
25768
26132
  })
25769
26133
  });
25770
26134
  }
26135
+ function terminatingToolJsonSchema(parameters) {
26136
+ const cloned = JSON.parse(JSON.stringify(parameters));
26137
+ return Object.freeze({
26138
+ ...cloned,
26139
+ $schema: "http://json-schema.org/draft-07/schema#"
26140
+ });
26141
+ }
25771
26142
  async function prepareAcpRoleEnvelope(options) {
25772
26143
  const { request } = options;
26144
+ if (options.socketPath === "") {
26145
+ throw new Error("prepareAcpRoleEnvelope requires socketPath");
26146
+ }
26147
+ const listTerminatingToolOnMcp = options.listTerminatingToolOnMcp !== false;
26148
+ const earlyTerminatingTool = packagedRoleOutputTool(request.activation.role);
26149
+ if (earlyTerminatingTool === void 0) {
26150
+ throw new Error(`role has no terminating tool: ${request.activation.role}`);
26151
+ }
25773
26152
  const flags = projectAcpActivationFlags(request);
25774
26153
  const tools = /* @__PURE__ */ new Map();
25775
26154
  const handlers = /* @__PURE__ */ new Map();
@@ -25781,19 +26160,19 @@ async function prepareAcpRoleEnvelope(options) {
25781
26160
  let rejection;
25782
26161
  let infrastructureRoundFailure;
25783
26162
  const hostAbort = new AbortController();
25784
- const runId = request.runDirectory.split("/").filter(Boolean).at(-1) ?? randomUUID6();
26163
+ const runId = request.runDirectory.split("/").filter(Boolean).at(-1) ?? randomUUID7();
25785
26164
  await mkdir5(request.runDirectory, { recursive: true });
25786
26165
  for (const method of request.methods) {
25787
26166
  if (method.kind !== "skill") continue;
25788
- const name = basename7(dirname17(method.path));
25789
- const raw = await readFile18(method.path, "utf8");
26167
+ const name = basename7(dirname18(method.path));
26168
+ const raw = await readFile19(method.path, "utf8");
25790
26169
  methodSkills.set(name, { path: method.path, body: stripSkillFrontmatter(raw).trim() });
25791
26170
  }
25792
- let sessionFile = options.sessionFile ?? join35(request.runDirectory, "session", "session.jsonl");
25793
- await mkdir5(dirname17(sessionFile), { recursive: true });
26171
+ let sessionFile = options.sessionFile ?? join38(request.runDirectory, "session", "session.jsonl");
26172
+ await mkdir5(dirname18(sessionFile), { recursive: true });
25794
26173
  if (request.continuation.kind !== "resume") {
25795
26174
  try {
25796
- await writeFile8(
26175
+ await writeFile9(
25797
26176
  sessionFile,
25798
26177
  `${JSON.stringify({
25799
26178
  type: "session",
@@ -25817,7 +26196,7 @@ async function prepareAcpRoleEnvelope(options) {
25817
26196
  getLeafEntry: () => sessionEntries.at(-1),
25818
26197
  getLeafId: () => runId,
25819
26198
  getEntries: () => sessionEntries,
25820
- getSessionDir: () => dirname17(sessionFile),
26199
+ getSessionDir: () => dirname18(sessionFile),
25821
26200
  getSessionFile: () => sessionFile,
25822
26201
  getHeader: () => ({ type: "session", id: runId }),
25823
26202
  setSessionFile(path) {
@@ -25918,7 +26297,7 @@ async function prepareAcpRoleEnvelope(options) {
25918
26297
  }
25919
26298
  };
25920
26299
  createRoleRuntimeExtension(options.dependencies)(envelope);
25921
- const token = randomUUID6();
26300
+ const token = randomUUID7();
25922
26301
  const server = createServer((socket) => serveSocket(socket));
25923
26302
  function rememberProjectedRejection(details, toolCallId) {
25924
26303
  if (typeof details !== "object" || details === null) return;
@@ -25992,6 +26371,68 @@ async function prepareAcpRoleEnvelope(options) {
25992
26371
  await emit("tool_execution_end", { toolCallId, toolName, isError: projected.isError });
25993
26372
  return projected;
25994
26373
  }
26374
+ async function invokeAkTool(name, args) {
26375
+ const tool = tools.get(name);
26376
+ if (tool === void 0) throw new Error(`Unknown AK tool: ${name}`);
26377
+ const toolCallId = randomUUID7();
26378
+ calls.push({ toolCallId, toolName: name });
26379
+ sessionEntries.push({
26380
+ type: "message",
26381
+ message: {
26382
+ role: "assistant",
26383
+ content: [{
26384
+ type: "toolCall",
26385
+ id: toolCallId,
26386
+ name,
26387
+ arguments: args ?? {}
26388
+ }]
26389
+ }
26390
+ });
26391
+ try {
26392
+ await emit("tool_execution_start", { toolCallId, toolName: name });
26393
+ const blocked = (await emit("tool_call", { toolCallId, toolName: name, input: args ?? {} })).some((value) => typeof value === "object" && value !== null && "block" in value && value.block === true);
26394
+ if (blocked) {
26395
+ return { content: [{ type: "text", text: `AK tool blocked: ${name}` }], isError: true, blocked: true };
26396
+ }
26397
+ } catch (error) {
26398
+ const declared = declareRoundInfrastructureFailure(error);
26399
+ try {
26400
+ const projected = await projectToolResult(toolCallId, name, {
26401
+ content: declared.content,
26402
+ details: declared.details,
26403
+ isError: true
26404
+ });
26405
+ return { content: projected.content, isError: true };
26406
+ } catch {
26407
+ return { content: declared.content, isError: true };
26408
+ }
26409
+ }
26410
+ try {
26411
+ const result = await tool.execute(toolCallId, args ?? {}, void 0, void 0, context);
26412
+ const projected = await projectToolResult(toolCallId, name, {
26413
+ content: result.content,
26414
+ details: result.details,
26415
+ isError: false
26416
+ });
26417
+ return { content: projected.content, isError: projected.isError };
26418
+ } catch (error) {
26419
+ let content;
26420
+ let details;
26421
+ if (isCorrectableExecuteError(error)) {
26422
+ const projected2 = projectCorrectableExecuteRejection(error);
26423
+ content = [{ type: "text", text: projected2.diagnostic }];
26424
+ details = projected2.details;
26425
+ } else {
26426
+ ({ content, details } = declareRoundInfrastructureFailure(error));
26427
+ }
26428
+ const projected = await projectToolResult(toolCallId, name, {
26429
+ content,
26430
+ details,
26431
+ isError: true
26432
+ });
26433
+ return { content: projected.content, isError: projected.isError };
26434
+ }
26435
+ }
25995
26436
  function reply(socket, id, result, error) {
25996
26437
  const rpcError = error instanceof Error ? { code: "ak-relay-failure", name: error.name, message: error.message } : { code: "ak-relay-failure", name: "RelayFailure", message: String(error) };
25997
26438
  socket.write(`${JSON.stringify({ id, ...error === void 0 ? { result } : { error: rpcError } })}
@@ -26020,8 +26461,9 @@ async function prepareAcpRoleEnvelope(options) {
26020
26461
  }
26021
26462
  try {
26022
26463
  if (rpc.method === "tools/list") {
26023
- reply(socket, rpc.id, { tools: [...tools.values()].map((tool2) => {
26024
- return { name: tool2.name, description: tool2.description, inputSchema: tool2.parameters };
26464
+ const listed = [...tools.values()].filter((tool) => listTerminatingToolOnMcp || tool.name !== earlyTerminatingTool);
26465
+ reply(socket, rpc.id, { tools: listed.map((tool) => {
26466
+ return { name: tool.name, description: tool.description, inputSchema: tool.parameters };
26025
26467
  }) });
26026
26468
  return;
26027
26469
  }
@@ -26029,74 +26471,15 @@ async function prepareAcpRoleEnvelope(options) {
26029
26471
  const params = rpc.params;
26030
26472
  const name = params?.name;
26031
26473
  if (typeof name !== "string") throw new Error("MCP tool name is missing");
26032
- const tool = tools.get(name);
26033
- if (tool === void 0) throw new Error(`Unknown AK tool: ${name}`);
26034
- const toolCallId = randomUUID6();
26035
- calls.push({ toolCallId, toolName: name });
26036
- {
26037
- const message = {
26038
- role: "assistant",
26039
- content: [{
26040
- type: "toolCall",
26041
- id: toolCallId,
26042
- name,
26043
- arguments: params?.arguments ?? {}
26044
- }]
26045
- };
26046
- sessionEntries.push({ type: "message", message });
26474
+ if (!listTerminatingToolOnMcp && name === earlyTerminatingTool) {
26475
+ throw new Error(`terminating tool ${name} is schema-channel only on this host`);
26047
26476
  }
26048
- try {
26049
- await emit("tool_execution_start", { toolCallId, toolName: name });
26050
- const blocked = (await emit("tool_call", { toolCallId, toolName: name, input: params?.arguments ?? {} })).some((value) => typeof value === "object" && value !== null && "block" in value && value.block === true);
26051
- if (blocked) {
26052
- reply(socket, rpc.id, void 0, new Error(`AK tool blocked: ${name}`));
26053
- return;
26054
- }
26055
- } catch (error) {
26056
- const declared = declareRoundInfrastructureFailure(error);
26057
- try {
26058
- const projected = await projectToolResult(toolCallId, name, {
26059
- content: declared.content,
26060
- details: declared.details,
26061
- isError: true
26062
- });
26063
- reply(socket, rpc.id, {
26064
- content: projected.content,
26065
- isError: true
26066
- });
26067
- } catch {
26068
- reply(socket, rpc.id, {
26069
- content: declared.content,
26070
- isError: true
26071
- });
26072
- }
26477
+ const outcome = await invokeAkTool(name, params?.arguments ?? {});
26478
+ if (outcome.blocked === true) {
26479
+ reply(socket, rpc.id, void 0, new Error(outcome.content.map((p) => p.type === "text" ? p.text : "").join("")));
26073
26480
  return;
26074
26481
  }
26075
- try {
26076
- const result = await tool.execute(toolCallId, params?.arguments ?? {}, void 0, void 0, context);
26077
- const projected = await projectToolResult(toolCallId, name, {
26078
- content: result.content,
26079
- details: result.details,
26080
- isError: false
26081
- });
26082
- reply(socket, rpc.id, { content: projected.content, ...projected.isError ? { isError: true } : {} });
26083
- } catch (error) {
26084
- let content;
26085
- let details;
26086
- if (isCorrectableExecuteError(error)) {
26087
- const projected2 = projectCorrectableExecuteRejection(error);
26088
- content = [{ type: "text", text: projected2.diagnostic }];
26089
- details = projected2.details;
26090
- } else {
26091
- ({ content, details } = declareRoundInfrastructureFailure(error));
26092
- }
26093
- const projected = await projectToolResult(toolCallId, name, {
26094
- content,
26095
- details,
26096
- isError: true
26097
- });
26098
- reply(socket, rpc.id, { content: projected.content, ...projected.isError ? { isError: true } : {} });
26099
- }
26482
+ reply(socket, rpc.id, { content: outcome.content, ...outcome.isError ? { isError: true } : {} });
26100
26483
  } catch (error) {
26101
26484
  reply(socket, rpc.id, void 0, error);
26102
26485
  }
@@ -26104,8 +26487,8 @@ async function prepareAcpRoleEnvelope(options) {
26104
26487
  }
26105
26488
  });
26106
26489
  }
26107
- await listen(server, options.socketPath);
26108
26490
  const relay = fileURLToPath2(new URL("./mcp-relay.mjs", import.meta.url));
26491
+ await listen(server, options.socketPath);
26109
26492
  let disposed = false;
26110
26493
  let priorAkRoleRunDir;
26111
26494
  let priorAkRoleCourtAttempt;
@@ -26148,6 +26531,11 @@ async function prepareAcpRoleEnvelope(options) {
26148
26531
  });
26149
26532
  }
26150
26533
  };
26534
+ const terminatingToolName = earlyTerminatingTool;
26535
+ async function ingestStructuredOutput(params) {
26536
+ if (calls.some((call) => call.toolName === terminatingToolName)) return;
26537
+ await invokeAkTool(terminatingToolName, params ?? {});
26538
+ }
26151
26539
  const closeRound = async () => {
26152
26540
  if (calls.length > 0) {
26153
26541
  const roundCalls = [...calls];
@@ -26194,7 +26582,7 @@ async function prepareAcpRoleEnvelope(options) {
26194
26582
  message: { role: "user", content: prompt }
26195
26583
  });
26196
26584
  }
26197
- const methodPrompt = (await Promise.all(request.methods.map(({ path }) => readFile18(path, "utf8")))).join("\n\n");
26585
+ const methodPrompt = (await Promise.all(request.methods.map(({ path }) => readFile19(path, "utf8")))).join("\n\n");
26198
26586
  const promptResults = await emit("before_agent_start", {
26199
26587
  prompt,
26200
26588
  systemPrompt: methodPrompt,
@@ -26214,6 +26602,11 @@ async function prepareAcpRoleEnvelope(options) {
26214
26602
  if (request.courtAttemptId === void 0) delete process.env.AK_ROLE_COURT_ATTEMPT;
26215
26603
  else process.env.AK_ROLE_COURT_ATTEMPT = request.courtAttemptId;
26216
26604
  runDirInjected = true;
26605
+ const terminating = tools.get(terminatingToolName);
26606
+ if (terminating === void 0) {
26607
+ throw new Error(`terminating tool not registered after activation: ${terminatingToolName}`);
26608
+ }
26609
+ const jsonSchema = terminatingToolJsonSchema(terminating.parameters);
26217
26610
  return {
26218
26611
  mcpServers: [{
26219
26612
  name: `ak-${request.activation.role}`,
@@ -26228,7 +26621,10 @@ async function prepareAcpRoleEnvelope(options) {
26228
26621
  prompt,
26229
26622
  abortSignal: hostAbort.signal,
26230
26623
  closeRound,
26231
- dispose
26624
+ dispose,
26625
+ jsonSchema,
26626
+ terminatingToolName,
26627
+ ingestStructuredOutput
26232
26628
  };
26233
26629
  } catch (error) {
26234
26630
  try {
@@ -26247,12 +26643,12 @@ async function prepareAcpRoleEnvelope(options) {
26247
26643
  // src/acp-host/seat-profile-soul.ts
26248
26644
  import { constants as constants3 } from "node:fs";
26249
26645
  import { access as access4, copyFile, lstat as lstat6, mkdir as mkdir6, readlink, symlink, unlink as unlink4 } from "node:fs/promises";
26250
- import { dirname as dirname18, join as join36, relative as relative3, resolve as resolve19 } from "node:path";
26646
+ import { dirname as dirname19, join as join39, relative as relative3, resolve as resolve19 } from "node:path";
26251
26647
  function seatProfileName(spec, role) {
26252
26648
  return `${spec.namePrefix}${role}`;
26253
26649
  }
26254
26650
  function packageRoleSoulPath(packageRoot, role) {
26255
- return join36(packageRoot, "souls", `${role}.md`);
26651
+ return join39(packageRoot, "souls", `${role}.md`);
26256
26652
  }
26257
26653
  async function pathExists(path) {
26258
26654
  try {
@@ -26269,16 +26665,16 @@ async function ensureSeatProfileSoul(options) {
26269
26665
  if (!await pathExists(soulTarget)) {
26270
26666
  throw new Error(`packaged role soul missing: ${soulTarget}`);
26271
26667
  }
26272
- const profilesRoot = join36(operatorHome, ...spec.profilesRootFromHome);
26273
- const profileDir = join36(profilesRoot, profileName);
26274
- const hostRoot = dirname18(profilesRoot);
26275
- const soulPath = join36(profileDir, spec.soulFileName);
26668
+ const profilesRoot = join39(operatorHome, ...spec.profilesRootFromHome);
26669
+ const profileDir = join39(profilesRoot, profileName);
26670
+ const hostRoot = dirname19(profilesRoot);
26671
+ const soulPath = join39(profileDir, spec.soulFileName);
26276
26672
  if (!await pathExists(profileDir)) {
26277
26673
  await mkdir6(profileDir, { recursive: true });
26278
26674
  for (const name of ["auth.json", ".env", "config.yaml"]) {
26279
- const source = join36(hostRoot, name);
26675
+ const source = join39(hostRoot, name);
26280
26676
  if (!await pathExists(source)) continue;
26281
- await copyFile(source, join36(profileDir, name));
26677
+ await copyFile(source, join39(profileDir, name));
26282
26678
  }
26283
26679
  } else {
26284
26680
  await mkdir6(profileDir, { recursive: true });
@@ -26304,17 +26700,17 @@ async function ensureSeatProfileSoul(options) {
26304
26700
  }
26305
26701
 
26306
26702
  // src/acp-host/session-identity.ts
26307
- import { mkdir as mkdir7, readFile as readFile19, rename, writeFile as writeFile9 } from "node:fs/promises";
26308
- import { dirname as dirname19, join as join37 } from "node:path";
26703
+ import { mkdir as mkdir7, readFile as readFile20, rename as rename2, writeFile as writeFile10 } from "node:fs/promises";
26704
+ import { dirname as dirname20, join as join40 } from "node:path";
26309
26705
  function createAcpSessionIdentityAuthority(authority, sessionBindingFile) {
26310
- const bindingPath = (principal) => join37(authority.decode(principal).sessionDirectory, sessionBindingFile);
26706
+ const bindingPath = (principal) => join40(authority.decode(principal).sessionDirectory, sessionBindingFile);
26311
26707
  return {
26312
26708
  resolveSessionFile(principal) {
26313
26709
  return authority.decode(principal).sessionFile;
26314
26710
  },
26315
26711
  async load(principal) {
26316
26712
  try {
26317
- const value = JSON.parse(await readFile19(bindingPath(principal), "utf8"));
26713
+ const value = JSON.parse(await readFile20(bindingPath(principal), "utf8"));
26318
26714
  if (typeof value !== "object" || value === null || typeof value.sessionId !== "string") {
26319
26715
  throw new Error("durable ACP session binding is invalid");
26320
26716
  }
@@ -26326,11 +26722,11 @@ function createAcpSessionIdentityAuthority(authority, sessionBindingFile) {
26326
26722
  },
26327
26723
  async bind(principal, sessionId) {
26328
26724
  const target = bindingPath(principal);
26329
- await mkdir7(dirname19(target), { recursive: true });
26725
+ await mkdir7(dirname20(target), { recursive: true });
26330
26726
  const temporary = `${target}.${process.pid}.tmp`;
26331
- await writeFile9(temporary, `${JSON.stringify({ sessionId })}
26727
+ await writeFile10(temporary, `${JSON.stringify({ sessionId })}
26332
26728
  `, { encoding: "utf8", mode: 384 });
26333
- await rename(temporary, target);
26729
+ await rename2(temporary, target);
26334
26730
  }
26335
26731
  };
26336
26732
  }
@@ -26339,6 +26735,9 @@ function createAcpSessionIdentityAuthority(authority, sessionBindingFile) {
26339
26735
  var navigatorRoutePlaybookPath = fileURLToPath3(
26340
26736
  new URL("../../resources/navigator-route-playbook.md", import.meta.url)
26341
26737
  );
26738
+ var collectorHandbookSeedPath = fileURLToPath3(
26739
+ new URL("../../resources/collector-bot-handbook.md", import.meta.url)
26740
+ );
26342
26741
  function createAcpRoleRuntimeDependencies(packageRoot) {
26343
26742
  const doctorAuditor = createPiDoctorAuditor();
26344
26743
  const reviewerAgent = createPerDispatchReviewerAgent({ packageRoot });
@@ -26346,13 +26745,14 @@ function createAcpRoleRuntimeDependencies(packageRoot) {
26346
26745
  return {
26347
26746
  loadJudgeSoul: () => loadMainRoleSessionMaterials("judge"),
26348
26747
  loadFixerSoul: () => loadMainRoleSessionMaterials("fixer"),
26349
- loadFixPacket: (path) => readFile20(path, "utf8"),
26748
+ loadFixPacket: (path) => readFile21(path, "utf8"),
26350
26749
  loadCoderSoul: () => loadMainRoleSessionMaterials("coder"),
26351
- loadCoderTask: (path) => readFile20(path, "utf8"),
26750
+ loadCoderTask: (path) => readFile21(path, "utf8"),
26352
26751
  loadReviewerSoul: () => loadMainRoleSessionMaterials("reviewer"),
26353
26752
  createReviewerPinnedGitReader: () => createReviewerPinnedGitReader(),
26354
26753
  createReviewerIssueFetcher: () => createGhIssueSoftFetcher(),
26355
26754
  loadCollectorSoul: () => loadMainRoleSessionMaterials("collector"),
26755
+ loadCollectorHandbookSeed: () => readFile21(collectorHandbookSeedPath, "utf8"),
26356
26756
  createCollectorTransport: () => createGhCollectorGitHubTransport(),
26357
26757
  loadDoctorSoul: () => loadMainRoleSessionMaterials("doctor"),
26358
26758
  loadDoctorCase,
@@ -26366,7 +26766,7 @@ function createAcpRoleRuntimeDependencies(packageRoot) {
26366
26766
  loadDiaristSoul: () => loadMainRoleSessionMaterials("diarist"),
26367
26767
  loadNotarySourceRun: loadNotarySourceRunLocator,
26368
26768
  loadMergerSoul: () => loadMainRoleSessionMaterials("merger"),
26369
- loadMergerInput: async (path) => JSON.parse(await readFile20(path, "utf8")),
26769
+ loadMergerInput: async (path) => JSON.parse(await readFile21(path, "utf8")),
26370
26770
  createMergerGitState: (repositoryRoot) => createProductionMergerGitState(repositoryRoot),
26371
26771
  async loadCanonicalSkillBinding(name) {
26372
26772
  if (name === "tdd") {
@@ -26395,7 +26795,7 @@ function createAcpRoleRuntimeDependencies(packageRoot) {
26395
26795
  authority: options.authority,
26396
26796
  invocationId: options.invocationId,
26397
26797
  loadSoul: () => loadMainRoleSessionMaterials("navigator"),
26398
- loadRoutePlaybook: () => readFile20(navigatorRoutePlaybookPath, "utf8"),
26798
+ loadRoutePlaybook: () => readFile21(navigatorRoutePlaybookPath, "utf8"),
26399
26799
  loadRoleHelp: async (role) => formatNavigatorRoleHelp(role),
26400
26800
  createSession: navigatorSessionFactory,
26401
26801
  ...options.contextError === void 0 ? {} : { contextError: options.contextError },