add-coder 0.3.33 → 0.3.34

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 (71) hide show
  1. package/package.json +1 -1
  2. package/templates/.add-coder-src-hash.json +70 -70
  3. package/templates/adapters/claude/hooks/doc-format-guard.mjs +4 -0
  4. package/templates/adapters/claude/hooks/notification.mjs +4 -0
  5. package/templates/adapters/claude/hooks/permission-denied.mjs +4 -0
  6. package/templates/adapters/claude/hooks/permission-gate.mjs +4 -0
  7. package/templates/adapters/claude/hooks/post-tool-use.mjs +4 -0
  8. package/templates/adapters/claude/hooks/pre-compact.mjs +4 -0
  9. package/templates/adapters/claude/hooks/pre-tool-use.mjs +4 -0
  10. package/templates/adapters/claude/hooks/prompt-submit.mjs +4 -0
  11. package/templates/adapters/claude/hooks/session-end.mjs +4 -0
  12. package/templates/adapters/claude/hooks/session-start.mjs +4 -0
  13. package/templates/adapters/claude/hooks/stop-check.mjs +87 -6
  14. package/templates/adapters/claude/hooks/stop-failure.mjs +4 -0
  15. package/templates/adapters/claude/hooks/subagent-guard.mjs +4 -0
  16. package/templates/adapters/claude/hooks/subagent-stop.mjs +4 -0
  17. package/templates/adapters/codex/hooks/doc-format-guard.mjs +4 -0
  18. package/templates/adapters/codex/hooks/notification.mjs +4 -0
  19. package/templates/adapters/codex/hooks/permission-gate.mjs +4 -0
  20. package/templates/adapters/codex/hooks/post-tool-failure.mjs +4 -0
  21. package/templates/adapters/codex/hooks/post-tool-use.mjs +4 -0
  22. package/templates/adapters/codex/hooks/pre-compact.mjs +4 -0
  23. package/templates/adapters/codex/hooks/pre-tool-use.mjs +4 -0
  24. package/templates/adapters/codex/hooks/prompt-submit.mjs +4 -0
  25. package/templates/adapters/codex/hooks/session-end.mjs +4 -0
  26. package/templates/adapters/codex/hooks/session-start.mjs +4 -0
  27. package/templates/adapters/codex/hooks/stop-check.mjs +87 -6
  28. package/templates/adapters/codex/hooks/subagent-guard.mjs +4 -0
  29. package/templates/adapters/codex/hooks/subagent-stop.mjs +4 -0
  30. package/templates/adapters/qoder/hooks/doc-format-guard.mjs +4 -0
  31. package/templates/adapters/qoder/hooks/notification.mjs +4 -0
  32. package/templates/adapters/qoder/hooks/permission-gate.mjs +4 -0
  33. package/templates/adapters/qoder/hooks/post-tool-failure.mjs +4 -0
  34. package/templates/adapters/qoder/hooks/post-tool-use.mjs +4 -0
  35. package/templates/adapters/qoder/hooks/pre-compact.mjs +4 -0
  36. package/templates/adapters/qoder/hooks/pre-tool-use.mjs +4 -0
  37. package/templates/adapters/qoder/hooks/prompt-submit.mjs +4 -0
  38. package/templates/adapters/qoder/hooks/review-checklist.mjs +4 -0
  39. package/templates/adapters/qoder/hooks/session-end.mjs +4 -0
  40. package/templates/adapters/qoder/hooks/session-start.mjs +4 -0
  41. package/templates/adapters/qoder/hooks/stop-check.mjs +87 -6
  42. package/templates/adapters/qoder/hooks/subagent-guard.mjs +4 -0
  43. package/templates/adapters/qoder/hooks/subagent-stop.mjs +4 -0
  44. package/templates/adapters/trae/hooks/doc-format-guard.mjs +4 -0
  45. package/templates/adapters/trae/hooks/notification.mjs +4 -0
  46. package/templates/adapters/trae/hooks/permission-gate.mjs +4 -0
  47. package/templates/adapters/trae/hooks/post-tool-failure.mjs +4 -0
  48. package/templates/adapters/trae/hooks/post-tool-use.mjs +4 -0
  49. package/templates/adapters/trae/hooks/pre-compact.mjs +4 -0
  50. package/templates/adapters/trae/hooks/pre-tool-use.mjs +4 -0
  51. package/templates/adapters/trae/hooks/prompt-submit.mjs +4 -0
  52. package/templates/adapters/trae/hooks/session-end.mjs +4 -0
  53. package/templates/adapters/trae/hooks/session-start.mjs +4 -0
  54. package/templates/adapters/trae/hooks/stop-check.mjs +87 -6
  55. package/templates/adapters/trae/hooks/subagent-guard.mjs +4 -0
  56. package/templates/adapters/trae/hooks/subagent-stop.mjs +4 -0
  57. package/templates/adapters/vscode/hooks/doc-format-guard.mjs +4 -0
  58. package/templates/adapters/vscode/hooks/notification.mjs +4 -0
  59. package/templates/adapters/vscode/hooks/permission-gate.mjs +4 -0
  60. package/templates/adapters/vscode/hooks/post-tool-failure.mjs +4 -0
  61. package/templates/adapters/vscode/hooks/post-tool-use.mjs +4 -0
  62. package/templates/adapters/vscode/hooks/pre-compact.mjs +4 -0
  63. package/templates/adapters/vscode/hooks/pre-tool-use.mjs +4 -0
  64. package/templates/adapters/vscode/hooks/prompt-submit.mjs +4 -0
  65. package/templates/adapters/vscode/hooks/session-end.mjs +4 -0
  66. package/templates/adapters/vscode/hooks/session-start.mjs +4 -0
  67. package/templates/adapters/vscode/hooks/stop-check.mjs +87 -6
  68. package/templates/adapters/vscode/hooks/subagent-guard.mjs +4 -0
  69. package/templates/adapters/vscode/hooks/subagent-stop.mjs +4 -0
  70. package/templates/core/governance/rules.ts +4 -0
  71. package/templates/core/governance/stop-router.ts +101 -7
