@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
@@ -1,9 +1,10 @@
1
1
  import { emptyCollectorManifest, loadCollectorManifest, parseCollectorPrNumber, parseCollectorRepository, } from "./collector-config.js";
2
- import { createSystemCollectorClock, } from "./collector-evidence.js";
2
+ import { COLLECTOR_DEFAULT_WAIT_WINDOW_MS, createSystemCollectorClock, } from "./collector-evidence.js";
3
3
  import { createGhApiRunner, listPullRequestNumbersByTicket, } from "./collector-github.js";
4
- import { COLLECTOR_BIND_TARGET_TOOL, COLLECTOR_OBSERVE_TOOL, COLLECTOR_OUTPUT_TOOL, COLLECTOR_READ_TOOL, COLLECTOR_REQUEST_TOOL, COLLECTOR_WAIT_TOOL, projectEvidenceEntryView, } from "./collector-ledger.js";
4
+ import { createCollectorHandbookStore, resolveCollectorHandbookRoot, } from "./collector-handbook.js";
5
+ import { COLLECTOR_BIND_TARGET_TOOL, COLLECTOR_HANDBOOK_WRITE_TOOL, COLLECTOR_OBSERVE_TOOL, COLLECTOR_OPEN_WAIT_WINDOW_TOOL, COLLECTOR_OUTPUT_TOOL, COLLECTOR_READ_TOOL, COLLECTOR_REQUEST_TOOL, COLLECTOR_WAIT_TOOL, projectEvidenceEntryView, } from "./collector-ledger.js";
5
6
  import { buildCollectorReceipt, } from "./collector-receipt.js";
6
- import { collectorBindTargetArgsSchema, collectorObserveArgsSchema, collectorOutputArgsSchema, collectorReadArgsSchema, collectorRequestArgsSchema, collectorWaitArgsSchema, } from "./collector-tool-schemas.js";
7
+ import { collectorBindTargetArgsSchema, collectorHandbookWriteArgsSchema, collectorObserveArgsSchema, collectorOpenWaitWindowArgsSchema, collectorOutputArgsSchema, collectorReadArgsSchema, collectorRequestArgsSchema, collectorWaitArgsSchema, } from "./collector-tool-schemas.js";
7
8
  import { COLLECTOR_ACCEPTED_TEXT } from "./package-contracts/collector-output.js";
8
9
  import { CorrectableSubmissionError, isCorrectableExecuteError } from "./submission-correctable-error.js";
9
10
  import { CollectorUnknownEvidenceError } from "./collector-identity.js";
@@ -26,13 +27,15 @@ export class CollectorTargetBindError extends CorrectableSubmissionError {
26
27
  this.name = "CollectorTargetBindError";
27
28
  }
28
29
  }
29
- export { COLLECTOR_BIND_TARGET_TOOL, COLLECTOR_OBSERVE_TOOL, COLLECTOR_OUTPUT_TOOL, COLLECTOR_READ_TOOL, COLLECTOR_REQUEST_TOOL, COLLECTOR_WAIT_TOOL, };
30
+ export { COLLECTOR_BIND_TARGET_TOOL, COLLECTOR_HANDBOOK_WRITE_TOOL, COLLECTOR_OBSERVE_TOOL, COLLECTOR_OPEN_WAIT_WINDOW_TOOL, COLLECTOR_OUTPUT_TOOL, COLLECTOR_READ_TOOL, COLLECTOR_REQUEST_TOOL, COLLECTOR_WAIT_TOOL, };
30
31
  export const COLLECTOR_REQUIRED_TOOLS = [
31
32
  COLLECTOR_BIND_TARGET_TOOL,
32
33
  COLLECTOR_OBSERVE_TOOL,
33
34
  COLLECTOR_READ_TOOL,
34
35
  COLLECTOR_REQUEST_TOOL,
36
+ COLLECTOR_OPEN_WAIT_WINDOW_TOOL,
35
37
  COLLECTOR_WAIT_TOOL,
38
+ COLLECTOR_HANDBOOK_WRITE_TOOL,
36
39
  COLLECTOR_OUTPUT_TOOL,
37
40
  ];
