@akagilnc/pi-workflow-roles 0.1.3789 → 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.
package/README.md CHANGED
@@ -92,9 +92,11 @@ ak-role coder apply --attach ./plan.md "Implement the approved slice."
92
92
  # reviewer — fixed-target two-axis review; completed ≠ approved, read the findings
93
93
  ak-role reviewer --base main "Review the branch."
94
94
 
95
- # collector — GitHub PR review evidence (bind target, read handbook/field activity, trigger as needed, return materials)
95
+ # collector — GitHub PR review evidence (bind target, read handbook/field activity, trigger as needed, wait window, return materials)
96
96
  ak-role collector --pr 42 --repo owner/repository "Collect findings for the assigned issue."
97
97
  ak-role collector --repo owner/repository "Collect findings for #42"
98
+ # optional: wait-window ms after the work step opens (default 600000 = 10 minutes)
99
+ ak-role collector --pr 42 --repo owner/repository --wait-ms 120000 "Collect with a 2-minute window."
98
100
 
99
101
  # fixer — repair the assigned findings
100
102
  ak-role fixer --attach ./findings.md --prerequisites ./prereqs.json "Repair the findings."
package/README.zh-CN.md CHANGED
@@ -86,9 +86,11 @@ ak-role coder apply --attach ./plan.md "Implement the approved slice."
86
86
  # 御史台——固定目标双轴察举;completed ≠ 准行,findings 在 Terminal 里
87
87
  ak-role reviewer --base main "Review the branch."
88
88
 
89
- # 通进司——GitHub PR 收证(认票、读手册/现场活动、按需触发、交回材料)
89
+ # 通进司——GitHub PR 收证(认票、读手册/现场活动、按需触发、等待窗、交回材料)
90
90
  ak-role collector --pr 42 --repo owner/repository "为所指 issue 收证。"
91
91
  ak-role collector --repo owner/repository "为 #42 收证。"
92
+ # 可选:工作步骤开启后的等待窗毫秒(默认 600000=十分钟)
93
+ ak-role collector --pr 42 --repo owner/repository --wait-ms 120000 "两分钟窗收证。"
92
94
 
93
95
  # 修内司——缮修所指 findings
94
96
  ak-role fixer --attach ./findings.md --prerequisites ./prereqs.json "Repair the findings."
@@ -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
@@ -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 },
@@ -6088,6 +6095,20 @@ var init_option_definitions = __esm({
6088
6095
  en: "Optional request manifest JSON path ({requests:[{id,body}]}). Role may also decide request bodies from handbook/field activity without this file.",
6089
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"
6090
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"
6111
+ }
6091
6112
  }
6092
6113
  ];
6093
6114
  DOCTOR_OPTIONS = [
@@ -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
  }
@@ -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",
@@ -12521,13 +12567,27 @@ function projectObserveContextView(modelView) {
12521
12567
  function isOperationalTool(name) {
12522
12568
  return COLLECTOR_OPERATIONAL_TOOLS.includes(name);
12523
12569
  }
12524
- 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
+ };
12525
12584
  const clock = options?.clock;
12526
12585
  const journal = options?.journal;
12527
12586
  let fatal2 = false;
12528
12587
  let fatalReason;
12529
12588
  let outputCandidate = false;
12530
12589
  let pendingOutputCallId;
12590
+ let sessionReady = false;
12531
12591
  let activationTime;
12532
12592
  let deadlineTime;
12533
12593
  let activationMono;
@@ -12571,7 +12631,7 @@ function createCollectorLedger(config, options) {
12571
12631
  return monoNowOrThrow(clock2) >= deadlineMono;
12572
12632
  };
12573
12633
  const remainingMs = (clock2) => {
12574
- if (deadlineMono === void 0) return COLLECTOR_ELIGIBILITY_MS;
12634
+ if (deadlineMono === void 0) return config.waitWindowMs;
12575
12635
  return Math.max(0, deadlineMono - monoNowOrThrow(clock2));
12576
12636
  };