@@ -117,6 +117,10 @@ var protocol = {
117
117
  ".trae",
118
118
  ".codex"
119
119
  ]
120
+ },
121
+ "stop": {
122
+ "max_prompt_per_context": 3,
123
+ "window_minutes": 30
120
124
  }
121
125
  };
122
126
 
@@ -122,6 +122,10 @@ var protocol = {
122
122
  ".trae",
123
123
  ".codex"
124
124
  ]
125
+ },
126
+ "stop": {
127
+ "max_prompt_per_context": 3,
128
+ "window_minutes": 30
125
129
  }
126
130
  };
127
131
 
@@ -195,6 +195,10 @@ var protocol = {
195
195
  ".trae",
196
196
  ".codex"
197
197
  ]
198
+ },
199
+ "stop": {
200
+ "max_prompt_per_context": 3,
201
+ "window_minutes": 30
198
202
  }
199
203
  };
200
204
 
@@ -409,6 +413,10 @@ function buildStopContext(quadrant, info) {
409
413
  }
410
414
 
411
415
  // templates/core/governance/stop-router.ts
416
+ import { createHash as createHash2 } from "node:crypto";
417
+ import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
418
+ import { tmpdir } from "node:os";
419
+ import { join as join2 } from "node:path";
412
420
  var StopRouter = class {
413
421
  /** 主路由:返回 exit code(0 放行 / 2 阻断) */
414
422
  run() {
@@ -437,14 +445,20 @@ var StopRouter = class {
437
445
  }
438
446
  // ─────────────────────────── 扩展点 ───────────────────────────
439
447
  /**
440
- * Q4 验收决策(双维度组合——2026-08-14 Task 9.4.4④ 上提,回流: I2):
441
- * 维度 1(前置): DB 任务进度(step = done/total,数值且 done<total 未完成阻断提示)
442
- * 维度 2: checklist 质量(checkAddCompleteness 未闭环阻断)
443
- * 互补非替代——codex DB 进度分流语义上提 core,core checklist 质量语义保留。
444
- */
448
+ * Q4 验收决策(双维度组合——2026-08-14 Task 9.4.4④ 上提,回流: I2):
449
+ * 维度 0(新增,临时方案): 弹框频控——同项目同 Plan 窗口内达上限降级放行
450
+ * 维度 1(前置): DB 任务进度(step = done/total,数值且 done<total 未完成阻断提示)
451
+ * 维度 2: checklist 质量(checkAddCompleteness 未闭环 阻断)
452
+ * 互补非替代——codex 原 DB 进度分流语义上提 core,core checklist 质量语义保留。
453
+ */
445
454
  q4Check(plan, rounds, step, handoff, addRoute) {
446
- void plan;
447
455
  void rounds;
456
+ const limited = this.stopPromptLimited(plan);
457
+ if (limited) {
458
+ process.stderr.write(`[ADD Stop] \u5DF2\u8FBE\u672C Plan \u5F39\u6846\u4E0A\u9650(${this.stopPromptMax()})\uFF0C\u672C\u6B21\u653E\u884C\u3002\u8BF7\u5728\u540E\u7EED\u5B9E\u65BD\u4E2D\u5B8C\u6210\u9A8C\u6536\u95ED\u73AF\uFF08devlog + handoff\uFF09\u540E\u505C\u6B62\u3002
459
+ `);
460
+ return 0;
461
+ }
448
462
  const [donePart, totalPart] = step.split("/");
449
463
  if (/^\d+$/.test(donePart) && /^\d+$/.test(totalPart) && Number(donePart) < Number(totalPart)) {
450
464
  return this.emitQ4Unclosed(
@@ -461,6 +475,73 @@ var StopRouter = class {
461
475
  clearDevAction();
462
476
  return this.emitQ4Pass();
463
477
  }
478
+ // ── 弹框频控(临时方案,规则真源: hook-protocol-rules.toml [protocol.stop])──
479
+ // 计数隔离: 文件级 = PROJECT_DIR md5(跨项目不互扰);key 级 = planName(同项目跨 Plan 不互扰)
480
+ // 故障降级: 哨兵读/写异常 → fail-open 放行(不阻塞主流程)
481
+ /** 哨兵记录:同一项目同一 Plan 的弹框计数 */
482
+ stopPromptMax() {
483
+ const cfg = protocol.stop;
484
+ return cfg?.max_prompt_per_context ?? 3;
485
+ }
486
+ /** 哨兵窗口(毫秒) */
487
+ stopPromptWindowMs() {
488
+ const cfg = protocol.stop;
489
+ return (cfg?.window_minutes ?? 30) * 6e4;
490
+ }
491
+ /** 哨兵文件路径(项目隔离:PROJECT_DIR md5) */
492
+ stopSentinelPath() {
493
+ const projectDir = process.env.PROJECT_DIR || process.env.QODER_PROJECT_DIR || process.env.QODERCN_PROJECT_DIR || process.env.CLAUDE_PROJECT_DIR || process.cwd();
494
+ const md5 = createHash2("md5").update(projectDir).digest("hex").slice(0, 8);
495
+ return join2(tmpdir(), `add_stop_${md5}.json`);
496
+ }
497
+ /** 写哨兵(失败静默,fail-open) */
498
+ writeStopPromptSentinel(data) {
499
+ try {
500
+ writeFileSync2(this.stopSentinelPath(), JSON.stringify(data), "utf-8");
501
+ } catch {
502
+ }
503
+ }
504
+ /**
505
+ * 频控判定:返回 true = 已达上限应放行(不弹框)
506
+ * 生成态缺失 protocol.stop(TOML 未同步)→ 跳过频控保持既有行为(生成链幂等校验兜底)
507
+ */
508
+ stopPromptLimited(plan) {
509
+ try {
510
+ const stopCfg = protocol.stop;
511
+ if (!stopCfg) return false;
512
+ const max = this.stopPromptMax();
513
+ const windowMs = this.stopPromptWindowMs();
514
+ const path3 = this.stopSentinelPath();
515
+ let data = {};
516
+ if (existsSync2(path3)) {
517
+ try {
518
+ data = JSON.parse(readFileSync2(path3, "utf-8")) ?? {};
519
+ } catch {
520
+ return true;
521
+ }
522
+ }
523
+ const now = Date.now();
524
+ const entry = data[plan];
525
+ if (!entry) {
526
+ data[plan] = { count: 1, lastPromptAt: now };
527
+ this.writeStopPromptSentinel(data);
528
+ return false;
529
+ }
530
+ if (now - entry.lastPromptAt > windowMs) {
531
+ data[plan] = { count: 1, lastPromptAt: now };
532
+ this.writeStopPromptSentinel(data);
533
+ return false;
534
+ }
535
+ if (entry.count >= max) {
536
+ return true;
537
+ }
538
+ data[plan] = { count: entry.count + 1, lastPromptAt: now };
539
+ this.writeStopPromptSentinel(data);
540
+ return false;
541
+ } catch {
542
+ return true;
543
+ }
544
+ }
464
545
  /** Q0: DB 不可用(core: stderr + 2) */
465
546
  emitQ0(reason) {
466
547
  process.stderr.write(
@@ -116,6 +116,10 @@ var protocol = {
116
116
  ".trae",
117
117
  ".codex"
118
118
  ]
119
+ },
120
+ "stop": {
121
+ "max_prompt_per_context": 3,
122
+ "window_minutes": 30
119
123
  }
120
124
  };
121
125
 
@@ -117,6 +117,10 @@ var protocol = {
117
117
  ".trae",
118
118
  ".codex"
119
119
  ]
120
+ },
121
+ "stop": {
122
+ "max_prompt_per_context": 3,
123
+ "window_minutes": 30
120
124
  }
121
125
  };
122
126
 
@@ -388,6 +388,10 @@ var protocol = {
388
388
  ".trae",
389
389
  ".codex"
390
390
  ]
391
+ },
392
+ "stop": {
393
+ "max_prompt_per_context": 3,
394
+ "window_minutes": 30
391
395
  }
392
396
  };
393
397
 
@@ -116,6 +116,10 @@ var protocol = {
116
116
  ".trae",
117
117
  ".codex"
118
118
  ]
119
+ },
120
+ "stop": {
121
+ "max_prompt_per_context": 3,
122
+ "window_minutes": 30
119
123
  }