38
41
  /** Envelope-owned transport flags (ADR 0018 / #676 E). */
@@ -58,23 +61,61 @@ export const COLLECTOR_TRANSPORT_FLAGS = Object.freeze([
58
61
  type: "string",
59
62
  }),
60
63
  }),
64
+ Object.freeze({
65
+ name: "ak-collector-wait-ms",
66
+ definition: Object.freeze({
67
+ 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).`,
68
+ type: "string",
69
+ }),
70
+ }),
61
71
  ]);
62
72
  const observeSchema = collectorObserveArgsSchema;
63
73
  const readSchema = collectorReadArgsSchema;
64
74
  const requestSchema = collectorRequestArgsSchema;
75
+ const openWaitWindowSchema = collectorOpenWaitWindowArgsSchema;
65
76
  const waitSchema = collectorWaitArgsSchema;
66
77
  const bindSchema = collectorBindTargetArgsSchema;
78
+ const handbookWriteSchema = collectorHandbookWriteArgsSchema;
67
79
  const outputSchema = collectorOutputArgsSchema;
80
+ function parseWaitWindowMsFlag(raw) {
81
+ if (raw === undefined || raw === null || raw === "")
82
+ return COLLECTOR_DEFAULT_WAIT_WINDOW_MS;
83
+ if (typeof raw === "number" && Number.isSafeInteger(raw) && raw >= 1)
84
+ return raw;
85
+ if (typeof raw === "string" && /^[1-9]\d*$/.test(raw.trim())) {
86
+ const value = Number(raw.trim());
87
+ if (Number.isSafeInteger(value) && value >= 1)
88
+ return value;
89
+ }
90
+ throw new Error("Collector --ak-collector-wait-ms must be a positive safe-integer millisecond string");
91
+ }
68
92
  function buildMethodContext(activation) {
69
93
  const pr = activation.ledger.config.prNumber;
70
- return [
94
+ const handbook = activation.handbookView;
95
+ const lines = [
71
96
  "<collector_method>",
72
97
  `host: github.com`,
73
98
  `repository: ${activation.repository.canonical}`,
74
- `prNumber: ${pr === undefined ? "unbound — call ak_collector_bind_target with the role-decided issue/PR before observe" : String(pr)}`,
99
+ `prNumber: ${pr === undefined ? "未绑定" : String(pr)}`,
100
+ `waitWindowMs: ${String(activation.ledger.config.waitWindowMs)}`,
75
101
  `requests: ${JSON.stringify(activation.manifest.requests.map((request) => ({ id: request.id })))}`,
102
+ `handbookGeneralSource: ${handbook.generalSource}`,
103
+ `handbookRepoSource: ${handbook.repoSource}`,
76
104
  "</collector_method>",
77
- ].join("\n");
105
+ ];
106
+ // Opaque working memory only — no directional instructions (ADR 0073).
107
+ // JSON + `<` → \u003c keeps bodies from forging the delivery close tag (#677).
108
+ if (handbook.general.length > 0 || handbook.repo.length > 0) {
109
+ const payload = JSON.stringify({
110
+ general: handbook.general,
111
+ repo: handbook.repo,
112
+ generalSource: handbook.generalSource,
113
+ repoSource: handbook.repoSource,
114
+ repository: activation.repository.canonical,
115
+ }).replaceAll("<", "\\u003c");
116
+ lines.push("", "<collector_handbook>", payload, "</collector_handbook>");
117
+ }
118
+ return lines.join("\n");
78
119
  }
79
120
  function parsePositiveTicket(raw, label) {
80
121
  if (raw === undefined || raw === null)
@@ -83,7 +124,7 @@ function parsePositiveTicket(raw, label) {
83
124
  return raw;
84
125
  if (typeof raw === "string" && /^[1-9]\d*$/.test(raw.trim()))
85
126
  return Number(raw.trim());
86
- throw new CollectorTargetBindError(`ak_collector_bind_target ${label} must be a positive safe integer`);
127
+ throw new CollectorTargetBindError(`通进司绑定 ${label} 须为正安全整数`);
87
128
  }
88
129
  /**
89
130
  * Shared envelope installs business tools and material callback after lifecycle gates.
@@ -100,6 +141,7 @@ export function createCollectorRoleRuntime(pi, dependencies, hostActions) {
100
141
  const repoFlag = pi.getFlag("ak-collector-repo");
101
142
  const prFlag = pi.getFlag("ak-collector-pr");
102
143
  const requestManifestFlag = pi.getFlag("ak-collector-request-manifest");
144
+ const waitMsFlag = pi.getFlag("ak-collector-wait-ms");
103
145
  if (typeof repoFlag !== "string" || repoFlag.trim().length === 0) {
104
146
  throw new Error("Collector requires --ak-collector-repo");
105
147
  }
@@ -115,9 +157,29 @@ export function createCollectorRoleRuntime(pi, dependencies, hostActions) {
115
157
  const manifest = typeof requestManifestFlag === "string" && requestManifestFlag.trim().length > 0
116
158
  ? await loadCollectorManifest(requestManifestFlag)
117
159
  : emptyCollectorManifest();
160
+ const waitWindowMs = parseWaitWindowMsFlag(waitMsFlag);
118
161
  const clock = dependencies.createClock?.() ?? createSystemCollectorClock();
119
162
  const transport = dependencies.createTransport();
120
- const ledger = dependencies.createLedger({ repository, prNumber, manifest }, clock, ctx);
163
+ const ledger = dependencies.createLedger({ repository, prNumber, manifest, waitWindowMs }, clock, ctx);
164
+ // #677: handbook under admitted book topology (session path → books/<key>/collector-handbook).
165
+ const sessionPath = ctx.sessionManager?.getSessionFile?.()
166
+ ?? ctx.sessionManager?.getSessionDir?.();
167
+ if (typeof sessionPath !== "string" || sessionPath.length === 0) {
168
+ throw new Error("通进司手册要求 session 路径位于 books/<bookKey>/");
169
+ }
170
+ const placement = resolveCollectorHandbookRoot(sessionPath);
171
+ const seedGeneral = dependencies.loadHandbookSeed === undefined
172
+ ? undefined
173
+ : (await dependencies.loadHandbookSeed()).trim();
174
+ const handbook = createCollectorHandbookStore({
175
+ ledgerHome: placement.ledgerHome,
176
+ handbookRoot: placement.root,
177
+ repositoryCanonical: repository.canonical,
178
+ ...(seedGeneral === undefined || seedGeneral.length === 0
179
+ ? {}
180
+ : { seedGeneral }),
181
+ });
182
+ const handbookView = await handbook.read();
121
183
  return {
122
184
  soul,
123
185
  repository,
@@ -125,6 +187,8 @@ export function createCollectorRoleRuntime(pi, dependencies, hostActions) {
125
187
  ledger,
126
188
  transport,
127
189
  clock,
190
+ handbook,
191
+ handbookView,
128
192
  };
129
193
  },
130
194
  assembleMaterials(activation, baseSystemPrompt) {
@@ -180,7 +244,7 @@ export function createCollectorRoleRuntime(pi, dependencies, hostActions) {
180
244
  const prNumber = parsePositiveTicket(params.prNumber, "prNumber");
181
245
  const issueNumber = parsePositiveTicket(params.issueNumber, "issueNumber");
182
246
  if (prNumber === undefined && issueNumber === undefined) {
183
- throw new CollectorTargetBindError("ak_collector_bind_target requires role-decided prNumber and/or issueNumber");
247
+ throw new CollectorTargetBindError("通进司绑定须由角色判定 prNumber 与/或 issueNumber");
184
248
  }
185
249
  let bound = prNumber;
186
250
  if (issueNumber !== undefined) {
@@ -190,14 +254,14 @@ export function createCollectorRoleRuntime(pi, dependencies, hostActions) {
190
254
  ticketNumber: issueNumber,
191
255
  });
192
256
  if (associated.length === 0) {
193
- throw new CollectorTargetBindError(`no PR associated with issue #${issueNumber} in ${activation.repository.canonical}; pass an explicit --pr or a different issueNumber`);
257
+ throw new CollectorTargetBindError(`${activation.repository.canonical} 的 issue #${issueNumber} 无关联 PR;请改用明确 --pr 或其他 issueNumber`);
194
258
  }
195
259
  if (associated.length > 1) {
196
- throw new CollectorTargetBindError(`multiple PRs associated with issue #${issueNumber}: ${associated.join(", ")}; pass an explicit prNumber or --pr`);
260
+ throw new CollectorTargetBindError(`issue #${issueNumber} 关联多个 PR:${associated.join("、")};请改用明确 prNumber 或 --pr`);
197
261
  }
198
262
  const fromIssue = associated[0];
199
263
  if (prNumber !== undefined && prNumber !== fromIssue) {
200
- throw new CollectorTargetBindError(`prNumber ${prNumber} conflicts with issue #${issueNumber} association PR ${fromIssue}`);
264
+ throw new CollectorTargetBindError(`prNumber ${prNumber} 与 issue #${issueNumber} 关联 PR ${fromIssue} 冲突`);
201
265
  }
202
266
  bound = fromIssue;
203
267
  }
@@ -297,8 +361,8 @@ export function createCollectorRoleRuntime(pi, dependencies, hostActions) {
297
361
  pi.registerTool({
298
362
  name: COLLECTOR_REQUEST_TOOL,
299
363
  label: "通进司请求",
300
- description: "按配置请求体与关联标记,在所引最新快照 HEAD 发一次请求。",
301
- promptSnippet: "按配置发一次请求",
364
+ description: "在所引最新快照 HEAD 发一次请求。requestId 可取配置清单,或角色依手册/现场判定的稳定 id;后者须同时提供 body。",
365
+ promptSnippet: "发一次评审请求",
302
366
  parameters: requestSchema,
303
367
  async execute(toolCallId, params, signal, _onUpdate, ctx) {
304
368
  const activation = getActivation();
@@ -306,7 +370,11 @@ export function createCollectorRoleRuntime(pi, dependencies, hostActions) {
306
370
  throw new Error("通进司未激活");
307
371
  try {
308
372
  activation.ledger.beginOperational(COLLECTOR_REQUEST_TOOL, toolCallId);
309
- const details = await activation.ledger.request(params, activation.transport, activation.clock, signal);
373
+ const details = await activation.ledger.request({
374
+ requestId: params.requestId,
375
+ snapshotId: params.snapshotId,
376
+ ...(typeof params.body === "string" ? { body: params.body } : {}),
377
+ }, activation.transport, activation.clock, signal);
310
378
  activation.ledger.completeOperational(toolCallId);
311
379
  return {
312
380
  content: [{
@@ -323,11 +391,105 @@ export function createCollectorRoleRuntime(pi, dependencies, hostActions) {
323
391
  }
324
392
  },
325
393
  });
394
+ pi.registerTool({
395
+ name: COLLECTOR_HANDBOOK_WRITE_TOOL,
396
+ label: "通进司手册写入",
397
+ description: "写入通用手册或当前仓库差异全文(整份替换)。",
398
+ promptSnippet: "更新 bot 手册",
399
+ parameters: handbookWriteSchema,
400
+ async execute(toolCallId, params, _signal, _onUpdate, ctx) {
401
+ const activation = getActivation();
402
+ if (activation === undefined)
403
+ throw new Error("通进司未激活");
404
+ try {
405
+ activation.ledger.beginOperational(COLLECTOR_HANDBOOK_WRITE_TOOL, toolCallId);
406
+ // scope/body shape authority = collectorHandbookWriteArgsSchema (host parameters).
407
+ const details = await activation.handbook.write(params.scope, params.body);
408
+ activation.handbookView = await activation.handbook.read();
409
+ activation.ledger.completeOperational(toolCallId);
410
+ return {
411
+ content: [{
412
+ type: "text",
413
+ text: `手册已写入:${details.scope}`,
414
+ }],
415
+ details: {
416
+ scope: details.scope,
417
+ path: details.path,
418
+ byteLength: details.byteLength,
419
+ generalSource: activation.handbookView.generalSource,
420
+ repoSource: activation.handbookView.repoSource,
421
+ },
422
+ };
423
+ }
424
+ catch (error) {
425
+ if (isCorrectableExecuteError(error))
426
+ throw error;
427
+ hostActions.failInfrastructure(error, ctx, toolCallId);
428
+ }
429
+ finally {
430
+ try {
431
+ activation.ledger.completeOperational(toolCallId);
432
+ }
433
+ catch {
434
+ // already completed or not begun
435
+ }
436
+ }
437
+ },
438
+ });
439
+ pi.registerTool({
440
+ name: COLLECTOR_OPEN_WAIT_WINDOW_TOOL,
441
+ label: "通进司开启等待窗",
442
+ description: "在工作步骤上开启等待窗:新建并自动触发的 PR 传创建成功时刻;已有 PR 在触发阶段结束后省略 startedAt(=现在)。窗长由使用方配置,默认十分钟;开启后不因 PR 更新重置。",
443
+ promptSnippet: "按工作步骤开启等待窗",
444
+ parameters: openWaitWindowSchema,
445
+ async execute(toolCallId, params, _signal, _onUpdate, ctx) {
446
+ const activation = getActivation();
447
+ if (activation === undefined)
448
+ throw new Error("通进司未激活");
449
+ try {
450
+ activation.ledger.beginOperational(COLLECTOR_OPEN_WAIT_WINDOW_TOOL, toolCallId);
451
+ let startedAt;
452
+ if (typeof params.startedAt === "string" && params.startedAt.trim().length > 0) {
453
+ const parsed = new Date(params.startedAt);
454
+ if (Number.isNaN(parsed.getTime())) {
455
+ throw new Error("通进司等待窗 startedAt 须为有效 ISO 时间");
456
+ }
457
+ startedAt = parsed;
458
+ }
459
+ activation.ledger.openWaitWindow(activation.clock, startedAt === undefined ? undefined : { startedAt });
460
+ activation.ledger.completeOperational(toolCallId);
461
+ return {
462
+ content: [{
463
+ type: "text",
464
+ text: "等待窗已开启",
465
+ }],
466
+ details: {
467
+ activationTime: activation.ledger.activationTime?.toISOString(),
468
+ deadlineTime: activation.ledger.deadlineTime?.toISOString(),
469
+ waitWindowMs: activation.ledger.config.waitWindowMs,
470
+ },
471
+ };
472
+ }
473
+ catch (error) {
474
+ if (isCorrectableExecuteError(error))
475
+ throw error;
476
+ hostActions.failInfrastructure(error, ctx, toolCallId);
477
+ }
478
+ finally {
479
+ try {
480
+ activation.ledger.completeOperational(toolCallId);
481
+ }
482
+ catch {
483
+ // already completed or not begun
484
+ }
485
+ }
486
+ },
487
+ });
326
488
  pi.registerTool({
327
489
  name: COLLECTOR_WAIT_TOOL,
328
490
  label: "通进司等待",
329
- description: "再观察前等待;单次上限五分钟且不超剩余资格。",
330
- promptSnippet: "资格截止前等待",
491
+ description: "再观察前等待;实际睡眠不超过剩余等待窗。",
492
+ promptSnippet: "等待窗内等待",
331
493
  parameters: waitSchema,
332
494
  async execute(toolCallId, params, signal, _onUpdate, ctx) {
333
495
  const activation = getActivation();
@@ -346,6 +508,8 @@ export function createCollectorRoleRuntime(pi, dependencies, hostActions) {
346
508
  };
347
509
  }
348
510
  catch (error) {
511
+ if (isCorrectableExecuteError(error))
512
+ throw error;
349
513
  hostActions.failInfrastructure(error, ctx, toolCallId);
350
514
  }
351
515
  },
@@ -1,17 +1,54 @@
1
1
  import { Type } from "typebox";
2
- import { COLLECTOR_ELIGIBILITY_MS } from "./collector-evidence.js";
3
2
  import { openToolObject } from "./open-tool-schema.js";
4
3
  import { withInfrastructureFailureDeclaration } from "./package-contracts/terminating-infrastructure.js";
5
4
  export const collectorObserveArgsSchema = Type.Object({}, { additionalProperties: false });
5
+ /**
6
+ * Stable request identity: non-empty after trim, no leading/trailing whitespace.
7
+ * Host schema + ledger identity seam share this contract (#677 / D2 dedup).
8
+ */
9
+ export const COLLECTOR_REQUEST_ID_PATTERN = /^\S(?:.*\S)?$/;
6
10
  export const collectorRequestArgsSchema = Type.Object({
7
- requestId: Type.String({ minLength: 1, description: "配置请求身份" }),
11
+ requestId: Type.String({
12
+ minLength: 1,
13
+ pattern: COLLECTOR_REQUEST_ID_PATTERN.source,
14
+ description: "请求身份(配置 id 或角色判定的稳定 id;首尾无空白)",
15
+ }),
8
16
  snapshotId: Type.String({ minLength: 1, description: "最新留存观察快照" }),
17
+ body: Type.Optional(Type.String({
18
+ minLength: 1,
19
+ description: "角色判定的请求正文;request-manifest 未收录该 requestId 时必填",
20
+ })),
21
+ }, { additionalProperties: false });
22
+ /** UTF-8 byte ceiling per handbook body — keeps next activation materials inside context budget. */
23
+ export const COLLECTOR_HANDBOOK_MAX_BYTES = 64 * 1024;
24
+ export const collectorHandbookWriteArgsSchema = Type.Object({
25
+ scope: Type.Union([
26
+ Type.Literal("general"),
27
+ Type.Literal("repo"),
28
+ ], { description: "general=通用手册;repo=当前仓库差异" }),
29
+ body: Type.String({
30
+ description: `手册全文(opaque 工作记忆;整份替换;UTF-8 至多 ${COLLECTOR_HANDBOOK_MAX_BYTES} 字节)`,
31
+ }),
9
32
  }, { additionalProperties: false });
10
33
  export const collectorReadArgsSchema = Type.Object({
11
34
  evidenceId: Type.String({ minLength: 1, description: "observe 返回的材料证据 id(evidenceId)" }),
12
35
  }, { additionalProperties: false });
13
36
  export const collectorWaitArgsSchema = Type.Object({
14
- durationMs: Type.Integer({ minimum: 1, maximum: COLLECTOR_ELIGIBILITY_MS, description: "等待毫秒;单次上限五分钟且不超剩余资格" }),
37
+ durationMs: Type.Integer({
38
+ minimum: 1,
39
+ description: "等待毫秒;实际睡眠不超过剩余等待窗(#678;无包内单次任意上限)",
40
+ }),
41
+ }, { additionalProperties: false });
42
+ /**
43
+ * #678 D4: open the wait window at a work step.
44
+ * Omit startedAt for existing-PR trigger-phase end (= now).
45
+ * Pass PR creation success time for new-PR auto-trigger rounds.
46
+ */
47
+ export const collectorOpenWaitWindowArgsSchema = Type.Object({
48
+ startedAt: Type.Optional(Type.String({
49
+ minLength: 1,
50
+ description: "等待窗起点 ISO 时间;新建 PR 用创建成功时刻;省略=现在(触发阶段结束)",
51
+ })),
15
52
  }, { additionalProperties: false });
16
53
  /**
17
54
  * #676 A: role-decided target bind. The model judges task materials and submits