12577
12637
  const prIdentity = (pr) => `${pr.state}|${pr.headOid}|${pr.updatedAt ?? ""}`;
@@ -12640,6 +12700,7 @@ function createCollectorLedger(config, options) {
12640
12700
  };
12641
12701
  const commitActivationWindow = (nextActivation, nextDeadline) => {
12642
12702
  if (activationTime !== void 0) return;
12703
+ sessionReady = true;
12643
12704
  activationTime = nextActivation;
12644
12705
  deadlineTime = nextDeadline;
12645
12706
  bindDeadlineMonoFromWall();
@@ -12747,6 +12808,8 @@ function createCollectorLedger(config, options) {
12747
12808
  if (entry.customType === COLLECTOR_ACTIVATION_ENTRY_TYPE) {
12748
12809
  if (typeof data.activationTime === "string" && typeof data.deadlineTime === "string") {
12749
12810
  commitActivationWindow(new Date(data.activationTime), new Date(data.deadlineTime));
12811
+ } else if (data.sessionReady === true) {
12812
+ sessionReady = true;
12750
12813
  }
12751
12814
  continue;
12752
12815
  }
@@ -12800,7 +12863,7 @@ function createCollectorLedger(config, options) {
12800
12863
  return outputCandidate || pendingOutputCallId !== void 0;
12801
12864
  },
12802
12865
  get activationRecorded() {
12803
- return activationTime !== void 0;
12866
+ return sessionReady;
12804
12867
  },
12805
12868
  get activationTime() {
12806
12869
  return activationTime;
@@ -12837,16 +12900,35 @@ function createCollectorLedger(config, options) {
12837
12900
  },
12838
12901
  latchFatal,
12839
12902
  assertNotFatal,
12840
- recordActivation(clock2) {
12903
+ recordActivation(_clock) {
12841
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
+ }
12842
12916
  if (activationTime !== void 0) return;
12843
- activationTime = clock2.wallNow();
12844
- activationMono = clock2.monoNow();
12845
- deadlineTime = new Date(activationTime.getTime() + COLLECTOR_ELIGIBILITY_MS);
12846
- 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);
12847
12928
  appendJournal(COLLECTOR_ACTIVATION_ENTRY_TYPE, {
12848
12929
  activationTime: activationTime.toISOString(),
12849
- deadlineTime: deadlineTime.toISOString()
12930
+ deadlineTime: deadlineTime.toISOString(),
12931
+ waitWindowMs: config.waitWindowMs
12850
12932
  });
12851
12933
  },
12852
12934
  recordOutputCandidate() {
@@ -12934,7 +13016,7 @@ function createCollectorLedger(config, options) {
12934
13016
  },
12935
13017
  async observe(transport, clock2, signal) {
12936
13018
  assertNotFatal();
12937
- if (activationTime === void 0) {
13019
+ if (!sessionReady) {
12938
13020
  throw latchFatal("\u901A\u8FDB\u53F8\u89C2\u5BDF\u9700\u8981\u6FC0\u6D3B");
12939
13021
  }
12940
13022
  if (signal?.aborted) {
@@ -13021,6 +13103,7 @@ function createCollectorLedger(config, options) {
13021
13103
  prNumber: requireBoundPr(),
13022
13104
  prState: pr.state,
13023
13105
  headOid: pr.headOid,
13106
+ ...pr.createdAt === void 0 ? {} : { prCreatedAt: pr.createdAt },
13024
13107
  complete: true,
13025
13108
  evidenceIds: storedIds,
13026
13109
  pageDiagnostics,
@@ -13052,23 +13135,23 @@ function createCollectorLedger(config, options) {
13052
13135
  contextView: projectObserveContextView(modelView)
13053
13136
  };
13054
13137
  },
13055
- async request(input, transport, clock2, signal) {
13138
+ async request(input2, transport, clock2, signal) {
13056
13139
  assertNotFatal();
13057
- if (activationTime === void 0 || deadlineTime === void 0) {
13140
+ if (!sessionReady) {
13058
13141
  throw latchFatal("\u901A\u8FDB\u53F8\u8BF7\u6C42\u9700\u8981\u6FC0\u6D3B");
13059
13142
  }
13060
13143
  if (ledger.unresolvedTransportFailure) {
13061
13144
  throw latchFatal("\u901A\u8FDB\u53F8\u8BF7\u6C42\u65F6\u5B58\u5728\u672A\u6062\u590D\u7684\u4F20\u8F93\u5931\u8D25");
13062
13145
  }
13063
- if (typeof input.requestId !== "string") {
13146
+ if (typeof input2.requestId !== "string") {
13064
13147
  throw new Error("\u901A\u8FDB\u53F8 requestId \u987B\u4E3A\u5B57\u7B26\u4E32");
13065
13148
  }
13066
- const requestId = input.requestId.trim();
13149
+ const requestId = input2.requestId.trim();
13067
13150
  if (requestId.length === 0) {
13068
13151
  throw new Error("\u901A\u8FDB\u53F8 requestId \u987B\u4E3A\u975E\u7A7A\uFF08\u9996\u5C3E\u7A7A\u767D\u4E0D\u6784\u6210\u8EAB\u4EFD\uFF09");
13069
13152
  }
13070
13153
  const configured = config.manifest.requests.find((item) => item.id === requestId);
13071
- const roleBody = typeof input.body === "string" ? input.body : void 0;
13154
+ const roleBody = typeof input2.body === "string" ? input2.body : void 0;
13072
13155
  if (configured === void 0) {
13073
13156
  if (roleBody === void 0 || roleBody.trim().length === 0) {
13074
13157
  throw new Error(
@@ -13076,9 +13159,9 @@ function createCollectorLedger(config, options) {
13076
13159
  );
13077
13160
  }
13078
13161
  }
13079
- const snapshot = snapshots.find((item) => item.snapshotId === input.snapshotId);
13162
+ const snapshot = snapshots.find((item) => item.snapshotId === input2.snapshotId);
13080
13163
  if (snapshot === void 0) {
13081
- throw new Error(`\u672A\u77E5\u901A\u8FDB\u53F8 snapshotId "${input.snapshotId}"`);
13164
+ throw new Error(`\u672A\u77E5\u901A\u8FDB\u53F8 snapshotId "${input2.snapshotId}"`);
13082
13165
  }
13083
13166
  if (snapshot.snapshotId !== latestCompleteSnapshotId) {
13084
13167
  throw new Error("\u901A\u8FDB\u53F8\u8BF7\u6C42\u8981\u6C42\u6700\u65B0\u5B8C\u6574\u5FEB\u7167");
@@ -13088,7 +13171,7 @@ function createCollectorLedger(config, options) {
13088
13171
  }
13089
13172
  if (pastCutoff(clock2)) {
13090
13173
  finalObservationRequired = true;
13091
- throw latchFatal("\u901A\u8FDB\u53F8\u8BF7\u6C42\u4E0D\u5728\u8D44\u683C\u622A\u6B62\u524D");
13174
+ throw new CollectorWaitWindowClosedError("request");
13092
13175
  }
13093
13176
  const configuredBody = configured?.requestBody ?? roleBody;
13094
13177
  const { body, marker } = buildCollectorRequestBody({
@@ -13190,22 +13273,20 @@ function createCollectorLedger(config, options) {
13190
13273
  journalRequest(void 0);
13191
13274
  throw latchFatal(`\u901A\u8FDB\u53F8\u8BF7\u6C42\u88AB\u62D2\uFF1A${result.diagnostics}`);
13192
13275
  },
13193
- async wait(input, clock2, signal) {
13276
+ async wait(input2, clock2, signal) {
13194
13277
  assertNotFatal();
13195
- if (activationTime === void 0) {
13278
+ if (!sessionReady) {
13196
13279
  throw latchFatal("\u901A\u8FDB\u53F8\u7B49\u5F85\u9700\u8981\u6FC0\u6D3B");
13197
13280
  }
13281
+ if (activationTime === void 0 || deadlineTime === void 0) {
13282
+ throw new CollectorWaitWindowClosedError("wait-before-open");
13283
+ }
13198
13284
  if (pastCutoff(clock2)) {
13199
13285
  finalObservationRequired = true;
13200
- throw latchFatal("\u901A\u8FDB\u53F8\u7B49\u5F85\u4E0D\u5728\u8D44\u683C\u622A\u6B62\u524D");
13286
+ throw new CollectorWaitWindowClosedError("wait");
13201
13287
  }
13202
13288
  const remaining = remainingMs(clock2);
13203
- const COLLECTOR_SINGLE_WAIT_MAX_MS = 3e5;
13204
- const effectiveMs = Math.min(
13205
- input.durationMs,
13206
- remaining,
13207
- COLLECTOR_SINGLE_WAIT_MAX_MS
13208
- );
13289
+ const effectiveMs = Math.min(input2.durationMs, remaining);
13209
13290
  const startedAt = clock2.wallNow().toISOString();
13210
13291
  const waitId = sha256Text(`wait:${startedAt}:${effectiveMs}`).slice(0, 16);
13211
13292
  await clock2.sleep(effectiveMs, signal);
@@ -13213,7 +13294,7 @@ function createCollectorLedger(config, options) {
13213
13294
  const cutoffReached = pastCutoff(clock2);
13214
13295
  const record4 = {
13215
13296
  waitId,
13216
- requestedMs: input.durationMs,
13297
+ requestedMs: input2.durationMs,
13217
13298
  effectiveMs,
13218
13299
  startedAt,
13219
13300
  endedAt,
@@ -13225,7 +13306,7 @@ function createCollectorLedger(config, options) {
13225
13306
  });
13226
13307
  return {
13227
13308
  waitId,
13228
- requestedMs: input.durationMs,
13309
+ requestedMs: input2.durationMs,
13229
13310
  effectiveMs,
13230
13311
  cutoffReached,
13231
13312
  remainingMsAfter: remainingMs(clock2)
@@ -13284,6 +13365,7 @@ function buildObserveModelView(input) {
13284
13365
  completedAt: input.snapshot.completedAt,
13285
13366
  prState: input.snapshot.prState,
13286
13367
  headOid: input.snapshot.headOid,
13368
+ ...input.snapshot.prCreatedAt === void 0 ? {} : { prCreatedAt: input.snapshot.prCreatedAt },
13287
13369
  complete: input.snapshot.complete,
13288
13370
  evidence: relevant.map((record4) => projectEvidenceEntryView(record4)),
13289
13371
  requestAttempts: input.attempts.map((attempt) => ({
@@ -13296,7 +13378,7 @@ function buildObserveModelView(input) {
13296
13378
  }))
13297
13379
  };
13298
13380
  }
13299
- var COLLECTOR_OBSERVE_TOOL, COLLECTOR_READ_TOOL, COLLECTOR_REQUEST_TOOL, COLLECTOR_WAIT_TOOL, COLLECTOR_BIND_TARGET_TOOL, COLLECTOR_HANDBOOK_WRITE_TOOL, COLLECTOR_OPERATIONAL_TOOLS, COLLECTOR_OBSERVE_BODY_HEAD_BYTES, COLLECTOR_ACTIVATION_ENTRY_TYPE, COLLECTOR_SNAPSHOT_ENTRY_TYPE, COLLECTOR_REQUEST_ENTRY_TYPE, COLLECTOR_WAIT_ENTRY_TYPE;
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;
13300
13382
  var init_collector_ledger = __esm({
13301
13383
  "src/collector-ledger.ts"() {
13302
13384
  "use strict";
@@ -13308,6 +13390,7 @@ var init_collector_ledger = __esm({
13308
13390
  COLLECTOR_READ_TOOL = "ak_collector_read";
13309
13391
  COLLECTOR_REQUEST_TOOL = "ak_collector_request";
13310
13392
  COLLECTOR_WAIT_TOOL = "ak_collector_wait";
13393
+ COLLECTOR_OPEN_WAIT_WINDOW_TOOL = "ak_collector_open_wait_window";
13311
13394
  COLLECTOR_BIND_TARGET_TOOL = "ak_collector_bind_target";
13312
13395
  COLLECTOR_HANDBOOK_WRITE_TOOL = "ak_collector_handbook_write";
13313
13396
  COLLECTOR_OPERATIONAL_TOOLS = [
@@ -13315,6 +13398,7 @@ var init_collector_ledger = __esm({
13315
13398
  COLLECTOR_OBSERVE_TOOL,
13316
13399
  COLLECTOR_READ_TOOL,
13317
13400
  COLLECTOR_REQUEST_TOOL,
13401
+ COLLECTOR_OPEN_WAIT_WINDOW_TOOL,
13318
13402
  COLLECTOR_WAIT_TOOL,
13319
13403
  COLLECTOR_HANDBOOK_WRITE_TOOL
13320
13404
  ];
@@ -20212,11 +20296,10 @@ var init_atomic_write = __esm({
20212
20296
 
20213
20297
  // src/collector-tool-schemas.ts
20214
20298
  import { Type as Type19 } from "typebox";
20215
- var collectorObserveArgsSchema, COLLECTOR_REQUEST_ID_PATTERN, collectorRequestArgsSchema, COLLECTOR_HANDBOOK_MAX_BYTES, collectorHandbookWriteArgsSchema, collectorReadArgsSchema, collectorWaitArgsSchema, collectorBindTargetArgsSchema, collectorFindingItemDeclaration, collectorOutputBaseSchema, collectorOutputArgsSchema;
20299
+ var collectorObserveArgsSchema, COLLECTOR_REQUEST_ID_PATTERN, collectorRequestArgsSchema, COLLECTOR_HANDBOOK_MAX_BYTES, collectorHandbookWriteArgsSchema, collectorReadArgsSchema, collectorWaitArgsSchema, collectorOpenWaitWindowArgsSchema, collectorBindTargetArgsSchema, collectorFindingItemDeclaration, collectorOutputBaseSchema, collectorOutputArgsSchema;
20216
20300
  var init_collector_tool_schemas = __esm({
20217
20301
  "src/collector-tool-schemas.ts"() {
20218
20302
  "use strict";
20219
- init_collector_evidence();
20220
20303
  init_open_tool_schema();
20221
20304
  init_terminating_infrastructure();
20222
20305
  collectorObserveArgsSchema = Type19.Object({}, { additionalProperties: false });
@@ -20247,7 +20330,16 @@ var init_collector_tool_schemas = __esm({
20247
20330
  evidenceId: Type19.String({ minLength: 1, description: "observe \u8FD4\u56DE\u7684\u6750\u6599\u8BC1\u636E id\uFF08evidenceId\uFF09" })
20248
20331
  }, { additionalProperties: false });
20249
20332
  collectorWaitArgsSchema = Type19.Object({
20250
- durationMs: Type19.Integer({ minimum: 1, maximum: COLLECTOR_ELIGIBILITY_MS, description: "\u7B49\u5F85\u6BEB\u79D2\uFF1B\u5355\u6B21\u4E0A\u9650\u4E94\u5206\u949F\u4E14\u4E0D\u8D85\u5269\u4F59\u8D44\u683C" })
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
+ }))
20251
20343
  }, { additionalProperties: false });
20252
20344
  collectorBindTargetArgsSchema = Type19.Object({
20253
20345
  prNumber: Type19.Optional(Type19.Unknown({
@@ -20523,6 +20615,15 @@ var init_collector_receipt = __esm({
20523
20615
  });
20524
20616
 
20525
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
+ }
20526
20627
  function buildMethodContext(activation) {
20527
20628
  const pr = activation.ledger.config.prNumber;
20528
20629
  const handbook = activation.handbookView;
@@ -20531,6 +20632,7 @@ function buildMethodContext(activation) {
20531
20632
  `host: github.com`,
20532
20633
  `repository: ${activation.repository.canonical}`,
20533
20634
  `prNumber: ${pr === void 0 ? "\u672A\u7ED1\u5B9A" : String(pr)}`,
20635
+ `waitWindowMs: ${String(activation.ledger.config.waitWindowMs)}`,
20534
20636
  `requests: ${JSON.stringify(activation.manifest.requests.map((request) => ({ id: request.id })))}`,
20535
20637
  `handbookGeneralSource: ${handbook.generalSource}`,
20536
20638
  `handbookRepoSource: ${handbook.repoSource}`,
@@ -20563,6 +20665,7 @@ function createCollectorRoleRuntime(pi, dependencies, hostActions) {
20563
20665
  const repoFlag = pi.getFlag("ak-collector-repo");
20564
20666
  const prFlag = pi.getFlag("ak-collector-pr");
20565
20667
  const requestManifestFlag = pi.getFlag("ak-collector-request-manifest");
20668
+ const waitMsFlag = pi.getFlag("ak-collector-wait-ms");
20566
20669
  if (typeof repoFlag !== "string" || repoFlag.trim().length === 0) {
20567
20670
  throw new Error("Collector requires --ak-collector-repo");
20568
20671
  }
@@ -20574,10 +20677,11 @@ function createCollectorRoleRuntime(pi, dependencies, hostActions) {
20574
20677
  prNumber = parseCollectorPrNumber(prFlag);
20575
20678
  }
20576
20679
  const manifest = typeof requestManifestFlag === "string" && requestManifestFlag.trim().length > 0 ? await loadCollectorManifest(requestManifestFlag) : emptyCollectorManifest();
20680
+ const waitWindowMs = parseWaitWindowMsFlag(waitMsFlag);
20577
20681
  const clock = dependencies.createClock?.() ?? createSystemCollectorClock();
20578
20682
  const transport = dependencies.createTransport();
20579
20683
  const ledger = dependencies.createLedger(
20580
- { repository, prNumber, manifest },
20684
+ { repository, prNumber, manifest, waitWindowMs },
20581
20685
  clock,
20582
20686
  ctx
20583
20687
  );
@@ -20840,11 +20944,57 @@ function createCollectorRoleRuntime(pi, dependencies, hostActions) {
20840
20944
  }
20841
20945
  }
20842
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
+ });
20843
20993
  pi.registerTool({
20844
20994
  name: COLLECTOR_WAIT_TOOL,
20845
20995
  label: "\u901A\u8FDB\u53F8\u7B49\u5F85",
20846
- description: "\u518D\u89C2\u5BDF\u524D\u7B49\u5F85\uFF1B\u5355\u6B21\u4E0A\u9650\u4E94\u5206\u949F\u4E14\u4E0D\u8D85\u5269\u4F59\u8D44\u683C\u3002",
20847
- 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",
20848
20998
  parameters: waitSchema,
20849
20999
  async execute(toolCallId, params, signal, _onUpdate, ctx) {
20850
21000
  const activation = getActivation();
@@ -20865,6 +21015,7 @@ function createCollectorRoleRuntime(pi, dependencies, hostActions) {
20865
21015
  details
20866
21016
  };
20867
21017
  } catch (error) {
21018
+ if (isCorrectableExecuteError(error)) throw error;
20868
21019
  hostActions.failInfrastructure(error, ctx, toolCallId);
20869
21020
  }
20870
21021
  }
@@ -20917,7 +21068,7 @@ function createCollectorRoleRuntime(pi, dependencies, hostActions) {
20917
21068
  }
20918
21069
  };
20919
21070
  }
20920
- var CollectorNormalCompletionDeclarationError, CollectorTargetBindError, COLLECTOR_REQUIRED_TOOLS, COLLECTOR_TRANSPORT_FLAGS, observeSchema, readSchema, requestSchema, waitSchema, bindSchema, handbookWriteSchema, outputSchema;
21071
+ var CollectorNormalCompletionDeclarationError, CollectorTargetBindError, COLLECTOR_REQUIRED_TOOLS, COLLECTOR_TRANSPORT_FLAGS, observeSchema, readSchema, requestSchema, openWaitWindowSchema, waitSchema, bindSchema, handbookWriteSchema, outputSchema;
20921
21072
  var init_collector_role = __esm({
20922
21073
  "src/collector-role.ts"() {
20923
21074
  "use strict";
@@ -20949,6 +21100,7 @@ var init_collector_role = __esm({
20949
21100
  COLLECTOR_OBSERVE_TOOL,
20950
21101
  COLLECTOR_READ_TOOL,
20951
21102
  COLLECTOR_REQUEST_TOOL,
21103
+ COLLECTOR_OPEN_WAIT_WINDOW_TOOL,
20952
21104
  COLLECTOR_WAIT_TOOL,
20953
21105
  COLLECTOR_HANDBOOK_WRITE_TOOL,
20954
21106
  COLLECTOR_OUTPUT_TOOL
@@ -20974,11 +21126,19 @@ var init_collector_role = __esm({
20974
21126
  description: "Path to the Collector v1 request manifest JSON file.",
20975
21127
  type: "string"
20976
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
+ })
20977
21136
  })
20978
21137
  ]);
20979
21138
  observeSchema = collectorObserveArgsSchema;
20980
21139
  readSchema = collectorReadArgsSchema;
20981
21140
  requestSchema = collectorRequestArgsSchema;
21141
+ openWaitWindowSchema = collectorOpenWaitWindowArgsSchema;
20982
21142
  waitSchema = collectorWaitArgsSchema;
20983
21143
  bindSchema = collectorBindTargetArgsSchema;
20984
21144
  handbookWriteSchema = collectorHandbookWriteArgsSchema;
@@ -26108,6 +26268,7 @@ function projectAcpActivationFlags(request) {
26108
26268
  flags.set("ak-collector-repo", activation.repo);
26109
26269
  if (activation.pr !== void 0) flags.set("ak-collector-pr", activation.pr);
26110
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);
26111
26272
  }
26112
26273
  return flags;
26113
26274
  }
@@ -1,5 +1,6 @@
1
1
  import { createHash } from "node:crypto";
2
- export const COLLECTOR_ELIGIBILITY_MS = 15 * 60 * 1000;
2
+ /** Default collector wait window (D4): 10 minutes from the work-step open, not from session activation. */
3
+ export const COLLECTOR_DEFAULT_WAIT_WINDOW_MS = 10 * 60 * 1000;
3
4
  export function createSystemCollectorClock() {
4
5
  const start = process.hrtime.bigint();
5
6
  return {
@@ -76,6 +77,7 @@ export function normalizePullRequestEvidence(pr, observedAt) {
76
77
  number: pr.number,
77
78
  state: pr.state,
78
79
  headOid: pr.headOid,
80
+ createdAt: pr.createdAt ?? null,
79
81
  updatedAt: pr.updatedAt ?? null,
80
82
  htmlUrl: pr.url,
81
83
  });
@@ -89,6 +91,7 @@ export function normalizePullRequestEvidence(pr, observedAt) {
89
91
  state: pr.state,
90
92
  commitOid: pr.headOid,
91
93
  htmlUrl: pr.url,
94
+ // Version clock stays updatedAt. Create success for the wait window is snapshot.prCreatedAt only (#678).
92
95
  authoritativeTime: pr.updatedAt ?? null,
93
96
  firstObservedAt: observedAt,
94
97
  raw: pr.raw,
@@ -289,6 +289,7 @@ export function normalizePullRequest(raw) {
289
289
  number,
290
290
  state,
291
291
  headOid: head["sha"],
292
+ ...(typeof raw["created_at"] === "string" ? { createdAt: raw["created_at"] } : {}),
292
293
  ...(typeof raw["updated_at"] === "string" ? { updatedAt: raw["updated_at"] } : {}),
293
294
  url: htmlUrl,
294
295
  raw,