@akagilnc/pi-workflow-roles 0.1.3783 → 0.1.3795

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 (37) hide show
  1. package/README.md +3 -1
  2. package/README.zh-CN.md +3 -1
  3. package/dist/acp-host/production-host.js +681 -269
  4. package/dist/atomic-write.js +23 -0
  5. package/dist/collector-evidence.js +4 -1
  6. package/dist/collector-github.js +1 -0
  7. package/dist/collector-handbook.js +142 -0
  8. package/dist/collector-identity.js +11 -0
  9. package/dist/collector-ledger.js +109 -63
  10. package/dist/collector-role.js +182 -18
  11. package/dist/collector-tool-schemas.js +40 -3
  12. package/dist/headless-host/production-host.js +682 -270
  13. package/dist/pi/role-turn-host.js +1 -0
  14. package/dist/public-cli/invocation.js +15 -0
  15. package/dist/public-cli/main.js +45 -77
  16. package/dist/public-cli/option-definitions.js +16 -2
  17. package/dist/public-cli/run-lifecycle.js +8 -0
  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/src/acp-host/production-host.ts +4 -0
  23. package/src/acp-host/role-envelope.ts +1 -0
  24. package/src/collector-evidence.ts +6 -1
  25. package/src/collector-github.ts +3 -0
  26. package/src/collector-handbook.ts +194 -0
  27. package/src/collector-identity.ts +14 -0
  28. package/src/collector-ledger.ts +132 -80
  29. package/src/collector-role.ts +198 -14
  30. package/src/collector-tool-schemas.ts +42 -3
  31. package/src/host-contracts.ts +2 -0
  32. package/src/pi/role-turn-host.ts +1 -0
  33. package/src/public-cli/collector-run.ts +2 -0
  34. package/src/public-cli/invocation.ts +21 -0
  35. package/src/public-cli/option-definitions.ts +16 -2
  36. package/src/public-cli/run-lifecycle.ts +10 -0
  37. package/src/role-runtime.ts +5 -0
