@event4u/agent-config 9.35.0 → 10.0.0

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 (117) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +95 -142
  3. package/agents/templates/.ai-council.yml.example +31 -51
  4. package/dist/agent-src/commands/analyze/conformance.md +15 -4
  5. package/dist/agent-src/commands/analyze/reference-repo.md +135 -42
  6. package/dist/agent-src/contexts/augment-infrastructure.md +1 -1
  7. package/dist/agent-src/rules/design-review-after-ui-write.md +53 -6
  8. package/dist/agent-src/rules/improve-before-implement.md +1 -1
  9. package/dist/agent-src/rules/session-canary.md +28 -0
  10. package/dist/agent-src/rules/ui-audit-gate.md +35 -0
  11. package/dist/agent-src/skills/design-system-capture/SKILL.md +2 -2
  12. package/dist/agent-src/skills/existing-ui-audit/SKILL.md +1 -1
  13. package/dist/agent-src/skills/fe-design/SKILL.md +84 -12
  14. package/dist/agent-src/skills/fe-design/evals/triggers.json +11 -3
  15. package/dist/agent-src/skills/prediction-pool-optimizer/SKILL.md +5 -5
  16. package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +1 -1
  17. package/dist/agent-src/skills/skill-writing/SKILL.md +24 -0
  18. package/dist/agent-src/skills/subagent-orchestration/prompts/README.md +29 -0
  19. package/dist/agent-src/templates/AGENTS.md +1 -1
  20. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  21. package/dist/cli-delegate/{chunk-2TGMGLBL.js → chunk-2H5SE7DU.js} +35 -5
  22. package/dist/cli-delegate/{chunk-DS6BLDMG.js → chunk-3JUTT26I.js} +8 -3
  23. package/dist/cli-delegate/{chunk-ZAXH3ZWU.js → chunk-HJSKTMIF.js} +14 -13
  24. package/dist/cli-delegate/{chunk-QEEB4LHO.js → chunk-LRXJK6GN.js} +1 -1
  25. package/dist/cli-delegate/{chunk-736JCWLM.js → chunk-M2DPGFZ4.js} +10 -0
  26. package/dist/cli-delegate/{chunk-H6F2CQFI.js → chunk-NX5AXSLD.js} +3 -3
  27. package/dist/cli-delegate/{chunk-AG47LAGQ.js → chunk-TVGXH7VA.js} +1 -1
  28. package/dist/cli-delegate/{chunk-55RI5UXK.js → chunk-XT2YTJCZ.js} +22 -18
  29. package/dist/cli-delegate/{chunk-JEJABGKB.js → chunk-XTC5ARB6.js} +16 -12
  30. package/dist/cli-delegate/cmd_analyze_session.js +1 -1
  31. package/dist/cli-delegate/cmd_brand_status.js +1 -1
  32. package/dist/cli-delegate/cmd_conformance.js +1038 -197
  33. package/dist/cli-delegate/cmd_doctor.js +4 -4
  34. package/dist/cli-delegate/cmd_explain.js +2 -2
  35. package/dist/cli-delegate/cmd_export.js +4 -4
  36. package/dist/cli-delegate/cmd_handoff.js +3 -3
  37. package/dist/cli-delegate/cmd_mcp_available.js +1 -1
  38. package/dist/cli-delegate/cmd_migrate.js +2 -2
  39. package/dist/cli-delegate/cmd_packs_active.js +2 -2
  40. package/dist/cli-delegate/cmd_prune.js +4 -4
  41. package/dist/cli-delegate/cmd_refresh.js +1 -1
  42. package/dist/cli-delegate/cmd_route_audit.js +2 -2
  43. package/dist/cli-delegate/cmd_route_explain.js +1 -1
  44. package/dist/cli-delegate/cmd_session_recycle.js +9 -2
  45. package/dist/cli-delegate/cmd_settings_get.js +1 -1
  46. package/dist/cli-delegate/cmd_settings_migrate.js +4 -4
  47. package/dist/cli-delegate/cmd_settings_set.js +1 -1
  48. package/dist/cli-delegate/cmd_sync.js +4 -4
  49. package/dist/cli-delegate/cmd_uninstall.js +4 -4
  50. package/dist/cli-delegate/cmd_update.js +1 -1
  51. package/dist/cli-delegate/cmd_upgrade.js +2 -2
  52. package/dist/cli-delegate/cmd_validate.js +4 -4
  53. package/dist/cli-delegate/cmd_versions.js +1 -1
  54. package/dist/discovery/deprecation-report.md +1 -1
  55. package/dist/discovery/discovery-manifest.json +14 -14
  56. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  57. package/dist/discovery/discovery-manifest.summary.md +1 -1
  58. package/dist/discovery/dormancy-report.md +1 -1
  59. package/dist/discovery/orphan-report.md +1 -1
  60. package/dist/discovery/packs.json +2 -2
  61. package/dist/discovery/trust-report.md +1 -1
  62. package/dist/discovery/workspaces.json +2 -2
  63. package/dist/hooks/dispatch.js +654 -411
  64. package/dist/install/install.mjs +39 -29
  65. package/dist/mcp/registry-manifest.json +1 -1
  66. package/dist/mcp/server.json +2 -2
  67. package/dist/mcp/server.mjs +1580 -617
  68. package/dist/router.json +1 -1
  69. package/dist/scripts/_lib/agent_settings.js +39 -25
  70. package/dist/scripts/_lib/agent_settings.js.map +1 -1
  71. package/dist/scripts/condense.js +15 -2
  72. package/dist/scripts/condense.js.map +1 -1
  73. package/dist/server/routes/wizard.js +23 -3
  74. package/dist/server/routes/wizard.js.map +1 -1
  75. package/dist/server/schemas/settings.js +11 -6
  76. package/dist/server/schemas/settings.js.map +1 -1
  77. package/docs/contracts/settings-classes.md +16 -9
  78. package/docs/guidelines/agent-infra/agent-interaction-and-decision-quality.md +46 -4
  79. package/package.json +2 -2
  80. package/src/agent-src/templates/AGENTS.md +1 -1
  81. package/src/config/agent-settings.template.yml +38 -36
  82. package/src/config/ci-local-parity.yml +44 -0
  83. package/src/config/gate-coverage.yml +12 -0
  84. package/src/scripts/_cli/cmd_doctor.ts +32 -0
  85. package/src/scripts/_cli/cmd_migrate.ts +26 -3
  86. package/src/scripts/_cli/cmd_refresh.ts +29 -0
  87. package/src/scripts/_cli/cmd_session_recycle.ts +40 -2
  88. package/src/scripts/_lib/agent_settings.ts +39 -25
  89. package/src/scripts/_lib/environment_detector.ts +52 -1
  90. package/src/scripts/_lib/hook_settings.ts +79 -0
  91. package/src/scripts/_lib/ui_surface.ts +97 -0
  92. package/src/scripts/ai_council/config.ts +62 -24
  93. package/src/scripts/before_complete_hook.ts +39 -0
  94. package/src/scripts/capture_skill_catalogue.ts +483 -0
  95. package/src/scripts/check_bridge_derivation.ts +89 -3
  96. package/src/scripts/check_ci_local_parity.ts +74 -0
  97. package/src/scripts/check_references.ts +15 -1
  98. package/src/scripts/condense.ts +16 -2
  99. package/src/scripts/conformance_scan.ts +200 -9
  100. package/src/scripts/council_cli.ts +95 -3
  101. package/src/scripts/hook_manifest.yaml +30 -9
  102. package/src/scripts/hooks/block_no_verify.ts +82 -9
  103. package/src/scripts/hooks/concern_registry.ts +2 -0
  104. package/src/scripts/hooks/design_slop_hook.ts +1 -1
  105. package/src/scripts/hooks/turn_end_gate_hook.ts +138 -105
  106. package/src/scripts/hooks/ui_route_nudge_hook.ts +250 -0
  107. package/src/scripts/lint_roadmap_complexity.ts +60 -0
  108. package/src/scripts/lint_rule_skill_pack_reach.ts +263 -0
  109. package/src/scripts/probe_promissory_closing.ts +180 -0
  110. package/src/scripts/probe_session_canary.ts +180 -0
  111. package/src/scripts/report_consultation_rate.ts +358 -0
  112. package/src/scripts/report_skill_activation.ts +5 -1
  113. package/src/server/schemas/settings.ts +14 -13
  114. /package/dist/agent-src/skills/design-system-capture/{reference → references}/design-system-json.md +0 -0
  115. /package/dist/agent-src/skills/prediction-pool-optimizer/{reference → references}/ev-fixtures.md +0 -0
  116. /package/dist/agent-src/skills/prediction-pool-optimizer/{reference → references}/odds-and-bonus.md +0 -0
  117. /package/dist/agent-src/skills/react-shadcn-ui/{reference → references}/registry.md +0 -0