120
124
  };
121
125
 
@@ -116,6 +116,10 @@ var protocol = {
116
116
  ".trae",
117
117
  ".codex"
118
118
  ]
119
+ },
120
+ "stop": {
121
+ "max_prompt_per_context": 3,
122
+ "window_minutes": 30
119
123
  }
120
124
  };
121
125
 
@@ -116,6 +116,10 @@ var protocol = {
116
116
  ".trae",
117
117
  ".codex"
118
118
  ]
119
+ },
120
+ "stop": {
121
+ "max_prompt_per_context": 3,
122
+ "window_minutes": 30
119
123
  }
120
124
  };
121
125
 
@@ -144,6 +144,10 @@ var protocol = {
144
144
  ".trae",
145
145
  ".codex"
146
146
  ]
147
+ },
148
+ "stop": {
149
+ "max_prompt_per_context": 3,
150
+ "window_minutes": 30
147
151
  }
148
152
  };
149
153
 
@@ -119,6 +119,10 @@ var protocol = {
119
119
  ".trae",
120
120
  ".codex"
121
121
  ]
122
+ },
123
+ "stop": {
124
+ "max_prompt_per_context": 3,
125
+ "window_minutes": 30
122
126
  }
123
127
  };
124
128
 
@@ -400,6 +400,10 @@ var protocol = {
400
400
  ".trae",
401
401
  ".codex"
402
402
  ]