@@ -348,6 +348,7 @@ function normalizePullRequest(raw) {
348
348
  number,
349
349
  state,
350
350
  headOid: head["sha"],
351
+ ...typeof raw["created_at"] === "string" ? { createdAt: raw["created_at"] } : {},
351
352
  ...typeof raw["updated_at"] === "string" ? { updatedAt: raw["updated_at"] } : {},
352
353
  url: htmlUrl,
353
354
  raw
@@ -883,10 +884,10 @@ __export(session_assistant_usage_exports, {
883
884
  });
884
885
  import { join as join2 } from "node:path";
885
886
  async function readAssistantUsageFromSessionFile(sessionFile) {
886
- const { readFile: readFile21 } = await import("node:fs/promises");
887
+ const { readFile: readFile22 } = await import("node:fs/promises");
887
888
  let text;
888
889
  try {
889
- text = await readFile21(sessionFile, "utf8");
890
+ text = await readFile22(sessionFile, "utf8");
890
891
  } catch (error) {
891
892
  if (error?.code === "ENOENT") return void 0;
892
893
  throw error;
@@ -1982,7 +1983,8 @@ function buildActivationFlagArgs(activation) {
1982
1983
  "--ak-collector-repo",
1983
1984
  activation.repo,
1984
1985
  ...activation.pr === void 0 ? [] : ["--ak-collector-pr", activation.pr],
1985
- ...activation.requestManifestPath === void 0 ? [] : ["--ak-collector-request-manifest", activation.requestManifestPath]
1986
+ ...activation.requestManifestPath === void 0 ? [] : ["--ak-collector-request-manifest", activation.requestManifestPath],
1987
+ ...activation.waitMs === void 0 ? [] : ["--ak-collector-wait-ms", activation.waitMs]
1986
1988
  ];
1987
1989
  case "doctor":
1988
1990
  return ["--ak-role", "doctor", "--ak-doctor-case", activation.casePath];
@@ -5104,6 +5106,7 @@ async function loadResumableRunRecord(home, runId, authority) {
5104
5106
  let repositoryDisplay;
5105
5107
  let requestManifestPath;
5106
5108
  let manifestDigest;
5109
+ let waitWindowMs;
5107
5110
  let issueNumber;
5108
5111
  let caseRunsPath;
5109
5112
  let caseIdentity2;
@@ -5157,6 +5160,9 @@ async function loadResumableRunRecord(home, runId, authority) {
5157
5160
  if (typeof record4.manifestDigest === "string" && record4.manifestDigest.trim() !== "") {
5158
5161
  manifestDigest = record4.manifestDigest;
5159
5162
  }
5163
+ if (typeof record4.waitWindowMs === "number" && Number.isSafeInteger(record4.waitWindowMs) && record4.waitWindowMs >= 1) {
5164
+ waitWindowMs = record4.waitWindowMs;
5165
+ }
5160
5166
  if (typeof record4.issueNumber === "number" && Number.isSafeInteger(record4.issueNumber) && record4.issueNumber >= 1) {
5161
5167
  issueNumber = record4.issueNumber;
5162
5168
  }
@@ -5272,6 +5278,7 @@ async function loadResumableRunRecord(home, runId, authority) {
5272
5278
  ...repositoryDisplay === void 0 ? {} : { repositoryDisplay },
5273
5279
  ...requestManifestPath === void 0 ? {} : { requestManifestPath },
5274
5280
  ...manifestDigest === void 0 ? {} : { manifestDigest },
5281
+ ...waitWindowMs === void 0 ? {} : { waitWindowMs },
5275
5282
  ...issueNumber === void 0 ? {} : { issueNumber },
5276
5283
  ...caseRunsPath === void 0 ? {} : { caseRunsPath },
5277
5284
  ...caseIdentity2 === void 0 ? {} : { caseIdentity: caseIdentity2 },
@@ -6085,8 +6092,22 @@ var init_option_definitions = __esm({
6085
6092
  repeatable: false,
6086
6093
  form: "option",
6087
6094
  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"
6095
+ en: "Optional request manifest JSON path ({requests:[{id,body}]}). Role may also decide request bodies from handbook/field activity without this file.",
6096
+ 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"
6097
+ }
6098
+ },
6099
+ {
6100
+ id: "wait-ms",
6101
+ owner: "collector",
6102
+ canonical: "--wait-ms",
6103
+ aliases: [],
6104
+ valueMetavar: "ms",
6105
+ required: false,
6106
+ repeatable: false,
6107
+ form: "option",
6108
+ description: {
6109
+ en: "Wait-window duration in milliseconds after the work step opens (default 600000 = 10 minutes). Does not require a code change to adjust.",
6110
+ zh: "\u5DE5\u4F5C\u6B65\u9AA4\u5F00\u542F\u540E\u7684\u7B49\u5F85\u7A97\u65F6\u957F\uFF08\u6BEB\u79D2\uFF1B\u9ED8\u8BA4 600000\uFF1D\u5341\u5206\u949F\uFF09\u3002\u6539\u914D\u7F6E\u5373\u53EF\uFF0C\u65E0\u9700\u6539\u4EE3\u7801\u3002"
6090
6111
  }
6091
6112
  }
6092
6113
  ];
@@ -7500,6 +7521,7 @@ function parseCollectorArgv(args) {
7500
7521
  let repo;
7501
7522
  let prNumber;
7502
7523
  let requestManifestPath;
7524
+ let waitWindowMs;
7503
7525
  const positional = [];
7504
7526
  const tokens = [...args];
7505
7527
  const definitions = roleOptions("collector");
@@ -7532,6 +7554,17 @@ function parseCollectorArgv(args) {
7532
7554
  requestManifestPath = requireOptionPath(taken.def.canonical, taken.value);
7533
7555
  continue;
7534
7556
  }
7557
+ if (taken.def.id === "wait-ms") {
7558
+ if (taken.value === void 0 || !/^[1-9]\d*$/.test(taken.value.trim())) {
7559
+ throw new CliUsageError("--wait-ms requires a positive safe-integer millisecond value");
7560
+ }
7561
+ const parsed = Number(taken.value.trim());
7562
+ if (!Number.isSafeInteger(parsed) || parsed < 1) {
7563
+ throw new CliUsageError("--wait-ms requires a positive safe-integer millisecond value");
7564
+ }
7565
+ waitWindowMs = parsed;
7566
+ continue;
7567
+ }
7535
7568
  throw new CliUsageError(`unknown collector option: ${taken.def.canonical}`);
7536
7569
  }
7537
7570
  const token = tokens.shift();
@@ -7547,7 +7580,8 @@ function parseCollectorArgv(args) {
7547
7580
  attachmentPaths,
7548
7581
  ...project === void 0 ? {} : { project },
7549
7582
  ...repo === void 0 ? {} : { repo },
7550
- ...requestManifestPath === void 0 ? {} : { requestManifestPath }
7583
+ ...requestManifestPath === void 0 ? {} : { requestManifestPath },
7584
+ ...waitWindowMs === void 0 ? {} : { waitWindowMs }
7551
7585
  };
7552
7586
  }
7553
7587
  function resolveGitHubRemoteRepository(projectRoot) {
@@ -7672,6 +7706,7 @@ async function admitCollectorInvocation(options) {
7672
7706
  repository: repository.canonical,
7673
7707
  repositoryDisplay: repository.display,
7674
7708
  ...requestManifestPath === void 0 ? {} : { requestManifestPath },
7709
+ ...options.waitWindowMs === void 0 ? {} : { waitWindowMs: options.waitWindowMs },
7675
7710
  manifestDigest,
7676
7711
  attachments: attachments.map((a) => ({
7677
7712
  provenancePath: a.provenancePath,
@@ -7701,6 +7736,7 @@ async function admitCollectorInvocation(options) {
7701
7736
  ...prNumber === void 0 ? {} : { prNumber },
7702
7737
  repository,
7703
7738
  ...requestManifestPath === void 0 ? {} : { requestManifestPath },
7739
+ ...options.waitWindowMs === void 0 ? {} : { waitWindowMs: options.waitWindowMs },
7704
7740
  manifestDigest
7705
7741
  };
7706
7742
  }
@@ -8518,11 +8554,11 @@ function parseAnalystCohortIssueToken(raw, flag) {
8518
8554
  `${flag} requires a comma-separated list of N or book:N`
8519
8555
  );
8520
8556
  }
8521
- const sep4 = trimmed.lastIndexOf(":");
8522
- if (sep4 > 0) {
8523
- const rhs = trimmed.slice(sep4 + 1);
8557
+ const sep5 = trimmed.lastIndexOf(":");
8558
+ if (sep5 > 0) {
8559
+ const rhs = trimmed.slice(sep5 + 1);
8524
8560
  if (ANALYST_TICKET_NUMBER_PATTERN.test(rhs)) {
8525
- const bookKey = trimmed.slice(0, sep4);
8561
+ const bookKey = trimmed.slice(0, sep5);
8526
8562
  if (bookKey.trim() === "") {
8527
8563
  throw new CliUsageError(
8528
8564
  `${flag} book:N requires a non-empty book key, got ${raw}`
@@ -11011,10 +11047,10 @@ function pairGateRounds(volumes) {
11011
11047
  return rounds.sort((a, b) => a.officerStartedAt.localeCompare(b.officerStartedAt)).map((round, index) => ({ ...round, roundIndex: index + 1 }));
11012
11048
  }
11013
11049
  async function resolveOfficerSessionFromPointerFile(pointerPath) {
11014
- const { readFile: readFile21 } = await import("node:fs/promises");
11050
+ const { readFile: readFile22 } = await import("node:fs/promises");
11015
11051
  let raw;
11016
11052
  try {
11017
- raw = JSON.parse(await readFile21(pointerPath, "utf8"));
11053
+ raw = JSON.parse(await readFile22(pointerPath, "utf8"));
11018
11054
  } catch (error) {
11019
11055
  throw new Error(
11020
11056
  `direct officer run pointer unreadable in ${pointerPath}: ${error instanceof Error ? error.message : String(error)}`,
@@ -12094,6 +12130,7 @@ function normalizePullRequestEvidence(pr, observedAt) {
12094
12130
  number: pr.number,
12095
12131
  state: pr.state,
12096
12132
  headOid: pr.headOid,
12133
+ createdAt: pr.createdAt ?? null,
12097
12134
  updatedAt: pr.updatedAt ?? null,
12098
12135
  htmlUrl: pr.url
12099
12136
  });
@@ -12107,6 +12144,7 @@ function normalizePullRequestEvidence(pr, observedAt) {
12107
12144
  state: pr.state,
12108
12145
  commitOid: pr.headOid,
12109
12146
  htmlUrl: pr.url,
12147
+ // Version clock stays updatedAt. Create success for the wait window is snapshot.prCreatedAt only (#678).
12110
12148
  authoritativeTime: pr.updatedAt ?? null,
12111
12149
  firstObservedAt: observedAt,
12112
12150
  raw: pr.raw
@@ -12304,11 +12342,11 @@ function assignWindowRelations(records2, activationTime, deadlineTime) {
12304
12342
  }
12305
12343
  }
12306
12344
  }
12307
- var COLLECTOR_ELIGIBILITY_MS;
12345
+ var COLLECTOR_DEFAULT_WAIT_WINDOW_MS;
12308
12346
  var init_collector_evidence = __esm({
12309
12347
  "src/collector-evidence.ts"() {
12310
12348
  "use strict";
12311
- COLLECTOR_ELIGIBILITY_MS = 15 * 60 * 1e3;
12349
+ COLLECTOR_DEFAULT_WAIT_WINDOW_MS = 10 * 60 * 1e3;
12312
12350
  }
12313
12351
  });
12314
12352
 
@@ -12473,7 +12511,7 @@ function extractCollectorUnfinishedReasons(candidate) {
12473
12511
  unprojected
12474
12512
  };
12475
12513
  }
12476
- var CollectorUnknownEvidenceError, CollectorFindingsValidationError, CollectorNonOpenRequestError, COLLECTOR_OUTPUT_CANONICAL_KEYS;
12514
+ var CollectorUnknownEvidenceError, CollectorFindingsValidationError, CollectorNonOpenRequestError, CollectorWaitWindowClosedError, COLLECTOR_OUTPUT_CANONICAL_KEYS;
12477
12515
  var init_collector_identity = __esm({
12478
12516
  "src/collector-identity.ts"() {
12479
12517
  "use strict";
@@ -12496,6 +12534,14 @@ var init_collector_identity = __esm({
12496
12534
  this.name = "CollectorNonOpenRequestError";
12497
12535
  }
12498
12536
  };
12537
+ CollectorWaitWindowClosedError = class extends CorrectableSubmissionError {
12538
+ constructor(action) {
12539
+ super(
12540
+ action === "request" ? "\u901A\u8FDB\u53F8\u8BF7\u6C42\u4E0D\u5728\u8D44\u683C\u622A\u6B62\u524D" : action === "wait-before-open" ? "\u901A\u8FDB\u53F8\u7B49\u5F85\u9700\u8981\u5148\u5728\u5DE5\u4F5C\u6B65\u9AA4\u5F00\u542F\u7B49\u5F85\u7A97\uFF08\u65B0\u5EFA PR \u7528\u521B\u5EFA\u6210\u529F\u65F6\u523B\uFF1B\u5DF2\u6709 PR \u5728\u89E6\u53D1\u9636\u6BB5\u7ED3\u675F\u540E\u5F00\u542F\uFF09" : "\u901A\u8FDB\u53F8\u7B49\u5F85\u4E0D\u5728\u8D44\u683C\u622A\u6B62\u524D"
12541
+ );
12542
+ this.name = "CollectorWaitWindowClosedError";
12543
+ }
12544
+ };
12499
12545
  COLLECTOR_OUTPUT_CANONICAL_KEYS = /* @__PURE__ */ new Set([
12500
12546
  "findings",
12501
12547
  "unfinishedReasons",
@@ -12504,76 +12550,7 @@ var init_collector_identity = __esm({
12504
12550
  }
12505
12551
  });
12506
12552
 
12507
- // src/collector-tool-schemas.ts
12508
- import { Type as Type13 } from "typebox";
12509
- var collectorObserveArgsSchema, collectorRequestArgsSchema, collectorReadArgsSchema, collectorWaitArgsSchema, collectorBindTargetArgsSchema, collectorFindingItemDeclaration, collectorOutputBaseSchema, collectorOutputArgsSchema;
12510
- var init_collector_tool_schemas = __esm({
12511
- "src/collector-tool-schemas.ts"() {
12512
- "use strict";
12513
- init_collector_evidence();
12514
- init_open_tool_schema();
12515
- init_terminating_infrastructure();
12516
- collectorObserveArgsSchema = Type13.Object({}, { additionalProperties: false });
12517
- collectorRequestArgsSchema = Type13.Object({
12518
- requestId: Type13.String({ minLength: 1, description: "\u914D\u7F6E\u8BF7\u6C42\u8EAB\u4EFD" }),
12519
- snapshotId: Type13.String({ minLength: 1, description: "\u6700\u65B0\u7559\u5B58\u89C2\u5BDF\u5FEB\u7167" })
12520
- }, { additionalProperties: false });
12521
- collectorReadArgsSchema = Type13.Object({
12522
- evidenceId: Type13.String({ minLength: 1, description: "observe \u8FD4\u56DE\u7684\u6750\u6599\u8BC1\u636E id\uFF08evidenceId\uFF09" })
12523
- }, { additionalProperties: false });
12524
- collectorWaitArgsSchema = Type13.Object({
12525
- 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" })
12526
- }, { additionalProperties: false });
12527
- collectorBindTargetArgsSchema = Type13.Object({
12528
- prNumber: Type13.Optional(Type13.Unknown({
12529
- 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"
12530
- })),
12531
- issueNumber: Type13.Optional(Type13.Unknown({
12532
- 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"
12533
- }))
12534
- }, { additionalProperties: true });
12535
- collectorFindingItemDeclaration = (() => {
12536
- const item = Type13.Object(
12537
- {
12538
- evidenceId: Type13.Unknown({
12539
- description: "observe \u8FD4\u56DE\u7684\u6750\u6599\u6307\u9488\uFF08\u5FC5\u586B\u8BED\u4E49\uFF09"
12540
- }),
12541
- category: Type13.Unknown({
12542
- description: "\u7B80\u77ED\u5F52\u7C7B\u6807\u7B7E\uFF0C\u4E0D\u662F\u6458\u8981"
12543
- }),
12544
- summary: Type13.Unknown({
12545
- description: "\u54EA\u4E2A bot\u3001\u4EC0\u4E48\u95EE\u9898\u7684\u6458\u8981\uFF1B\u4E0D\u8A8A\u6284\u6B63\u6587"
12546
- })
12547
- },
12548
- {
12549
- additionalProperties: true,
12550
- description: "\u5355\u6761 finding \u6307\u9488\uFF1AevidenceId + \u53EF\u9009 category/summary\u3002\u5F62\u72B6\u6307\u5F15\uFF0C\u975E schema \u95F8\u3002"
12551
- }
12552
- );
12553
- item.required = [];
12554
- return item;
12555
- })();
12556
- collectorOutputBaseSchema = openToolObject(
12557
- Type13.Object({
12558
- // No root type:array — host must not shape-reject non-array findings (#676 C).
12559
- // Nested item declarations ride `items` for registration preservation (ADR 0057).
12560
- findings: Type13.Unsafe({
12561
- 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",
12562
- items: collectorFindingItemDeclaration
12563
- }),
12564
- unfinishedReasons: Type13.Unknown({
12565
- 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"
12566
- })
12567
- })
12568
- );
12569
- collectorOutputArgsSchema = withInfrastructureFailureDeclaration(
12570
- collectorOutputBaseSchema
12571
- );
12572
- }
12573
- });
12574
-
12575
12553
  // src/collector-ledger.ts
12576
- import Value2 from "typebox/value";
12577
12554
  function utf8SafePrefix(text, maxBytes) {
12578
12555
  if (Buffer.byteLength(text, "utf8") <= maxBytes) return text;
12579
12556
  const bytes = Buffer.from(text, "utf8");
@@ -12590,13 +12567,27 @@ function projectObserveContextView(modelView) {
12590
12567
  function isOperationalTool(name) {
12591
12568
  return COLLECTOR_OPERATIONAL_TOOLS.includes(name);
12592
12569
  }
12593
- function createCollectorLedger(config, options) {
12570
+ function resolveWaitWindowMs(raw) {
12571
+ if (raw === void 0) return COLLECTOR_DEFAULT_WAIT_WINDOW_MS;
12572
+ if (!Number.isSafeInteger(raw) || raw < 1) {
12573
+ throw new Error("\u901A\u8FDB\u53F8 waitWindowMs \u987B\u4E3A\u6B63\u5B89\u5168\u6574\u6570\u6BEB\u79D2");
12574
+ }
12575
+ return raw;
12576
+ }
12577
+ function createCollectorLedger(input, options) {
12578
+ const config = {
12579
+ repository: input.repository,
12580
+ prNumber: input.prNumber,
12581
+ manifest: input.manifest,
12582
+ waitWindowMs: resolveWaitWindowMs(input.waitWindowMs)
12583
+ };
12594
12584
  const clock = options?.clock;
12595
12585
  const journal = options?.journal;
12596
12586
  let fatal2 = false;
12597
12587
  let fatalReason;
12598
12588
  let outputCandidate = false;
12599
12589
  let pendingOutputCallId;
12590
+ let sessionReady = false;
12600
12591
  let activationTime;
12601
12592
  let deadlineTime;
12602
12593
  let activationMono;
@@ -12640,15 +12631,13 @@ function createCollectorLedger(config, options) {
12640
12631
  return monoNowOrThrow(clock2) >= deadlineMono;
12641
12632
  };
12642
12633
  const remainingMs = (clock2) => {
12643
- if (deadlineMono === void 0) return COLLECTOR_ELIGIBILITY_MS;
12634
+ if (deadlineMono === void 0) return config.waitWindowMs;
12644
12635
  return Math.max(0, deadlineMono - monoNowOrThrow(clock2));
12645
12636
  };
12646
12637
  const prIdentity = (pr) => `${pr.state}|${pr.headOid}|${pr.updatedAt ?? ""}`;
12647
12638
  const requireBoundPr = () => {
12648
12639
  if (config.prNumber === void 0) {
12649
- throw new Error(
12650
- "Collector PR target is unbound; call ak_collector_bind_target with the role-decided issue/PR or pass --pr"
12651
- );
12640
+ throw new Error("\u901A\u8FDB\u53F8 PR \u76EE\u6807\u672A\u7ED1\u5B9A");
12652
12641
  }
12653
12642
  return config.prNumber;
12654
12643
  };
@@ -12711,6 +12700,7 @@ function createCollectorLedger(config, options) {
12711
12700
  };
12712
12701
  const commitActivationWindow = (nextActivation, nextDeadline) => {
12713
12702
  if (activationTime !== void 0) return;
12703
+ sessionReady = true;
12714
12704
  activationTime = nextActivation;
12715
12705
  deadlineTime = nextDeadline;
12716
12706
  bindDeadlineMonoFromWall();
@@ -12818,6 +12808,8 @@ function createCollectorLedger(config, options) {
12818
12808
  if (entry.customType === COLLECTOR_ACTIVATION_ENTRY_TYPE) {
12819
12809
  if (typeof data.activationTime === "string" && typeof data.deadlineTime === "string") {
12820
12810
  commitActivationWindow(new Date(data.activationTime), new Date(data.deadlineTime));
12811
+ } else if (data.sessionReady === true) {
12812
+ sessionReady = true;
12821
12813
  }
12822
12814
  continue;
12823
12815
  }
@@ -12871,7 +12863,7 @@ function createCollectorLedger(config, options) {
12871
12863
  return outputCandidate || pendingOutputCallId !== void 0;
12872
12864
  },
12873
12865
  get activationRecorded() {
12874
- return activationTime !== void 0;
12866
+ return sessionReady;
12875
12867
  },
12876
12868
  get activationTime() {
12877
12869
  return activationTime;
@@ -12908,16 +12900,35 @@ function createCollectorLedger(config, options) {
12908
12900
  },
12909
12901
  latchFatal,
12910
12902
  assertNotFatal,
12911
- recordActivation(clock2) {
12903
+ recordActivation(_clock) {
12912
12904
  assertNotFatal();
12905
+ if (sessionReady) return;
12906
+ sessionReady = true;
12907
+ appendJournal(COLLECTOR_ACTIVATION_ENTRY_TYPE, {
12908
+ sessionReady: true
12909
+ });
12910
+ },
12911
+ openWaitWindow(clock2, options2) {
12912
+ assertNotFatal();
12913
+ if (!sessionReady) {
12914
+ throw latchFatal("\u901A\u8FDB\u53F8\u5F00\u542F\u7B49\u5F85\u7A97\u9700\u8981\u5148\u6FC0\u6D3B\u4F1A\u8BDD");
12915
+ }
12913
12916
  if (activationTime !== void 0) return;
12914
- activationTime = clock2.wallNow();
12915
- activationMono = clock2.monoNow();
12916
- deadlineTime = new Date(activationTime.getTime() + COLLECTOR_ELIGIBILITY_MS);
12917
- deadlineMono = activationMono + COLLECTOR_ELIGIBILITY_MS;
12917
+ const startedAt = options2?.startedAt ?? clock2.wallNow();
12918
+ if (!(startedAt instanceof Date) || Number.isNaN(startedAt.getTime())) {
12919
+ throw new Error("\u901A\u8FDB\u53F8\u7B49\u5F85\u7A97 startedAt \u987B\u4E3A\u6709\u6548\u65F6\u95F4");
12920
+ }
12921
+ const nextDeadline = new Date(startedAt.getTime() + config.waitWindowMs);
12922
+ activationTime = startedAt;
12923
+ deadlineTime = nextDeadline;
12924
+ const wallNow = clock2.wallNow().getTime();
12925
+ const monoNow = clock2.monoNow();
12926
+ activationMono = monoNow - (wallNow - startedAt.getTime());
12927
+ deadlineMono = monoNow + (nextDeadline.getTime() - wallNow);
12918
12928
  appendJournal(COLLECTOR_ACTIVATION_ENTRY_TYPE, {
12919
12929
  activationTime: activationTime.toISOString(),
12920
- deadlineTime: deadlineTime.toISOString()
12930
+ deadlineTime: deadlineTime.toISOString(),
12931
+ waitWindowMs: config.waitWindowMs
12921
12932
  });
12922
12933
  },
12923
12934
  recordOutputCandidate() {
@@ -12930,11 +12941,11 @@ function createCollectorLedger(config, options) {
12930
12941
  throw new Error("\u901A\u8FDB\u53F8\u5DF2\u4EA7\u51FA\u8F93\u51FA\u5019\u9009\uFF0C\u672C\u5C40\u4E0D\u518D\u53D7\u7406\u76EE\u6807\u7ED1\u5B9A");
12931
12942
  }
12932
12943
  if (!Number.isSafeInteger(prNumber) || prNumber < 1) {
12933
- throw new Error("Collector bind target requires a positive safe-integer PR number");
12944
+ throw new Error("\u901A\u8FDB\u53F8\u7ED1\u5B9A\u76EE\u6807\u8981\u6C42\u6B63\u5B89\u5168\u6574\u6570 PR \u53F7");
12934
12945
  }
12935
12946
  if (config.prNumber !== void 0 && config.prNumber !== prNumber) {
12936
12947
  throw new Error(
12937
- `Collector target already bound to PR ${config.prNumber}; cannot rebind to ${prNumber}`
12948
+ `\u901A\u8FDB\u53F8\u76EE\u6807\u5DF2\u7ED1\u5B9A PR ${config.prNumber}\uFF0C\u4E0D\u53EF\u6539\u7ED1\u4E3A ${prNumber}`
12938
12949
  );
12939
12950
  }
12940
12951
  config.prNumber = prNumber;
@@ -13005,7 +13016,7 @@ function createCollectorLedger(config, options) {
13005
13016
  },
13006
13017
  async observe(transport, clock2, signal) {
13007
13018
  assertNotFatal();
13008
- if (activationTime === void 0) {
13019
+ if (!sessionReady) {
13009
13020
  throw latchFatal("\u901A\u8FDB\u53F8\u89C2\u5BDF\u9700\u8981\u6FC0\u6D3B");
13010
13021
  }
13011
13022
  if (signal?.aborted) {
@@ -13092,6 +13103,7 @@ function createCollectorLedger(config, options) {
13092
13103
  prNumber: requireBoundPr(),
13093
13104
  prState: pr.state,
13094
13105
  headOid: pr.headOid,
13106
+ ...pr.createdAt === void 0 ? {} : { prCreatedAt: pr.createdAt },
13095
13107
  complete: true,
13096
13108
  evidenceIds: storedIds,
13097
13109
  pageDiagnostics,
@@ -13123,21 +13135,33 @@ function createCollectorLedger(config, options) {
13123
13135
  contextView: projectObserveContextView(modelView)
13124
13136
  };
13125
13137
  },
13126
- async request(input, transport, clock2, signal) {
13138
+ async request(input2, transport, clock2, signal) {
13127
13139
  assertNotFatal();
13128
- if (activationTime === void 0 || deadlineTime === void 0) {
13140
+ if (!sessionReady) {
13129
13141
  throw latchFatal("\u901A\u8FDB\u53F8\u8BF7\u6C42\u9700\u8981\u6FC0\u6D3B");
13130
13142
  }
13131
13143
  if (ledger.unresolvedTransportFailure) {
13132
13144
  throw latchFatal("\u901A\u8FDB\u53F8\u8BF7\u6C42\u65F6\u5B58\u5728\u672A\u6062\u590D\u7684\u4F20\u8F93\u5931\u8D25");
13133
13145
  }
13134
- const request = config.manifest.requests.find((item) => item.id === input.requestId);
13135
- if (request === void 0) {
13136
- throw new Error(`\u672A\u77E5\u901A\u8FDB\u53F8 requestId "${input.requestId}"`);
13146
+ if (typeof input2.requestId !== "string") {
13147
+ throw new Error("\u901A\u8FDB\u53F8 requestId \u987B\u4E3A\u5B57\u7B26\u4E32");
13148
+ }
13149
+ const requestId = input2.requestId.trim();
13150
+ if (requestId.length === 0) {
13151
+ throw new Error("\u901A\u8FDB\u53F8 requestId \u987B\u4E3A\u975E\u7A7A\uFF08\u9996\u5C3E\u7A7A\u767D\u4E0D\u6784\u6210\u8EAB\u4EFD\uFF09");
13137
13152
  }
13138
- const snapshot = snapshots.find((item) => item.snapshotId === input.snapshotId);
13153
+ const configured = config.manifest.requests.find((item) => item.id === requestId);
13154
+ const roleBody = typeof input2.body === "string" ? input2.body : void 0;
13155
+ if (configured === void 0) {
13156
+ if (roleBody === void 0 || roleBody.trim().length === 0) {
13157
+ throw new Error(
13158
+ `\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`
13159
+ );
13160
+ }
13161
+ }
13162
+ const snapshot = snapshots.find((item) => item.snapshotId === input2.snapshotId);
13139
13163
  if (snapshot === void 0) {
13140
- throw new Error(`\u672A\u77E5\u901A\u8FDB\u53F8 snapshotId "${input.snapshotId}"`);
13164
+ throw new Error(`\u672A\u77E5\u901A\u8FDB\u53F8 snapshotId "${input2.snapshotId}"`);
13141
13165
  }
13142
13166
  if (snapshot.snapshotId !== latestCompleteSnapshotId) {
13143
13167
  throw new Error("\u901A\u8FDB\u53F8\u8BF7\u6C42\u8981\u6C42\u6700\u65B0\u5B8C\u6574\u5FEB\u7167");
@@ -13147,12 +13171,13 @@ function createCollectorLedger(config, options) {
13147
13171
  }
13148
13172
  if (pastCutoff(clock2)) {
13149
13173
  finalObservationRequired = true;
13150
- throw latchFatal("\u901A\u8FDB\u53F8\u8BF7\u6C42\u4E0D\u5728\u8D44\u683C\u622A\u6B62\u524D");
13174
+ throw new CollectorWaitWindowClosedError("request");
13151
13175
  }
13176
+ const configuredBody = configured?.requestBody ?? roleBody;
13152
13177
  const { body, marker } = buildCollectorRequestBody({
13153
- configuredBody: request.requestBody,
13178
+ configuredBody,
13154
13179
  manifestDigest: config.manifest.digest,
13155
- requestId: request.id,
13180
+ requestId,
13156
13181
  headOid: snapshot.headOid
13157
13182
  });
13158
13183
  const existingMarker = snapshot.evidenceIds.some((id) => {
@@ -13161,7 +13186,7 @@ function createCollectorLedger(config, options) {
13161
13186
  });
13162
13187
  if (existingMarker) {
13163
13188
  throw new Error(
13164
- `\u901A\u8FDB\u53F8\u5728\u6B64 HEAD \u5DF2\u6709\u540C marker \u7684\u5DF2\u8BA4\u8BC1\u8BF7\u6C42 "${input.requestId}"`
13189
+ `\u901A\u8FDB\u53F8\u5728\u6B64 HEAD \u5DF2\u6709\u540C marker \u7684\u5DF2\u8BA4\u8BC1\u8BF7\u6C42 "${requestId}"`
13165
13190
  );
13166
13191
  }
13167
13192
  const boundPr = requireBoundPr();
@@ -13169,18 +13194,18 @@ function createCollectorLedger(config, options) {
13169
13194
  config.repository.canonical,
13170
13195
  String(boundPr),
13171
13196
  snapshot.headOid,
13172
- request.id
13197
+ requestId
13173
13198
  ].join("|");
13174
13199
  if (attemptKeys.has(attemptKey)) {
13175
13200
  throw new Error(
13176
- `\u901A\u8FDB\u53F8\u8FDB\u7A0B\u5185\u8BF7\u6C42 "${request.id}" \u5728 HEAD ${snapshot.headOid} \u7684 attempt \u5DF2\u7528`
13201
+ `\u901A\u8FDB\u53F8\u8FDB\u7A0B\u5185\u8BF7\u6C42 "${requestId}" \u5728 HEAD ${snapshot.headOid} \u7684 attempt \u5DF2\u7528`
13177
13202
  );
13178
13203
  }
13179
13204
  const startedAt = clock2.wallNow().toISOString();
13180
13205
  const attemptId = sha256Text(`${attemptKey}:${startedAt}`).slice(0, 16);
13181
13206
  const attempt = {
13182
13207
  attemptId,
13183
- requestId: request.id,
13208
+ requestId,
13184
13209
  observedHead: snapshot.headOid,
13185
13210
  snapshotId: snapshot.snapshotId,
13186
13211
  marker,
@@ -13222,7 +13247,7 @@ function createCollectorLedger(config, options) {
13222
13247
  return {
13223
13248
  status: "succeeded",
13224
13249
  attemptId,
13225
- requestId: request.id,
13250
+ requestId,
13226
13251
  observedHead: snapshot.headOid,
13227
13252
  marker,
13228
13253
  commentEvidenceId: record4.evidenceId
@@ -13236,7 +13261,7 @@ function createCollectorLedger(config, options) {
13236
13261
  return {
13237
13262
  status: "ambiguous_loss",
13238
13263
  attemptId,
13239
- requestId: request.id,
13264
+ requestId,
13240
13265
  observedHead: snapshot.headOid,
13241
13266
  marker,
13242
13267
  diagnostics: result.diagnostics
@@ -13248,30 +13273,20 @@ function createCollectorLedger(config, options) {
13248
13273
  journalRequest(void 0);
13249
13274
  throw latchFatal(`\u901A\u8FDB\u53F8\u8BF7\u6C42\u88AB\u62D2\uFF1A${result.diagnostics}`);
13250
13275
  },
13251
- async wait(input, clock2, signal) {
13276
+ async wait(input2, clock2, signal) {
13252
13277
  assertNotFatal();
13253
- if (activationTime === void 0) {
13278
+ if (!sessionReady) {
13254
13279
  throw latchFatal("\u901A\u8FDB\u53F8\u7B49\u5F85\u9700\u8981\u6FC0\u6D3B");
13255
13280
  }
13256
- if (!Number.isSafeInteger(input.durationMs) || input.durationMs < 1) {
13257
- throw new Error("\u901A\u8FDB\u53F8\u7B49\u5F85 durationMs \u987B\u4E3A\u6B63\u5B89\u5168\u6574\u6570");
13258
- }
13259
- if (input.durationMs > COLLECTOR_ELIGIBILITY_MS) {
13260
- throw new Error(
13261
- `\u901A\u8FDB\u53F8\u7B49\u5F85 durationMs \u81F3\u591A\u4E3A ${COLLECTOR_ELIGIBILITY_MS}`
13262
- );
13281
+ if (activationTime === void 0 || deadlineTime === void 0) {
13282
+ throw new CollectorWaitWindowClosedError("wait-before-open");
13263
13283
  }
13264
13284
  if (pastCutoff(clock2)) {
13265
13285
  finalObservationRequired = true;
13266
- throw latchFatal("\u901A\u8FDB\u53F8\u7B49\u5F85\u4E0D\u5728\u8D44\u683C\u622A\u6B62\u524D");
13286
+ throw new CollectorWaitWindowClosedError("wait");
13267
13287
  }
13268
13288
  const remaining = remainingMs(clock2);
13269
- const COLLECTOR_SINGLE_WAIT_MAX_MS = 3e5;
13270
- const effectiveMs = Math.min(
13271
- input.durationMs,
13272
- remaining,
13273
- COLLECTOR_SINGLE_WAIT_MAX_MS
13274
- );
13289
+ const effectiveMs = Math.min(input2.durationMs, remaining);
13275
13290
  const startedAt = clock2.wallNow().toISOString();
13276
13291
  const waitId = sha256Text(`wait:${startedAt}:${effectiveMs}`).slice(0, 16);
13277
13292
  await clock2.sleep(effectiveMs, signal);
@@ -13279,7 +13294,7 @@ function createCollectorLedger(config, options) {
13279
13294
  const cutoffReached = pastCutoff(clock2);
13280
13295
  const record4 = {
13281
13296
  waitId,
13282
- requestedMs: input.durationMs,
13297
+ requestedMs: input2.durationMs,
13283
13298
  effectiveMs,
13284
13299
  startedAt,
13285
13300
  endedAt,
@@ -13291,7 +13306,7 @@ function createCollectorLedger(config, options) {
13291
13306
  });
13292
13307
  return {
13293
13308
  waitId,
13294
- requestedMs: input.durationMs,
13309
+ requestedMs: input2.durationMs,
13295
13310
  effectiveMs,
13296
13311
  cutoffReached,
13297
13312
  remainingMsAfter: remainingMs(clock2)
@@ -13350,6 +13365,7 @@ function buildObserveModelView(input) {
13350
13365
  completedAt: input.snapshot.completedAt,
13351
13366
  prState: input.snapshot.prState,
13352
13367
  headOid: input.snapshot.headOid,
13368
+ ...input.snapshot.prCreatedAt === void 0 ? {} : { prCreatedAt: input.snapshot.prCreatedAt },
13353
13369
  complete: input.snapshot.complete,
13354
13370
  evidence: relevant.map((record4) => projectEvidenceEntryView(record4)),
13355
13371
  requestAttempts: input.attempts.map((attempt) => ({
@@ -13362,26 +13378,29 @@ function buildObserveModelView(input) {
13362
13378
  }))
13363
13379
  };
13364
13380
  }
13365
- 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;
13381
+ var COLLECTOR_OBSERVE_TOOL, COLLECTOR_READ_TOOL, COLLECTOR_REQUEST_TOOL, COLLECTOR_WAIT_TOOL, COLLECTOR_OPEN_WAIT_WINDOW_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;
13366
13382
  var init_collector_ledger = __esm({
13367
13383
  "src/collector-ledger.ts"() {
13368
13384
  "use strict";
13369
13385
  init_collector_evidence();
13370
13386
  init_collector_github();
13371
13387
  init_collector_identity();
13372
- init_collector_tool_schemas();
13373
13388
  init_collector_output();
13374
13389
  COLLECTOR_OBSERVE_TOOL = "ak_collector_observe";
13375
13390
  COLLECTOR_READ_TOOL = "ak_collector_read";
13376
13391
  COLLECTOR_REQUEST_TOOL = "ak_collector_request";
13377
13392
  COLLECTOR_WAIT_TOOL = "ak_collector_wait";
13393
+ COLLECTOR_OPEN_WAIT_WINDOW_TOOL = "ak_collector_open_wait_window";
13378
13394
  COLLECTOR_BIND_TARGET_TOOL = "ak_collector_bind_target";
13395
+ COLLECTOR_HANDBOOK_WRITE_TOOL = "ak_collector_handbook_write";
13379
13396
  COLLECTOR_OPERATIONAL_TOOLS = [
13380
13397
  COLLECTOR_BIND_TARGET_TOOL,
13381
13398
  COLLECTOR_OBSERVE_TOOL,
13382
13399
  COLLECTOR_READ_TOOL,
13383
13400
  COLLECTOR_REQUEST_TOOL,
13384
- COLLECTOR_WAIT_TOOL
13401
+ COLLECTOR_OPEN_WAIT_WINDOW_TOOL,
13402
+ COLLECTOR_WAIT_TOOL,
13403
+ COLLECTOR_HANDBOOK_WRITE_TOOL
13385
13404
  ];
13386
13405
  COLLECTOR_OBSERVE_BODY_HEAD_BYTES = 512;
13387
13406
  COLLECTOR_ACTIVATION_ENTRY_TYPE = "ak-collector-activation";
@@ -17921,11 +17940,11 @@ async function summonPublicRole(options) {
17921
17940
  };
17922
17941
  }
17923
17942
  async function parentInvocationHost(sourceRunDirectory) {
17924
- const { readFile: readFile21 } = await import("node:fs/promises");
17943
+ const { readFile: readFile22 } = await import("node:fs/promises");
17925
17944
  const path = join28(sourceRunDirectory, "invocation.json");
17926
17945
  let text;
17927
17946
  try {
17928
- text = await readFile21(path, "utf8");
17947
+ text = await readFile22(path, "utf8");
17929
17948
  } catch (error) {
17930
17949
  const code = error instanceof Error && "code" in error ? error.code : void 0;
17931
17950
  throw new Error(
@@ -18026,7 +18045,7 @@ __export(compliance_transport_exports, {
18026
18045
  runComplianceAudit: () => runComplianceAudit,
18027
18046
  tryReadComplianceCandidate: () => tryReadComplianceCandidate
18028
18047
  });
18029
- import { Type as Type14 } from "typebox";
18048
+ import { Type as Type13 } from "typebox";
18030
18049
  function readListField(value) {
18031
18050
  return Array.isArray(value) ? value : value === void 0 ? [] : [value];
18032
18051
  }
@@ -18124,9 +18143,9 @@ var init_compliance_transport = __esm({
18124
18143
  "use strict";
18125
18144
  init_auditor_dossier_tool();
18126
18145
  AUDITOR_DOSSIER_PROMPT = "\u672C run \u5377\u5B97\u5DF2\u5C31\u7EEA\u3002";
18127
- nonblank2 = Type14.String({ minLength: 1, pattern: "\\S" });
18128
- decisionGateSchema = Type14.Object({ question: nonblank2, options: Type14.Array(nonblank2, { minItems: 1 }) }, { additionalProperties: false });
18129
- 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: [] });
18146
+ nonblank2 = Type13.String({ minLength: 1, pattern: "\\S" });
18147
+ decisionGateSchema = Type13.Object({ question: nonblank2, options: Type13.Array(nonblank2, { minItems: 1 }) }, { additionalProperties: false });
18148
+ 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: [] });
18130
18149
  COMPLIANCE_RESPONSE_ENTRY_TYPE = "ak_compliance_response";
18131
18150
  AUDITOR_PARENT_ATTEMPT_BINDING_ENTRY_TYPE = "ak_auditor_parent_attempt_binding";
18132
18151
  AUDITOR_COMPLIANCE_FAILURE_ENTRY_TYPE = "ak_auditor_compliance_failure";
@@ -18220,8 +18239,8 @@ var init_doctor_auditor = __esm({
18220
18239
  });
18221
18240
 
18222
18241
  // src/navigator-session-contracts.ts
18223
- import { Type as Type15 } from "typebox";
18224
- import { Value as Value3 } from "typebox/value";
18242
+ import { Type as Type14 } from "typebox";
18243
+ import { Value as Value2 } from "typebox/value";
18225
18244
  function navigatorUnavailableKey(value) {
18226
18245
  return typeof value === "string" && NAVIGATOR_UNAVAILABLE_KEYS.has(value) ? value : void 0;
18227
18246
  }
@@ -18372,26 +18391,26 @@ var init_navigator_session_contracts = __esm({
18372
18391
  this.originalCause = originalCause;
18373
18392
  }
18374
18393
  };
18375
- navigatorProviderFailureSchema = Type15.Object({
18376
- source: Type15.Union([
18377
- Type15.Literal("context"),
18378
- Type15.Literal("session"),
18379
- Type15.Literal("model"),
18380
- Type15.Literal("thinking"),
18381
- Type15.Literal("auth"),
18382
- Type15.Literal("quota"),
18383
- Type15.Literal("transport"),
18384
- Type15.Literal("unknown")
18394
+ navigatorProviderFailureSchema = Type14.Object({
18395
+ source: Type14.Union([
18396
+ Type14.Literal("context"),
18397
+ Type14.Literal("session"),
18398
+ Type14.Literal("model"),
18399
+ Type14.Literal("thinking"),
18400
+ Type14.Literal("auth"),
18401
+ Type14.Literal("quota"),
18402
+ Type14.Literal("transport"),
18403
+ Type14.Literal("unknown")
18385
18404
  ]),
18386
- cause: Type15.Union([
18387
- Type15.Literal("context"),
18388
- Type15.Literal("session"),
18389
- Type15.Literal("model"),
18390
- Type15.Literal("thinking"),
18391
- Type15.Literal("auth"),
18392
- Type15.Literal("quota"),
18393
- Type15.Literal("transport"),
18394
- Type15.Literal("unknown")
18405
+ cause: Type14.Union([
18406
+ Type14.Literal("context"),
18407
+ Type14.Literal("session"),
18408
+ Type14.Literal("model"),
18409
+ Type14.Literal("thinking"),
18410
+ Type14.Literal("auth"),
18411
+ Type14.Literal("quota"),
18412
+ Type14.Literal("transport"),
18413
+ Type14.Literal("unknown")
18395
18414
  ])
18396
18415
  }, { additionalProperties: false });
18397
18416
  }
@@ -18743,7 +18762,7 @@ var init_navigator_public_session = __esm({
18743
18762
  import { createHash as createHash9 } from "node:crypto";
18744
18763
  import { resolve as resolve14 } from "node:path";
18745
18764
  import "@earendil-works/pi-coding-agent";
18746
- import { Type as Type16 } from "typebox";
18765
+ import { Type as Type15 } from "typebox";
18747
18766
  function resolveNavigatorAuthorityMaterial(roleInput, fileAuthority) {
18748
18767
  if (roleInput !== void 0 && roleInput.trim() !== "") return roleInput;
18749
18768
  if (fileAuthority !== void 0 && fileAuthority.trim() !== "") return fileAuthority;
@@ -19406,8 +19425,8 @@ var init_navigator_attendance = __esm({
19406
19425
  NAVIGATOR_EVENT_TYPE = "ak-navigator-attendance";
19407
19426
  NAVIGATOR_PREPARE_ACCEPTED_TEXT = "\u6E38\u5955\u4F7F\u51C6\u5907\u5DF2\u63A5\u53D7";
19408
19427
  NAVIGATOR_TARGETS = PACKAGED_ROLE_REGISTRY.map(({ role, phases }) => ({ role, phases }));
19409
- prepareSchema = Type16.Object({
19410
- candidates: Type16.Optional(Type16.Unknown({
19428
+ prepareSchema = Type15.Object({
19429
+ candidates: Type15.Optional(Type15.Unknown({
19411
19430
  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"
19412
19431
  }))
19413
19432
  }, { additionalProperties: true });
@@ -19420,7 +19439,7 @@ var init_navigator_attendance = __esm({
19420
19439
  });
19421
19440
 
19422
19441
  // src/engine-detour-tool.ts
19423
- import { Type as Type17 } from "typebox";
19442
+ import { Type as Type16 } from "typebox";
19424
19443
  function isCallerCancellation(error, signal) {
19425
19444
  if (signal?.aborted === true) return true;
19426
19445
  if (typeof error === "object" && error !== null && error.name === "AbortError") {
@@ -19495,9 +19514,9 @@ var init_engine_detour_tool = __esm({
19495
19514
  "src/engine-detour-tool.ts"() {
19496
19515
  "use strict";
19497
19516
  init_engine_detour();
19498
- engineDetourArgsSchema = Type17.Object(
19517
+ engineDetourArgsSchema = Type16.Object(
19499
19518
  {
19500
- argv: Type17.Array(Type17.String({ minLength: 1 }), {
19519
+ argv: Type16.Array(Type16.String({ minLength: 1 }), {
19501
19520
  minItems: 1,
19502
19521
  description: "\u9996\u9879\u4E3A PATH \u4E2D\u7684\u53EF\u6267\u884C\u6587\u4EF6\uFF0C\u5176\u4F59\u9879\u4E3A\u53C2\u6570\u3002"
19503
19522
  })
@@ -19824,7 +19843,7 @@ var init_oauth_keepalive = __esm({
19824
19843
  });
19825
19844
 
19826
19845
  // src/activation-trace.ts
19827
- import { Type as Type18 } from "typebox";
19846
+ import { Type as Type17 } from "typebox";
19828
19847
  function namedActivationCause(error) {
19829
19848
  const evidenceId = `activation-cause-${++activationCauseEvidence}`;
19830
19849
  retainedActivationCauses.set(evidenceId, error);
@@ -19845,17 +19864,17 @@ var causeSchema, activationTraceRecordSchema, activationCauseEvidence, retainedA
19845
19864
  var init_activation_trace = __esm({
19846
19865
  "src/activation-trace.ts"() {
19847
19866
  "use strict";
19848
- causeSchema = Type18.Object({
19849
- identity: Type18.String({ minLength: 1 }),
19850
- name: Type18.String({ minLength: 1 }),
19851
- message: Type18.String(),
19852
- evidenceId: Type18.Optional(Type18.String({ minLength: 1 }))
19867
+ causeSchema = Type17.Object({
19868
+ identity: Type17.String({ minLength: 1 }),
19869
+ name: Type17.String({ minLength: 1 }),
19870
+ message: Type17.String(),
19871
+ evidenceId: Type17.Optional(Type17.String({ minLength: 1 }))
19853
19872
  }, { additionalProperties: false });
19854
- activationTraceRecordSchema = Type18.Object({
19855
- role: Type18.String({ minLength: 1 }),
19856
- stageId: Type18.String({ pattern: "^[a-z][a-z0-9-]*$" }),
19857
- status: Type18.Literal("failed"),
19858
- timestamp: Type18.String({ format: "date-time" }),
19873
+ activationTraceRecordSchema = Type17.Object({
19874
+ role: Type17.String({ minLength: 1 }),
19875
+ stageId: Type17.String({ pattern: "^[a-z][a-z0-9-]*$" }),
19876
+ status: Type17.Literal("failed"),
19877
+ timestamp: Type17.String({ format: "date-time" }),
19859
19878
  cause: causeSchema
19860
19879
  }, { additionalProperties: false });
19861
19880
  activationCauseEvidence = 0;
@@ -20137,10 +20156,10 @@ var init_stderr_jsonl = __esm({
20137
20156
 
20138
20157
  // src/tool-execution-observation.ts
20139
20158
  import { writeSync as writeSync3 } from "node:fs";
20140
- import { Type as Type19 } from "typebox";
20141
- import { Value as Value4 } from "typebox/value";
20159
+ import { Type as Type18 } from "typebox";
20160
+ import { Value as Value3 } from "typebox/value";
20142
20161
  function validateToolExecutionObservationRecord(record4) {
20143
- if (!Value4.Check(toolExecutionObservationRecordSchema, record4)) {
20162
+ if (!Value3.Check(toolExecutionObservationRecordSchema, record4)) {
20144
20163
  throw new TypeError("Tool execution observation record does not match its contract");
20145
20164
  }
20146
20165
  return record4;
@@ -20231,29 +20250,274 @@ var init_tool_execution_observation = __esm({
20231
20250
  init_stderr_jsonl();
20232
20251
  TOOL_EXECUTION_UPDATE_THROTTLE_MS = 3e4;
20233
20252
  observationBase = {
20234
- role: Type19.String({ minLength: 1 }),
20235
- toolCallId: Type19.String({ minLength: 1 }),
20236
- toolName: Type19.String({ minLength: 1 }),
20237
- timestamp: Type19.String({ format: "date-time" })
20253
+ role: Type18.String({ minLength: 1 }),
20254
+ toolCallId: Type18.String({ minLength: 1 }),
20255
+ toolName: Type18.String({ minLength: 1 }),
20256
+ timestamp: Type18.String({ format: "date-time" })
20238
20257
  };
20239
- toolExecutionObservationRecordSchema = Type19.Union([
20240
- Type19.Object({
20258
+ toolExecutionObservationRecordSchema = Type18.Union([
20259
+ Type18.Object({
20241
20260
  ...observationBase,
20242
- event: Type19.Literal("tool_execution_start")
20261
+ event: Type18.Literal("tool_execution_start")
20243
20262
  }, { additionalProperties: true }),
20244
- Type19.Object({
20263
+ Type18.Object({
20245
20264
  ...observationBase,
20246
- event: Type19.Literal("tool_execution_update")
20265
+ event: Type18.Literal("tool_execution_update")
20247
20266
  }, { additionalProperties: true }),
20248
- Type19.Object({
20267
+ Type18.Object({
20249
20268
  ...observationBase,
20250
- event: Type19.Literal("tool_execution_end"),
20251
- isError: Type19.Boolean()
20269
+ event: Type18.Literal("tool_execution_end"),
20270
+ isError: Type18.Boolean()
20252
20271
  }, { additionalProperties: true })
20253
20272
  ]);
20254
20273
  }
20255
20274
  });
20256
20275
 
20276
+ // src/atomic-write.ts
20277
+ import { randomUUID as randomUUID6 } from "node:crypto";
20278
+ import { rename, rm as rm2, writeFile as writeFile8 } from "node:fs/promises";
20279
+ import { dirname as dirname17, join as join32 } from "node:path";
20280
+ async function writeFileAtomically(destination, contents) {
20281
+ const parent = dirname17(destination);
20282
+ const temporary = join32(parent, `.atomic-write-${randomUUID6()}.tmp`);
20283
+ try {
20284
+ await writeFile8(temporary, contents);
20285
+ await rename(temporary, destination);
20286
+ } catch (error) {
20287
+ await rm2(temporary, { force: true }).catch(() => void 0);
20288
+ throw error;
20289
+ }
20290
+ }
20291
+ var init_atomic_write = __esm({
20292
+ "src/atomic-write.ts"() {
20293
+ "use strict";
20294
+ }
20295
+ });
20296
+
20297
+ // src/collector-tool-schemas.ts
20298
+ import { Type as Type19 } from "typebox";
20299
+ var collectorObserveArgsSchema, COLLECTOR_REQUEST_ID_PATTERN, collectorRequestArgsSchema, COLLECTOR_HANDBOOK_MAX_BYTES, collectorHandbookWriteArgsSchema, collectorReadArgsSchema, collectorWaitArgsSchema, collectorOpenWaitWindowArgsSchema, collectorBindTargetArgsSchema, collectorFindingItemDeclaration, collectorOutputBaseSchema, collectorOutputArgsSchema;
20300
+ var init_collector_tool_schemas = __esm({
20301
+ "src/collector-tool-schemas.ts"() {
20302
+ "use strict";
20303
+ init_open_tool_schema();
20304
+ init_terminating_infrastructure();
20305
+ collectorObserveArgsSchema = Type19.Object({}, { additionalProperties: false });
20306
+ COLLECTOR_REQUEST_ID_PATTERN = /^\S(?:.*\S)?$/;
20307
+ collectorRequestArgsSchema = Type19.Object({
20308
+ requestId: Type19.String({
20309
+ minLength: 1,
20310
+ pattern: COLLECTOR_REQUEST_ID_PATTERN.source,
20311
+ 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"
20312
+ }),
20313
+ snapshotId: Type19.String({ minLength: 1, description: "\u6700\u65B0\u7559\u5B58\u89C2\u5BDF\u5FEB\u7167" }),
20314
+ body: Type19.Optional(Type19.String({
20315
+ minLength: 1,
20316
+ description: "\u89D2\u8272\u5224\u5B9A\u7684\u8BF7\u6C42\u6B63\u6587\uFF1Brequest-manifest \u672A\u6536\u5F55\u8BE5 requestId \u65F6\u5FC5\u586B"
20317
+ }))
20318
+ }, { additionalProperties: false });
20319
+ COLLECTOR_HANDBOOK_MAX_BYTES = 64 * 1024;
20320
+ collectorHandbookWriteArgsSchema = Type19.Object({
20321
+ scope: Type19.Union([
20322
+ Type19.Literal("general"),
20323
+ Type19.Literal("repo")
20324
+ ], { description: "general\uFF1D\u901A\u7528\u624B\u518C\uFF1Brepo\uFF1D\u5F53\u524D\u4ED3\u5E93\u5DEE\u5F02" }),
20325
+ body: Type19.String({
20326
+ 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`
20327
+ })
20328
+ }, { additionalProperties: false });
20329
+ collectorReadArgsSchema = Type19.Object({
20330
+ evidenceId: Type19.String({ minLength: 1, description: "observe \u8FD4\u56DE\u7684\u6750\u6599\u8BC1\u636E id\uFF08evidenceId\uFF09" })
20331
+ }, { additionalProperties: false });
20332
+ collectorWaitArgsSchema = Type19.Object({
20333
+ durationMs: Type19.Integer({
20334
+ minimum: 1,
20335
+ description: "\u7B49\u5F85\u6BEB\u79D2\uFF1B\u5B9E\u9645\u7761\u7720\u4E0D\u8D85\u8FC7\u5269\u4F59\u7B49\u5F85\u7A97\uFF08#678\uFF1B\u65E0\u5305\u5185\u5355\u6B21\u4EFB\u610F\u4E0A\u9650\uFF09"
20336
+ })
20337
+ }, { additionalProperties: false });
20338
+ collectorOpenWaitWindowArgsSchema = Type19.Object({
20339
+ startedAt: Type19.Optional(Type19.String({
20340
+ minLength: 1,
20341
+ description: "\u7B49\u5F85\u7A97\u8D77\u70B9 ISO \u65F6\u95F4\uFF1B\u65B0\u5EFA PR \u7528\u521B\u5EFA\u6210\u529F\u65F6\u523B\uFF1B\u7701\u7565\uFF1D\u73B0\u5728\uFF08\u89E6\u53D1\u9636\u6BB5\u7ED3\u675F\uFF09"
20342
+ }))
20343
+ }, { additionalProperties: false });
20344
+ collectorBindTargetArgsSchema = Type19.Object({
20345
+ prNumber: Type19.Optional(Type19.Unknown({
20346
+ 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"
20347
+ })),
20348
+ issueNumber: Type19.Optional(Type19.Unknown({
20349
+ 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"
20350
+ }))
20351
+ }, { additionalProperties: true });
20352
+ collectorFindingItemDeclaration = (() => {
20353
+ const item = Type19.Object(
20354
+ {
20355
+ evidenceId: Type19.Unknown({
20356
+ description: "observe \u8FD4\u56DE\u7684\u6750\u6599\u6307\u9488\uFF08\u5FC5\u586B\u8BED\u4E49\uFF09"
20357
+ }),
20358
+ category: Type19.Unknown({
20359
+ description: "\u7B80\u77ED\u5F52\u7C7B\u6807\u7B7E\uFF0C\u4E0D\u662F\u6458\u8981"
20360
+ }),
20361
+ summary: Type19.Unknown({
20362
+ description: "\u54EA\u4E2A bot\u3001\u4EC0\u4E48\u95EE\u9898\u7684\u6458\u8981\uFF1B\u4E0D\u8A8A\u6284\u6B63\u6587"
20363
+ })
20364
+ },
20365
+ {
20366
+ additionalProperties: true,
20367
+ description: "\u5355\u6761 finding \u6307\u9488\uFF1AevidenceId + \u53EF\u9009 category/summary\u3002\u5F62\u72B6\u6307\u5F15\uFF0C\u975E schema \u95F8\u3002"
20368
+ }
20369
+ );
20370
+ item.required = [];
20371
+ return item;
20372
+ })();
20373
+ collectorOutputBaseSchema = openToolObject(
20374
+ Type19.Object({
20375
+ // No root type:array — host must not shape-reject non-array findings (#676 C).
20376
+ // Nested item declarations ride `items` for registration preservation (ADR 0057).
20377
+ findings: Type19.Unsafe({
20378
+ 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",
20379
+ items: collectorFindingItemDeclaration
20380
+ }),
20381
+ unfinishedReasons: Type19.Unknown({
20382
+ 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"
20383
+ })
20384
+ })
20385
+ );
20386
+ collectorOutputArgsSchema = withInfrastructureFailureDeclaration(
20387
+ collectorOutputBaseSchema
20388
+ );
20389
+ }
20390
+ });
20391
+
20392
+ // src/collector-handbook.ts
20393
+ import { readFile as readFile18 } from "node:fs/promises";
20394
+ import { join as join33, sep as sep4 } from "node:path";
20395
+ function resolveCollectorHandbookRoot(sessionPath) {
20396
+ if (typeof sessionPath !== "string" || sessionPath.trim().length === 0) {
20397
+ throw new Error("\u901A\u8FDB\u53F8\u624B\u518C\u8981\u6C42\u975E\u7A7A session \u8DEF\u5F84\uFF0C\u4E14\u4F4D\u4E8E books/<bookKey>/");
20398
+ }
20399
+ const segments = sessionPath.split(sep4);
20400
+ let bookKey;
20401
+ for (let i = 0; i + 3 < segments.length; i += 1) {
20402
+ if (segments[i] === ".ak-roles" && segments[i + 1] === "books") {
20403
+ const candidate = segments[i + 2];
20404
+ if (candidate.length > 0) {
20405
+ bookKey = candidate;
20406
+ break;
20407
+ }
20408
+ }
20409
+ }
20410
+ if (bookKey === void 0) {
20411
+ throw new Error(
20412
+ `\u901A\u8FDB\u53F8\u624B\u518C\u8981\u6C42 session \u4F4D\u4E8E books/<bookKey>/\uFF1B\u6536\u5230 ${sessionPath}`
20413
+ );
20414
+ }
20415
+ if (bookKey === "." || bookKey === "..") {
20416
+ throw new Error(`\u901A\u8FDB\u53F8\u624B\u518C\u62D2\u7EDD\u4E0D\u5B89\u5168 bookKey ${JSON.stringify(bookKey)}`);
20417
+ }
20418
+ const ledgerHome = resolveActivationLedgerHomeForPath(sessionPath);
20419
+ const root = join33(activationBookDirectory(ledgerHome, bookKey), "collector-handbook");
20420
+ return { ledgerHome, bookKey, root };
20421
+ }
20422
+ function collectorHandbookRepoFileName(repositoryCanonical) {
20423
+ if (!/^[a-z0-9][a-z0-9._-]*\/[a-z0-9][a-z0-9._-]*$/.test(repositoryCanonical)) {
20424
+ throw new Error(
20425
+ `\u901A\u8FDB\u53F8\u624B\u518C\u4ED3\u5E93\u6587\u4EF6\u8981\u6C42\u89C4\u8303 owner/repo\uFF0C\u6536\u5230 ${JSON.stringify(repositoryCanonical)}`
20426
+ );
20427
+ }
20428
+ return `${repositoryCanonical.replaceAll("/", "__")}.md`;
20429
+ }
20430
+ function createCollectorHandbookStore(input) {
20431
+ const generalPath = join33(input.handbookRoot, "general.md");
20432
+ const repoDir = join33(input.handbookRoot, "repos");
20433
+ const repoPath = join33(repoDir, collectorHandbookRepoFileName(input.repositoryCanonical));
20434
+ const assertHandbookBudget = (body, label) => {
20435
+ const byteLength = Buffer.byteLength(body, "utf8");
20436
+ if (byteLength > COLLECTOR_HANDBOOK_MAX_BYTES) {
20437
+ throw new Error(
20438
+ `\u901A\u8FDB\u53F8\u624B\u518C${label} UTF-8 \u81F3\u591A ${COLLECTOR_HANDBOOK_MAX_BYTES} \u5B57\u8282\uFF0C\u6536\u5230 ${byteLength}`
20439
+ );
20440
+ }
20441
+ return byteLength;
20442
+ };
20443
+ const readOptional = async (path, parentDir2) => {
20444
+ ensureRealDirectoryTree(input.ledgerHome, parentDir2);
20445
+ assertLedgerFileInsideHome(path, input.ledgerHome);
20446
+ try {
20447
+ const body = await readFile18(path, "utf8");
20448
+ assertHandbookBudget(body, "\u6B63\u6587");
20449
+ return body;
20450
+ } catch (error) {
20451
+ if (isNotFound(error)) return void 0;
20452
+ throw error;
20453
+ }
20454
+ };
20455
+ return {
20456
+ root: input.handbookRoot,
20457
+ repositoryCanonical: input.repositoryCanonical,
20458
+ async read() {
20459
+ const bookGeneral = await readOptional(generalPath, input.handbookRoot);
20460
+ const bookRepo = await readOptional(repoPath, repoDir);
20461
+ if (bookGeneral !== void 0) {
20462
+ return {
20463
+ general: bookGeneral,
20464
+ repo: bookRepo ?? "",
20465
+ generalSource: "book",
20466
+ repoSource: bookRepo === void 0 ? "empty" : "book",
20467
+ generalPath,
20468
+ repoPath
20469
+ };
20470
+ }
20471
+ const seed = input.seedGeneral;
20472
+ if (typeof seed === "string" && seed.length > 0) {
20473
+ assertHandbookBudget(seed, "\u6B63\u6587");
20474
+ return {
20475
+ general: seed,
20476
+ repo: bookRepo ?? "",
20477
+ generalSource: "seed",
20478
+ repoSource: bookRepo === void 0 ? "empty" : "book",
20479
+ generalPath,
20480
+ repoPath
20481
+ };
20482
+ }
20483
+ return {
20484
+ general: "",
20485
+ repo: bookRepo ?? "",
20486
+ generalSource: "empty",
20487
+ repoSource: bookRepo === void 0 ? "empty" : "book",
20488
+ generalPath,
20489
+ repoPath
20490
+ };
20491
+ },
20492
+ async write(scope, body) {
20493
+ const byteLength = assertHandbookBudget(body, "\u6B63\u6587");
20494
+ ensureRealDirectoryTree(input.ledgerHome, input.handbookRoot);
20495
+ const path = scope === "general" ? generalPath : repoPath;
20496
+ if (scope === "repo") {
20497
+ ensureRealDirectoryTree(input.ledgerHome, repoDir);
20498
+ }
20499
+ assertLedgerFileInsideHome(path, input.ledgerHome);
20500
+ await writeFileAtomically(path, body);
20501
+ return {
20502
+ scope,
20503
+ path,
20504
+ byteLength
20505
+ };
20506
+ }
20507
+ };
20508
+ }
20509
+ function isNotFound(error) {
20510
+ return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
20511
+ }
20512
+ var init_collector_handbook = __esm({
20513
+ "src/collector-handbook.ts"() {
20514
+ "use strict";
20515
+ init_atomic_write();
20516
+ init_activation_ledger_topology();
20517
+ init_collector_tool_schemas();
20518
+ }
20519
+ });
20520
+
20257
20521
  // src/collector-receipt.ts
20258
20522
  function fail4(message) {
20259
20523
  throw new Error(message);
@@ -20351,22 +20615,46 @@ var init_collector_receipt = __esm({
20351
20615
  });
20352
20616
 
20353
20617
  // src/collector-role.ts
20618
+ function parseWaitWindowMsFlag(raw) {
20619
+ if (raw === void 0 || raw === null || raw === "") return COLLECTOR_DEFAULT_WAIT_WINDOW_MS;
20620
+ if (typeof raw === "number" && Number.isSafeInteger(raw) && raw >= 1) return raw;
20621
+ if (typeof raw === "string" && /^[1-9]\d*$/.test(raw.trim())) {
20622
+ const value = Number(raw.trim());
20623
+ if (Number.isSafeInteger(value) && value >= 1) return value;
20624
+ }
20625
+ throw new Error("Collector --ak-collector-wait-ms must be a positive safe-integer millisecond string");
20626
+ }
20354
20627
  function buildMethodContext(activation) {
20355
20628
  const pr = activation.ledger.config.prNumber;
20356
- return [
20629
+ const handbook = activation.handbookView;
20630
+ const lines = [
20357
20631
  "<collector_method>",
20358
20632
  `host: github.com`,
20359
20633
  `repository: ${activation.repository.canonical}`,
20360
- `prNumber: ${pr === void 0 ? "unbound \u2014 call ak_collector_bind_target with the role-decided issue/PR before observe" : String(pr)}`,
20634
+ `prNumber: ${pr === void 0 ? "\u672A\u7ED1\u5B9A" : String(pr)}`,
20635
+ `waitWindowMs: ${String(activation.ledger.config.waitWindowMs)}`,
20361
20636
  `requests: ${JSON.stringify(activation.manifest.requests.map((request) => ({ id: request.id })))}`,
20637
+ `handbookGeneralSource: ${handbook.generalSource}`,
20638
+ `handbookRepoSource: ${handbook.repoSource}`,
20362
20639
  "</collector_method>"
20363
- ].join("\n");
20640
+ ];
20641
+ if (handbook.general.length > 0 || handbook.repo.length > 0) {
20642
+ const payload = JSON.stringify({
20643
+ general: handbook.general,
20644
+ repo: handbook.repo,
20645
+ generalSource: handbook.generalSource,
20646
+ repoSource: handbook.repoSource,
20647
+ repository: activation.repository.canonical
20648
+ }).replaceAll("<", "\\u003c");
20649
+ lines.push("", "<collector_handbook>", payload, "</collector_handbook>");
20650
+ }
20651
+ return lines.join("\n");
20364
20652
  }
20365
20653
  function parsePositiveTicket(raw, label) {
20366
20654
  if (raw === void 0 || raw === null) return void 0;
20367
20655
  if (typeof raw === "number" && Number.isSafeInteger(raw) && raw >= 1) return raw;
20368
20656
  if (typeof raw === "string" && /^[1-9]\d*$/.test(raw.trim())) return Number(raw.trim());
20369
- throw new CollectorTargetBindError(`ak_collector_bind_target ${label} must be a positive safe integer`);
20657
+ throw new CollectorTargetBindError(`\u901A\u8FDB\u53F8\u7ED1\u5B9A ${label} \u987B\u4E3A\u6B63\u5B89\u5168\u6574\u6570`);
20370
20658
  }
20371
20659
  function createCollectorRoleRuntime(pi, dependencies, hostActions) {
20372
20660
  let toolsRegistered = false;
@@ -20377,6 +20665,7 @@ function createCollectorRoleRuntime(pi, dependencies, hostActions) {
20377
20665
  const repoFlag = pi.getFlag("ak-collector-repo");
20378
20666
  const prFlag = pi.getFlag("ak-collector-pr");
20379
20667
  const requestManifestFlag = pi.getFlag("ak-collector-request-manifest");
20668
+ const waitMsFlag = pi.getFlag("ak-collector-wait-ms");
20380
20669
  if (typeof repoFlag !== "string" || repoFlag.trim().length === 0) {
20381
20670
  throw new Error("Collector requires --ak-collector-repo");
20382
20671
  }
@@ -20388,20 +20677,36 @@ function createCollectorRoleRuntime(pi, dependencies, hostActions) {
20388
20677
  prNumber = parseCollectorPrNumber(prFlag);
20389
20678
  }
20390
20679
  const manifest = typeof requestManifestFlag === "string" && requestManifestFlag.trim().length > 0 ? await loadCollectorManifest(requestManifestFlag) : emptyCollectorManifest();
20680
+ const waitWindowMs = parseWaitWindowMsFlag(waitMsFlag);
20391
20681
  const clock = dependencies.createClock?.() ?? createSystemCollectorClock();
20392
20682
  const transport = dependencies.createTransport();
20393
20683
  const ledger = dependencies.createLedger(
20394
- { repository, prNumber, manifest },
20684
+ { repository, prNumber, manifest, waitWindowMs },
20395
20685
  clock,
20396
20686
  ctx
20397
20687
  );
20688
+ const sessionPath = ctx.sessionManager?.getSessionFile?.() ?? ctx.sessionManager?.getSessionDir?.();
20689
+ if (typeof sessionPath !== "string" || sessionPath.length === 0) {
20690
+ throw new Error("\u901A\u8FDB\u53F8\u624B\u518C\u8981\u6C42 session \u8DEF\u5F84\u4F4D\u4E8E books/<bookKey>/");
20691
+ }
20692
+ const placement = resolveCollectorHandbookRoot(sessionPath);
20693
+ const seedGeneral = dependencies.loadHandbookSeed === void 0 ? void 0 : (await dependencies.loadHandbookSeed()).trim();
20694
+ const handbook = createCollectorHandbookStore({
20695
+ ledgerHome: placement.ledgerHome,
20696
+ handbookRoot: placement.root,
20697
+ repositoryCanonical: repository.canonical,
20698
+ ...seedGeneral === void 0 || seedGeneral.length === 0 ? {} : { seedGeneral }
20699
+ });
20700
+ const handbookView = await handbook.read();
20398
20701
  return {
20399
20702
  soul,
20400
20703
  repository,
20401
20704
  manifest,
20402
20705
  ledger,
20403
20706
  transport,
20404
- clock
20707
+ clock,
20708
+ handbook,
20709
+ handbookView
20405
20710
  };
20406
20711
  },
20407
20712
  assembleMaterials(activation, baseSystemPrompt) {
@@ -20454,7 +20759,7 @@ function createCollectorRoleRuntime(pi, dependencies, hostActions) {
20454
20759
  const issueNumber = parsePositiveTicket(params.issueNumber, "issueNumber");
20455
20760
  if (prNumber === void 0 && issueNumber === void 0) {
20456
20761
  throw new CollectorTargetBindError(
20457
- "ak_collector_bind_target requires role-decided prNumber and/or issueNumber"
20762
+ "\u901A\u8FDB\u53F8\u7ED1\u5B9A\u987B\u7531\u89D2\u8272\u5224\u5B9A prNumber \u4E0E/\u6216 issueNumber"
20458
20763
  );
20459
20764
  }
20460
20765
  let bound = prNumber;
@@ -20466,18 +20771,18 @@ function createCollectorRoleRuntime(pi, dependencies, hostActions) {
20466
20771
  });
20467
20772
  if (associated.length === 0) {
20468
20773
  throw new CollectorTargetBindError(
20469
- `no PR associated with issue #${issueNumber} in ${activation.repository.canonical}; pass an explicit --pr or a different issueNumber`
20774
+ `${activation.repository.canonical} \u7684 issue #${issueNumber} \u65E0\u5173\u8054 PR\uFF1B\u8BF7\u6539\u7528\u660E\u786E --pr \u6216\u5176\u4ED6 issueNumber`
20470
20775
  );
20471
20776
  }
20472
20777
  if (associated.length > 1) {
20473
20778
  throw new CollectorTargetBindError(
20474
- `multiple PRs associated with issue #${issueNumber}: ${associated.join(", ")}; pass an explicit prNumber or --pr`
20779
+ `issue #${issueNumber} \u5173\u8054\u591A\u4E2A PR\uFF1A${associated.join("\u3001")}\uFF1B\u8BF7\u6539\u7528\u660E\u786E prNumber \u6216 --pr`
20475
20780
  );
20476
20781
  }
20477
20782
  const fromIssue = associated[0];
20478
20783
  if (prNumber !== void 0 && prNumber !== fromIssue) {
20479
20784
  throw new CollectorTargetBindError(
20480
- `prNumber ${prNumber} conflicts with issue #${issueNumber} association PR ${fromIssue}`
20785
+ `prNumber ${prNumber} \u4E0E issue #${issueNumber} \u5173\u8054 PR ${fromIssue} \u51B2\u7A81`
20481
20786
  );
20482
20787
  }
20483
20788
  bound = fromIssue;
@@ -20569,8 +20874,8 @@ function createCollectorRoleRuntime(pi, dependencies, hostActions) {
20569
20874
  pi.registerTool({
20570
20875
  name: COLLECTOR_REQUEST_TOOL,
20571
20876
  label: "\u901A\u8FDB\u53F8\u8BF7\u6C42",
20572
- 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",
20573
- promptSnippet: "\u6309\u914D\u7F6E\u53D1\u4E00\u6B21\u8BF7\u6C42",
20877
+ 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",
20878
+ promptSnippet: "\u53D1\u4E00\u6B21\u8BC4\u5BA1\u8BF7\u6C42",
20574
20879
  parameters: requestSchema,
20575
20880
  async execute(toolCallId, params, signal, _onUpdate, ctx) {
20576
20881
  const activation = getActivation();
@@ -20578,7 +20883,11 @@ function createCollectorRoleRuntime(pi, dependencies, hostActions) {
20578
20883
  try {
20579
20884
  activation.ledger.beginOperational(COLLECTOR_REQUEST_TOOL, toolCallId);
20580
20885
  const details = await activation.ledger.request(
20581
- params,
20886
+ {
20887
+ requestId: params.requestId,
20888
+ snapshotId: params.snapshotId,
20889
+ ...typeof params.body === "string" ? { body: params.body } : {}
20890
+ },
20582
20891
  activation.transport,
20583
20892
  activation.clock,
20584
20893
  signal
@@ -20597,11 +20906,95 @@ function createCollectorRoleRuntime(pi, dependencies, hostActions) {
20597
20906
  }
20598
20907
  }
20599
20908
  });
20909
+ pi.registerTool({
20910
+ name: COLLECTOR_HANDBOOK_WRITE_TOOL,
20911
+ label: "\u901A\u8FDB\u53F8\u624B\u518C\u5199\u5165",
20912
+ description: "\u5199\u5165\u901A\u7528\u624B\u518C\u6216\u5F53\u524D\u4ED3\u5E93\u5DEE\u5F02\u5168\u6587\uFF08\u6574\u4EFD\u66FF\u6362\uFF09\u3002",
20913
+ promptSnippet: "\u66F4\u65B0 bot \u624B\u518C",
20914
+ parameters: handbookWriteSchema,
20915
+ async execute(toolCallId, params, _signal, _onUpdate, ctx) {
20916
+ const activation = getActivation();
20917
+ if (activation === void 0) throw new Error("\u901A\u8FDB\u53F8\u672A\u6FC0\u6D3B");
20918
+ try {
20919
+ activation.ledger.beginOperational(COLLECTOR_HANDBOOK_WRITE_TOOL, toolCallId);
20920
+ const details = await activation.handbook.write(params.scope, params.body);
20921
+ activation.handbookView = await activation.handbook.read();
20922
+ activation.ledger.completeOperational(toolCallId);
20923
+ return {
20924
+ content: [{
20925
+ type: "text",
20926
+ text: `\u624B\u518C\u5DF2\u5199\u5165\uFF1A${details.scope}`
20927
+ }],
20928
+ details: {
20929
+ scope: details.scope,
20930
+ path: details.path,
20931
+ byteLength: details.byteLength,
20932
+ generalSource: activation.handbookView.generalSource,
20933
+ repoSource: activation.handbookView.repoSource
20934
+ }
20935
+ };
20936
+ } catch (error) {
20937
+ if (isCorrectableExecuteError(error)) throw error;
20938
+ hostActions.failInfrastructure(error, ctx, toolCallId);
20939
+ } finally {
20940
+ try {
20941
+ activation.ledger.completeOperational(toolCallId);
20942
+ } catch {
20943
+ }
20944
+ }
20945
+ }
20946
+ });
20947
+ pi.registerTool({
20948
+ name: COLLECTOR_OPEN_WAIT_WINDOW_TOOL,
20949
+ label: "\u901A\u8FDB\u53F8\u5F00\u542F\u7B49\u5F85\u7A97",
20950
+ description: "\u5728\u5DE5\u4F5C\u6B65\u9AA4\u4E0A\u5F00\u542F\u7B49\u5F85\u7A97\uFF1A\u65B0\u5EFA\u5E76\u81EA\u52A8\u89E6\u53D1\u7684 PR \u4F20\u521B\u5EFA\u6210\u529F\u65F6\u523B\uFF1B\u5DF2\u6709 PR \u5728\u89E6\u53D1\u9636\u6BB5\u7ED3\u675F\u540E\u7701\u7565 startedAt\uFF08=\u73B0\u5728\uFF09\u3002\u7A97\u957F\u7531\u4F7F\u7528\u65B9\u914D\u7F6E\uFF0C\u9ED8\u8BA4\u5341\u5206\u949F\uFF1B\u5F00\u542F\u540E\u4E0D\u56E0 PR \u66F4\u65B0\u91CD\u7F6E\u3002",
20951
+ promptSnippet: "\u6309\u5DE5\u4F5C\u6B65\u9AA4\u5F00\u542F\u7B49\u5F85\u7A97",
20952
+ parameters: openWaitWindowSchema,
20953
+ async execute(toolCallId, params, _signal, _onUpdate, ctx) {
20954
+ const activation = getActivation();
20955
+ if (activation === void 0) throw new Error("\u901A\u8FDB\u53F8\u672A\u6FC0\u6D3B");
20956
+ try {
20957
+ activation.ledger.beginOperational(COLLECTOR_OPEN_WAIT_WINDOW_TOOL, toolCallId);
20958
+ let startedAt;
20959
+ if (typeof params.startedAt === "string" && params.startedAt.trim().length > 0) {
20960
+ const parsed = new Date(params.startedAt);
20961
+ if (Number.isNaN(parsed.getTime())) {
20962
+ throw new Error("\u901A\u8FDB\u53F8\u7B49\u5F85\u7A97 startedAt \u987B\u4E3A\u6709\u6548 ISO \u65F6\u95F4");
20963
+ }
20964
+ startedAt = parsed;
20965
+ }
20966
+ activation.ledger.openWaitWindow(
20967
+ activation.clock,
20968
+ startedAt === void 0 ? void 0 : { startedAt }
20969
+ );
20970
+ activation.ledger.completeOperational(toolCallId);
20971
+ return {
20972
+ content: [{
20973
+ type: "text",
20974
+ text: "\u7B49\u5F85\u7A97\u5DF2\u5F00\u542F"
20975
+ }],
20976
+ details: {
20977
+ activationTime: activation.ledger.activationTime?.toISOString(),
20978
+ deadlineTime: activation.ledger.deadlineTime?.toISOString(),
20979
+ waitWindowMs: activation.ledger.config.waitWindowMs
20980
+ }
20981
+ };
20982
+ } catch (error) {
20983
+ if (isCorrectableExecuteError(error)) throw error;
20984
+ hostActions.failInfrastructure(error, ctx, toolCallId);
20985
+ } finally {
20986
+ try {
20987
+ activation.ledger.completeOperational(toolCallId);
20988
+ } catch {
20989
+ }
20990
+ }
20991
+ }
20992
+ });
20600
20993
  pi.registerTool({
20601
20994
  name: COLLECTOR_WAIT_TOOL,
20602
20995
  label: "\u901A\u8FDB\u53F8\u7B49\u5F85",
20603
- description: "\u518D\u89C2\u5BDF\u524D\u7B49\u5F85\uFF1B\u5355\u6B21\u4E0A\u9650\u4E94\u5206\u949F\u4E14\u4E0D\u8D85\u5269\u4F59\u8D44\u683C\u3002",
20604
- promptSnippet: "\u8D44\u683C\u622A\u6B62\u524D\u7B49\u5F85",
20996
+ description: "\u518D\u89C2\u5BDF\u524D\u7B49\u5F85\uFF1B\u5B9E\u9645\u7761\u7720\u4E0D\u8D85\u8FC7\u5269\u4F59\u7B49\u5F85\u7A97\u3002",
20997
+ promptSnippet: "\u7B49\u5F85\u7A97\u5185\u7B49\u5F85",
20605
20998
  parameters: waitSchema,
20606
20999
  async execute(toolCallId, params, signal, _onUpdate, ctx) {
20607
21000
  const activation = getActivation();
@@ -20622,6 +21015,7 @@ function createCollectorRoleRuntime(pi, dependencies, hostActions) {
20622
21015
  details
20623
21016
  };
20624
21017
  } catch (error) {
21018
+ if (isCorrectableExecuteError(error)) throw error;
20625
21019
  hostActions.failInfrastructure(error, ctx, toolCallId);
20626
21020
  }
20627
21021
  }
@@ -20674,13 +21068,14 @@ function createCollectorRoleRuntime(pi, dependencies, hostActions) {
20674
21068
  }
20675
21069
  };
20676
21070
  }
20677
- var CollectorNormalCompletionDeclarationError, CollectorTargetBindError, COLLECTOR_REQUIRED_TOOLS, COLLECTOR_TRANSPORT_FLAGS, observeSchema, readSchema, requestSchema, waitSchema, bindSchema, outputSchema;
21071
+ var CollectorNormalCompletionDeclarationError, CollectorTargetBindError, COLLECTOR_REQUIRED_TOOLS, COLLECTOR_TRANSPORT_FLAGS, observeSchema, readSchema, requestSchema, openWaitWindowSchema, waitSchema, bindSchema, handbookWriteSchema, outputSchema;
20678
21072
  var init_collector_role = __esm({
20679
21073
  "src/collector-role.ts"() {
20680
21074
  "use strict";
20681
21075
  init_collector_config();
20682
21076
  init_collector_evidence();
20683
21077
  init_collector_github();
21078
+ init_collector_handbook();
20684
21079
  init_collector_ledger();
20685
21080
  init_collector_receipt();
20686
21081
  init_collector_tool_schemas();
@@ -20705,7 +21100,9 @@ var init_collector_role = __esm({
20705
21100
  COLLECTOR_OBSERVE_TOOL,
20706
21101
  COLLECTOR_READ_TOOL,
20707
21102
  COLLECTOR_REQUEST_TOOL,
21103
+ COLLECTOR_OPEN_WAIT_WINDOW_TOOL,
20708
21104
  COLLECTOR_WAIT_TOOL,
21105
+ COLLECTOR_HANDBOOK_WRITE_TOOL,
20709
21106
  COLLECTOR_OUTPUT_TOOL
20710
21107
  ];
20711
21108
  COLLECTOR_TRANSPORT_FLAGS = Object.freeze([
@@ -20729,13 +21126,22 @@ var init_collector_role = __esm({
20729
21126
  description: "Path to the Collector v1 request manifest JSON file.",
20730
21127
  type: "string"
20731
21128
  })
21129
+ }),
21130
+ Object.freeze({
21131
+ name: "ak-collector-wait-ms",
21132
+ definition: Object.freeze({
21133
+ description: `Collector wait-window duration in milliseconds (default ${COLLECTOR_DEFAULT_WAIT_WINDOW_MS}). Caller-configurable; opens at a work step, not session start (#678 D4).`,
21134
+ type: "string"
21135
+ })
20732
21136
  })
20733
21137
  ]);
20734
21138
  observeSchema = collectorObserveArgsSchema;
20735
21139
  readSchema = collectorReadArgsSchema;
20736
21140
  requestSchema = collectorRequestArgsSchema;
21141
+ openWaitWindowSchema = collectorOpenWaitWindowArgsSchema;
20737
21142
  waitSchema = collectorWaitArgsSchema;
20738
21143
  bindSchema = collectorBindTargetArgsSchema;
21144
+ handbookWriteSchema = collectorHandbookWriteArgsSchema;
20739
21145
  outputSchema = collectorOutputArgsSchema;
20740
21146
  }
20741
21147
  });
@@ -21846,11 +22252,11 @@ function reliableWindow(cwd, baseline, head) {
21846
22252
  const raw = git2(cwd, ["log", "--format=%P%x1e%s", range]);
21847
22253
  if (raw.length === 0) return [];
21848
22254
  return raw.split("\n").flatMap((line2) => {
21849
- const sep4 = line2.indexOf("");
21850
- if (sep4 < 0) return [];
22255
+ const sep5 = line2.indexOf("");
22256
+ if (sep5 < 0) return [];
21851
22257
  return [{
21852
- subject: line2.slice(sep4 + 1),
21853
- merge: line2.slice(0, sep4).trim().includes(" ")
22258
+ subject: line2.slice(sep5 + 1),
22259
+ merge: line2.slice(0, sep5).trim().includes(" ")
21854
22260
  }];
21855
22261
  });
21856
22262
  }
@@ -22468,8 +22874,8 @@ var init_activation_reconciliation = __esm({
22468
22874
 
22469
22875
  // src/role-runtime.ts
22470
22876
  import { readFileSync as readFileSync5, writeSync as writeSync4 } from "node:fs";
22471
- import { join as join32 } from "node:path";
22472
- import { Value as Value5 } from "typebox/value";
22877
+ import { join as join34 } from "node:path";
22878
+ import { Value as Value4 } from "typebox/value";
22473
22879
  function decodeReviewerAdmittedInputs(getFlag) {
22474
22880
  let reviewScopeKeys;
22475
22881
  const rawScopeKeys = getFlag("ak-review-scope-keys");
@@ -22596,7 +23002,7 @@ function activationStage(role, runtime) {
22596
23002
  }
22597
23003
  }
22598
23004
  function validateActivationTraceRecord(record4) {
22599
- if (!Value5.Check(activationTraceRecordSchema, record4)) {
23005
+ if (!Value4.Check(activationTraceRecordSchema, record4)) {
22600
23006
  throw new TypeError("Activation trace record does not match its closed contract");
22601
23007
  }
22602
23008
  return record4;
@@ -22840,7 +23246,7 @@ function readDiaristRunCoordinates() {
22840
23246
  if (typeof runDirectory !== "string" || runDirectory.trim() === "") {
22841
23247
  throw new Error("diarist accept requires AK_ROLE_RUN_DIR");
22842
23248
  }
22843
- const admittedPath = join32(runDirectory, "admitted-request.json");
23249
+ const admittedPath = join34(runDirectory, "admitted-request.json");
22844
23250
  const admitted = JSON.parse(readFileSync5(admittedPath, "utf8"));
22845
23251
  if (typeof admitted.projectRoot !== "string" || admitted.projectRoot.trim() === "") {
22846
23252
  throw new Error(`diarist admitted-request missing projectRoot (${admittedPath})`);
@@ -23458,7 +23864,8 @@ function createRoleRuntimeExtension(dependencies) {
23458
23864
  dossierEntries: context.sessionManager?.getEntries?.() ?? []
23459
23865
  });
23460
23866
  },
23461
- ...dependencies.createCollectorClock === void 0 ? {} : { createClock: dependencies.createCollectorClock }
23867
+ ...dependencies.createCollectorClock === void 0 ? {} : { createClock: dependencies.createCollectorClock },
23868
+ ...dependencies.loadCollectorHandbookSeed === void 0 ? {} : { loadHandbookSeed: dependencies.loadCollectorHandbookSeed }
23462
23869
  },
23463
23870
  hostActions
23464
23871
  );
@@ -24199,9 +24606,9 @@ __export(in_process_session_exports, {
24199
24606
  DEFAULT_COMPLIANCE_IDLE_MAX_RETRIES: () => DEFAULT_COMPLIANCE_IDLE_MAX_RETRIES,
24200
24607
  openPiInProcessSession: () => openPiInProcessSession
24201
24608
  });
24202
- import { mkdtemp as mkdtemp2, rm as rm2 } from "node:fs/promises";
24609
+ import { mkdtemp as mkdtemp2, rm as rm3 } from "node:fs/promises";
24203
24610
  import { tmpdir as tmpdir2 } from "node:os";
24204
- import { join as join33 } from "node:path";
24611
+ import { join as join35 } from "node:path";
24205
24612
  import {
24206
24613
  createAgentSession,
24207
24614
  DefaultResourceLoader,
@@ -24324,7 +24731,7 @@ async function openPiInProcessSession(options) {
24324
24731
  let scratchDir;
24325
24732
  let resolvedAgentDir = options.agentDir;
24326
24733
  if (resolvedAgentDir === void 0) {
24327
- scratchDir = await mkdtemp2(join33(options.credentialScratchParent ?? tmpdir2(), "ak-institutional-"));
24734
+ scratchDir = await mkdtemp2(join35(options.credentialScratchParent ?? tmpdir2(), "ak-institutional-"));
24328
24735
  resolvedAgentDir = scratchDir;
24329
24736
  }
24330
24737
  try {
@@ -24806,7 +25213,7 @@ async function openPiInProcessSession(options) {
24806
25213
  }
24807
25214
  if (scratchDir !== void 0) {
24808
25215
  try {
24809
- await rm2(scratchDir, { recursive: true, force: true });
25216
+ await rm3(scratchDir, { recursive: true, force: true });
24810
25217
  } catch (error) {
24811
25218
  cleanupFailures.push(error);
24812
25219
  }
@@ -24831,7 +25238,7 @@ async function openPiInProcessSession(options) {
24831
25238
  } catch (openError) {
24832
25239
  if (scratchDir !== void 0) {
24833
25240
  try {
24834
- await rm2(scratchDir, { recursive: true, force: true });
25241
+ await rm3(scratchDir, { recursive: true, force: true });
24835
25242
  } catch (cleanupFailure) {
24836
25243
  throw new AggregateError(
24837
25244
  [openError, cleanupFailure],
@@ -25018,9 +25425,9 @@ var init_reviewer_child_executor = __esm({
25018
25425
 
25019
25426
  // src/reviewer-workspace.ts
25020
25427
  import { spawn as spawn4 } from "node:child_process";
25021
- import { mkdtemp as mkdtemp3, rm as rm3 } from "node:fs/promises";
25428
+ import { mkdtemp as mkdtemp3, rm as rm4 } from "node:fs/promises";
25022
25429
  import { tmpdir as tmpdir3 } from "node:os";
25023
- import { join as join34 } from "node:path";
25430
+ import { join as join36 } from "node:path";
25024
25431
  async function runCommand(command, args, options = {}) {
25025
25432
  return await new Promise((resolve20, reject) => {
25026
25433
  const child = spawn4(command, args, { ...options.cwd === void 0 ? {} : { cwd: options.cwd }, stdio: ["ignore", "pipe", "pipe"], signal: options.signal });
@@ -25069,8 +25476,8 @@ async function prepareSnapshot(accepted, signal, dependencies) {
25069
25476
  if (!sameReviewerPinnedTarget({ repositoryRoot: accepted.repositoryRoot, objectFormat, targetHead }, accepted)) throw new Error("Accepted Reviewer target identity no longer matches the repository");
25070
25477
  await git3(accepted.repositoryRoot, ["cat-file", "-e", `${targetHead}^{commit}`], signal);
25071
25478
  dependencies.fault?.("mirror.before-create");
25072
- mirrorRoot = await mkdtemp3(join34(tmpdir3(), "ak-reviewer-snapshot-"));
25073
- const mirrorPath = join34(mirrorRoot, "repository.git");
25479
+ mirrorRoot = await mkdtemp3(join36(tmpdir3(), "ak-reviewer-snapshot-"));
25480
+ const mirrorPath = join36(mirrorRoot, "repository.git");
25074
25481
  dependencies.fault?.("mirror.create");
25075
25482
  await runCommand("git", ["init", "--bare", `--object-format=${accepted.objectFormat}`, mirrorPath], signal === void 0 ? {} : { signal });
25076
25483
  await git3(mirrorPath, ["fetch", "--no-tags", accepted.repositoryRoot, targetHead], signal);
@@ -25087,7 +25494,7 @@ async function prepareClone(snapshot, signal, dependencies) {
25087
25494
  const target = { repositoryRoot: snapshot.repositoryRoot, objectFormat: snapshot.objectFormat, targetHead: snapshot.targetHead, refs: { ...snapshot.refs } };
25088
25495
  try {
25089
25496
  dependencies.fault?.("workspace.before-create");
25090
- workspace = await mkdtemp3(join34(tmpdir3(), "ak-reviewer-leg-"));
25497
+ workspace = await mkdtemp3(join36(tmpdir3(), "ak-reviewer-leg-"));
25091
25498
  dependencies.fault?.("workspace.init");
25092
25499
  await git3(workspace, ["init", `--object-format=${snapshot.objectFormat}`, "--initial-branch=ak-reviewer-unborn"], signal);
25093
25500
  dependencies.fault?.("workspace.fetch");
@@ -25121,12 +25528,12 @@ function createReviewerWorkspaceOwner(dependencies = {}) {
25121
25528
  return Object.freeze({ target: frozenTarget, workspaces: Object.freeze(workspaces) });
25122
25529
  },
25123
25530
  async dispose(workspace) {
25124
- await rm3(workspace.path, { recursive: true, force: false });
25531
+ await rm4(workspace.path, { recursive: true, force: false });
25125
25532
  return "deleted";
25126
25533
  },
25127
25534
  async shutdown() {
25128
25535
  if (ownedSnapshot === void 0) return;
25129
- cleanupPromise ??= rm3(ownedSnapshot.mirrorRoot, { recursive: true, force: false });
25536
+ cleanupPromise ??= rm4(ownedSnapshot.mirrorRoot, { recursive: true, force: false });
25130
25537
  await cleanupPromise;
25131
25538
  }
25132
25539
  };
@@ -25288,7 +25695,7 @@ var init_reviewer_agent = __esm({
25288
25695
  });
25289
25696
 
25290
25697
  // src/acp-host/production-host.ts
25291
- import { readFile as readFile20 } from "node:fs/promises";
25698
+ import { readFile as readFile21 } from "node:fs/promises";
25292
25699
  import { fileURLToPath as fileURLToPath3 } from "node:url";
25293
25700
 
25294
25701
  // src/canonical-skill-binding.ts
@@ -25502,9 +25909,9 @@ init_auditor_soul();
25502
25909
  init_session_opening_materials();
25503
25910
 
25504
25911
  // src/acp-host/description.ts
25505
- import { join as join35 } from "node:path";
25912
+ import { join as join37 } from "node:path";
25506
25913
  function resolveAcpBinary(description, operatorHome) {
25507
- return join35(operatorHome, ...description.binaryFromHome);
25914
+ return join37(operatorHome, ...description.binaryFromHome);
25508
25915
  }
25509
25916
  function acpStdioArgs(description, model, seat) {
25510
25917
  const { prefix, suffix, modelFlag, thinkingFlag } = description.argv;
@@ -25527,10 +25934,10 @@ init_gatekeeper_pass_envelope();
25527
25934
  init_packaged_role_registry();
25528
25935
  init_method_skill();
25529
25936
  init_role_runtime();
25530
- import { randomUUID as randomUUID6 } from "node:crypto";
25531
- import { mkdir as mkdir5, readFile as readFile18, writeFile as writeFile8 } from "node:fs/promises";
25937
+ import { randomUUID as randomUUID7 } from "node:crypto";
25938
+ import { mkdir as mkdir5, readFile as readFile19, writeFile as writeFile9 } from "node:fs/promises";
25532
25939
  import { createServer } from "node:net";
25533
- import { basename as basename7, dirname as dirname17, join as join36 } from "node:path";
25940
+ import { basename as basename7, dirname as dirname18, join as join38 } from "node:path";
25534
25941
  import { fileURLToPath as fileURLToPath2 } from "node:url";
25535
25942
 
25536
25943
  // src/acp-host/role-turn-host.ts
@@ -25829,7 +26236,7 @@ function buildAcpSkillExpansion(methodSkills, prompt) {
25829
26236
  return Object.freeze({
25830
26237
  name: parsed.name,
25831
26238
  location: method.path,
25832
- content: `References are relative to ${dirname17(method.path)}.
26239
+ content: `References are relative to ${dirname18(method.path)}.
25833
26240
 
25834
26241
  ${method.body}`,
25835
26242
  userMessage: parsed.userMessage
@@ -25861,6 +26268,7 @@ function projectAcpActivationFlags(request) {
25861
26268
  flags.set("ak-collector-repo", activation.repo);
25862
26269
  if (activation.pr !== void 0) flags.set("ak-collector-pr", activation.pr);
25863
26270
  if (activation.requestManifestPath !== void 0) flags.set("ak-collector-request-manifest", activation.requestManifestPath);
26271
+ if (activation.waitMs !== void 0) flags.set("ak-collector-wait-ms", activation.waitMs);
25864
26272
  }
25865
26273
  return flags;
25866
26274
  }
@@ -25881,7 +26289,7 @@ function createComposedAcpRoleTurnHost(config) {
25881
26289
  dependencies: config.roleRuntimeDependencies,
25882
26290
  // Same durable-principal path settlement uses for isAvailable (#617 DK-4 layout).
25883
26291
  sessionFile: config.sessionIdentity.resolveSessionFile(request.principal),
25884
- socketPath: config.socketPath?.(request) ?? `/tmp/ak-acp-mcp-${randomUUID6()}.sock`
26292
+ socketPath: config.socketPath?.(request) ?? `/tmp/ak-acp-mcp-${randomUUID7()}.sock`
25885
26293
  })
25886
26294
  });
25887
26295
  }
@@ -25913,19 +26321,19 @@ async function prepareAcpRoleEnvelope(options) {
25913
26321
  let rejection;
25914
26322
  let infrastructureRoundFailure;
25915
26323
  const hostAbort = new AbortController();
25916
- const runId = request.runDirectory.split("/").filter(Boolean).at(-1) ?? randomUUID6();
26324
+ const runId = request.runDirectory.split("/").filter(Boolean).at(-1) ?? randomUUID7();
25917
26325
  await mkdir5(request.runDirectory, { recursive: true });
25918
26326
  for (const method of request.methods) {
25919
26327
  if (method.kind !== "skill") continue;
25920
- const name = basename7(dirname17(method.path));
25921
- const raw = await readFile18(method.path, "utf8");
26328
+ const name = basename7(dirname18(method.path));
26329
+ const raw = await readFile19(method.path, "utf8");
25922
26330
  methodSkills.set(name, { path: method.path, body: stripSkillFrontmatter(raw).trim() });
25923
26331
  }
25924
- let sessionFile = options.sessionFile ?? join36(request.runDirectory, "session", "session.jsonl");
25925
- await mkdir5(dirname17(sessionFile), { recursive: true });
26332
+ let sessionFile = options.sessionFile ?? join38(request.runDirectory, "session", "session.jsonl");
26333
+ await mkdir5(dirname18(sessionFile), { recursive: true });
25926
26334
  if (request.continuation.kind !== "resume") {
25927
26335
  try {
25928
- await writeFile8(
26336
+ await writeFile9(
25929
26337
  sessionFile,
25930
26338
  `${JSON.stringify({
25931
26339
  type: "session",
@@ -25949,7 +26357,7 @@ async function prepareAcpRoleEnvelope(options) {
25949
26357
  getLeafEntry: () => sessionEntries.at(-1),
25950
26358
  getLeafId: () => runId,
25951
26359
  getEntries: () => sessionEntries,
25952
- getSessionDir: () => dirname17(sessionFile),
26360
+ getSessionDir: () => dirname18(sessionFile),
25953
26361
  getSessionFile: () => sessionFile,
25954
26362
  getHeader: () => ({ type: "session", id: runId }),
25955
26363
  setSessionFile(path) {
@@ -26050,7 +26458,7 @@ async function prepareAcpRoleEnvelope(options) {
26050
26458
  }
26051
26459
  };
26052
26460
  createRoleRuntimeExtension(options.dependencies)(envelope);
26053
- const token = randomUUID6();
26461
+ const token = randomUUID7();
26054
26462
  const server = createServer((socket) => serveSocket(socket));
26055
26463
  function rememberProjectedRejection(details, toolCallId) {
26056
26464
  if (typeof details !== "object" || details === null) return;
@@ -26127,7 +26535,7 @@ async function prepareAcpRoleEnvelope(options) {
26127
26535
  async function invokeAkTool(name, args) {
26128
26536
  const tool = tools.get(name);
26129
26537
  if (tool === void 0) throw new Error(`Unknown AK tool: ${name}`);
26130
- const toolCallId = randomUUID6();
26538
+ const toolCallId = randomUUID7();
26131
26539
  calls.push({ toolCallId, toolName: name });
26132
26540
  sessionEntries.push({
26133
26541
  type: "message",
@@ -26335,7 +26743,7 @@ async function prepareAcpRoleEnvelope(options) {
26335
26743
  message: { role: "user", content: prompt }
26336
26744
  });
26337
26745
  }
26338
- const methodPrompt = (await Promise.all(request.methods.map(({ path }) => readFile18(path, "utf8")))).join("\n\n");
26746
+ const methodPrompt = (await Promise.all(request.methods.map(({ path }) => readFile19(path, "utf8")))).join("\n\n");
26339
26747
  const promptResults = await emit("before_agent_start", {
26340
26748
  prompt,
26341
26749
  systemPrompt: methodPrompt,
@@ -26396,12 +26804,12 @@ async function prepareAcpRoleEnvelope(options) {
26396
26804
  // src/acp-host/seat-profile-soul.ts
26397
26805
  import { constants as constants3 } from "node:fs";
26398
26806
  import { access as access4, copyFile, lstat as lstat6, mkdir as mkdir6, readlink, symlink, unlink as unlink4 } from "node:fs/promises";
26399
- import { dirname as dirname18, join as join37, relative as relative3, resolve as resolve19 } from "node:path";
26807
+ import { dirname as dirname19, join as join39, relative as relative3, resolve as resolve19 } from "node:path";
26400
26808
  function seatProfileName(spec, role) {
26401
26809
  return `${spec.namePrefix}${role}`;
26402
26810
  }
26403
26811
  function packageRoleSoulPath(packageRoot, role) {
26404
- return join37(packageRoot, "souls", `${role}.md`);
26812
+ return join39(packageRoot, "souls", `${role}.md`);
26405
26813
  }
26406
26814
  async function pathExists(path) {
26407
26815
  try {
@@ -26418,16 +26826,16 @@ async function ensureSeatProfileSoul(options) {
26418
26826
  if (!await pathExists(soulTarget)) {
26419
26827
  throw new Error(`packaged role soul missing: ${soulTarget}`);
26420
26828
  }
26421
- const profilesRoot = join37(operatorHome, ...spec.profilesRootFromHome);
26422
- const profileDir = join37(profilesRoot, profileName);
26423
- const hostRoot = dirname18(profilesRoot);
26424
- const soulPath = join37(profileDir, spec.soulFileName);
26829
+ const profilesRoot = join39(operatorHome, ...spec.profilesRootFromHome);
26830
+ const profileDir = join39(profilesRoot, profileName);
26831
+ const hostRoot = dirname19(profilesRoot);
26832
+ const soulPath = join39(profileDir, spec.soulFileName);
26425
26833
  if (!await pathExists(profileDir)) {
26426
26834
  await mkdir6(profileDir, { recursive: true });
26427
26835
  for (const name of ["auth.json", ".env", "config.yaml"]) {
26428
- const source = join37(hostRoot, name);
26836
+ const source = join39(hostRoot, name);
26429
26837
  if (!await pathExists(source)) continue;
26430
- await copyFile(source, join37(profileDir, name));
26838
+ await copyFile(source, join39(profileDir, name));
26431
26839
  }
26432
26840
  } else {
26433
26841
  await mkdir6(profileDir, { recursive: true });
@@ -26453,17 +26861,17 @@ async function ensureSeatProfileSoul(options) {
26453
26861
  }
26454
26862
 
26455
26863
  // src/acp-host/session-identity.ts
26456
- import { mkdir as mkdir7, readFile as readFile19, rename, writeFile as writeFile9 } from "node:fs/promises";
26457
- import { dirname as dirname19, join as join38 } from "node:path";
26864
+ import { mkdir as mkdir7, readFile as readFile20, rename as rename2, writeFile as writeFile10 } from "node:fs/promises";
26865
+ import { dirname as dirname20, join as join40 } from "node:path";
26458
26866
  function createAcpSessionIdentityAuthority(authority, sessionBindingFile) {
26459
- const bindingPath = (principal) => join38(authority.decode(principal).sessionDirectory, sessionBindingFile);
26867
+ const bindingPath = (principal) => join40(authority.decode(principal).sessionDirectory, sessionBindingFile);
26460
26868
  return {
26461
26869
  resolveSessionFile(principal) {
26462
26870
  return authority.decode(principal).sessionFile;
26463
26871
  },
26464
26872
  async load(principal) {
26465
26873
  try {
26466
- const value = JSON.parse(await readFile19(bindingPath(principal), "utf8"));
26874
+ const value = JSON.parse(await readFile20(bindingPath(principal), "utf8"));
26467
26875
  if (typeof value !== "object" || value === null || typeof value.sessionId !== "string") {
26468
26876
  throw new Error("durable ACP session binding is invalid");
26469
26877
  }
@@ -26475,11 +26883,11 @@ function createAcpSessionIdentityAuthority(authority, sessionBindingFile) {
26475
26883
  },
26476
26884
  async bind(principal, sessionId) {
26477
26885
  const target = bindingPath(principal);
26478
- await mkdir7(dirname19(target), { recursive: true });
26886
+ await mkdir7(dirname20(target), { recursive: true });
26479
26887
  const temporary = `${target}.${process.pid}.tmp`;
26480
- await writeFile9(temporary, `${JSON.stringify({ sessionId })}
26888
+ await writeFile10(temporary, `${JSON.stringify({ sessionId })}
26481
26889
  `, { encoding: "utf8", mode: 384 });
26482
- await rename(temporary, target);
26890
+ await rename2(temporary, target);
26483
26891
  }
26484
26892
  };
26485
26893
  }
@@ -26488,6 +26896,9 @@ function createAcpSessionIdentityAuthority(authority, sessionBindingFile) {
26488
26896
  var navigatorRoutePlaybookPath = fileURLToPath3(
26489
26897
  new URL("../../resources/navigator-route-playbook.md", import.meta.url)
26490
26898
  );
26899
+ var collectorHandbookSeedPath = fileURLToPath3(
26900
+ new URL("../../resources/collector-bot-handbook.md", import.meta.url)
26901
+ );
26491
26902
  function createAcpRoleRuntimeDependencies(packageRoot) {
26492
26903
  const doctorAuditor = createPiDoctorAuditor();
26493
26904
  const reviewerAgent = createPerDispatchReviewerAgent({ packageRoot });
@@ -26495,13 +26906,14 @@ function createAcpRoleRuntimeDependencies(packageRoot) {
26495
26906
  return {
26496
26907
  loadJudgeSoul: () => loadMainRoleSessionMaterials("judge"),
26497
26908
  loadFixerSoul: () => loadMainRoleSessionMaterials("fixer"),
26498
- loadFixPacket: (path) => readFile20(path, "utf8"),
26909
+ loadFixPacket: (path) => readFile21(path, "utf8"),
26499
26910
  loadCoderSoul: () => loadMainRoleSessionMaterials("coder"),
26500
- loadCoderTask: (path) => readFile20(path, "utf8"),
26911
+ loadCoderTask: (path) => readFile21(path, "utf8"),
26501
26912
  loadReviewerSoul: () => loadMainRoleSessionMaterials("reviewer"),
26502
26913
  createReviewerPinnedGitReader: () => createReviewerPinnedGitReader(),
26503
26914
  createReviewerIssueFetcher: () => createGhIssueSoftFetcher(),
26504
26915
  loadCollectorSoul: () => loadMainRoleSessionMaterials("collector"),
26916
+ loadCollectorHandbookSeed: () => readFile21(collectorHandbookSeedPath, "utf8"),
26505
26917
  createCollectorTransport: () => createGhCollectorGitHubTransport(),
26506
26918
  loadDoctorSoul: () => loadMainRoleSessionMaterials("doctor"),
26507
26919
  loadDoctorCase,
@@ -26515,7 +26927,7 @@ function createAcpRoleRuntimeDependencies(packageRoot) {
26515
26927
  loadDiaristSoul: () => loadMainRoleSessionMaterials("diarist"),
26516
26928
  loadNotarySourceRun: loadNotarySourceRunLocator,
26517
26929
  loadMergerSoul: () => loadMainRoleSessionMaterials("merger"),
26518
- loadMergerInput: async (path) => JSON.parse(await readFile20(path, "utf8")),
26930
+ loadMergerInput: async (path) => JSON.parse(await readFile21(path, "utf8")),
26519
26931
  createMergerGitState: (repositoryRoot) => createProductionMergerGitState(repositoryRoot),
26520
26932
  async loadCanonicalSkillBinding(name) {
26521
26933
  if (name === "tdd") {
@@ -26544,7 +26956,7 @@ function createAcpRoleRuntimeDependencies(packageRoot) {
26544
26956
  authority: options.authority,
26545
26957
  invocationId: options.invocationId,
26546
26958
  loadSoul: () => loadMainRoleSessionMaterials("navigator"),
26547
- loadRoutePlaybook: () => readFile20(navigatorRoutePlaybookPath, "utf8"),
26959
+ loadRoutePlaybook: () => readFile21(navigatorRoutePlaybookPath, "utf8"),
26548
26960
  loadRoleHelp: async (role) => formatNavigatorRoleHelp(role),
26549
26961
  createSession: navigatorSessionFactory,
26550
26962
  ...options.contextError === void 0 ? {} : { contextError: options.contextError },