@@ -112,17 +112,17 @@ var require_visit = __commonJS({
112
112
  visit.BREAK = BREAK;
113
113
  visit.SKIP = SKIP;
114
114
  visit.REMOVE = REMOVE;
115
- function visit_(key, node, visitor, path67) {
116
- const ctrl = callVisitor(key, node, visitor, path67);
115
+ function visit_(key, node, visitor, path69) {
116
+ const ctrl = callVisitor(key, node, visitor, path69);
117
117
  if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
118
- replaceNode(key, path67, ctrl);
119
- return visit_(key, ctrl, visitor, path67);
118
+ replaceNode(key, path69, ctrl);
119
+ return visit_(key, ctrl, visitor, path69);
120
120
  }
121
121
  if (typeof ctrl !== "symbol") {
122
122
  if (identity.isCollection(node)) {
123
- path67 = Object.freeze(path67.concat(node));
123
+ path69 = Object.freeze(path69.concat(node));
124
124
  for (let i = 0; i < node.items.length; ++i) {
125
- const ci = visit_(i, node.items[i], visitor, path67);
125
+ const ci = visit_(i, node.items[i], visitor, path69);
126
126
  if (typeof ci === "number")
127
127
  i = ci - 1;
128
128
  else if (ci === BREAK)
@@ -133,13 +133,13 @@ var require_visit = __commonJS({
133
133
  }
134
134
  }
135
135
  } else if (identity.isPair(node)) {
136
- path67 = Object.freeze(path67.concat(node));
137
- const ck = visit_("key", node.key, visitor, path67);
136
+ path69 = Object.freeze(path69.concat(node));
137
+ const ck = visit_("key", node.key, visitor, path69);
138
138
  if (ck === BREAK)
139
139
  return BREAK;
140
140
  else if (ck === REMOVE)
141
141
  node.key = null;
142
- const cv = visit_("value", node.value, visitor, path67);
142
+ const cv = visit_("value", node.value, visitor, path69);
143
143
  if (cv === BREAK)
144
144
  return BREAK;
145
145
  else if (cv === REMOVE)
@@ -160,17 +160,17 @@ var require_visit = __commonJS({
160
160
  visitAsync.BREAK = BREAK;
161
161
  visitAsync.SKIP = SKIP;
162
162
  visitAsync.REMOVE = REMOVE;
163
- async function visitAsync_(key, node, visitor, path67) {
164
- const ctrl = await callVisitor(key, node, visitor, path67);
163
+ async function visitAsync_(key, node, visitor, path69) {
164
+ const ctrl = await callVisitor(key, node, visitor, path69);
165
165
  if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
166
- replaceNode(key, path67, ctrl);
167
- return visitAsync_(key, ctrl, visitor, path67);
166
+ replaceNode(key, path69, ctrl);
167
+ return visitAsync_(key, ctrl, visitor, path69);
168
168
  }
169
169
  if (typeof ctrl !== "symbol") {
170
170
  if (identity.isCollection(node)) {
171
- path67 = Object.freeze(path67.concat(node));
171
+ path69 = Object.freeze(path69.concat(node));
172
172
  for (let i = 0; i < node.items.length; ++i) {
173
- const ci = await visitAsync_(i, node.items[i], visitor, path67);
173
+ const ci = await visitAsync_(i, node.items[i], visitor, path69);
174
174
  if (typeof ci === "number")
175
175
  i = ci - 1;
176
176
  else if (ci === BREAK)
@@ -181,13 +181,13 @@ var require_visit = __commonJS({
181
181
  }
182
182
  }
183
183
  } else if (identity.isPair(node)) {
184
- path67 = Object.freeze(path67.concat(node));
185
- const ck = await visitAsync_("key", node.key, visitor, path67);
184
+ path69 = Object.freeze(path69.concat(node));
185
+ const ck = await visitAsync_("key", node.key, visitor, path69);
186
186
  if (ck === BREAK)
187
187
  return BREAK;
188
188
  else if (ck === REMOVE)
189
189
  node.key = null;
190
- const cv = await visitAsync_("value", node.value, visitor, path67);
190
+ const cv = await visitAsync_("value", node.value, visitor, path69);
191
191
  if (cv === BREAK)
192
192
  return BREAK;
193
193
  else if (cv === REMOVE)
@@ -214,23 +214,23 @@ var require_visit = __commonJS({
214
214
  }
215
215
  return visitor;
216
216
  }
217
- function callVisitor(key, node, visitor, path67) {
217
+ function callVisitor(key, node, visitor, path69) {
218
218
  if (typeof visitor === "function")
219
- return visitor(key, node, path67);
219
+ return visitor(key, node, path69);
220
220
  if (identity.isMap(node))
221
- return visitor.Map?.(key, node, path67);
221
+ return visitor.Map?.(key, node, path69);
222
222
  if (identity.isSeq(node))
223
- return visitor.Seq?.(key, node, path67);
223
+ return visitor.Seq?.(key, node, path69);
224
224
  if (identity.isPair(node))
225
- return visitor.Pair?.(key, node, path67);
225
+ return visitor.Pair?.(key, node, path69);
226
226
  if (identity.isScalar(node))
227
- return visitor.Scalar?.(key, node, path67);
227
+ return visitor.Scalar?.(key, node, path69);
228
228
  if (identity.isAlias(node))
229
- return visitor.Alias?.(key, node, path67);
229
+ return visitor.Alias?.(key, node, path69);
230
230
  return void 0;
231
231
  }
232
- function replaceNode(key, path67, node) {
233
- const parent = path67[path67.length - 1];
232
+ function replaceNode(key, path69, node) {
233
+ const parent = path69[path69.length - 1];
234
234
  if (identity.isCollection(parent)) {
235
235
  parent.items[key] = node;
236
236
  } else if (identity.isPair(parent)) {
@@ -840,10 +840,10 @@ var require_Collection = __commonJS({
840
840
  var createNode = require_createNode();
841
841
  var identity = require_identity();
842
842
  var Node = require_Node();
843
- function collectionFromPath(schema, path67, value) {
843
+ function collectionFromPath(schema, path69, value) {
844
844
  let v = value;
845
- for (let i = path67.length - 1; i >= 0; --i) {
846
- const k = path67[i];
845
+ for (let i = path69.length - 1; i >= 0; --i) {
846
+ const k = path69[i];
847
847
  if (typeof k === "number" && Number.isInteger(k) && k >= 0) {
848
848
  const a = [];
849
849
  a[k] = v;
@@ -862,7 +862,7 @@ var require_Collection = __commonJS({
862
862
  sourceObjects: /* @__PURE__ */ new Map()
863
863
  });
864
864
  }
865
- var isEmptyPath = (path67) => path67 == null || typeof path67 === "object" && !!path67[Symbol.iterator]().next().done;
865
+ var isEmptyPath = (path69) => path69 == null || typeof path69 === "object" && !!path69[Symbol.iterator]().next().done;
866
866
  var Collection = class extends Node.NodeBase {
867
867
  constructor(type, schema) {
868
868
  super(type);
@@ -892,11 +892,11 @@ var require_Collection = __commonJS({
892
892
  * be a Pair instance or a `{ key, value }` object, which may not have a key
893
893
  * that already exists in the map.
894
894
  */
895
- addIn(path67, value) {
896
- if (isEmptyPath(path67))
895
+ addIn(path69, value) {
896
+ if (isEmptyPath(path69))
897
897
  this.add(value);
898
898
  else {
899
- const [key, ...rest] = path67;
899
+ const [key, ...rest] = path69;
900
900
  const node = this.get(key, true);
901
901
  if (identity.isCollection(node))
902
902
  node.addIn(rest, value);
@@ -910,8 +910,8 @@ var require_Collection = __commonJS({
910
910
  * Removes a value from the collection.
911
911
  * @returns `true` if the item was found and removed.
912
912
  */
913
- deleteIn(path67) {
914
- const [key, ...rest] = path67;
913
+ deleteIn(path69) {
914
+ const [key, ...rest] = path69;
915
915
  if (rest.length === 0)
916
916
  return this.delete(key);
917
917
  const node = this.get(key, true);
@@ -925,8 +925,8 @@ var require_Collection = __commonJS({
925
925
  * scalar values from their surrounding node; to disable set `keepScalar` to
926
926
  * `true` (collections are always returned intact).
927
927
  */
928
- getIn(path67, keepScalar) {
929
- const [key, ...rest] = path67;
928
+ getIn(path69, keepScalar) {
929
+ const [key, ...rest] = path69;
930
930
  const node = this.get(key, true);
931
931
  if (rest.length === 0)
932
932
  return !keepScalar && identity.isScalar(node) ? node.value : node;
@@ -944,8 +944,8 @@ var require_Collection = __commonJS({
944
944
  /**
945
945
  * Checks if the collection includes a value with the key `key`.
946
946
  */
947
- hasIn(path67) {
948
- const [key, ...rest] = path67;
947
+ hasIn(path69) {
948
+ const [key, ...rest] = path69;
949
949
  if (rest.length === 0)
950
950
  return this.has(key);
951
951
  const node = this.get(key, true);
@@ -955,8 +955,8 @@ var require_Collection = __commonJS({
955
955
  * Sets a value in this collection. For `!!set`, `value` needs to be a
956
956
  * boolean to add/remove the item from the set.
957
957
  */
958
- setIn(path67, value) {
959
- const [key, ...rest] = path67;
958
+ setIn(path69, value) {
959
+ const [key, ...rest] = path69;
960
960
  if (rest.length === 0) {
961
961
  this.set(key, value);
962
962
  } else {
@@ -3471,9 +3471,9 @@ var require_Document = __commonJS({
3471
3471
  this.contents.add(value);
3472
3472
  }
3473
3473
  /** Adds a value to the document. */
3474
- addIn(path67, value) {
3474
+ addIn(path69, value) {
3475
3475
  if (assertCollection(this.contents))
3476
- this.contents.addIn(path67, value);
3476
+ this.contents.addIn(path69, value);
3477
3477
  }
3478
3478
  /**
3479
3479
  * Create a new `Alias` node, ensuring that the target `node` has the required anchor.
@@ -3548,14 +3548,14 @@ var require_Document = __commonJS({
3548
3548
  * Removes a value from the document.
3549
3549
  * @returns `true` if the item was found and removed.
3550
3550
  */
3551
- deleteIn(path67) {
3552
- if (Collection.isEmptyPath(path67)) {
3551
+ deleteIn(path69) {
3552
+ if (Collection.isEmptyPath(path69)) {
3553
3553
  if (this.contents == null)
3554
3554
  return false;
3555
3555
  this.contents = null;
3556
3556
  return true;
3557
3557
  }
3558
- return assertCollection(this.contents) ? this.contents.deleteIn(path67) : false;
3558
+ return assertCollection(this.contents) ? this.contents.deleteIn(path69) : false;
3559
3559
  }
3560
3560
  /**
3561
3561
  * Returns item at `key`, or `undefined` if not found. By default unwraps
@@ -3570,10 +3570,10 @@ var require_Document = __commonJS({
3570
3570
  * scalar values from their surrounding node; to disable set `keepScalar` to
3571
3571
  * `true` (collections are always returned intact).
3572
3572
  */
3573
- getIn(path67, keepScalar) {
3574
- if (Collection.isEmptyPath(path67))
3573
+ getIn(path69, keepScalar) {
3574
+ if (Collection.isEmptyPath(path69))
3575
3575
  return !keepScalar && identity.isScalar(this.contents) ? this.contents.value : this.contents;
3576
- return identity.isCollection(this.contents) ? this.contents.getIn(path67, keepScalar) : void 0;
3576
+ return identity.isCollection(this.contents) ? this.contents.getIn(path69, keepScalar) : void 0;
3577
3577
  }
3578
3578
  /**
3579
3579
  * Checks if the document includes a value with the key `key`.
@@ -3584,10 +3584,10 @@ var require_Document = __commonJS({
3584
3584
  /**
3585
3585
  * Checks if the document includes a value at `path`.
3586
3586
  */
3587
- hasIn(path67) {
3588
- if (Collection.isEmptyPath(path67))
3587
+ hasIn(path69) {
3588
+ if (Collection.isEmptyPath(path69))
3589
3589
  return this.contents !== void 0;
3590
- return identity.isCollection(this.contents) ? this.contents.hasIn(path67) : false;
3590
+ return identity.isCollection(this.contents) ? this.contents.hasIn(path69) : false;
3591
3591
  }
3592
3592
  /**
3593
3593
  * Sets a value in this document. For `!!set`, `value` needs to be a
@@ -3604,13 +3604,13 @@ var require_Document = __commonJS({
3604
3604
  * Sets a value in this document. For `!!set`, `value` needs to be a
3605
3605
  * boolean to add/remove the item from the set.
3606
3606
  */
3607
- setIn(path67, value) {
3608
- if (Collection.isEmptyPath(path67)) {
3607
+ setIn(path69, value) {
3608
+ if (Collection.isEmptyPath(path69)) {
3609
3609
  this.contents = value;
3610
3610
  } else if (this.contents == null) {
3611
- this.contents = Collection.collectionFromPath(this.schema, Array.from(path67), value);
3611
+ this.contents = Collection.collectionFromPath(this.schema, Array.from(path69), value);
3612
3612
  } else if (assertCollection(this.contents)) {
3613
- this.contents.setIn(path67, value);
3613
+ this.contents.setIn(path69, value);
3614
3614
  }
3615
3615
  }
3616
3616
  /**
@@ -5570,9 +5570,9 @@ var require_cst_visit = __commonJS({
5570
5570
  visit.BREAK = BREAK;
5571
5571
  visit.SKIP = SKIP;
5572
5572
  visit.REMOVE = REMOVE;
5573
- visit.itemAtPath = (cst, path67) => {
5573
+ visit.itemAtPath = (cst, path69) => {
5574
5574
  let item = cst;
5575
- for (const [field, index] of path67) {
5575
+ for (const [field, index] of path69) {
5576
5576
  const tok = item?.[field];
5577
5577
  if (tok && "items" in tok) {
5578
5578
  item = tok.items[index];
@@ -5581,23 +5581,23 @@ var require_cst_visit = __commonJS({
5581
5581
  }
5582
5582
  return item;
5583
5583
  };
5584
- visit.parentCollection = (cst, path67) => {
5585
- const parent = visit.itemAtPath(cst, path67.slice(0, -1));
5586
- const field = path67[path67.length - 1][0];
5584
+ visit.parentCollection = (cst, path69) => {
5585
+ const parent = visit.itemAtPath(cst, path69.slice(0, -1));
5586
+ const field = path69[path69.length - 1][0];
5587
5587
  const coll = parent?.[field];
5588
5588
  if (coll && "items" in coll)
5589
5589
  return coll;
5590
5590
  throw new Error("Parent collection not found");
5591
5591
  };
5592
- function _visit(path67, item, visitor) {
5593
- let ctrl = visitor(item, path67);
5592
+ function _visit(path69, item, visitor) {
5593
+ let ctrl = visitor(item, path69);
5594
5594
  if (typeof ctrl === "symbol")
5595
5595
  return ctrl;
5596
5596
  for (const field of ["key", "value"]) {
5597
5597
  const token = item[field];
5598
5598
  if (token && "items" in token) {
5599
5599
  for (let i = 0; i < token.items.length; ++i) {
5600
- const ci = _visit(Object.freeze(path67.concat([[field, i]])), token.items[i], visitor);
5600
+ const ci = _visit(Object.freeze(path69.concat([[field, i]])), token.items[i], visitor);
5601
5601
  if (typeof ci === "number")
5602
5602
  i = ci - 1;
5603
5603
  else if (ci === BREAK)
@@ -5608,10 +5608,10 @@ var require_cst_visit = __commonJS({
5608
5608
  }
5609
5609
  }
5610
5610
  if (typeof ctrl === "function" && field === "key")
5611
- ctrl = ctrl(item, path67);
5611
+ ctrl = ctrl(item, path69);
5612
5612
  }
5613
5613
  }
5614
- return typeof ctrl === "function" ? ctrl(item, path67) : ctrl;
5614
+ return typeof ctrl === "function" ? ctrl(item, path69) : ctrl;
5615
5615
  }
5616
5616
  exports.visit = visit;
5617
5617
  }
@@ -6913,14 +6913,14 @@ var require_parser = __commonJS({
6913
6913
  case "scalar":
6914
6914
  case "single-quoted-scalar":
6915
6915
  case "double-quoted-scalar": {
6916
- const fs64 = this.flowScalar(this.type);
6916
+ const fs66 = this.flowScalar(this.type);
6917
6917
  if (atNextItem || it.value) {
6918
- map.items.push({ start, key: fs64, sep: [] });
6918
+ map.items.push({ start, key: fs66, sep: [] });
6919
6919
  this.onKeyLine = true;
6920
6920
  } else if (it.sep) {
6921
- this.stack.push(fs64);
6921
+ this.stack.push(fs66);
6922
6922
  } else {
6923
- Object.assign(it, { key: fs64, sep: [] });
6923
+ Object.assign(it, { key: fs66, sep: [] });
6924
6924
  this.onKeyLine = true;
6925
6925
  }
6926
6926
  return;
@@ -7048,13 +7048,13 @@ var require_parser = __commonJS({
7048
7048
  case "scalar":
7049
7049
  case "single-quoted-scalar":
7050
7050
  case "double-quoted-scalar": {
7051
- const fs64 = this.flowScalar(this.type);
7051
+ const fs66 = this.flowScalar(this.type);
7052
7052
  if (!it || it.value)
7053
- fc.items.push({ start: [], key: fs64, sep: [] });
7053
+ fc.items.push({ start: [], key: fs66, sep: [] });
7054
7054
  else if (it.sep)
7055
- this.stack.push(fs64);
7055
+ this.stack.push(fs66);
7056
7056
  else
7057
- Object.assign(it, { key: fs64, sep: [] });
7057
+ Object.assign(it, { key: fs66, sep: [] });
7058
7058
  return;
7059
7059
  }
7060
7060
  case "flow-map-end":
@@ -7363,15 +7363,15 @@ var require_dist = __commonJS({
7363
7363
  });
7364
7364
 
7365
7365
  // src/scripts/hooks/dispatch_entry.ts
7366
- import * as path66 from "node:path";
7367
- import { fileURLToPath as fileURLToPath47 } from "node:url";
7366
+ import * as path68 from "node:path";
7367
+ import { fileURLToPath as fileURLToPath48 } from "node:url";
7368
7368
 
7369
7369
  // src/scripts/hooks/dispatch_hook.ts
7370
7370
  var import_yaml6 = __toESM(require_dist(), 1);
7371
7371
  import { spawnSync as spawnSync7 } from "node:child_process";
7372
- import fs63 from "node:fs";
7373
- import path65 from "node:path";
7374
- import { fileURLToPath as fileURLToPath46, pathToFileURL as pathToFileURL40 } from "node:url";
7372
+ import fs65 from "node:fs";
7373
+ import path67 from "node:path";
7374
+ import { fileURLToPath as fileURLToPath47, pathToFileURL as pathToFileURL41 } from "node:url";
7375
7375
 
7376
7376
  // src/scripts/_lib/spawn_env.ts
7377
7377
  var DENY_EXACT = /* @__PURE__ */ new Set([
@@ -11852,14 +11852,18 @@ function load_agent_settings(options = {}) {
11852
11852
  _warn_removed_always_on_keys(merged);
11853
11853
  return merged;
11854
11854
  }
11855
- var REMOVED_ALWAYS_ON_KEYS = [
11856
- "subagents.enabled",
11857
- "subagents.auto",
11858
- "subagents.host_capabilities",
11859
- "subagents.budget_routing",
11860
- "ai_team.enabled"
11861
- ];
11862
- var _warnedRemovedAlwaysOnKeys = /* @__PURE__ */ new Set();
11855
+ var REMOVED_KEYS = /* @__PURE__ */ new Map([
11856
+ ["subagents.enabled", "always-on orchestration"],
11857
+ ["subagents.auto", "always-on orchestration"],
11858
+ ["subagents.host_capabilities", "always-on orchestration"],
11859
+ ["subagents.budget_routing", "always-on orchestration"],
11860
+ ["ai_team.enabled", "always-on orchestration"],
11861
+ ["hooks.turn_end_gate.enabled", "the turn-end gate is always armed"],
11862
+ ["hooks.turn_end_gate.promissory", "the turn-end gate is always armed"],
11863
+ ["hooks.turn_end_gate.language", "the turn-end gate is always armed"],
11864
+ ["hooks.turn_end_gate.verification", "the turn-end gate is always armed"]
11865
+ ]);
11866
+ var _warnedRemovedKeys = /* @__PURE__ */ new Set();
11863
11867
  function _readDottedSettingsPath(root, dotted) {
11864
11868
  let node = root;
11865
11869
  for (const part of dotted.split(".")) {
@@ -11871,15 +11875,15 @@ function _readDottedSettingsPath(root, dotted) {
11871
11875
  return node;
11872
11876
  }
11873
11877
  function _warn_removed_always_on_keys(merged) {
11874
- for (const key of REMOVED_ALWAYS_ON_KEYS) {
11875
- if (_warnedRemovedAlwaysOnKeys.has(key)) {
11878
+ for (const [key, reason] of REMOVED_KEYS) {
11879
+ if (_warnedRemovedKeys.has(key)) {
11876
11880
  continue;
11877
11881
  }
11878
11882
  if (_readDottedSettingsPath(merged, key) === void 0) {
11879
11883
  continue;
11880
11884
  }
11881
- _warnedRemovedAlwaysOnKeys.add(key);
11882
- process.stderr.write(`${key} was removed (always-on orchestration); ignored.
11885
+ _warnedRemovedKeys.add(key);
11886
+ process.stderr.write(`${key} was removed (${reason}); ignored.
11883
11887
  `);
11884
11888
  }
11885
11889
  }
@@ -14048,7 +14052,6 @@ var _VALID_PROVIDERS = /* @__PURE__ */ new Set([
14048
14052
  "xai",
14049
14053
  "perplexity"
14050
14054
  ]);
14051
- var _VALID_MODES = /* @__PURE__ */ new Set(["api", "manual", "cli", "auto"]);
14052
14055
  var _RAW_KEY_PREFIXES = [
14053
14056
  "sk-",
14054
14057
  "sk-ant-",
@@ -14301,7 +14304,11 @@ function _build_config(raw, source_path) {
14301
14304
  if (!_isBool(enabled4)) {
14302
14305
  throw new CouncilConfigError("`enabled` must be a bool.");
14303
14306
  }
14304
- const defaults = _build_defaults(_asDict(_getOr(raw, "defaults", {})));
14307
+ const ignored_transport_keys = [];
14308
+ const defaults = _build_defaults(
14309
+ _asDict(_getOr(raw, "defaults", {})),
14310
+ ignored_transport_keys
14311
+ );
14305
14312
  const cost_budget = _build_cost_budget(
14306
14313
  _asDict(_getOr(raw, "cost_budget", {}))
14307
14314
  );
@@ -14313,7 +14320,12 @@ function _build_config(raw, source_path) {
14313
14320
  for (const [name, cfg] of Object.entries(members_raw)) {
14314
14321
  members.set(
14315
14322
  name,
14316
- _build_member(name, _asDict(_orEmpty(cfg)), defaults.mode)
14323
+ _build_member(
14324
+ name,
14325
+ _asDict(_orEmpty(cfg)),
14326
+ defaults.mode,
14327
+ ignored_transport_keys
14328
+ )
14317
14329
  );
14318
14330
  }
14319
14331
  const advisors_raw = _getOr(raw, "advisors", {});
@@ -14412,7 +14424,8 @@ function _build_config(raw, source_path) {
14412
14424
  routing,
14413
14425
  low_impact,
14414
14426
  lens_overrides,
14415
- source_path
14427
+ source_path,
14428
+ ignored_transport_keys
14416
14429
  };
14417
14430
  }
14418
14431
  function _orEmpty(value) {
@@ -14890,16 +14903,14 @@ function _build_consensus_scoring(d) {
14890
14903
  };
14891
14904
  }
14892
14905
  var _VALID_MEMBER_MODES = /* @__PURE__ */ new Set(["cli", "api"]);
14893
- function _build_defaults(d) {
14906
+ function _build_defaults(d, ignored = []) {
14894
14907
  if (!_isDict(d)) {
14895
14908
  throw new CouncilConfigError("`defaults` must be a mapping.");
14896
14909
  }
14897
- const mode = _get(d, "mode", "auto");
14898
- if (!(_isStr(mode) && _VALID_MODES.has(mode))) {
14899
- throw new CouncilConfigError(
14900
- `defaults.mode=${_pyRepr3(mode)} not in ${_sortedListRepr(_VALID_MODES)}.`
14901
- );
14910
+ if (_get(d, "mode", null) !== null) {
14911
+ ignored.push("defaults.mode");
14902
14912
  }
14913
+ const mode = "auto";
14903
14914
  const member_mode = _get(d, "member_mode", "cli");
14904
14915
  if (!(_isStr(member_mode) && _VALID_MEMBER_MODES.has(member_mode))) {
14905
14916
  throw new CouncilConfigError(
@@ -15056,7 +15067,7 @@ function _build_cost_budget(d) {
15056
15067
  }
15057
15068
  return cb;
15058
15069
  }
15059
- function _build_member(name, cfg, default_mode = "auto") {
15070
+ function _build_member(name, cfg, default_mode = "auto", ignored = []) {
15060
15071
  if (!_VALID_PROVIDERS.has(name)) {
15061
15072
  throw new CouncilConfigError(
15062
15073
  `members.${name}: unknown provider; valid: ${_sortedListRepr(_VALID_PROVIDERS)}.`
@@ -15067,14 +15078,11 @@ function _build_member(name, cfg, default_mode = "auto") {
15067
15078
  const model = _pyTruthy(modelVal) ? modelVal : "";
15068
15079
  const api_key_ref_raw = _get(cfg, "api_key_ref", null);
15069
15080
  const api_key_ref = api_key_ref_raw === void 0 ? null : api_key_ref_raw;
15070
- const member_mode_raw = _get(cfg, "mode", null);
15071
- const member_mode = member_mode_raw === void 0 ? null : member_mode_raw;
15072
- if (member_mode !== null && !(_isStr(member_mode) && _VALID_MODES.has(member_mode))) {
15073
- throw new CouncilConfigError(
15074
- `members.${name}.mode=${_pyRepr3(member_mode)} not in ${_sortedListRepr(_VALID_MODES)}.`
15075
- );
15081
+ if (_get(cfg, "mode", null) !== null) {
15082
+ ignored.push(`members.${name}.mode`);
15076
15083
  }
15077
- const effective_mode = member_mode !== null ? member_mode : default_mode;
15084
+ const member_mode = null;
15085
+ const effective_mode = default_mode;
15078
15086
  const binary_raw = _get(cfg, "binary", null);
15079
15087
  const binary = binary_raw === void 0 ? null : binary_raw;
15080
15088
  if (binary !== null) {
@@ -17233,6 +17241,14 @@ function _empty_state2() {
17233
17241
  verified_this_turn: false,
17234
17242
  ci_saw_pending: false,
17235
17243
  nonevidence_this_turn: 0,
17244
+ // Round 7 § Phase 1 — the last CI read, SESSION-scoped on purpose. Every
17245
+ // other counter here is turn-scoped because a stale POSITIVE would wrongly
17246
+ // vouch ("I verified"). This one is a NEGATIVE ("CI was not settled"), and a
17247
+ // stale negative only ever refuses more often — so surviving the turn
17248
+ // boundary preserves the freshness invariant rather than bypassing it. It
17249
+ // has to survive it: the measured failure is a completion claim in a LATER
17250
+ // turn than the poll it rests on.
17251
+ ci_last: null,
17236
17252
  checked_at: _now2()
17237
17253
  };
17238
17254
  }
@@ -17360,6 +17376,7 @@ function _update2(state, event, envelope) {
17360
17376
  if (session_id && session_id !== state["session_id"]) {
17361
17377
  state["session_id"] = session_id;
17362
17378
  state["verifications_this_session"] = 0;
17379
+ state["ci_last"] = null;
17363
17380
  state = _reset_turn(state, session_id);
17364
17381
  }
17365
17382
  let payload = envelope["payload"];
@@ -17385,6 +17402,12 @@ function _update2(state, event, envelope) {
17385
17402
  } else {
17386
17403
  counts = false;
17387
17404
  }
17405
+ state["ci_last"] = {
17406
+ at: _now2(),
17407
+ command: cmd.slice(0, 512),
17408
+ pending,
17409
+ settled: pending === 0 && counts === true
17410
+ };
17388
17411
  }
17389
17412
  state["last_verification"] = {
17390
17413
  command: cmd.slice(0, 512),
@@ -22054,28 +22077,51 @@ function _looks_like_git_invocation(cmd, depth = 0) {
22054
22077
  }
22055
22078
  return false;
22056
22079
  }
22080
+ var _SHELL_CONSUMER_RE = /(?:^|[|&;]|\$\(|`)\s*(?:env\s+(?:[A-Za-z_][A-Za-z0-9_]*=\S*\s+)*)?(?:\S*\/)?(?:ba|z|k)?sh\b/;
22081
+ function _heredocs(cmd) {
22082
+ const re = /<<-?\s*(['"]?)([A-Za-z_][A-Za-z0-9_]*)\1([\s\S]*?)^\s*\2\s*$/gm;
22083
+ const docs = [];
22084
+ let stripped = "";
22085
+ let last = 0;
22086
+ let m;
22087
+ while ((m = re.exec(cmd)) !== null) {
22088
+ const lineStart = cmd.lastIndexOf("\n", m.index) + 1;
22089
+ const prefix = cmd.slice(lineStart, m.index);
22090
+ docs.push({ body: m[3] ?? "", shellConsumed: _SHELL_CONSUMER_RE.test(prefix) });
22091
+ stripped += cmd.slice(last, m.index) + "<<HEREDOC";
22092
+ last = m.index + m[0].length;
22093
+ }
22094
+ stripped += cmd.slice(last);
22095
+ return { stripped, docs };
22096
+ }
22057
22097
  function _check_command(cmd, depth = 0) {
22098
+ const { stripped, docs } = depth <= 3 ? _heredocs(cmd) : { stripped: cmd, docs: [] };
22058
22099
  if (depth <= 3) {
22059
- const withoutHeredocs = cmd.replace(
22060
- /<<-?\s*(['"]?)([A-Za-z_][A-Za-z0-9_]*)\1[\s\S]*?^\s*\2\s*$/gm,
22061
- "<<HEREDOC"
22062
- );
22063
- for (const payload of substitutionPayloads(withoutHeredocs)) {
22100
+ for (const payload of substitutionPayloads(stripped)) {
22064
22101
  const [blocked, reason] = _check_command(payload, depth + 1);
22065
22102
  if (blocked) {
22066
22103
  return [true, reason];
22067
22104
  }
22068
22105
  }
22106
+ for (const doc of docs) {
22107
+ if (!doc.shellConsumed) {
22108
+ continue;
22109
+ }
22110
+ const [blocked, reason] = _check_command(doc.body, depth + 1);
22111
+ if (blocked) {
22112
+ return [true, reason];
22113
+ }
22114
+ }
22069
22115
  }
22070
22116
  let tokens;
22071
22117
  try {
22072
- tokens = shlexSplit(cmd);
22118
+ tokens = shlexSplit(stripped);
22073
22119
  } catch (e) {
22074
22120
  if (e instanceof ShlexError) {
22075
- if (_looks_like_git_invocation(cmd)) {
22121
+ if (_looks_like_git_invocation(stripped)) {
22076
22122
  return [
22077
22123
  true,
22078
- "command parse failed (shlex) on a git-containing command \u2014 fail-closed (git-history-discipline). \nMost common cause: an apostrophe or backtick inside a heredoc commit message in the SAME compound command as `git`. \nFix: write the message to a file and use `git commit -F <file>` \u2014 do not retry the heredoc."
22124
+ "command parse failed (shlex) on a git-containing command \u2014 fail-closed (git-history-discipline). \nThe quoting is unbalanced OUTSIDE any terminated heredoc \u2014 an unterminated heredoc, or an odd quote. \nbash refuses this command too; fix the quoting rather than working around the guard."
22079
22125
  ];
22080
22126
  }
22081
22127
  return [false, ""];
@@ -22995,6 +23041,44 @@ import fs51 from "node:fs";
22995
23041
  import path52 from "node:path";
22996
23042
  import { fileURLToPath as fileURLToPath37, pathToFileURL as pathToFileURL30 } from "node:url";
22997
23043
 
23044
+ // src/scripts/_lib/ui_surface.ts
23045
+ var UI_EXTENSIONS = [
23046
+ "html",
23047
+ "htm",
23048
+ "css",
23049
+ "scss",
23050
+ "sass",
23051
+ "less",
23052
+ "vue",
23053
+ "svelte",
23054
+ "astro",
23055
+ "jsx",
23056
+ "tsx"
23057
+ ];
23058
+ var UI_COMPOUND_SUFFIXES = [".blade.php"];
23059
+ var UI_EXT = new RegExp(
23060
+ `(\\.(${UI_EXTENSIONS.join("|")})|${UI_COMPOUND_SUFFIXES.map((s) => s.replace(/\./g, "\\.")).join("|")})$`,
23061
+ "i"
23062
+ );
23063
+ function isUiPath(p) {
23064
+ return UI_EXT.test(p);
23065
+ }
23066
+ var UI_PATH_FRAGMENTS = [
23067
+ "resources/views/",
23068
+ "resources/js/",
23069
+ // `components/` already subsumes `src/components/` under substring
23070
+ // matching — listing both here would be dead weight. The rules' own
23071
+ // `path_prefix` list keeps both because matching there is anchored.
23072
+ "components/",
23073
+ "pages/"
23074
+ ];
23075
+ var UI_TREE_EXCLUSIONS = ["pages/api/"];
23076
+ function isUiTreePath(p) {
23077
+ const normalized = p.replace(/\\/g, "/").toLowerCase();
23078
+ if (UI_TREE_EXCLUSIONS.some((fragment) => normalized.includes(fragment))) return false;
23079
+ return UI_PATH_FRAGMENTS.some((fragment) => normalized.includes(fragment));
23080
+ }
23081
+
22998
23082
  // src/scripts/lint_design_slop.ts
22999
23083
  import fs50 from "node:fs";
23000
23084
  import path51 from "node:path";
@@ -23584,7 +23668,6 @@ var SETTINGS_FILE7 = ".agent-settings.yml";
23584
23668
  var EXIT_ALLOW13 = 0;
23585
23669
  var EXIT_WARN6 = 2;
23586
23670
  var DEGRADE_AFTER = 3;
23587
- var UI_EXT = /\.(html|htm|css|scss|sass|less|vue|svelte|astro|jsx|tsx)$/i;
23588
23671
  function isObject2(v) {
23589
23672
  return typeof v === "object" && v !== null && !Array.isArray(v);
23590
23673
  }
@@ -23993,11 +24076,180 @@ function isCliEntry11() {
23993
24076
  }
23994
24077
  if (isCliEntry11()) process.exit(main36());
23995
24078
 
23996
- // src/scripts/hooks/orchestration_record_hook.ts
23997
- import * as crypto4 from "node:crypto";
24079
+ // src/scripts/hooks/ui_route_nudge_hook.ts
23998
24080
  import * as fs55 from "node:fs";
23999
24081
  import * as path56 from "node:path";
24000
- import { fileURLToPath as fileURLToPath39, pathToFileURL as pathToFileURL33 } from "node:url";
24082
+ import { fileURLToPath as fileURLToPath39, pathToFileURL as pathToFileURL32 } from "node:url";
24083
+
24084
+ // src/scripts/_lib/hook_settings.ts
24085
+ import * as fs54 from "node:fs";
24086
+ import * as path55 from "node:path";
24087
+ var SETTINGS_FILE9 = ".agent-settings.yml";
24088
+ function hookSectionEnabled(root, section) {
24089
+ const file = path55.join(root, SETTINGS_FILE9);
24090
+ let text;
24091
+ try {
24092
+ if (!fs54.statSync(file).isFile()) return false;
24093
+ text = fs54.readFileSync(file, "utf-8");
24094
+ } catch {
24095
+ return false;
24096
+ }
24097
+ const escaped = section.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
24098
+ const sectionPattern = new RegExp(`^(\\s+)${escaped}\\s*:\\s*$`);
24099
+ let inHooks = false;
24100
+ let sectionIndent = null;
24101
+ const indentOf = (line) => line.length - line.replace(/^\s+/, "").length;
24102
+ for (const raw of text.split(/\r\n|\r|\n/)) {
24103
+ const line = raw.replace(/\s+$/, "");
24104
+ if (!line || line.replace(/^\s+/, "").startsWith("#")) continue;
24105
+ if (!(line.startsWith(" ") || line.startsWith(" "))) {
24106
+ inHooks = /^hooks\s*:\s*$/.test(line);
24107
+ sectionIndent = null;
24108
+ continue;
24109
+ }
24110
+ if (inHooks) {
24111
+ const opened = sectionPattern.exec(line);
24112
+ if (opened) {
24113
+ sectionIndent = opened[1].length;
24114
+ continue;
24115
+ }
24116
+ if (sectionIndent !== null && indentOf(line) <= sectionIndent) {
24117
+ sectionIndent = null;
24118
+ }
24119
+ }
24120
+ if (sectionIndent !== null && /^\s+enabled\s*:\s*true\b/.test(line)) return true;
24121
+ }
24122
+ return false;
24123
+ }
24124
+
24125
+ // src/scripts/hooks/ui_route_nudge_hook.ts
24126
+ var EXIT_ALLOW15 = 0;
24127
+ var EXIT_WARN8 = 2;
24128
+ var MAX_NUDGES = 2;
24129
+ var DESIGN_SURFACES = [
24130
+ "fe-design",
24131
+ "existing-ui-audit",
24132
+ "design-review",
24133
+ "design-intelligence"
24134
+ ];
24135
+ function isObject4(v) {
24136
+ return typeof v === "object" && v !== null && !Array.isArray(v);
24137
+ }
24138
+ function unwrap2(envelope) {
24139
+ const inner = envelope["payload"];
24140
+ return isObject4(inner) ? inner : envelope;
24141
+ }
24142
+ function extractEvent(outer) {
24143
+ const envelope = unwrap2(outer);
24144
+ const ti = envelope["tool_input"] ?? envelope["toolInput"] ?? envelope["input"];
24145
+ if (!isObject4(ti)) return null;
24146
+ const fileVal = ti["file_path"] ?? ti["path"] ?? ti["filePath"];
24147
+ const file = typeof fileVal === "string" ? fileVal : "";
24148
+ let isWrite = false;
24149
+ for (const key of ["content", "new_string", "new_str", "text", "newText"]) {
24150
+ if (typeof ti[key] === "string" && ti[key].length > 0) isWrite = true;
24151
+ }
24152
+ return { file, isWrite };
24153
+ }
24154
+ function isConsultation(event) {
24155
+ if (event.isWrite || !event.file) return false;
24156
+ const normalized = event.file.replace(/\\/g, "/").toLowerCase();
24157
+ return DESIGN_SURFACES.some((surface) => normalized.includes(`skills/${surface}/`));
24158
+ }
24159
+ function isUiWrite(event) {
24160
+ if (!event.isWrite || !event.file) return false;
24161
+ return isUiPath(event.file) || isUiTreePath(event.file);
24162
+ }
24163
+ function stateFile2(root) {
24164
+ return path56.join(root, "agents", "runtime", "state", "ui-route-nudge.json");
24165
+ }
24166
+ function readState2(root, session) {
24167
+ try {
24168
+ const all = JSON.parse(fs55.readFileSync(stateFile2(root), "utf-8"));
24169
+ const entry = all[session];
24170
+ if (entry && typeof entry.consulted === "boolean" && typeof entry.nudges === "number") {
24171
+ return entry;
24172
+ }
24173
+ } catch {
24174
+ }
24175
+ return { consulted: false, nudges: 0 };
24176
+ }
24177
+ var MAX_SESSIONS = 50;
24178
+ function pruneSessions(all, keep = MAX_SESSIONS) {
24179
+ const keys = Object.keys(all);
24180
+ if (keys.length <= keep) return all;
24181
+ const survivors = keys.slice(keys.length - keep);
24182
+ const pruned = {};
24183
+ for (const key of survivors) pruned[key] = all[key];
24184
+ return pruned;
24185
+ }
24186
+ function writeState2(root, session, state) {
24187
+ try {
24188
+ const file = stateFile2(root);
24189
+ let all = {};
24190
+ try {
24191
+ all = JSON.parse(fs55.readFileSync(file, "utf-8"));
24192
+ } catch {
24193
+ }
24194
+ if (typeof all !== "object" || all === null || Array.isArray(all)) all = {};
24195
+ all[session] = state;
24196
+ fs55.mkdirSync(path56.dirname(file), { recursive: true });
24197
+ fs55.writeFileSync(file, JSON.stringify(pruneSessions(all)));
24198
+ } catch {
24199
+ }
24200
+ }
24201
+ function decide4(event, state) {
24202
+ if (isConsultation(event)) {
24203
+ return { state: { ...state, consulted: true }, warn: false };
24204
+ }
24205
+ if (!isUiWrite(event)) return { state, warn: false };
24206
+ if (state.consulted) return { state, warn: false };
24207
+ if (state.nudges >= MAX_NUDGES) return { state, warn: false };
24208
+ return { state: { ...state, nudges: state.nudges + 1 }, warn: true };
24209
+ }
24210
+ function nudgeReason2(file) {
24211
+ return `Non-trivial UI write to ${file} with no design consultation this session. Run \`existing-ui-audit\` first, then the fe-design loop (brief \u2192 build \u2192 review). Skip only if this is ui-trivial: <=1 file, <=5 lines, no new component, no new state, no new dependency.`;
24212
+ }
24213
+ function main37() {
24214
+ let envelope;
24215
+ try {
24216
+ const raw = readHookStdin();
24217
+ if (!raw.trim()) return EXIT_ALLOW15;
24218
+ envelope = JSON.parse(raw);
24219
+ } catch {
24220
+ return EXIT_ALLOW15;
24221
+ }
24222
+ if (!isObject4(envelope)) return EXIT_ALLOW15;
24223
+ const rootVal = envelope["workspace_root"];
24224
+ const root = typeof rootVal === "string" && rootVal ? rootVal : process.cwd();
24225
+ if (!hookSectionEnabled(root, "ui_route_nudge")) return EXIT_ALLOW15;
24226
+ const sessionVal = envelope["session_id"];
24227
+ const session = typeof sessionVal === "string" && sessionVal ? sessionVal : "unknown";
24228
+ const event = extractEvent(envelope);
24229
+ if (!event) return EXIT_ALLOW15;
24230
+ const before = readState2(root, session);
24231
+ const { state, warn } = decide4(event, before);
24232
+ if (state.consulted !== before.consulted || state.nudges !== before.nudges) {
24233
+ writeState2(root, session, state);
24234
+ }
24235
+ if (!warn) return EXIT_ALLOW15;
24236
+ process.stdout.write(`${JSON.stringify({ reason: nudgeReason2(event.file) })}
24237
+ `);
24238
+ return EXIT_WARN8;
24239
+ }
24240
+ function isCliEntry12() {
24241
+ const entry = process.argv[1];
24242
+ if (!entry) return false;
24243
+ return pathToFileURL32(path56.resolve(entry)).href === import.meta.url;
24244
+ }
24245
+ if (isCliEntry12()) process.exit(main37());
24246
+ var _HOOK_FILE = fileURLToPath39(import.meta.url);
24247
+
24248
+ // src/scripts/hooks/orchestration_record_hook.ts
24249
+ import * as crypto4 from "node:crypto";
24250
+ import * as fs57 from "node:fs";
24251
+ import * as path58 from "node:path";
24252
+ import { fileURLToPath as fileURLToPath40, pathToFileURL as pathToFileURL34 } from "node:url";
24001
24253
 
24002
24254
  // src/scripts/_lib/orchestration_record.ts
24003
24255
  var DISPATCH_OUTCOMES = ["DONE", "DONE_WITH_CONCERNS", "NEEDS_CONTEXT", "BLOCKED", "killed"];
@@ -24193,9 +24445,9 @@ function buildOrchestrationLine(input) {
24193
24445
 
24194
24446
  // src/scripts/orchestration_record.ts
24195
24447
  import * as crypto3 from "node:crypto";
24196
- import * as fs54 from "node:fs";
24197
- import * as path55 from "node:path";
24198
- import { pathToFileURL as pathToFileURL32 } from "node:url";
24448
+ import * as fs56 from "node:fs";
24449
+ import * as path57 from "node:path";
24450
+ import { pathToFileURL as pathToFileURL33 } from "node:url";
24199
24451
  var DEFAULT_DIR = "agents/runtime/state/audit";
24200
24452
  function parseFlags(argv) {
24201
24453
  const flags = {};
@@ -24245,7 +24497,7 @@ function contentHashId(input) {
24245
24497
  });
24246
24498
  return crypto3.createHash("sha256").update(canonical).digest("hex").slice(0, 26).toUpperCase();
24247
24499
  }
24248
- function main37(argv = process.argv.slice(2)) {
24500
+ function main38(argv = process.argv.slice(2)) {
24249
24501
  const flags = parseFlags(argv);
24250
24502
  const dir = str2(flags, "dir") ?? DEFAULT_DIR;
24251
24503
  const dryRun = flags["dry-run"] === true;
@@ -24306,27 +24558,27 @@ function main37(argv = process.argv.slice(2)) {
24306
24558
  process.stdout.write(serialized + "\n");
24307
24559
  return 0;
24308
24560
  }
24309
- fs54.mkdirSync(dir, { recursive: true });
24310
- const file = path55.join(dir, `${ts.slice(0, 7)}.jsonl`);
24311
- fs54.appendFileSync(file, serialized + "\n", "utf8");
24561
+ fs56.mkdirSync(dir, { recursive: true });
24562
+ const file = path57.join(dir, `${ts.slice(0, 7)}.jsonl`);
24563
+ fs56.appendFileSync(file, serialized + "\n", "utf8");
24312
24564
  process.stdout.write(`orchestration telemetry recorded \u2192 ${file} (id ${line.id})
24313
24565
  `);
24314
24566
  return 0;
24315
24567
  }
24316
24568
  if (process.argv[1] !== void 0) {
24317
- const invokedUrl = pathToFileURL32(path55.resolve(process.argv[1])).href;
24318
- if (import.meta.url === invokedUrl) process.exit(main37());
24569
+ const invokedUrl = pathToFileURL33(path57.resolve(process.argv[1])).href;
24570
+ if (import.meta.url === invokedUrl) process.exit(main38());
24319
24571
  }
24320
24572
 
24321
24573
  // src/scripts/hooks/orchestration_record_hook.ts
24322
- var EXIT_ALLOW15 = 0;
24323
- function isObject4(v) {
24574
+ var EXIT_ALLOW16 = 0;
24575
+ function isObject5(v) {
24324
24576
  return typeof v === "object" && v !== null && !Array.isArray(v);
24325
24577
  }
24326
24578
  var DISPATCH_TOOL_NAMES = /* @__PURE__ */ new Set(["Agent", "Task"]);
24327
24579
  function unwrapPayload(envelope) {
24328
24580
  const inner = envelope["payload"];
24329
- return isObject4(inner) ? inner : envelope;
24581
+ return isObject5(inner) ? inner : envelope;
24330
24582
  }
24331
24583
  function extractToolName(payload) {
24332
24584
  const v = payload["tool_name"] ?? payload["toolName"] ?? payload["tool"];
@@ -24334,12 +24586,12 @@ function extractToolName(payload) {
24334
24586
  }
24335
24587
  function extractToolInput(payload) {
24336
24588
  const v = payload["tool_input"] ?? payload["toolInput"];
24337
- return isObject4(v) ? v : null;
24589
+ return isObject5(v) ? v : null;
24338
24590
  }
24339
24591
  function extractToolResult(payload) {
24340
24592
  for (const key of ["tool_response", "toolResponse", "tool_result", "toolUseResult"]) {
24341
24593
  const v = payload[key];
24342
- if (isObject4(v)) return v;
24594
+ if (isObject5(v)) return v;
24343
24595
  }
24344
24596
  return null;
24345
24597
  }
@@ -24360,7 +24612,7 @@ function extractDispatchFacts(payload) {
24360
24612
  const result = extractToolResult(payload);
24361
24613
  const resolvedModel = result && typeof result["resolvedModel"] === "string" ? result["resolvedModel"] : null;
24362
24614
  let totalTokens = result ? numOrNull(result["totalTokens"]) : null;
24363
- if (totalTokens === null && result && isObject4(result["usage"])) {
24615
+ if (totalTokens === null && result && isObject5(result["usage"])) {
24364
24616
  const usage = result["usage"];
24365
24617
  const inTok = numOrNull(usage["input_tokens"]);
24366
24618
  const outTok = numOrNull(usage["output_tokens"]);
@@ -24409,35 +24661,35 @@ function buildRecordInput(facts, ts, id) {
24409
24661
  return input;
24410
24662
  }
24411
24663
  function auditFileFor(consumerRoot, ts) {
24412
- return path56.join(consumerRoot, DEFAULT_DIR, `${ts.slice(0, 7)}.jsonl`);
24664
+ return path58.join(consumerRoot, DEFAULT_DIR, `${ts.slice(0, 7)}.jsonl`);
24413
24665
  }
24414
24666
  function appendLine(consumerRoot, ts, line) {
24415
24667
  if (is_replay_mode()) return;
24416
24668
  const file = auditFileFor(consumerRoot, ts);
24417
- fs55.mkdirSync(path56.dirname(file), { recursive: true });
24418
- fs55.appendFileSync(file, `${JSON.stringify(line)}
24669
+ fs57.mkdirSync(path58.dirname(file), { recursive: true });
24670
+ fs57.appendFileSync(file, `${JSON.stringify(line)}
24419
24671
  `, "utf8");
24420
24672
  }
24421
24673
  function processEnvelope(envelope, consumer_root) {
24422
24674
  try {
24423
- if (!isObject4(envelope)) return EXIT_ALLOW15;
24675
+ if (!isObject5(envelope)) return EXIT_ALLOW16;
24424
24676
  const payload = unwrapPayload(envelope);
24425
24677
  const toolName = extractToolName(payload);
24426
- if (toolName === null || !DISPATCH_TOOL_NAMES.has(toolName)) return EXIT_ALLOW15;
24678
+ if (toolName === null || !DISPATCH_TOOL_NAMES.has(toolName)) return EXIT_ALLOW16;
24427
24679
  const facts = extractDispatchFacts(payload);
24428
24680
  const ts = (/* @__PURE__ */ new Date()).toISOString();
24429
24681
  const id = crypto4.randomUUID();
24430
24682
  const input = buildRecordInput(facts, ts, id);
24431
24683
  const { line, errors } = buildOrchestrationLine(input);
24432
- if (errors.length || line === null) return EXIT_ALLOW15;
24684
+ if (errors.length || line === null) return EXIT_ALLOW16;
24433
24685
  appendLine(consumer_root, ts, line);
24434
24686
  } catch {
24435
- return EXIT_ALLOW15;
24687
+ return EXIT_ALLOW16;
24436
24688
  }
24437
- return EXIT_ALLOW15;
24689
+ return EXIT_ALLOW16;
24438
24690
  }
24439
24691
  function _resolveRoot(envelope) {
24440
- if (isObject4(envelope)) {
24692
+ if (isObject5(envelope)) {
24441
24693
  const cwd = envelope["cwd"];
24442
24694
  if (typeof cwd === "string" && cwd) return cwd;
24443
24695
  const pr = envelope["workspace_root"] ?? envelope["project_root"];
@@ -24445,13 +24697,13 @@ function _resolveRoot(envelope) {
24445
24697
  }
24446
24698
  return process.cwd();
24447
24699
  }
24448
- function main38() {
24700
+ function main39() {
24449
24701
  const raw = readHookStdin();
24450
24702
  let envelope = {};
24451
24703
  try {
24452
24704
  envelope = raw.trim() ? JSON.parse(raw) : {};
24453
24705
  } catch {
24454
- return EXIT_ALLOW15;
24706
+ return EXIT_ALLOW16;
24455
24707
  }
24456
24708
  return processEnvelope(envelope, _resolveRoot(envelope));
24457
24709
  }
@@ -24460,20 +24712,20 @@ function _isCliEntry29() {
24460
24712
  return false;
24461
24713
  }
24462
24714
  if (process.argv[1] === void 0) return false;
24463
- const argvUrl = pathToFileURL33(path56.resolve(process.argv[1])).href;
24715
+ const argvUrl = pathToFileURL34(path58.resolve(process.argv[1])).href;
24464
24716
  if (import.meta.url === argvUrl) return true;
24465
24717
  try {
24466
- return fs55.realpathSync(fileURLToPath39(import.meta.url)) === fs55.realpathSync(path56.resolve(process.argv[1]));
24718
+ return fs57.realpathSync(fileURLToPath40(import.meta.url)) === fs57.realpathSync(path58.resolve(process.argv[1]));
24467
24719
  } catch {
24468
24720
  return false;
24469
24721
  }
24470
24722
  }
24471
- if (_isCliEntry29()) process.exit(main38());
24723
+ if (_isCliEntry29()) process.exit(main39());
24472
24724
 
24473
24725
  // src/scripts/hooks/delegation_nudge_hook.ts
24474
- import fs56 from "node:fs";
24475
- import path57 from "node:path";
24476
- import { fileURLToPath as fileURLToPath40, pathToFileURL as pathToFileURL34 } from "node:url";
24726
+ import fs58 from "node:fs";
24727
+ import path59 from "node:path";
24728
+ import { fileURLToPath as fileURLToPath41, pathToFileURL as pathToFileURL35 } from "node:url";
24477
24729
 
24478
24730
  // src/scripts/_lib/host_capability.ts
24479
24731
  import process10 from "node:process";
@@ -24808,8 +25060,8 @@ function resolveSubagentRouting(inp) {
24808
25060
  }
24809
25061
 
24810
25062
  // src/scripts/hooks/delegation_nudge_hook.ts
24811
- var EXIT_ALLOW16 = 0;
24812
- var EXIT_WARN8 = 2;
25063
+ var EXIT_ALLOW17 = 0;
25064
+ var EXIT_WARN9 = 2;
24813
25065
  function _isObject13(v) {
24814
25066
  return typeof v === "object" && v !== null && !Array.isArray(v);
24815
25067
  }
@@ -24966,34 +25218,34 @@ function _workspaceRoot3(envelope) {
24966
25218
  }
24967
25219
  return process.cwd();
24968
25220
  }
24969
- function main39() {
25221
+ function main40() {
24970
25222
  let envelope = {};
24971
25223
  try {
24972
25224
  const raw = readHookStdin();
24973
25225
  envelope = raw.trim() ? JSON.parse(raw) : {};
24974
25226
  } catch {
24975
- return EXIT_ALLOW16;
25227
+ return EXIT_ALLOW17;
24976
25228
  }
24977
25229
  const env = _isObject13(envelope) ? envelope : {};
24978
25230
  const event = env["event"];
24979
25231
  const slot = typeof event === "string" && event !== "" ? event : "user_prompt_submit";
24980
25232
  if (slot !== "user_prompt_submit") {
24981
- return EXIT_ALLOW16;
25233
+ return EXIT_ALLOW17;
24982
25234
  }
24983
25235
  const payload = _isObject13(env["payload"]) ? env["payload"] : env;
24984
25236
  const prompt = _extractPrompt2(payload);
24985
25237
  if (!prompt) {
24986
- return EXIT_ALLOW16;
25238
+ return EXIT_ALLOW17;
24987
25239
  }
24988
25240
  if (isSyntheticPrompt(prompt)) {
24989
- return EXIT_ALLOW16;
25241
+ return EXIT_ALLOW17;
24990
25242
  }
24991
25243
  const root = _workspaceRoot3(env);
24992
25244
  const platform = env["platform"];
24993
25245
  const hostId = typeof platform === "string" && platform ? platform : null;
24994
25246
  const result = classifyPrompt(prompt, root, hostId);
24995
25247
  if (!result) {
24996
- return EXIT_ALLOW16;
25248
+ return EXIT_ALLOW17;
24997
25249
  }
24998
25250
  process.stdout.write(
24999
25251
  `${JSON.stringify({
@@ -25003,7 +25255,7 @@ function main39() {
25003
25255
  })}
25004
25256
  `
25005
25257
  );
25006
- return EXIT_WARN8;
25258
+ return EXIT_WARN9;
25007
25259
  }
25008
25260
  function _isCliEntry30() {
25009
25261
  if (true) {
@@ -25012,29 +25264,29 @@ function _isCliEntry30() {
25012
25264
  if (process.argv[1] === void 0) {
25013
25265
  return false;
25014
25266
  }
25015
- const argvUrl = pathToFileURL34(path57.resolve(process.argv[1])).href;
25267
+ const argvUrl = pathToFileURL35(path59.resolve(process.argv[1])).href;
25016
25268
  if (import.meta.url === argvUrl) {
25017
25269
  return true;
25018
25270
  }
25019
25271
  try {
25020
- const here = fs56.realpathSync(fileURLToPath40(import.meta.url));
25021
- const argv = fs56.realpathSync(path57.resolve(process.argv[1]));
25272
+ const here = fs58.realpathSync(fileURLToPath41(import.meta.url));
25273
+ const argv = fs58.realpathSync(path59.resolve(process.argv[1]));
25022
25274
  return here === argv;
25023
25275
  } catch {
25024
25276
  return false;
25025
25277
  }
25026
25278
  }
25027
25279
  if (_isCliEntry30()) {
25028
- process.exit(main39());
25280
+ process.exit(main40());
25029
25281
  }
25030
25282
 
25031
25283
  // src/scripts/hooks/end_review_nudge_hook.ts
25032
25284
  import { spawnSync as spawnSync5 } from "node:child_process";
25033
25285
  import * as crypto5 from "node:crypto";
25034
- import * as fs57 from "node:fs";
25286
+ import * as fs59 from "node:fs";
25035
25287
  import * as os6 from "node:os";
25036
- import * as path58 from "node:path";
25037
- import { fileURLToPath as fileURLToPath41, pathToFileURL as pathToFileURL35 } from "node:url";
25288
+ import * as path60 from "node:path";
25289
+ import { fileURLToPath as fileURLToPath42, pathToFileURL as pathToFileURL36 } from "node:url";
25038
25290
 
25039
25291
  // src/scripts/_lib/review_skipped_record.ts
25040
25292
  function isNonNegInt(n) {
@@ -25081,19 +25333,19 @@ function isSafeTranscriptPath(rawPath, opts = {}) {
25081
25333
  const homeDir = opts.homeDir ?? os6.homedir();
25082
25334
  const maxBytes = opts.maxBytes ?? TRANSCRIPT_SCAN_MAX_BYTES;
25083
25335
  try {
25084
- const realHome = fs57.realpathSync(homeDir);
25085
- const realPath = fs57.realpathSync(rawPath);
25086
- const relative9 = path58.relative(realHome, realPath);
25087
- if (relative9 === "" || relative9.startsWith("..") || path58.isAbsolute(relative9)) {
25336
+ const realHome = fs59.realpathSync(homeDir);
25337
+ const realPath = fs59.realpathSync(rawPath);
25338
+ const relative9 = path60.relative(realHome, realPath);
25339
+ if (relative9 === "" || relative9.startsWith("..") || path60.isAbsolute(relative9)) {
25088
25340
  return false;
25089
25341
  }
25090
- const { size } = fs57.statSync(realPath);
25342
+ const { size } = fs59.statSync(realPath);
25091
25343
  return size <= maxBytes;
25092
25344
  } catch {
25093
25345
  return false;
25094
25346
  }
25095
25347
  }
25096
- var EXIT_WARN9 = 2;
25348
+ var EXIT_WARN10 = 2;
25097
25349
  function parseNumstat(raw) {
25098
25350
  const rows = [];
25099
25351
  for (const line of raw.split("\n")) {
@@ -25166,7 +25418,7 @@ function totalNonDocMutatedLinesWithMeasure(cwd) {
25166
25418
  );
25167
25419
  return { lines: trackedLines + untrackedLines, measure: "exact" };
25168
25420
  }
25169
- function isObject5(v) {
25421
+ function isObject6(v) {
25170
25422
  return typeof v === "object" && v !== null && !Array.isArray(v);
25171
25423
  }
25172
25424
  function str3(v) {
@@ -25186,16 +25438,16 @@ function scanTranscriptForReviewer(transcriptText) {
25186
25438
  } catch {
25187
25439
  continue;
25188
25440
  }
25189
- if (!isObject5(obj) || obj["type"] !== "assistant") continue;
25441
+ if (!isObject6(obj) || obj["type"] !== "assistant") continue;
25190
25442
  const msg = obj["message"];
25191
- if (!isObject5(msg)) continue;
25443
+ if (!isObject6(msg)) continue;
25192
25444
  const content = msg["content"];
25193
25445
  if (!Array.isArray(content)) continue;
25194
25446
  for (const blk of content) {
25195
- if (!isObject5(blk) || blk["type"] !== "tool_use") continue;
25447
+ if (!isObject6(blk) || blk["type"] !== "tool_use") continue;
25196
25448
  const name = str3(blk["name"]);
25197
25449
  const input = blk["input"];
25198
- const inputObj = isObject5(input) ? input : {};
25450
+ const inputObj = isObject6(input) ? input : {};
25199
25451
  if (DISPATCH_TOOL_RE.test(name)) {
25200
25452
  const label = [
25201
25453
  str3(inputObj["description"]),
@@ -25230,19 +25482,19 @@ function appendReviewSkippedTelemetry(workspaceRoot2, diffLines, mutationMeasure
25230
25482
  });
25231
25483
  if (errors.length || line === null) return;
25232
25484
  try {
25233
- const dir = path58.join(workspaceRoot2, "agents", "runtime", "state", "audit");
25234
- fs57.mkdirSync(dir, { recursive: true });
25235
- const file = path58.join(dir, `${ts.slice(0, 7)}.jsonl`);
25236
- fs57.appendFileSync(file, `${JSON.stringify(line)}
25485
+ const dir = path60.join(workspaceRoot2, "agents", "runtime", "state", "audit");
25486
+ fs59.mkdirSync(dir, { recursive: true });
25487
+ const file = path60.join(dir, `${ts.slice(0, 7)}.jsonl`);
25488
+ fs59.appendFileSync(file, `${JSON.stringify(line)}
25237
25489
  `, "utf8");
25238
25490
  } catch {
25239
25491
  }
25240
25492
  }
25241
25493
  function sessionStateDir(workspaceRoot2) {
25242
- return path58.join(workspaceRoot2, "agents", "runtime", "state", "end-review-nudge");
25494
+ return path60.join(workspaceRoot2, "agents", "runtime", "state", "end-review-nudge");
25243
25495
  }
25244
25496
  function sessionStateFile(workspaceRoot2, sessionKey) {
25245
- return path58.join(sessionStateDir(workspaceRoot2), `${sessionKey}.json`);
25497
+ return path60.join(sessionStateDir(workspaceRoot2), `${sessionKey}.json`);
25246
25498
  }
25247
25499
  function deriveSessionKey(envelope, payload) {
25248
25500
  const raw = str3(envelope["session_id"]) || str3(payload["transcript_path"] ?? payload["transcriptPath"]);
@@ -25251,7 +25503,7 @@ function deriveSessionKey(envelope, payload) {
25251
25503
  }
25252
25504
  function hasFiredThisSession(workspaceRoot2, sessionKey) {
25253
25505
  try {
25254
- return fs57.existsSync(sessionStateFile(workspaceRoot2, sessionKey));
25506
+ return fs59.existsSync(sessionStateFile(workspaceRoot2, sessionKey));
25255
25507
  } catch {
25256
25508
  return false;
25257
25509
  }
@@ -25265,7 +25517,7 @@ function markFiredThisSession(workspaceRoot2, sessionKey, ts) {
25265
25517
  function _read_stdin3() {
25266
25518
  return readHookStdin();
25267
25519
  }
25268
- function main40() {
25520
+ function main41() {
25269
25521
  const [envelope, payload] = unwrap(_read_stdin3(), "claude");
25270
25522
  const event = String(envelope["event"] ?? "");
25271
25523
  if (event !== "" && event !== "stop") {
@@ -25294,7 +25546,7 @@ function main40() {
25294
25546
  let reviewerRan = false;
25295
25547
  if (transcriptPath && isSafeTranscriptPath(transcriptPath)) {
25296
25548
  try {
25297
- reviewerRan = scanTranscriptForReviewer(fs57.readFileSync(transcriptPath, "utf-8"));
25549
+ reviewerRan = scanTranscriptForReviewer(fs59.readFileSync(transcriptPath, "utf-8"));
25298
25550
  } catch {
25299
25551
  reviewerRan = false;
25300
25552
  }
@@ -25315,7 +25567,7 @@ function main40() {
25315
25567
  })}
25316
25568
  `
25317
25569
  );
25318
- return EXIT_WARN9;
25570
+ return EXIT_WARN10;
25319
25571
  }
25320
25572
  function _isCliEntry31() {
25321
25573
  if (true) {
@@ -25324,29 +25576,29 @@ function _isCliEntry31() {
25324
25576
  if (process.argv[1] === void 0) {
25325
25577
  return false;
25326
25578
  }
25327
- const argvUrl = pathToFileURL35(path58.resolve(process.argv[1])).href;
25579
+ const argvUrl = pathToFileURL36(path60.resolve(process.argv[1])).href;
25328
25580
  if (import.meta.url === argvUrl) {
25329
25581
  return true;
25330
25582
  }
25331
25583
  try {
25332
- const here = fs57.realpathSync(fileURLToPath41(import.meta.url));
25333
- const argv = fs57.realpathSync(path58.resolve(process.argv[1]));
25584
+ const here = fs59.realpathSync(fileURLToPath42(import.meta.url));
25585
+ const argv = fs59.realpathSync(path60.resolve(process.argv[1]));
25334
25586
  return here === argv;
25335
25587
  } catch {
25336
25588
  return false;
25337
25589
  }
25338
25590
  }
25339
25591
  if (_isCliEntry31()) {
25340
- process.exit(main40());
25592
+ process.exit(main41());
25341
25593
  }
25342
25594
 
25343
25595
  // src/scripts/hooks/turn_end_gate_hook.ts
25344
25596
  import * as crypto6 from "node:crypto";
25345
- import * as fs58 from "node:fs";
25346
- import * as path59 from "node:path";
25347
- import { fileURLToPath as fileURLToPath42, pathToFileURL as pathToFileURL36 } from "node:url";
25597
+ import * as fs60 from "node:fs";
25598
+ import * as path61 from "node:path";
25599
+ import { fileURLToPath as fileURLToPath43, pathToFileURL as pathToFileURL37 } from "node:url";
25348
25600
  var EXIT_BLOCK4 = 1;
25349
- var EXIT_ALLOW17 = 0;
25601
+ var EXIT_ALLOW18 = 0;
25350
25602
  var TRANSCRIPT_READ_MAX_BYTES = 8 * 1024 * 1024;
25351
25603
  function stripFencedBlocks(text) {
25352
25604
  const out = [];
@@ -25448,9 +25700,36 @@ function detectPromissory(reply) {
25448
25700
  }
25449
25701
  return null;
25450
25702
  }
25703
+ function readCiSettled(workspaceRoot2) {
25704
+ try {
25705
+ const raw = fs60.readFileSync(path61.join(workspaceRoot2, STATE_FILE3), "utf-8");
25706
+ const decoded = JSON.parse(raw);
25707
+ if (typeof decoded === "object" && decoded !== null && !Array.isArray(decoded)) {
25708
+ const ci = decoded["ci_last"];
25709
+ if (typeof ci === "object" && ci !== null && !Array.isArray(ci)) {
25710
+ return { seen: true, settled: ci["settled"] === true };
25711
+ }
25712
+ }
25713
+ } catch {
25714
+ }
25715
+ return { seen: false, settled: false };
25716
+ }
25717
+ var _COMPLETION_RE = /(^|\n)\s*(?:\*\*)?(?:fertig\b|damit ist alles erledigt|aufgabe erledigt|alles erledigt\b|komplett(?:er)? (?:auftrag|abgearbeitet)|der komplette auftrag ist durch|done[.!]|all done\b|task complete)/i;
25718
+ function detectCompletionClaim(reply, ci) {
25719
+ if (!ci.seen || ci.settled) return null;
25720
+ const prose = visibleProse(reply);
25721
+ const m = _COMPLETION_RE.exec(prose);
25722
+ if (!m) return null;
25723
+ const at = m.index;
25724
+ return {
25725
+ detector: "completion",
25726
+ evidence: prose.slice(at, at + 120).trim(),
25727
+ reason: "a completion claim while the last CI read was not settled \u2014 read the verdict, then claim it (verify-before-complete)"
25728
+ };
25729
+ }
25451
25730
  function readLanguagePin(workspaceRoot2) {
25452
25731
  try {
25453
- const raw = fs58.readFileSync(path59.join(workspaceRoot2, STATE_FILE5), "utf-8");
25732
+ const raw = fs60.readFileSync(path61.join(workspaceRoot2, STATE_FILE5), "utf-8");
25454
25733
  const decoded = JSON.parse(raw);
25455
25734
  if (typeof decoded === "object" && decoded !== null && !Array.isArray(decoded)) {
25456
25735
  const lang = decoded["language"];
@@ -25499,17 +25778,17 @@ function detectUnverifiedEdit(toolCalls) {
25499
25778
  };
25500
25779
  }
25501
25780
  function stateDir(workspaceRoot2) {
25502
- return path59.join(workspaceRoot2, "agents", "runtime", "state", "turn-end-gate");
25781
+ return path61.join(workspaceRoot2, "agents", "runtime", "state", "turn-end-gate");
25503
25782
  }
25504
25783
  function sessionStateFile2(workspaceRoot2, sessionKey) {
25505
- return path59.join(stateDir(workspaceRoot2), `${sessionKey}.json`);
25784
+ return path61.join(stateDir(workspaceRoot2), `${sessionKey}.json`);
25506
25785
  }
25507
25786
  function deriveSessionKey2(sessionId2) {
25508
25787
  return crypto6.createHash("sha256").update(sessionId2).digest("hex").slice(0, 32);
25509
25788
  }
25510
25789
  function alreadyRefusedTurn(workspaceRoot2, sessionKey, turnOrdinal) {
25511
25790
  try {
25512
- const raw = fs58.readFileSync(sessionStateFile2(workspaceRoot2, sessionKey), "utf-8");
25791
+ const raw = fs60.readFileSync(sessionStateFile2(workspaceRoot2, sessionKey), "utf-8");
25513
25792
  const decoded = JSON.parse(raw);
25514
25793
  if (typeof decoded === "object" && decoded !== null && !Array.isArray(decoded)) {
25515
25794
  return decoded["refused_turn"] === turnOrdinal;
@@ -25534,10 +25813,10 @@ function readTranscriptTail(transcriptPath, opts = {}) {
25534
25813
  if (!transcriptPath || !isSafeTranscriptPath(transcriptPath, opts)) return empty;
25535
25814
  let lines;
25536
25815
  try {
25537
- if (opts.maxBytes !== void 0 && fs58.statSync(transcriptPath).size > opts.maxBytes) {
25816
+ if (opts.maxBytes !== void 0 && fs60.statSync(transcriptPath).size > opts.maxBytes) {
25538
25817
  return empty;
25539
25818
  }
25540
- lines = fs58.readFileSync(transcriptPath, "utf-8").split("\n");
25819
+ lines = fs60.readFileSync(transcriptPath, "utf-8").split("\n");
25541
25820
  } catch {
25542
25821
  return empty;
25543
25822
  }
@@ -25610,83 +25889,47 @@ function _messageText(content) {
25610
25889
  }
25611
25890
  return parts.length > 0 ? parts.join("\n") : null;
25612
25891
  }
25613
- function _isOn(v) {
25614
- if (typeof v === "boolean") return v;
25615
- if (typeof v !== "string") return null;
25616
- const s = v.trim().toLowerCase();
25617
- if (s === "true" || s === "yes" || s === "on") return true;
25618
- if (s === "false" || s === "no" || s === "off") return false;
25619
- return null;
25620
- }
25621
- function readGateSettings(workspaceRoot2) {
25622
- const off = {
25623
- enabled: false,
25624
- promissory: true,
25625
- language: true,
25626
- verification: true
25627
- };
25628
- let settings;
25629
- try {
25630
- settings = load_agent_settings({ cwd: workspaceRoot2 });
25631
- } catch {
25632
- return off;
25633
- }
25634
- const hooks = settings["hooks"];
25635
- if (typeof hooks !== "object" || hooks === null || Array.isArray(hooks)) return off;
25636
- const block = hooks["turn_end_gate"];
25637
- if (typeof block !== "object" || block === null || Array.isArray(block)) return off;
25638
- const gate = block;
25639
- const flag = (name, dflt) => {
25640
- const v = _isOn(gate[name]);
25641
- return v === null ? dflt : v;
25642
- };
25643
- return {
25644
- enabled: flag("enabled", false),
25645
- promissory: flag("promissory", true),
25646
- language: flag("language", true),
25647
- verification: flag("verification", true)
25648
- };
25649
- }
25650
25892
  function str4(v) {
25651
25893
  return typeof v === "string" ? v : "";
25652
25894
  }
25653
- function main41() {
25895
+ function main42() {
25654
25896
  let envelope;
25655
25897
  let payload;
25656
25898
  try {
25657
25899
  [envelope, payload] = unwrap(readHookStdin(), "claude");
25658
25900
  } catch {
25659
- return EXIT_ALLOW17;
25901
+ return EXIT_ALLOW18;
25660
25902
  }
25661
- if (payload["stop_hook_active"] === true) return EXIT_ALLOW17;
25903
+ if (payload["stop_hook_active"] === true) return EXIT_ALLOW18;
25662
25904
  const workspaceRoot2 = str4(envelope["workspace_root"]) || process.cwd();
25663
- const settings = readGateSettings(workspaceRoot2);
25664
- if (!settings.enabled) return EXIT_ALLOW17;
25665
25905
  const transcriptPath = str4(
25666
25906
  payload["transcript_path"] ?? payload["transcriptPath"]
25667
25907
  );
25668
25908
  const { lastAssistant, turnOrdinal, toolCalls } = readTranscriptTail(transcriptPath, {
25669
25909
  maxBytes: TRANSCRIPT_READ_MAX_BYTES
25670
25910
  });
25671
- if (!lastAssistant) return EXIT_ALLOW17;
25911
+ if (!lastAssistant) return EXIT_ALLOW18;
25672
25912
  const sessionKey = deriveSessionKey2(
25673
25913
  str4(envelope["session_id"]) || "unknown-session"
25674
25914
  );
25675
- if (alreadyRefusedTurn(workspaceRoot2, sessionKey, turnOrdinal)) return EXIT_ALLOW17;
25915
+ if (alreadyRefusedTurn(workspaceRoot2, sessionKey, turnOrdinal)) return EXIT_ALLOW18;
25676
25916
  const findings = [];
25677
- if (settings.promissory) {
25678
- const f = detectPromissory(lastAssistant);
25679
- if (f) findings.push(f);
25680
- }
25681
- if (settings.language) {
25682
- const f = detectLanguage(lastAssistant, readLanguagePin(workspaceRoot2));
25683
- if (f) findings.push(f);
25684
- }
25685
- if (settings.verification) {
25686
- const f = detectUnverifiedEdit(toolCalls);
25917
+ for (const f of [
25918
+ detectPromissory(lastAssistant),
25919
+ detectLanguage(lastAssistant, readLanguagePin(workspaceRoot2)),
25920
+ detectUnverifiedEdit(toolCalls),
25921
+ // Round 7 § Phase 1 — detector D, in the same unconditional list as the
25922
+ // other three. It shipped with its own settings flag one commit earlier
25923
+ // and that flag is gone: `hooks.turn_end_gate.*` was deleted on
25924
+ // 2026-08-12 because a default-off safety gate is an absent one. Its
25925
+ // gating is where the comment above says gating belongs — inside the
25926
+ // detector: no CI observed, or a settled read, or no completion claim
25927
+ // ⇒ no finding.
25928
+ detectCompletionClaim(lastAssistant, readCiSettled(workspaceRoot2))
25929
+ ]) {
25687
25930
  if (f) findings.push(f);
25688
25931
  }
25689
- if (findings.length === 0) return EXIT_ALLOW17;
25932
+ if (findings.length === 0) return EXIT_ALLOW18;
25690
25933
  markRefusedTurn(workspaceRoot2, sessionKey, turnOrdinal, findings[0].detector);
25691
25934
  const lines = findings.map(
25692
25935
  (f) => ` \xB7 ${f.detector}: ${f.reason}
@@ -25695,9 +25938,8 @@ function main41() {
25695
25938
  process.stderr.write(
25696
25939
  `turn-end-gate: REFUSED \u2014 this turn is not finished.
25697
25940
  ${lines.join("\n")}
25698
- Do the promised work now, correct the language, or run the verification the edit needs, then end the turn.
25941
+ Do the promised work now, correct the language, run the verification the edit needs, or read the CI verdict before claiming it \u2014 then end the turn.
25699
25942
  This turn will not be refused a second time.
25700
- Disable: hooks.turn_end_gate.enabled: false in .agent-settings.yml
25701
25943
  `
25702
25944
  );
25703
25945
  return EXIT_BLOCK4;
@@ -25709,30 +25951,30 @@ function _isCliEntry32() {
25709
25951
  if (process.argv[1] === void 0) {
25710
25952
  return false;
25711
25953
  }
25712
- const argvUrl = pathToFileURL36(path59.resolve(process.argv[1])).href;
25954
+ const argvUrl = pathToFileURL37(path61.resolve(process.argv[1])).href;
25713
25955
  if (import.meta.url === argvUrl) {
25714
25956
  return true;
25715
25957
  }
25716
25958
  try {
25717
- const here = fs58.realpathSync(fileURLToPath42(import.meta.url));
25718
- const argv = fs58.realpathSync(path59.resolve(process.argv[1]));
25959
+ const here = fs60.realpathSync(fileURLToPath43(import.meta.url));
25960
+ const argv = fs60.realpathSync(path61.resolve(process.argv[1]));
25719
25961
  return here === argv;
25720
25962
  } catch {
25721
25963
  return false;
25722
25964
  }
25723
25965
  }
25724
25966
  if (_isCliEntry32()) {
25725
- process.exit(main41());
25967
+ process.exit(main42());
25726
25968
  }
25727
25969
 
25728
25970
  // src/scripts/hooks/edit_shape_hook.ts
25729
25971
  import { spawnSync as spawnSync6 } from "node:child_process";
25730
25972
  import * as crypto7 from "node:crypto";
25731
- import * as fs59 from "node:fs";
25732
- import * as path60 from "node:path";
25733
- import { fileURLToPath as fileURLToPath43, pathToFileURL as pathToFileURL37 } from "node:url";
25734
- var EXIT_ALLOW18 = 0;
25735
- var EXIT_WARN10 = 2;
25973
+ import * as fs61 from "node:fs";
25974
+ import * as path62 from "node:path";
25975
+ import { fileURLToPath as fileURLToPath44, pathToFileURL as pathToFileURL38 } from "node:url";
25976
+ var EXIT_ALLOW19 = 0;
25977
+ var EXIT_WARN11 = 2;
25736
25978
  var MIN_FILE_LINES = 50;
25737
25979
  var MAX_DIFF_RATIO = 0.2;
25738
25980
  var EXEMPT_PATH_PATTERNS = [
@@ -25747,7 +25989,7 @@ var EXEMPT_PATH_PATTERNS = [
25747
25989
  /(^|\/)agents\/runtime\//i
25748
25990
  // agents/runtime/**
25749
25991
  ];
25750
- function isObject6(v) {
25992
+ function isObject7(v) {
25751
25993
  return typeof v === "object" && v !== null && !Array.isArray(v);
25752
25994
  }
25753
25995
  function str5(v) {
@@ -25783,7 +26025,7 @@ function effectiveDiffLines(cwd, relPath) {
25783
26025
  }
25784
26026
  function fileLineCount(absPath) {
25785
26027
  try {
25786
- const text = fs59.readFileSync(absPath, "utf8");
26028
+ const text = fs61.readFileSync(absPath, "utf8");
25787
26029
  if (text.length === 0) return 0;
25788
26030
  return text.split("\n").length - (text.endsWith("\n") ? 1 : 0);
25789
26031
  } catch {
@@ -25800,11 +26042,11 @@ function deriveSessionKey3(envelope, payload) {
25800
26042
  return crypto7.createHash("sha256").update(material).digest("hex");
25801
26043
  }
25802
26044
  function sessionStateFile3(workspaceRoot2, sessionKey) {
25803
- return path60.join(workspaceRoot2, "agents", "runtime", "state", "edit-shape", `${sessionKey}.json`);
26045
+ return path62.join(workspaceRoot2, "agents", "runtime", "state", "edit-shape", `${sessionKey}.json`);
25804
26046
  }
25805
26047
  function hasFiredThisSession2(workspaceRoot2, sessionKey) {
25806
26048
  try {
25807
- return fs59.existsSync(sessionStateFile3(workspaceRoot2, sessionKey));
26049
+ return fs61.existsSync(sessionStateFile3(workspaceRoot2, sessionKey));
25808
26050
  } catch {
25809
26051
  return false;
25810
26052
  }
@@ -25822,29 +26064,29 @@ function extractToolName2(payload) {
25822
26064
  }
25823
26065
  function extractFilePath(payload) {
25824
26066
  const ti = payload["tool_input"] ?? payload["toolInput"] ?? payload["input"];
25825
- if (!isObject6(ti)) return "";
26067
+ if (!isObject7(ti)) return "";
25826
26068
  return str5(ti["file_path"] ?? ti["path"] ?? ti["filePath"]);
25827
26069
  }
25828
- function main42() {
26070
+ function main43() {
25829
26071
  try {
25830
26072
  const [envelope, payload] = unwrap(readHookStdin(), "claude");
25831
26073
  const event = str5(envelope["event"]);
25832
- if (event !== "" && event !== "post_tool_use") return EXIT_ALLOW18;
26074
+ if (event !== "" && event !== "post_tool_use") return EXIT_ALLOW19;
25833
26075
  const toolName = extractToolName2(payload);
25834
- if (toolName !== "Write") return EXIT_ALLOW18;
26076
+ if (toolName !== "Write") return EXIT_ALLOW19;
25835
26077
  const filePath = extractFilePath(payload);
25836
- if (!filePath) return EXIT_ALLOW18;
26078
+ if (!filePath) return EXIT_ALLOW19;
25837
26079
  const workspaceRoot2 = str5(envelope["workspace_root"]).trim() || process.cwd();
25838
- const absPath = path60.isAbsolute(filePath) ? filePath : path60.resolve(workspaceRoot2, filePath);
25839
- const relPath = path60.relative(workspaceRoot2, absPath);
25840
- if (isExemptPath(relPath) || isExemptPath(absPath)) return EXIT_ALLOW18;
26080
+ const absPath = path62.isAbsolute(filePath) ? filePath : path62.resolve(workspaceRoot2, filePath);
26081
+ const relPath = path62.relative(workspaceRoot2, absPath);
26082
+ if (isExemptPath(relPath) || isExemptPath(absPath)) return EXIT_ALLOW19;
25841
26083
  const fileLines = fileLineCount(absPath);
25842
- if (fileLines < MIN_FILE_LINES) return EXIT_ALLOW18;
26084
+ if (fileLines < MIN_FILE_LINES) return EXIT_ALLOW19;
25843
26085
  const diffLines = effectiveDiffLines(workspaceRoot2, relPath.startsWith("..") ? absPath : relPath);
25844
- if (diffLines === 0) return EXIT_ALLOW18;
25845
- if (diffLines / fileLines > MAX_DIFF_RATIO) return EXIT_ALLOW18;
26086
+ if (diffLines === 0) return EXIT_ALLOW19;
26087
+ if (diffLines / fileLines > MAX_DIFF_RATIO) return EXIT_ALLOW19;
25846
26088
  const sessionKey = deriveSessionKey3(envelope, payload);
25847
- if (hasFiredThisSession2(workspaceRoot2, sessionKey)) return EXIT_ALLOW18;
26089
+ if (hasFiredThisSession2(workspaceRoot2, sessionKey)) return EXIT_ALLOW19;
25848
26090
  markFiredThisSession2(workspaceRoot2, sessionKey);
25849
26091
  process.stdout.write(
25850
26092
  `${JSON.stringify({
@@ -25854,9 +26096,9 @@ function main42() {
25854
26096
  })}
25855
26097
  `
25856
26098
  );
25857
- return EXIT_WARN10;
26099
+ return EXIT_WARN11;
25858
26100
  } catch {
25859
- return EXIT_ALLOW18;
26101
+ return EXIT_ALLOW19;
25860
26102
  }
25861
26103
  }
25862
26104
  function _isCliEntry33() {
@@ -25866,29 +26108,29 @@ function _isCliEntry33() {
25866
26108
  if (process.argv[1] === void 0) {
25867
26109
  return false;
25868
26110
  }
25869
- const argvUrl = pathToFileURL37(path60.resolve(process.argv[1])).href;
26111
+ const argvUrl = pathToFileURL38(path62.resolve(process.argv[1])).href;
25870
26112
  if (import.meta.url === argvUrl) {
25871
26113
  return true;
25872
26114
  }
25873
26115
  try {
25874
- const here = fs59.realpathSync(fileURLToPath43(import.meta.url));
25875
- const argv = fs59.realpathSync(path60.resolve(process.argv[1]));
26116
+ const here = fs61.realpathSync(fileURLToPath44(import.meta.url));
26117
+ const argv = fs61.realpathSync(path62.resolve(process.argv[1]));
25876
26118
  return here === argv;
25877
26119
  } catch {
25878
26120
  return false;
25879
26121
  }
25880
26122
  }
25881
26123
  if (_isCliEntry33()) {
25882
- process.exit(main42());
26124
+ process.exit(main43());
25883
26125
  }
25884
26126
 
25885
26127
  // src/scripts/hooks/reread_guard_hook.ts
25886
26128
  import * as crypto8 from "node:crypto";
25887
- import * as fs60 from "node:fs";
25888
- import * as path61 from "node:path";
25889
- import { fileURLToPath as fileURLToPath44, pathToFileURL as pathToFileURL38 } from "node:url";
25890
- var EXIT_ALLOW19 = 0;
25891
- var EXIT_WARN11 = 2;
26129
+ import * as fs62 from "node:fs";
26130
+ import * as path63 from "node:path";
26131
+ import { fileURLToPath as fileURLToPath45, pathToFileURL as pathToFileURL39 } from "node:url";
26132
+ var EXIT_ALLOW20 = 0;
26133
+ var EXIT_WARN12 = 2;
25892
26134
  var EXEMPT_PATH_PATTERNS2 = [
25893
26135
  /(^|\/)dist\//i,
25894
26136
  // dist/**
@@ -25903,7 +26145,7 @@ var EXEMPT_PATH_PATTERNS2 = [
25903
26145
  ];
25904
26146
  var READ_TOOLS = /* @__PURE__ */ new Set(["Read"]);
25905
26147
  var WRITE_TOOLS2 = /* @__PURE__ */ new Set(["Edit", "Write"]);
25906
- function isObject7(v) {
26148
+ function isObject8(v) {
25907
26149
  return typeof v === "object" && v !== null && !Array.isArray(v);
25908
26150
  }
25909
26151
  function str6(v) {
@@ -25922,16 +26164,16 @@ function deriveSessionKey4(envelope, payload) {
25922
26164
  return crypto8.createHash("sha256").update(material).digest("hex");
25923
26165
  }
25924
26166
  function ledgerFile(workspaceRoot2, sessionKey) {
25925
- return path61.join(workspaceRoot2, "agents", "runtime", "state", "reread-guard", `${sessionKey}.json`);
26167
+ return path63.join(workspaceRoot2, "agents", "runtime", "state", "reread-guard", `${sessionKey}.json`);
25926
26168
  }
25927
26169
  function readLedger(workspaceRoot2, sessionKey) {
25928
26170
  try {
25929
- const parsed = JSON.parse(fs60.readFileSync(ledgerFile(workspaceRoot2, sessionKey), "utf8"));
25930
- if (!isObject7(parsed)) return emptyLedger();
26171
+ const parsed = JSON.parse(fs62.readFileSync(ledgerFile(workspaceRoot2, sessionKey), "utf8"));
26172
+ if (!isObject8(parsed)) return emptyLedger();
25931
26173
  return {
25932
- reads: isObject7(parsed["reads"]) ? parsed["reads"] : {},
25933
- writes: isObject7(parsed["writes"]) ? parsed["writes"] : {},
25934
- fired: isObject7(parsed["fired"]) ? parsed["fired"] : {}
26174
+ reads: isObject8(parsed["reads"]) ? parsed["reads"] : {},
26175
+ writes: isObject8(parsed["writes"]) ? parsed["writes"] : {},
26176
+ fired: isObject8(parsed["fired"]) ? parsed["fired"] : {}
25935
26177
  };
25936
26178
  } catch {
25937
26179
  return emptyLedger();
@@ -25948,7 +26190,7 @@ function extractToolName3(payload) {
25948
26190
  }
25949
26191
  function extractToolInput2(payload) {
25950
26192
  const ti = payload["tool_input"] ?? payload["toolInput"] ?? payload["input"];
25951
- return isObject7(ti) ? ti : {};
26193
+ return isObject8(ti) ? ti : {};
25952
26194
  }
25953
26195
  function extractFilePath2(toolInput) {
25954
26196
  return str6(toolInput["file_path"] ?? toolInput["path"] ?? toolInput["filePath"]);
@@ -25967,41 +26209,41 @@ function buildDuplicateReadLine(relPath, earlierTs) {
25967
26209
  function buildPostEditReadLine(relPath) {
25968
26210
  return `re-read guard: this session just edited ${relPath} \u2014 a full-file re-read re-pays for content you already have; a ranged Read (offset/limit) over the edited hunk is enough to verify the change.`;
25969
26211
  }
25970
- function main43() {
26212
+ function main44() {
25971
26213
  try {
25972
26214
  const [envelope, payload] = unwrap(readHookStdin(), "claude");
25973
26215
  const event = str6(envelope["event"]);
25974
- if (event !== "" && event !== "pre_tool_use") return EXIT_ALLOW19;
26216
+ if (event !== "" && event !== "pre_tool_use") return EXIT_ALLOW20;
25975
26217
  const toolName = extractToolName3(payload);
25976
26218
  const isRead = READ_TOOLS.has(toolName);
25977
26219
  const isWrite = WRITE_TOOLS2.has(toolName);
25978
- if (!isRead && !isWrite) return EXIT_ALLOW19;
26220
+ if (!isRead && !isWrite) return EXIT_ALLOW20;
25979
26221
  const toolInput = extractToolInput2(payload);
25980
26222
  const filePath = extractFilePath2(toolInput);
25981
- if (!filePath) return EXIT_ALLOW19;
26223
+ if (!filePath) return EXIT_ALLOW20;
25982
26224
  const workspaceRoot2 = str6(envelope["workspace_root"]).trim() || process.cwd();
25983
- const absPath = path61.isAbsolute(filePath) ? filePath : path61.resolve(workspaceRoot2, filePath);
25984
- const relPath = path61.relative(workspaceRoot2, absPath);
25985
- if (isExemptPath2(relPath) || isExemptPath2(absPath)) return EXIT_ALLOW19;
26225
+ const absPath = path63.isAbsolute(filePath) ? filePath : path63.resolve(workspaceRoot2, filePath);
26226
+ const relPath = path63.relative(workspaceRoot2, absPath);
26227
+ if (isExemptPath2(relPath) || isExemptPath2(absPath)) return EXIT_ALLOW20;
25986
26228
  const sessionKey = deriveSessionKey4(envelope, payload);
25987
26229
  const ledger = readLedger(workspaceRoot2, sessionKey);
25988
26230
  const key = relPath.startsWith("..") ? absPath : relPath;
25989
26231
  if (isWrite) {
25990
26232
  ledger.writes[key] = Date.now();
25991
26233
  writeLedger(workspaceRoot2, sessionKey, ledger);
25992
- return EXIT_ALLOW19;
26234
+ return EXIT_ALLOW20;
25993
26235
  }
25994
26236
  if (isRangedRead(toolInput)) {
25995
- return EXIT_ALLOW19;
26237
+ return EXIT_ALLOW20;
25996
26238
  }
25997
26239
  let mtime;
25998
26240
  let size;
25999
26241
  try {
26000
- const st = fs60.statSync(absPath);
26242
+ const st = fs62.statSync(absPath);
26001
26243
  mtime = st.mtimeMs;
26002
26244
  size = st.size;
26003
26245
  } catch {
26004
- return EXIT_ALLOW19;
26246
+ return EXIT_ALLOW20;
26005
26247
  }
26006
26248
  const prior = ledger.reads[key];
26007
26249
  const ownWrite = ledger.writes[key];
@@ -26016,7 +26258,7 @@ function main43() {
26016
26258
  if (ownWrite !== void 0) delete ledger.writes[key];
26017
26259
  if (advisory !== null) ledger.fired[key] = true;
26018
26260
  writeLedger(workspaceRoot2, sessionKey, ledger);
26019
- if (advisory === null) return EXIT_ALLOW19;
26261
+ if (advisory === null) return EXIT_ALLOW20;
26020
26262
  process.stdout.write(
26021
26263
  `${JSON.stringify({
26022
26264
  decision: "warn",
@@ -26025,9 +26267,9 @@ function main43() {
26025
26267
  })}
26026
26268
  `
26027
26269
  );
26028
- return EXIT_WARN11;
26270
+ return EXIT_WARN12;
26029
26271
  } catch {
26030
- return EXIT_ALLOW19;
26272
+ return EXIT_ALLOW20;
26031
26273
  }
26032
26274
  }
26033
26275
  function _isCliEntry34() {
@@ -26037,27 +26279,27 @@ function _isCliEntry34() {
26037
26279
  if (process.argv[1] === void 0) {
26038
26280
  return false;
26039
26281
  }
26040
- const argvUrl = pathToFileURL38(path61.resolve(process.argv[1])).href;
26282
+ const argvUrl = pathToFileURL39(path63.resolve(process.argv[1])).href;
26041
26283
  if (import.meta.url === argvUrl) {
26042
26284
  return true;
26043
26285
  }
26044
26286
  try {
26045
- const here = fs60.realpathSync(fileURLToPath44(import.meta.url));
26046
- const argv = fs60.realpathSync(path61.resolve(process.argv[1]));
26287
+ const here = fs62.realpathSync(fileURLToPath45(import.meta.url));
26288
+ const argv = fs62.realpathSync(path63.resolve(process.argv[1]));
26047
26289
  return here === argv;
26048
26290
  } catch {
26049
26291
  return false;
26050
26292
  }
26051
26293
  }
26052
26294
  if (_isCliEntry34()) {
26053
- process.exit(main43());
26295
+ process.exit(main44());
26054
26296
  }
26055
26297
 
26056
26298
  // src/scripts/hooks/session_eol_hook.ts
26057
- import * as fs62 from "node:fs";
26058
- import * as path64 from "node:path";
26299
+ import * as fs64 from "node:fs";
26300
+ import * as path66 from "node:path";
26059
26301
  import process11 from "node:process";
26060
- import { fileURLToPath as fileURLToPath45, pathToFileURL as pathToFileURL39 } from "node:url";
26302
+ import { fileURLToPath as fileURLToPath46, pathToFileURL as pathToFileURL40 } from "node:url";
26061
26303
 
26062
26304
  // src/config/recycle-threshold-budget.json
26063
26305
  var recycle_threshold_budget_default = {
@@ -26075,13 +26317,13 @@ var recycle_threshold_budget_default = {
26075
26317
 
26076
26318
  // src/scripts/_lib/session_eol.ts
26077
26319
  import * as crypto9 from "node:crypto";
26078
- import * as fs61 from "node:fs";
26079
- import * as path63 from "node:path";
26320
+ import * as fs63 from "node:fs";
26321
+ import * as path65 from "node:path";
26080
26322
 
26081
26323
  // src/scripts/_lib/cc_transcript.ts
26082
- import * as path62 from "node:path";
26324
+ import * as path64 from "node:path";
26083
26325
  import { homedir as homedir6 } from "node:os";
26084
- var DEFAULT_PROJECTS_ROOT = path62.join(homedir6(), ".claude", "projects");
26326
+ var DEFAULT_PROJECTS_ROOT = path64.join(homedir6(), ".claude", "projects");
26085
26327
  function billableInputTokens(u) {
26086
26328
  return u.input_tokens + u.cache_read_input_tokens + u.cache_creation_input_tokens;
26087
26329
  }
@@ -26190,17 +26432,17 @@ function scanEolSlice(text, prior) {
26190
26432
  return next;
26191
26433
  }
26192
26434
  function eolStateDir(workspaceRoot2) {
26193
- return path63.join(workspaceRoot2, "agents", "runtime", "state", "session-eol");
26435
+ return path65.join(workspaceRoot2, "agents", "runtime", "state", "session-eol");
26194
26436
  }
26195
26437
  function eolStateFile(workspaceRoot2, sessionKey) {
26196
- return path63.join(eolStateDir(workspaceRoot2), `${sessionKey}.json`);
26438
+ return path65.join(eolStateDir(workspaceRoot2), `${sessionKey}.json`);
26197
26439
  }
26198
26440
  function eolSessionKey(raw) {
26199
26441
  return crypto9.createHash("sha256").update(raw || "unknown-session").digest("hex");
26200
26442
  }
26201
26443
  function readNewCompleteLines(filePath, fromByte) {
26202
26444
  try {
26203
- const { size } = fs61.statSync(filePath);
26445
+ const { size } = fs63.statSync(filePath);
26204
26446
  if (size < fromByte) {
26205
26447
  return { text: "", nextOffset: 0, truncated: true };
26206
26448
  }
@@ -26209,11 +26451,11 @@ function readNewCompleteLines(filePath, fromByte) {
26209
26451
  }
26210
26452
  const length = size - fromByte;
26211
26453
  const buffer = Buffer.alloc(length);
26212
- const fd = fs61.openSync(filePath, "r");
26454
+ const fd = fs63.openSync(filePath, "r");
26213
26455
  try {
26214
- fs61.readSync(fd, buffer, 0, length, fromByte);
26456
+ fs63.readSync(fd, buffer, 0, length, fromByte);
26215
26457
  } finally {
26216
- fs61.closeSync(fd);
26458
+ fs63.closeSync(fd);
26217
26459
  }
26218
26460
  const lastNewline = buffer.lastIndexOf(10);
26219
26461
  if (lastNewline === -1) {
@@ -26230,21 +26472,21 @@ function readNewCompleteLines(filePath, fromByte) {
26230
26472
  }
26231
26473
 
26232
26474
  // src/scripts/hooks/session_eol_hook.ts
26233
- var EXIT_WARN12 = 2;
26475
+ var EXIT_WARN13 = 2;
26234
26476
  var THRESHOLD_OVERRIDE_ENV = "AGENT_RECYCLE_THRESHOLD_TOKENS";
26235
- var CONTEXT_FILL_REL = path64.join("agents", "runtime", "state", "context-fill.json");
26477
+ var CONTEXT_FILL_REL = path66.join("agents", "runtime", "state", "context-fill.json");
26236
26478
  function str7(value) {
26237
26479
  return typeof value === "string" ? value : "";
26238
26480
  }
26239
- var stateFile2 = eolStateFile;
26481
+ var stateFile3 = eolStateFile;
26240
26482
  function deriveSessionKey5(envelope, payload) {
26241
26483
  return eolSessionKey(
26242
26484
  str7(envelope["session_id"]) || str7(payload["transcript_path"] ?? payload["transcriptPath"])
26243
26485
  );
26244
26486
  }
26245
- function readState2(file) {
26487
+ function readState3(file) {
26246
26488
  try {
26247
- const parsed = JSON.parse(fs62.readFileSync(file, "utf-8"));
26489
+ const parsed = JSON.parse(fs64.readFileSync(file, "utf-8"));
26248
26490
  if (parsed && typeof parsed === "object" && parsed.schema_version === 1 && parsed.counters && typeof parsed.counters.scanned_bytes === "number") {
26249
26491
  return {
26250
26492
  schema_version: 1,
@@ -26276,7 +26518,7 @@ function buildAdvisoryLine3(tokens, threshold) {
26276
26518
  }
26277
26519
  function writeContextFill(workspaceRoot2, tokens, threshold, ts) {
26278
26520
  try {
26279
- atomic_write_json(path64.join(workspaceRoot2, CONTEXT_FILL_REL), {
26521
+ atomic_write_json(path66.join(workspaceRoot2, CONTEXT_FILL_REL), {
26280
26522
  schema_version: 1,
26281
26523
  final_context_tokens: tokens,
26282
26524
  recycle_threshold_tokens: threshold,
@@ -26286,7 +26528,7 @@ function writeContextFill(workspaceRoot2, tokens, threshold, ts) {
26286
26528
  } catch {
26287
26529
  }
26288
26530
  }
26289
- function main44() {
26531
+ function main45() {
26290
26532
  const [envelope, payload] = unwrap(readHookStdin(), "claude");
26291
26533
  const event = String(envelope["event"] ?? "");
26292
26534
  if (event !== "" && event !== "stop") {
@@ -26303,8 +26545,8 @@ function main44() {
26303
26545
  return 0;
26304
26546
  }
26305
26547
  const sessionKey = deriveSessionKey5(envelope, payload);
26306
- const file = stateFile2(workspaceRoot2, sessionKey);
26307
- const state = readState2(file);
26548
+ const file = stateFile3(workspaceRoot2, sessionKey);
26549
+ const state = readState3(file);
26308
26550
  let counters = state.counters;
26309
26551
  const read = readNewCompleteLines(transcriptPath, counters.scanned_bytes);
26310
26552
  if (read.truncated) {
@@ -26341,7 +26583,7 @@ function main44() {
26341
26583
  })}
26342
26584
  `
26343
26585
  );
26344
- return EXIT_WARN12;
26586
+ return EXIT_WARN13;
26345
26587
  }
26346
26588
  return 0;
26347
26589
  }
@@ -26352,20 +26594,20 @@ function _isCliEntry35() {
26352
26594
  if (process11.argv[1] === void 0) {
26353
26595
  return false;
26354
26596
  }
26355
- const argvUrl = pathToFileURL39(path64.resolve(process11.argv[1])).href;
26597
+ const argvUrl = pathToFileURL40(path66.resolve(process11.argv[1])).href;
26356
26598
  if (import.meta.url === argvUrl) {
26357
26599
  return true;
26358
26600
  }
26359
26601
  try {
26360
- const here = fs62.realpathSync(fileURLToPath45(import.meta.url));
26361
- const argv = fs62.realpathSync(path64.resolve(process11.argv[1]));
26602
+ const here = fs64.realpathSync(fileURLToPath46(import.meta.url));
26603
+ const argv = fs64.realpathSync(path66.resolve(process11.argv[1]));
26362
26604
  return here === argv;
26363
26605
  } catch {
26364
26606
  return false;
26365
26607
  }
26366
26608
  }
26367
26609
  if (_isCliEntry35()) {
26368
- process11.exit(main44());
26610
+ process11.exit(main45());
26369
26611
  }
26370
26612
 
26371
26613
  // src/scripts/hooks/concern_registry.ts
@@ -26400,13 +26642,14 @@ var CONCERN_REGISTRY = {
26400
26642
  "src/scripts/hooks/rtk_wrap_hook.ts": main33,
26401
26643
  "src/scripts/hooks/design_slop_hook.ts": main35,
26402
26644
  "src/scripts/hooks/code_graph_nudge_hook.ts": main36,
26403
- "src/scripts/hooks/orchestration_record_hook.ts": main38,
26404
- "src/scripts/hooks/delegation_nudge_hook.ts": main39,
26405
- "src/scripts/hooks/end_review_nudge_hook.ts": main40,
26406
- "src/scripts/hooks/turn_end_gate_hook.ts": main41,
26407
- "src/scripts/hooks/edit_shape_hook.ts": main42,
26408
- "src/scripts/hooks/reread_guard_hook.ts": main43,
26409
- "src/scripts/hooks/session_eol_hook.ts": main44
26645
+ "src/scripts/hooks/ui_route_nudge_hook.ts": main37,
26646
+ "src/scripts/hooks/orchestration_record_hook.ts": main39,
26647
+ "src/scripts/hooks/delegation_nudge_hook.ts": main40,
26648
+ "src/scripts/hooks/end_review_nudge_hook.ts": main41,
26649
+ "src/scripts/hooks/turn_end_gate_hook.ts": main42,
26650
+ "src/scripts/hooks/edit_shape_hook.ts": main43,
26651
+ "src/scripts/hooks/reread_guard_hook.ts": main44,
26652
+ "src/scripts/hooks/session_eol_hook.ts": main45
26410
26653
  };
26411
26654
 
26412
26655
  // src/scripts/hooks/host_semantics.ts
@@ -26460,14 +26703,14 @@ function emitFor(platform, event, severity, reasons, legacyExit) {
26460
26703
 
26461
26704
  // src/scripts/hooks/dispatch_hook.ts
26462
26705
  var _IN_BUNDLE = true;
26463
- var REPO_ROOT = path65.resolve(
26464
- path65.dirname(fileURLToPath46(import.meta.url)),
26706
+ var REPO_ROOT = path67.resolve(
26707
+ path67.dirname(fileURLToPath47(import.meta.url)),
26465
26708
  ..._IN_BUNDLE ? ["..", ".."] : ["..", "..", ".."]
26466
26709
  );
26467
- var MANIFEST_PATH = path65.join(REPO_ROOT, "src", "scripts", "hook_manifest.yaml");
26468
- var EXIT_ALLOW20 = 0;
26710
+ var MANIFEST_PATH = path67.join(REPO_ROOT, "src", "scripts", "hook_manifest.yaml");
26711
+ var EXIT_ALLOW21 = 0;
26469
26712
  var EXIT_BLOCK5 = 1;
26470
- var EXIT_WARN13 = 2;
26713
+ var EXIT_WARN14 = 2;
26471
26714
  var EVENT_VOCABULARY = /* @__PURE__ */ new Set([
26472
26715
  "session_start",
26473
26716
  "session_end",
@@ -26479,9 +26722,9 @@ var EVENT_VOCABULARY = /* @__PURE__ */ new Set([
26479
26722
  "agent_error"
26480
26723
  ]);
26481
26724
  var _SEVERITY_BY_EXIT = {
26482
- [EXIT_ALLOW20]: "allow",
26725
+ [EXIT_ALLOW21]: "allow",
26483
26726
  [EXIT_BLOCK5]: "block",
26484
- [EXIT_WARN13]: "warn"
26727
+ [EXIT_WARN14]: "warn"
26485
26728
  };
26486
26729
  function _isObject14(v) {
26487
26730
  return typeof v === "object" && v !== null && !Array.isArray(v);
@@ -26516,7 +26759,7 @@ function _parse_concern_stdout(stdout_text) {
26516
26759
  return _isObject14(parsed) ? parsed : { _raw: parsed };
26517
26760
  }
26518
26761
  function _load_yaml3(p) {
26519
- const text = fs63.readFileSync(p, "utf-8");
26762
+ const text = fs65.readFileSync(p, "utf-8");
26520
26763
  const data = (0, import_yaml6.parse)(text, { version: "1.1" });
26521
26764
  return _isObject14(data) ? data : {};
26522
26765
  }
@@ -26673,7 +26916,7 @@ function _maybe_capture_payload(args, payload_text) {
26673
26916
  }
26674
26917
  try {
26675
26918
  const target = _expanduser3(capture_dir);
26676
- fs63.mkdirSync(target, { recursive: true });
26919
+ fs65.mkdirSync(target, { recursive: true });
26677
26920
  let payload;
26678
26921
  try {
26679
26922
  payload = payload_text.trim() ? JSON.parse(payload_text) : {};
@@ -26690,8 +26933,8 @@ function _maybe_capture_payload(args, payload_text) {
26690
26933
  const ts = Date.now();
26691
26934
  const native = (args.native_event || args.event).replace(/\//g, "_");
26692
26935
  const fname = `${args.platform}__${native}__${ts}__${process.pid}.json`;
26693
- fs63.writeFileSync(
26694
- path65.join(target, fname),
26936
+ fs65.writeFileSync(
26937
+ path67.join(target, fname),
26695
26938
  _py_json_dumps2(record, 2) + "\n",
26696
26939
  { encoding: "utf-8" }
26697
26940
  );
@@ -26702,7 +26945,7 @@ function _maybe_capture_payload(args, payload_text) {
26702
26945
  function _expanduser3(p) {
26703
26946
  if (p === "~" || p.startsWith("~/")) {
26704
26947
  const home = process.env["HOME"] || process.env["USERPROFILE"] || "";
26705
- return path65.join(home, p.slice(1));
26948
+ return path67.join(home, p.slice(1));
26706
26949
  }
26707
26950
  return p;
26708
26951
  }
@@ -26734,25 +26977,25 @@ function _resolve_tsx_invocation2(scriptPath, scriptArgs) {
26734
26977
  const walkUp = (start) => {
26735
26978
  let dir = start;
26736
26979
  for (; ; ) {
26737
- const candidate = path65.join(dir, "node_modules", ".bin", binName);
26980
+ const candidate = path67.join(dir, "node_modules", ".bin", binName);
26738
26981
  if (_isFile7(candidate)) {
26739
26982
  return candidate;
26740
26983
  }
26741
- const parent = path65.dirname(dir);
26984
+ const parent = path67.dirname(dir);
26742
26985
  if (parent === dir) {
26743
26986
  return null;
26744
26987
  }
26745
26988
  dir = parent;
26746
26989
  }
26747
26990
  };
26748
- const tsx = walkUp(path65.dirname(scriptPath)) ?? walkUp(path65.dirname(fileURLToPath46(import.meta.url)));
26991
+ const tsx = walkUp(path67.dirname(scriptPath)) ?? walkUp(path67.dirname(fileURLToPath47(import.meta.url)));
26749
26992
  if (tsx !== null) {
26750
26993
  return { command: tsx, args: [scriptPath, ...scriptArgs] };
26751
26994
  }
26752
26995
  return { command: "npx", args: ["tsx", scriptPath, ...scriptArgs] };
26753
26996
  }
26754
26997
  function _run_concern_inproc(main_fn, concern, envelope) {
26755
- const scriptAbs = path65.join(REPO_ROOT, String(concern["script"]));
26998
+ const scriptAbs = path67.join(REPO_ROOT, String(concern["script"]));
26756
26999
  const argsList = Array.isArray(concern["args"]) ? concern["args"].map((a) => String(a)) : [];
26757
27000
  argsList.push("--platform", String(envelope["platform"] || "generic"));
26758
27001
  const workspace = String(envelope["workspace_root"] || process.cwd());
@@ -26829,7 +27072,7 @@ function _run_concern(concern, envelope) {
26829
27072
  return _run_concern_inproc(inproc, concern, envelope);
26830
27073
  }
26831
27074
  }
26832
- const script = path65.join(REPO_ROOT, String(concern["script"]));
27075
+ const script = path67.join(REPO_ROOT, String(concern["script"]));
26833
27076
  const argsList = Array.isArray(concern["args"]) ? concern["args"].map((a) => String(a)) : [];
26834
27077
  const cmd = [script, ...argsList];
26835
27078
  cmd.push("--platform", String(envelope["platform"] || "generic"));
@@ -26886,7 +27129,7 @@ function _run_concern(concern, envelope) {
26886
27129
  }
26887
27130
  function _isFile7(p) {
26888
27131
  try {
26889
- return fs63.statSync(p).isFile();
27132
+ return fs65.statSync(p).isFile();
26890
27133
  } catch {
26891
27134
  return false;
26892
27135
  }
@@ -26898,20 +27141,20 @@ function _reduce(rcs) {
26898
27141
  if (rcs.some((rc) => rc === EXIT_BLOCK5)) {
26899
27142
  return EXIT_BLOCK5;
26900
27143
  }
26901
- if (rcs.some((rc) => rc === EXIT_WARN13)) {
26902
- return EXIT_WARN13;
27144
+ if (rcs.some((rc) => rc === EXIT_WARN14)) {
27145
+ return EXIT_WARN14;
26903
27146
  }
26904
- return EXIT_ALLOW20;
27147
+ return EXIT_ALLOW21;
26905
27148
  }
26906
27149
  function _write_feedback(envelope, session_id, entries, final_rc, started_at) {
26907
27150
  if (is_replay_mode()) {
26908
27151
  return;
26909
27152
  }
26910
27153
  const workspace = String(envelope["workspace_root"] || process.cwd());
26911
- const state_root = path65.join(workspace, "agents", "runtime", "state");
27154
+ const state_root = path67.join(workspace, "agents", "runtime", "state");
26912
27155
  const fb_dir = feedback_dir(state_root, session_id);
26913
27156
  try {
26914
- fs63.mkdirSync(fb_dir, { recursive: true });
27157
+ fs65.mkdirSync(fb_dir, { recursive: true });
26915
27158
  } catch (exc) {
26916
27159
  const msg = exc instanceof Error ? exc.message : String(exc);
26917
27160
  process.stderr.write(`dispatch_hook: feedback dir unavailable: ${msg}
@@ -26919,7 +27162,7 @@ function _write_feedback(envelope, session_id, entries, final_rc, started_at) {
26919
27162
  return;
26920
27163
  }
26921
27164
  for (const entry of entries) {
26922
- const target = path65.join(fb_dir, `${entry["concern"]}.json`);
27165
+ const target = path67.join(fb_dir, `${entry["concern"]}.json`);
26923
27166
  try {
26924
27167
  atomic_write_json(target, entry);
26925
27168
  } catch (exc) {
@@ -26959,7 +27202,7 @@ function _write_feedback(envelope, session_id, entries, final_rc, started_at) {
26959
27202
  })
26960
27203
  };
26961
27204
  try {
26962
- atomic_write_json(path65.join(fb_dir, "summary.json"), summary);
27205
+ atomic_write_json(path67.join(fb_dir, "summary.json"), summary);
26963
27206
  } catch (exc) {
26964
27207
  const msg = exc instanceof Error ? exc.message : String(exc);
26965
27208
  process.stderr.write(`dispatch_hook: summary write failed: ${msg}
@@ -26969,17 +27212,17 @@ function _write_feedback(envelope, session_id, entries, final_rc, started_at) {
26969
27212
  function _record_rule_trips(envelope, entries) {
26970
27213
  if (is_replay_mode()) return;
26971
27214
  const tripped = entries.filter(
26972
- (e) => e["exit_code"] === EXIT_BLOCK5 || e["exit_code"] === EXIT_WARN13
27215
+ (e) => e["exit_code"] === EXIT_BLOCK5 || e["exit_code"] === EXIT_WARN14
26973
27216
  );
26974
27217
  if (tripped.length === 0) return;
26975
27218
  try {
26976
27219
  const workspace = String(envelope["workspace_root"] || process.cwd());
26977
- const state_dir = path65.join(workspace, "agents", "runtime", "state");
26978
- const target = path65.join(state_dir, "rule-trips.json");
26979
- fs63.mkdirSync(state_dir, { recursive: true });
27220
+ const state_dir = path67.join(workspace, "agents", "runtime", "state");
27221
+ const target = path67.join(state_dir, "rule-trips.json");
27222
+ fs65.mkdirSync(state_dir, { recursive: true });
26980
27223
  let doc = { schema_version: 1, concerns: {} };
26981
27224
  try {
26982
- const parsed = JSON.parse(fs63.readFileSync(target, "utf-8"));
27225
+ const parsed = JSON.parse(fs65.readFileSync(target, "utf-8"));
26983
27226
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) doc = parsed;
26984
27227
  } catch {
26985
27228
  }
@@ -26990,7 +27233,7 @@ function _record_rule_trips(envelope, entries) {
26990
27233
  const prev = concerns[name] ?? { block: 0, warn: 0 };
26991
27234
  concerns[name] = {
26992
27235
  block: (Number(prev["block"]) || 0) + (e["exit_code"] === EXIT_BLOCK5 ? 1 : 0),
26993
- warn: (Number(prev["warn"]) || 0) + (e["exit_code"] === EXIT_WARN13 ? 1 : 0),
27236
+ warn: (Number(prev["warn"]) || 0) + (e["exit_code"] === EXIT_WARN14 ? 1 : 0),
26994
27237
  last_trip: today
26995
27238
  };
26996
27239
  }
@@ -27078,7 +27321,7 @@ function _parse_args(argv) {
27078
27321
  }
27079
27322
  return args;
27080
27323
  }
27081
- function main45(argv) {
27324
+ function main46(argv) {
27082
27325
  const args = _parse_args(argv ?? process.argv.slice(2));
27083
27326
  if (args.project_dir) {
27084
27327
  const project_dir = _expanduser3(args.project_dir);
@@ -27096,13 +27339,13 @@ function main45(argv) {
27096
27339
  `dispatch_hook: unknown event '${args.event}'; allowed: ${_sortedRepr(EVENT_VOCABULARY)}
27097
27340
  `
27098
27341
  );
27099
- return EXIT_ALLOW20;
27342
+ return EXIT_ALLOW21;
27100
27343
  }
27101
27344
  const manifest_path = args.manifest;
27102
- if (!fs63.existsSync(manifest_path)) {
27345
+ if (!fs65.existsSync(manifest_path)) {
27103
27346
  process.stderr.write(`dispatch_hook: manifest missing at ${manifest_path}
27104
27347
  `);
27105
- return EXIT_ALLOW20;
27348
+ return EXIT_ALLOW21;
27106
27349
  }
27107
27350
  const manifest = _load_yaml3(manifest_path);
27108
27351
  if (args.min_version) {
@@ -27126,10 +27369,10 @@ function main45(argv) {
27126
27369
  concerns: concerns.map((c) => c["name"])
27127
27370
  };
27128
27371
  process.stdout.write(_py_json_dumps2(plan, 2) + "\n");
27129
- return EXIT_ALLOW20;
27372
+ return EXIT_ALLOW21;
27130
27373
  }
27131
27374
  if (concerns.length === 0) {
27132
- return EXIT_ALLOW20;
27375
+ return EXIT_ALLOW21;
27133
27376
  }
27134
27377
  const envelope = _build_envelope(args, payload_text);
27135
27378
  const session_id = _resolve_session_id(envelope);
@@ -27149,7 +27392,7 @@ function main45(argv) {
27149
27392
  const raw_rc = rc;
27150
27393
  if (rc >= 3) {
27151
27394
  if (!concern["fail_closed"]) {
27152
- rc = EXIT_ALLOW20;
27395
+ rc = EXIT_ALLOW21;
27153
27396
  } else {
27154
27397
  rc = EXIT_BLOCK5;
27155
27398
  }
@@ -27162,7 +27405,7 @@ function main45(argv) {
27162
27405
  `dispatch_hook: concern '${String(concern["name"])}' is declared severity: advisory but returned BLOCK \u2014 downgraded to warn.
27163
27406
  `
27164
27407
  );
27165
- rc = EXIT_WARN13;
27408
+ rc = EXIT_WARN14;
27166
27409
  }
27167
27410
  rcs.push(rc);
27168
27411
  const reply = _parse_concern_stdout(stdout_text);
@@ -27172,7 +27415,7 @@ function main45(argv) {
27172
27415
  if (message) {
27173
27416
  concern_messages.push({ rc, text: message });
27174
27417
  }
27175
- if (args.event === "session_start" && rc === EXIT_ALLOW20 && typeof reply["context"] === "string" && reply["context"].trim()) {
27418
+ if (args.event === "session_start" && rc === EXIT_ALLOW21 && typeof reply["context"] === "string" && reply["context"].trim()) {
27176
27419
  context_blocks.push(reply["context"].trim());
27177
27420
  }
27178
27421
  feedback_entries.push({
@@ -27191,7 +27434,7 @@ function main45(argv) {
27191
27434
  const final_rc = _reduce(rcs);
27192
27435
  _write_feedback(envelope, session_id, feedback_entries, final_rc, started_at);
27193
27436
  _record_rule_trips(envelope, feedback_entries);
27194
- if (context_blocks.length > 0 && final_rc === EXIT_ALLOW20) {
27437
+ if (context_blocks.length > 0 && final_rc === EXIT_ALLOW21) {
27195
27438
  process.stdout.write(context_blocks.join("\n\n") + "\n");
27196
27439
  }
27197
27440
  const decidingReasons = concern_messages.filter((m) => m.rc === final_rc).map((m) => m.text);
@@ -27212,7 +27455,7 @@ function main45(argv) {
27212
27455
  }
27213
27456
  function _isDir4(p) {
27214
27457
  try {
27215
- return fs63.statSync(p).isDirectory();
27458
+ return fs65.statSync(p).isDirectory();
27216
27459
  } catch {
27217
27460
  return false;
27218
27461
  }
@@ -27223,7 +27466,7 @@ function _sortedRepr(s) {
27223
27466
  }
27224
27467
  function _readStdin14() {
27225
27468
  try {
27226
- return fs63.readFileSync(0, "utf-8");
27469
+ return fs65.readFileSync(0, "utf-8");
27227
27470
  } catch {
27228
27471
  return "";
27229
27472
  }
@@ -27235,29 +27478,29 @@ function _isCliEntry36() {
27235
27478
  if (process.argv[1] === void 0) {
27236
27479
  return false;
27237
27480
  }
27238
- const argvUrl = pathToFileURL40(path65.resolve(process.argv[1])).href;
27481
+ const argvUrl = pathToFileURL41(path67.resolve(process.argv[1])).href;
27239
27482
  if (import.meta.url === argvUrl) {
27240
27483
  return true;
27241
27484
  }
27242
27485
  try {
27243
- const here = fs63.realpathSync(fileURLToPath46(import.meta.url));
27244
- const argv = fs63.realpathSync(path65.resolve(process.argv[1]));
27486
+ const here = fs65.realpathSync(fileURLToPath47(import.meta.url));
27487
+ const argv = fs65.realpathSync(path67.resolve(process.argv[1]));
27245
27488
  return here === argv;
27246
27489
  } catch {
27247
27490
  return false;
27248
27491
  }
27249
27492
  }
27250
- var isCliEntry12 = _isCliEntry36();
27251
- if (isCliEntry12) {
27252
- process.exit(main45(process.argv.slice(2)));
27493
+ var isCliEntry13 = _isCliEntry36();
27494
+ if (isCliEntry13) {
27495
+ process.exit(main46(process.argv.slice(2)));
27253
27496
  }
27254
27497
 
27255
27498
  // src/scripts/hooks/dispatch_entry.ts
27256
- var _selfPath = fileURLToPath47(import.meta.url);
27257
- var _invokedDirectly2 = globalThis.__AC_HOOKS_BUNDLE_DIRECT === true || process.argv[1] !== void 0 && path66.resolve(process.argv[1]) === path66.resolve(_selfPath);
27499
+ var _selfPath = fileURLToPath48(import.meta.url);
27500
+ var _invokedDirectly2 = globalThis.__AC_HOOKS_BUNDLE_DIRECT === true || process.argv[1] !== void 0 && path68.resolve(process.argv[1]) === path68.resolve(_selfPath);
27258
27501
  if (_invokedDirectly2) {
27259
- process.exitCode = main45(process.argv.slice(2));
27502
+ process.exitCode = main46(process.argv.slice(2));
27260
27503
  }
27261
27504
  export {
27262
- main45 as main
27505
+ main46 as main
27263
27506
  };