403
+ },
404
+ "stop": {
405
+ "max_prompt_per_context": 3,
406
+ "window_minutes": 30
403
407
  }
404
408
  };
405
409
 
@@ -145,6 +145,10 @@ var protocol = {
145
145
  ".trae",
146
146
  ".codex"
147
147
  ]
148
+ },
149
+ "stop": {
150
+ "max_prompt_per_context": 3,
151
+ "window_minutes": 30
148
152
  }
149
153
  };
150
154
 
@@ -119,6 +119,10 @@ var protocol = {
119
119
  ".trae",
120
120
  ".codex"
121
121
  ]
122
+ },
123
+ "stop": {
124
+ "max_prompt_per_context": 3,
125
+ "window_minutes": 30
122
126
  }
123
127
  };
124
128
 
@@ -116,6 +116,10 @@ var protocol = {
116
116
  ".trae",
117
117
  ".codex"
118
118
  ]
119
+ },
120
+ "stop": {
121
+ "max_prompt_per_context": 3,
122
+ "window_minutes": 30
119
123
  }
120
124
  };
121
125
 
@@ -121,6 +121,10 @@ var protocol = {
121
121
  ".trae",
122
122
  ".codex"
123
123
  ]
124
+ },
125
+ "stop": {
126
+ "max_prompt_per_context": 3,
127
+ "window_minutes": 30
124
128
  }
125
129
  };
126
130
 
@@ -192,6 +192,10 @@ var protocol = {
192
192
  ".trae",
193
193
  ".codex"
194
194
  ]
195
+ },
196
+ "stop": {
197
+ "max_prompt_per_context": 3,
198
+ "window_minutes": 30
195
199
  }
196
200
  };
197
201
 
@@ -406,6 +410,10 @@ function buildStopContext(quadrant, info) {
406
410
  }
407
411
 
408
412
  // templates/core/governance/stop-router.ts
413
+ import { createHash as createHash2 } from "node:crypto";
414
+ import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
415
+ import { tmpdir } from "node:os";
416
+ import { join as join2 } from "node:path";
409
417
  var StopRouter = class {
410
418
  /** 主路由:返回 exit code(0 放行 / 2 阻断) */
411
419
  run() {
@@ -434,14 +442,20 @@ var StopRouter = class {
434
442
  }
435
443
  // ─────────────────────────── 扩展点 ───────────────────────────
436
444
  /**
437
- * Q4 验收决策(双维度组合——2026-08-14 Task 9.4.4④ 上提,回流: I2):
438
- * 维度 1(前置): DB 任务进度(step = done/total,数值且 done<total 未完成阻断提示)
439
- * 维度 2: checklist 质量(checkAddCompleteness 未闭环阻断)
440
- * 互补非替代——codex DB 进度分流语义上提 core,core checklist 质量语义保留。
441
- */
445
+ * Q4 验收决策(双维度组合——2026-08-14 Task 9.4.4④ 上提,回流: I2):
446
+ * 维度 0(新增,临时方案): 弹框频控——同项目同 Plan 窗口内达上限降级放行
447
+ * 维度 1(前置): DB 任务进度(step = done/total,数值且 done<total 未完成阻断提示)
448
+ * 维度 2: checklist 质量(checkAddCompleteness 未闭环 阻断)
449
+ * 互补非替代——codex 原 DB 进度分流语义上提 core,core checklist 质量语义保留。
450
+ */
442
451
  q4Check(plan, rounds, step, handoff, addRoute) {
443
- void plan;
444
452
  void rounds;
453
+ const limited = this.stopPromptLimited(plan);
454
+ if (limited) {
455
+ process.stderr.write(`[ADD Stop] \u5DF2\u8FBE\u672C Plan \u5F39\u6846\u4E0A\u9650(${this.stopPromptMax()})\uFF0C\u672C\u6B21\u653E\u884C\u3002\u8BF7\u5728\u540E\u7EED\u5B9E\u65BD\u4E2D\u5B8C\u6210\u9A8C\u6536\u95ED\u73AF\uFF08devlog + handoff\uFF09\u540E\u505C\u6B62\u3002
456
+ `);
457
+ return 0;
458
+ }
445
459
  const [donePart, totalPart] = step.split("/");
446
460
  if (/^\d+$/.test(donePart) && /^\d+$/.test(totalPart) && Number(donePart) < Number(totalPart)) {
447
461
  return this.emitQ4Unclosed(
@@ -458,6 +472,73 @@ var StopRouter = class {
458
472
  clearDevAction();
459
473
  return this.emitQ4Pass();
460
474
  }
475
+ // ── 弹框频控(临时方案,规则真源: hook-protocol-rules.toml [protocol.stop])──
476
+ // 计数隔离: 文件级 = PROJECT_DIR md5(跨项目不互扰);key 级 = planName(同项目跨 Plan 不互扰)
477
+ // 故障降级: 哨兵读/写异常 → fail-open 放行(不阻塞主流程)
478
+ /** 哨兵记录:同一项目同一 Plan 的弹框计数 */
479
+ stopPromptMax() {
480
+ const cfg = protocol.stop;
481
+ return cfg?.max_prompt_per_context ?? 3;
482
+ }
483
+ /** 哨兵窗口(毫秒) */
484
+ stopPromptWindowMs() {
485
+ const cfg = protocol.stop;
486
+ return (cfg?.window_minutes ?? 30) * 6e4;
487
+ }
488
+ /** 哨兵文件路径(项目隔离:PROJECT_DIR md5) */
489
+ stopSentinelPath() {
490
+ const projectDir = process.env.PROJECT_DIR || process.env.QODER_PROJECT_DIR || process.env.QODERCN_PROJECT_DIR || process.env.CLAUDE_PROJECT_DIR || process.cwd();
491
+ const md5 = createHash2("md5").update(projectDir).digest("hex").slice(0, 8);
492
+ return join2(tmpdir(), `add_stop_${md5}.json`);
493
+ }
494
+ /** 写哨兵(失败静默,fail-open) */
495
+ writeStopPromptSentinel(data) {
496
+ try {
497
+ writeFileSync2(this.stopSentinelPath(), JSON.stringify(data), "utf-8");
498
+ } catch {
499
+ }
500
+ }
501
+ /**
502
+ * 频控判定:返回 true = 已达上限应放行(不弹框)
503
+ * 生成态缺失 protocol.stop(TOML 未同步)→ 跳过频控保持既有行为(生成链幂等校验兜底)
504
+ */
505
+ stopPromptLimited(plan) {
506
+ try {
507
+ const stopCfg = protocol.stop;
508
+ if (!stopCfg) return false;
509
+ const max = this.stopPromptMax();
510
+ const windowMs = this.stopPromptWindowMs();
511
+ const path3 = this.stopSentinelPath();
512
+ let data = {};
513
+ if (existsSync2(path3)) {
514
+ try {
515
+ data = JSON.parse(readFileSync2(path3, "utf-8")) ?? {};
516
+ } catch {
517
+ return true;
518
+ }
519
+ }
520
+ const now = Date.now();
521
+ const entry = data[plan];
522
+ if (!entry) {
523
+ data[plan] = { count: 1, lastPromptAt: now };
524
+ this.writeStopPromptSentinel(data);
525
+ return false;
526
+ }
527
+ if (now - entry.lastPromptAt > windowMs) {
528
+ data[plan] = { count: 1, lastPromptAt: now };
529
+ this.writeStopPromptSentinel(data);
530
+ return false;
531
+ }
532
+ if (entry.count >= max) {
533
+ return true;
534
+ }
535
+ data[plan] = { count: entry.count + 1, lastPromptAt: now };
536
+ this.writeStopPromptSentinel(data);
537
+ return false;
538
+ } catch {
539
+ return true;
540
+ }
541
+ }
461
542
  /** Q0: DB 不可用(core: stderr + 2) */
462
543
  emitQ0(reason) {
463
544
  process.stderr.write(
@@ -116,6 +116,10 @@ var protocol = {
116
116
  ".trae",
117
117
  ".codex"
118
118
  ]
119
+ },
120
+ "stop": {
121
+ "max_prompt_per_context": 3,
122
+ "window_minutes": 30
119
123
  }
120
124
  };
121
125
 
@@ -116,6 +116,10 @@ var protocol = {
116
116
  ".trae",
117
117
  ".codex"
118
118
  ]
119
+ },
120
+ "stop": {
121
+ "max_prompt_per_context": 3,
122
+ "window_minutes": 30
119
123
  }
120
124
  };
121
125
 
@@ -388,6 +388,10 @@ var protocol = {
388
388
  ".trae",
389
389
  ".codex"
390
390
  ]
391
+ },
392
+ "stop": {
393
+ "max_prompt_per_context": 3,
394
+ "window_minutes": 30
391
395
  }
392
396
  };
393
397
 
@@ -116,6 +116,10 @@ var protocol = {
116
116
  ".trae",
117
117
  ".codex"
118
118
  ]
119
+ },
120
+ "stop": {
121
+ "max_prompt_per_context": 3,
122
+ "window_minutes": 30
119
123
  }
120
124
  };
121
125
 
@@ -114,6 +114,10 @@ var protocol = {
114
114
  ".trae",
115
115
  ".codex"
116
116
  ]
117
+ },
118
+ "stop": {
119
+ "max_prompt_per_context": 3,
120
+ "window_minutes": 30
117
121
  }
118
122
  };
119
123
 
@@ -114,6 +114,10 @@ var protocol = {
114
114
  ".trae",
115
115
  ".codex"
116
116
  ]
117
+ },
118
+ "stop": {
119
+ "max_prompt_per_context": 3,
120
+ "window_minutes": 30
117
121
  }
118
122
  };
119
123
 
@@ -142,6 +142,10 @@ var protocol = {
142
142
  ".trae",
143
143
  ".codex"
144
144
  ]
145
+ },
146
+ "stop": {
147
+ "max_prompt_per_context": 3,
148
+ "window_minutes": 30
145
149
  }
146
150
  };
147
151
 
@@ -119,6 +119,10 @@ var protocol = {
119
119
  ".trae",
120
120
  ".codex"
121
121
  ]
122
+ },
123
+ "stop": {
124
+ "max_prompt_per_context": 3,
125
+ "window_minutes": 30
122
126
  }
123
127
  };
124
128
 
@@ -400,6 +400,10 @@ var protocol = {
400
400
  ".trae",
401
401
  ".codex"
402
402
  ]
403
+ },
404
+ "stop": {
405
+ "max_prompt_per_context": 3,
406
+ "window_minutes": 30
403
407
  }
404
408
  };
405
409
 
@@ -145,6 +145,10 @@ var protocol = {
145
145
  ".trae",
146
146
  ".codex"
147
147
  ]
148
+ },
149
+ "stop": {
150
+ "max_prompt_per_context": 3,
151
+ "window_minutes": 30
148
152
  }
149
153
  };
150
154
 
@@ -119,6 +119,10 @@ var protocol = {
119
119
  ".trae",
120
120
  ".codex"
121
121
  ]
122
+ },
123
+ "stop": {
124
+ "max_prompt_per_context": 3,
125
+ "window_minutes": 30
122
126
  }
123
127
  };
124
128
 
@@ -121,6 +121,10 @@ var protocol = {
121
121
  ".trae",
122
122
  ".codex"
123
123
  ]
124
+ },
125
+ "stop": {
126
+ "max_prompt_per_context": 3,
127
+ "window_minutes": 30
124
128
  }
125
129
  };
126
130