@event4u/agent-config 9.24.0 → 9.26.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 (97) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +136 -0
  3. package/README.md +1 -1
  4. package/dist/agent-src/commands/analyze/conformance.md +182 -0
  5. package/dist/agent-src/commands/analyze/inbox.md +33 -2
  6. package/dist/agent-src/commands/review/changes.md +6 -5
  7. package/dist/agent-src/commands/roadmap/next.md +194 -0
  8. package/dist/agent-src/commands/roadmap.md +12 -4
  9. package/dist/agent-src/contexts/execution/subagent-routing.md +4 -1
  10. package/dist/agent-src/rules/decision-revisit-gate.md +2 -0
  11. package/dist/agent-src/rules/delegation-policy.md +3 -2
  12. package/dist/agent-src/rules/design-fidelity.md +17 -1
  13. package/dist/agent-src/rules/design-review-after-ui-write.md +116 -0
  14. package/dist/agent-src/rules/evaluator-independence.md +111 -0
  15. package/dist/agent-src/rules/session-canary.md +15 -1
  16. package/dist/agent-src/rules/settings-ask-protocol.md +176 -0
  17. package/dist/agent-src/rules/token-budget-discipline.md +6 -3
  18. package/dist/agent-src/rules/ui-audit-gate.md +3 -0
  19. package/dist/agent-src/rules/user-interaction.md +23 -0
  20. package/dist/agent-src/skills/finishing-a-development-branch/SKILL.md +1 -1
  21. package/dist/agent-src/skills/recursive-verification/SKILL.md +13 -0
  22. package/dist/agent-src/skills/rule-writing/SKILL.md +45 -0
  23. package/dist/agent-src/skills/skill-writing/SKILL.md +114 -0
  24. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  25. package/dist/cli/registry.js +1 -0
  26. package/dist/cli/registry.js.map +1 -1
  27. package/dist/cli-delegate/cmd_route_audit.js +4 -1
  28. package/dist/cli-delegate/cmd_route_explain.js +4 -1
  29. package/dist/discovery/deprecation-report.md +1 -1
  30. package/dist/discovery/discovery-manifest.json +146 -28
  31. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  32. package/dist/discovery/discovery-manifest.summary.md +5 -5
  33. package/dist/discovery/orphan-report.md +1 -1
  34. package/dist/discovery/packs.json +16 -11
  35. package/dist/discovery/trust-report.md +3 -3
  36. package/dist/discovery/workspaces.json +12 -7
  37. package/dist/hooks/dispatch.js +1501 -511
  38. package/dist/mcp/registry-manifest.json +3 -3
  39. package/dist/mcp/server.json +2 -2
  40. package/dist/router.json +1 -1
  41. package/dist/server/nicknameResolver.js +116 -0
  42. package/dist/server/nicknameResolver.js.map +1 -0
  43. package/dist/server/routes/ping.js +29 -11
  44. package/dist/server/routes/ping.js.map +1 -1
  45. package/dist/shared/interactiveContext.js +73 -0
  46. package/dist/shared/interactiveContext.js.map +1 -0
  47. package/dist/shared/nicknamePrefill.js +59 -0
  48. package/dist/shared/nicknamePrefill.js.map +1 -0
  49. package/dist/shared/settingsAsks.js +128 -0
  50. package/dist/shared/settingsAsks.js.map +1 -0
  51. package/dist/shared/settingsConsent.js +93 -0
  52. package/dist/shared/settingsConsent.js.map +1 -0
  53. package/package.json +1 -1
  54. package/src/config/agents-paths.yml +15 -0
  55. package/src/config/evaluator-budgets.json +68 -68
  56. package/src/config/gate-coverage.yml +131 -5
  57. package/src/config/gate-violation-baselines.json +11 -0
  58. package/src/scripts/_cli/cmd_route_audit.ts +4 -1
  59. package/src/scripts/_cli/cmd_route_explain.ts +9 -1
  60. package/src/scripts/_dispatch.bash +12 -0
  61. package/src/scripts/ai-video/stitch.sh +27 -9
  62. package/src/scripts/before_complete_hook.ts +146 -5
  63. package/src/scripts/bench_ab_v2_run.ts +272 -16
  64. package/src/scripts/bench_ab_v2_stats.ts +156 -3
  65. package/src/scripts/check_completion_review.ts +80 -3
  66. package/src/scripts/check_corpus_staleness.ts +692 -0
  67. package/src/scripts/check_depth_budget.ts +295 -0
  68. package/src/scripts/check_gate_coverage.ts +67 -0
  69. package/src/scripts/check_hook_bundle_freshness.ts +183 -0
  70. package/src/scripts/conformance_scan.ts +422 -0
  71. package/src/scripts/dispatch_r2_reviewer.ts +31 -2
  72. package/src/scripts/git_authorization_hook.ts +328 -0
  73. package/src/scripts/hook_manifest.yaml +69 -9
  74. package/src/scripts/hooks/block_no_verify.ts +3 -1
  75. package/src/scripts/hooks/block_unauthorized_git.ts +371 -0
  76. package/src/scripts/hooks/concern_registry.ts +8 -0
  77. package/src/scripts/hooks/design_slop_hook.ts +13 -1
  78. package/src/scripts/hooks/dispatch_hook.ts +97 -2
  79. package/src/scripts/hooks/evidence_independence.ts +368 -0
  80. package/src/scripts/language_mirror_hook.ts +456 -0
  81. package/src/scripts/lint_abstraction_thresholds.ts +41 -8
  82. package/src/scripts/lint_agents_layout.ts +2 -0
  83. package/src/scripts/lint_decision_impact.ts +246 -0
  84. package/src/scripts/lint_example_fences.ts +609 -0
  85. package/src/scripts/lint_hook_manifest.ts +29 -0
  86. package/src/scripts/lint_rule_interactions.ts +90 -0
  87. package/src/scripts/lint_rule_migration_ledger.ts +480 -0
  88. package/src/scripts/lint_skill_descriptions.ts +86 -2
  89. package/src/scripts/memory_learn_hook.ts +109 -6
  90. package/src/scripts/pr_url_reminder_hook.ts +17 -2
  91. package/src/scripts/release.ts +38 -1
  92. package/src/scripts/schemas/review-findings.schema.json +99 -0
  93. package/src/scripts/schemas/rule.schema.json +10 -0
  94. package/src/shared/interactiveContext.ts +98 -0
  95. package/src/shared/nicknamePrefill.ts +96 -0
  96. package/src/shared/settingsAsks.ts +176 -0
  97. package/src/shared/settingsConsent.ts +136 -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, path43) {
116
- const ctrl = callVisitor(key, node, visitor, path43);
115
+ function visit_(key, node, visitor, path47) {
116
+ const ctrl = callVisitor(key, node, visitor, path47);
117
117
  if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
118
- replaceNode(key, path43, ctrl);
119
- return visit_(key, ctrl, visitor, path43);
118
+ replaceNode(key, path47, ctrl);
119
+ return visit_(key, ctrl, visitor, path47);
120
120
  }
121
121
  if (typeof ctrl !== "symbol") {
122
122
  if (identity.isCollection(node)) {
123
- path43 = Object.freeze(path43.concat(node));
123
+ path47 = Object.freeze(path47.concat(node));
124
124
  for (let i = 0; i < node.items.length; ++i) {
125
- const ci = visit_(i, node.items[i], visitor, path43);
125
+ const ci = visit_(i, node.items[i], visitor, path47);
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
- path43 = Object.freeze(path43.concat(node));
137
- const ck = visit_("key", node.key, visitor, path43);
136
+ path47 = Object.freeze(path47.concat(node));
137
+ const ck = visit_("key", node.key, visitor, path47);
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, path43);
142
+ const cv = visit_("value", node.value, visitor, path47);
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, path43) {
164
- const ctrl = await callVisitor(key, node, visitor, path43);
163
+ async function visitAsync_(key, node, visitor, path47) {
164
+ const ctrl = await callVisitor(key, node, visitor, path47);
165
165
  if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
166
- replaceNode(key, path43, ctrl);
167
- return visitAsync_(key, ctrl, visitor, path43);
166
+ replaceNode(key, path47, ctrl);
167
+ return visitAsync_(key, ctrl, visitor, path47);
168
168
  }
169
169
  if (typeof ctrl !== "symbol") {
170
170
  if (identity.isCollection(node)) {
171
- path43 = Object.freeze(path43.concat(node));
171
+ path47 = Object.freeze(path47.concat(node));
172
172
  for (let i = 0; i < node.items.length; ++i) {
173
- const ci = await visitAsync_(i, node.items[i], visitor, path43);
173
+ const ci = await visitAsync_(i, node.items[i], visitor, path47);
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
- path43 = Object.freeze(path43.concat(node));
185
- const ck = await visitAsync_("key", node.key, visitor, path43);
184
+ path47 = Object.freeze(path47.concat(node));
185
+ const ck = await visitAsync_("key", node.key, visitor, path47);
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, path43);
190
+ const cv = await visitAsync_("value", node.value, visitor, path47);
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, path43) {
217
+ function callVisitor(key, node, visitor, path47) {
218
218
  if (typeof visitor === "function")
219
- return visitor(key, node, path43);
219
+ return visitor(key, node, path47);
220
220
  if (identity.isMap(node))
221
- return visitor.Map?.(key, node, path43);
221
+ return visitor.Map?.(key, node, path47);
222
222
  if (identity.isSeq(node))
223
- return visitor.Seq?.(key, node, path43);
223
+ return visitor.Seq?.(key, node, path47);
224
224
  if (identity.isPair(node))
225
- return visitor.Pair?.(key, node, path43);
225
+ return visitor.Pair?.(key, node, path47);
226
226
  if (identity.isScalar(node))
227
- return visitor.Scalar?.(key, node, path43);
227
+ return visitor.Scalar?.(key, node, path47);
228
228
  if (identity.isAlias(node))
229
- return visitor.Alias?.(key, node, path43);
229
+ return visitor.Alias?.(key, node, path47);
230
230
  return void 0;
231
231
  }
232
- function replaceNode(key, path43, node) {
233
- const parent = path43[path43.length - 1];
232
+ function replaceNode(key, path47, node) {
233
+ const parent = path47[path47.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, path43, value) {
843
+ function collectionFromPath(schema, path47, value) {
844
844
  let v = value;
845
- for (let i = path43.length - 1; i >= 0; --i) {
846
- const k = path43[i];
845
+ for (let i = path47.length - 1; i >= 0; --i) {
846
+ const k = path47[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 = (path43) => path43 == null || typeof path43 === "object" && !!path43[Symbol.iterator]().next().done;
865
+ var isEmptyPath = (path47) => path47 == null || typeof path47 === "object" && !!path47[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(path43, value) {
896
- if (isEmptyPath(path43))
895
+ addIn(path47, value) {
896
+ if (isEmptyPath(path47))
897
897
  this.add(value);
898
898
  else {
899
- const [key, ...rest] = path43;
899
+ const [key, ...rest] = path47;
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(path43) {
914
- const [key, ...rest] = path43;
913
+ deleteIn(path47) {
914
+ const [key, ...rest] = path47;
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(path43, keepScalar) {
929
- const [key, ...rest] = path43;
928
+ getIn(path47, keepScalar) {
929
+ const [key, ...rest] = path47;
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(path43) {
948
- const [key, ...rest] = path43;
947
+ hasIn(path47) {
948
+ const [key, ...rest] = path47;
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(path43, value) {
959
- const [key, ...rest] = path43;
958
+ setIn(path47, value) {
959
+ const [key, ...rest] = path47;
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(path43, value) {
3474
+ addIn(path47, value) {
3475
3475
  if (assertCollection(this.contents))
3476
- this.contents.addIn(path43, value);
3476
+ this.contents.addIn(path47, 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(path43) {
3552
- if (Collection.isEmptyPath(path43)) {
3551
+ deleteIn(path47) {
3552
+ if (Collection.isEmptyPath(path47)) {
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(path43) : false;
3558
+ return assertCollection(this.contents) ? this.contents.deleteIn(path47) : 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(path43, keepScalar) {
3574
- if (Collection.isEmptyPath(path43))
3573
+ getIn(path47, keepScalar) {
3574
+ if (Collection.isEmptyPath(path47))
3575
3575
  return !keepScalar && identity.isScalar(this.contents) ? this.contents.value : this.contents;
3576
- return identity.isCollection(this.contents) ? this.contents.getIn(path43, keepScalar) : void 0;
3576
+ return identity.isCollection(this.contents) ? this.contents.getIn(path47, 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(path43) {
3588
- if (Collection.isEmptyPath(path43))
3587
+ hasIn(path47) {
3588
+ if (Collection.isEmptyPath(path47))
3589
3589
  return this.contents !== void 0;
3590
- return identity.isCollection(this.contents) ? this.contents.hasIn(path43) : false;
3590
+ return identity.isCollection(this.contents) ? this.contents.hasIn(path47) : 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(path43, value) {
3608
- if (Collection.isEmptyPath(path43)) {
3607
+ setIn(path47, value) {
3608
+ if (Collection.isEmptyPath(path47)) {
3609
3609
  this.contents = value;
3610
3610
  } else if (this.contents == null) {
3611
- this.contents = Collection.collectionFromPath(this.schema, Array.from(path43), value);
3611
+ this.contents = Collection.collectionFromPath(this.schema, Array.from(path47), value);
3612
3612
  } else if (assertCollection(this.contents)) {
3613
- this.contents.setIn(path43, value);
3613
+ this.contents.setIn(path47, 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, path43) => {
5573
+ visit.itemAtPath = (cst, path47) => {
5574
5574
  let item = cst;
5575
- for (const [field, index] of path43) {
5575
+ for (const [field, index] of path47) {
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, path43) => {
5585
- const parent = visit.itemAtPath(cst, path43.slice(0, -1));
5586
- const field = path43[path43.length - 1][0];
5584
+ visit.parentCollection = (cst, path47) => {
5585
+ const parent = visit.itemAtPath(cst, path47.slice(0, -1));
5586
+ const field = path47[path47.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(path43, item, visitor) {
5593
- let ctrl = visitor(item, path43);
5592
+ function _visit(path47, item, visitor) {
5593
+ let ctrl = visitor(item, path47);
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(path43.concat([[field, i]])), token.items[i], visitor);
5600
+ const ci = _visit(Object.freeze(path47.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, path43);
5611
+ ctrl = ctrl(item, path47);
5612
5612
  }
5613
5613
  }
5614
- return typeof ctrl === "function" ? ctrl(item, path43) : ctrl;
5614
+ return typeof ctrl === "function" ? ctrl(item, path47) : 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 fs42 = this.flowScalar(this.type);
6916
+ const fs46 = this.flowScalar(this.type);
6917
6917
  if (atNextItem || it.value) {
6918
- map.items.push({ start, key: fs42, sep: [] });
6918
+ map.items.push({ start, key: fs46, sep: [] });
6919
6919
  this.onKeyLine = true;
6920
6920
  } else if (it.sep) {
6921
- this.stack.push(fs42);
6921
+ this.stack.push(fs46);
6922
6922
  } else {
6923
- Object.assign(it, { key: fs42, sep: [] });
6923
+ Object.assign(it, { key: fs46, 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 fs42 = this.flowScalar(this.type);
7051
+ const fs46 = this.flowScalar(this.type);
7052
7052
  if (!it || it.value)
7053
- fc.items.push({ start: [], key: fs42, sep: [] });
7053
+ fc.items.push({ start: [], key: fs46, sep: [] });
7054
7054
  else if (it.sep)
7055
- this.stack.push(fs42);
7055
+ this.stack.push(fs46);
7056
7056
  else
7057
- Object.assign(it, { key: fs42, sep: [] });
7057
+ Object.assign(it, { key: fs46, 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 path42 from "node:path";
7367
- import { fileURLToPath as fileURLToPath32 } from "node:url";
7366
+ import * as path46 from "node:path";
7367
+ import { fileURLToPath as fileURLToPath36 } 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 spawnSync5 } from "node:child_process";
7372
- import fs41 from "node:fs";
7373
- import path41 from "node:path";
7374
- import { fileURLToPath as fileURLToPath31, pathToFileURL as pathToFileURL26 } from "node:url";
7372
+ import fs45 from "node:fs";
7373
+ import path45 from "node:path";
7374
+ import { fileURLToPath as fileURLToPath35, pathToFileURL as pathToFileURL30 } from "node:url";
7375
7375
 
7376
7376
  // src/scripts/_lib/spawn_env.ts
7377
7377
  var DENY_EXACT = /* @__PURE__ */ new Set([
@@ -15061,6 +15061,8 @@ function _empty_state2() {
15061
15061
  verifications_this_session: 0,
15062
15062
  last_stop_at: null,
15063
15063
  verified_this_turn: false,
15064
+ ci_saw_pending: false,
15065
+ nonevidence_this_turn: 0,
15064
15066
  checked_at: _now2()
15065
15067
  };
15066
15068
  }
@@ -15107,13 +15109,70 @@ function _extract_command(payload) {
15107
15109
  return [tool, null];
15108
15110
  }
15109
15111
  function _is_verification(command) {
15110
- return _VERIFICATION_RE.test(command);
15112
+ return _VERIFICATION_RE.test(command) || isCiPoll(command);
15113
+ }
15114
+ var _VACUOUS_PATTERNS = [
15115
+ // gh pr checks / gh run — no checks registered at all.
15116
+ /\b0\s+(?:checks?|runs?)\b/i,
15117
+ // Test runners reporting an empty run.
15118
+ /\bno tests? (?:ran|found|to run|were run)\b/i,
15119
+ /\bNo test files found\b/i,
15120
+ /\b0\s+pass(?:ed|ing)?\b[\s,|·]*\b0\s+fail(?:ed|ing|ures)?\b/i,
15121
+ /\bTests?\s+0\s+passed\b/i,
15122
+ /\bRan 0 tests?\b/i,
15123
+ // Linters / scanners with an empty target set.
15124
+ /\bno files? (?:matched|to (?:lint|check|scan)|found)\b/i,
15125
+ /\b0\s+files?\s+(?:checked|scanned|linted)\b/i,
15126
+ /\bnothing to check\b/i
15127
+ ];
15128
+ function isVacuousOutput(output) {
15129
+ const text = output.trim();
15130
+ if (!text) {
15131
+ return false;
15132
+ }
15133
+ const lines = text.split("\n").filter((l) => l.trim());
15134
+ return lines.every((l) => _VACUOUS_PATTERNS.some((re) => re.test(l)));
15135
+ }
15136
+ var _CI_POLL_RE = /\bgh\s+(?:pr\s+checks|run\s+(?:watch|list|view))\b/i;
15137
+ function isCiPoll(command) {
15138
+ return _CI_POLL_RE.test(command);
15139
+ }
15140
+ function pendingCount(output) {
15141
+ const m = /(\d+)\s+(?:checks? )?pending\b/i.exec(output) ?? /\bpending[:=]\s*(\d+)/i.exec(output);
15142
+ if (m?.[1] !== void 0) {
15143
+ return Number(m[1]);
15144
+ }
15145
+ const rows = output.match(/^\S.*\b(pending|in_progress|queued)\b/gim);
15146
+ if (rows) {
15147
+ return rows.length;
15148
+ }
15149
+ if (/\bno checks reported\b/i.test(output)) {
15150
+ return null;
15151
+ }
15152
+ if (/^\S+\s+(pass|fail|skipping|successful|failing)\b/im.test(output)) {
15153
+ return 0;
15154
+ }
15155
+ return null;
15156
+ }
15157
+ function _extract_output(payload) {
15158
+ for (const key of ["tool_response", "toolResponse", "output", "stdout", "result"]) {
15159
+ const v = payload[key];
15160
+ if (typeof v === "string") {
15161
+ return v;
15162
+ }
15163
+ if (v !== null && typeof v === "object") {
15164
+ return JSON.stringify(v);
15165
+ }
15166
+ }
15167
+ return null;
15111
15168
  }
15112
15169
  function _reset_turn(state, session_id) {
15113
15170
  state["session_id"] = session_id || state["session_id"] || "";
15114
15171
  state["turn_started_at"] = _now2();
15115
15172
  state["verifications_this_turn"] = 0;
15116
15173
  state["verified_this_turn"] = false;
15174
+ state["ci_saw_pending"] = false;
15175
+ state["nonevidence_this_turn"] = 0;
15117
15176
  return state;
15118
15177
  }
15119
15178
  function _asInt2(v) {
@@ -15143,15 +15202,35 @@ function _update2(state, event, envelope) {
15143
15202
  } else if (event === "post_tool_use") {
15144
15203
  const [tool, cmd] = _extract_command(pl);
15145
15204
  if (cmd && _is_verification(cmd)) {
15205
+ const output = _extract_output(pl);
15206
+ const vacuous = output !== null && isVacuousOutput(output);
15207
+ let counts = !vacuous;
15208
+ if (isCiPoll(cmd)) {
15209
+ const pending = output === null ? null : pendingCount(output);
15210
+ if (pending !== null && pending > 0) {
15211
+ state["ci_saw_pending"] = true;
15212
+ counts = false;
15213
+ } else if (pending === 0) {
15214
+ counts = !vacuous && state["ci_saw_pending"] === true;
15215
+ } else {
15216
+ counts = false;
15217
+ }
15218
+ }
15146
15219
  state["last_verification"] = {
15147
15220
  command: cmd.slice(0, 512),
15148
15221
  tool,
15149
15222
  at: _now2(),
15150
- platform: envelope["platform"] || ""
15223
+ platform: envelope["platform"] || "",
15224
+ vacuous,
15225
+ counted: counts
15151
15226
  };
15152
- state["verifications_this_turn"] = _asInt2(state["verifications_this_turn"]) + 1;
15153
- state["verifications_this_session"] = _asInt2(state["verifications_this_session"]) + 1;
15154
- state["verified_this_turn"] = true;
15227
+ if (counts) {
15228
+ state["verifications_this_turn"] = _asInt2(state["verifications_this_turn"]) + 1;
15229
+ state["verifications_this_session"] = _asInt2(state["verifications_this_session"]) + 1;
15230
+ state["verified_this_turn"] = true;
15231
+ } else {
15232
+ state["nonevidence_this_turn"] = _asInt2(state["nonevidence_this_turn"]) + 1;
15233
+ }
15155
15234
  }
15156
15235
  } else if (event === "stop") {
15157
15236
  state["last_stop_at"] = _now2();
@@ -15765,15 +15844,53 @@ if (_isCliEntry11()) {
15765
15844
  import fs22 from "node:fs";
15766
15845
  import path21 from "node:path";
15767
15846
  import { fileURLToPath as fileURLToPath16, pathToFileURL as pathToFileURL12 } from "node:url";
15847
+
15848
+ // src/shared/settingsClasses.ts
15849
+ function isConservativeDefault(value) {
15850
+ if (value === null || value === false || value === "" || value === 0) {
15851
+ return true;
15852
+ }
15853
+ if (Array.isArray(value)) {
15854
+ return value.length === 0;
15855
+ }
15856
+ if (typeof value === "object" && value !== null) {
15857
+ return Object.keys(value).length === 0;
15858
+ }
15859
+ return false;
15860
+ }
15861
+
15862
+ // src/shared/settingsConsent.ts
15863
+ var HUMAN_SOURCES = ["jit-answer", "gui", "manual"];
15864
+ function consentVerdict(query) {
15865
+ if (query.cls !== "B") {
15866
+ return "not-a-consent-key";
15867
+ }
15868
+ if (isConservativeDefault(query.value)) {
15869
+ return "withheld-default";
15870
+ }
15871
+ if (query.handEdited === true) {
15872
+ return "granted";
15873
+ }
15874
+ if (query.source === void 0) {
15875
+ return "withheld-unrecorded";
15876
+ }
15877
+ if (!HUMAN_SOURCES.includes(query.source)) {
15878
+ return "withheld-machine-inferred";
15879
+ }
15880
+ return "granted";
15881
+ }
15882
+
15883
+ // src/scripts/memory_learn_hook.ts
15768
15884
  var SETTINGS_FILE4 = ".agent-settings.yml";
15769
15885
  var BUDGET_MS = 2e3;
15770
- function enabled(root) {
15886
+ var LEARN_KEY_CLASS = "B";
15887
+ function readLearnValue(root) {
15771
15888
  const p = path21.join(root, SETTINGS_FILE4);
15772
15889
  let text;
15773
15890
  try {
15774
15891
  text = fs22.readFileSync(p, "utf8");
15775
15892
  } catch {
15776
- return false;
15893
+ return void 0;
15777
15894
  }
15778
15895
  let inMemory = false;
15779
15896
  for (const rawLine of text.split("\n")) {
@@ -15791,7 +15908,17 @@ function enabled(root) {
15791
15908
  if (m) return m[1] === "true";
15792
15909
  }
15793
15910
  }
15794
- return false;
15911
+ return void 0;
15912
+ }
15913
+ function learnConsent(root) {
15914
+ return consentVerdict({
15915
+ cls: LEARN_KEY_CLASS,
15916
+ value: readLearnValue(root) ?? false,
15917
+ handEdited: true
15918
+ });
15919
+ }
15920
+ function enabled(root) {
15921
+ return learnConsent(root) === "granted";
15795
15922
  }
15796
15923
  function runLearn(root, nowIso, budgetMs = BUDGET_MS) {
15797
15924
  const started = Date.now();
@@ -17130,6 +17257,10 @@ var _PR_URL = /https?:\/\/github\.com\/[^\s"'`<>]+\/pull\/\d+/i;
17130
17257
  function _isObject4(v) {
17131
17258
  return typeof v === "object" && v !== null && !Array.isArray(v);
17132
17259
  }
17260
+ function _unwrap(envelope) {
17261
+ const inner = envelope["payload"];
17262
+ return _isObject4(inner) ? inner : envelope;
17263
+ }
17133
17264
  function _extractCommand(payload) {
17134
17265
  const toolRaw = payload["tool_name"] ?? payload["toolName"] ?? payload["tool"];
17135
17266
  const tool = typeof toolRaw === "string" ? toolRaw : null;
@@ -17182,11 +17313,12 @@ function main21() {
17182
17313
  if (!_isObject4(envelope)) {
17183
17314
  return EXIT_ALLOW3;
17184
17315
  }
17185
- const [tool, command] = _extractCommand(envelope);
17316
+ const inner = _unwrap(envelope);
17317
+ const [tool, command] = _extractCommand(inner);
17186
17318
  if (!_isPrCreate(tool, command)) {
17187
17319
  return EXIT_ALLOW3;
17188
17320
  }
17189
- const match = _PR_URL.exec(_toolOutput(envelope));
17321
+ const match = _PR_URL.exec(_toolOutput(inner));
17190
17322
  if (match === null) {
17191
17323
  return EXIT_ALLOW3;
17192
17324
  }
@@ -17398,194 +17530,1012 @@ if (_isCliEntry18()) {
17398
17530
  process.exit(main22());
17399
17531
  }
17400
17532
 
17401
- // src/scripts/hooks/block_no_verify.ts
17402
- import * as fs33 from "node:fs";
17533
+ // src/scripts/language_mirror_hook.ts
17534
+ import fs33 from "node:fs";
17535
+ import path33 from "node:path";
17403
17536
  import { fileURLToPath as fileURLToPath25, pathToFileURL as pathToFileURL20 } from "node:url";
17404
- import * as path33 from "node:path";
17405
- var _HERE3 = fileURLToPath25(import.meta.url);
17406
- var _SHELL_SEPARATORS = /* @__PURE__ */ new Set(["&&", "||", ";", "|"]);
17407
- var _NO_VERIFY_FLAGS = /* @__PURE__ */ new Set(["--no-verify"]);
17408
- var _NO_VERIFY_SHORT = /* @__PURE__ */ new Set(["-n"]);
17409
- var _HOOKS_PATH_RE = /^core\.hooksPath\s*=/i;
17410
- var _HOOKS_PATH_KEY_RE = /^core\.hooksPath$/i;
17411
- var _GIT_GLOBAL_OPTS_WITH_VALUE = /* @__PURE__ */ new Set([
17412
- "-C",
17413
- "-c",
17414
- "--config",
17415
- "--git-dir",
17416
- "--work-tree",
17417
- "--namespace",
17418
- "--exec-path",
17419
- "--super-prefix"
17420
- ]);
17421
- var _CONFIG_READ_OR_RESTORE = /* @__PURE__ */ new Set([
17422
- "--get",
17423
- "--get-all",
17424
- "--get-regexp",
17425
- "--get-urlmatch",
17426
- "--list",
17427
- "-l",
17428
- "--unset",
17429
- "--unset-all"
17430
- ]);
17431
- var ShlexError = class extends Error {
17432
- };
17433
- function shlexSplit(s) {
17434
- const whitespace = " \r\n\f\v";
17435
- const quotes = `'"`;
17436
- const escape = "\\";
17437
- const escapedquotes = '"';
17438
- const tokens = [];
17439
- let token = null;
17440
- let i = 0;
17441
- const n = s.length;
17442
- let state = "ws";
17443
- const push = (ch) => {
17444
- token = (token ?? "") + ch;
17445
- };
17446
- while (i < n) {
17447
- const c = s[i];
17448
- if (state === "ws") {
17449
- if (whitespace.includes(c)) {
17450
- i += 1;
17451
- continue;
17452
- }
17453
- state = "word";
17454
- token = "";
17455
- }
17456
- if (whitespace.includes(c)) {
17457
- tokens.push(token);
17458
- token = null;
17459
- state = "ws";
17460
- i += 1;
17537
+ var EXIT_ALLOW5 = 0;
17538
+ var EXIT_WARN3 = 2;
17539
+ var STATE_FILE5 = path33.join("agents", "state", "language-mirror.json");
17540
+ function _isObject6(v) {
17541
+ return typeof v === "object" && v !== null && !Array.isArray(v);
17542
+ }
17543
+ var DE_MARKERS = /\b(der|die|das|den|dem|und|ist|sind|nicht|kein|keine|mach|mache|bitte|warum|wieso|weshalb|weiter|kannst|sollst|soll|musst|muss|hast|habe|haben|wir|ich|du|dann|noch|auch|schon|wenn|aber|alle|mit|ohne|damit|dass|wurde|werden|gibt|nochmal|erstell|erstelle|erstelle|fehler|regeln|arbeite|analysiere|fixe|nimm|lege|prüfe|pruefe|schau|zeig|mir|dir|sich|eine|einen|einem|einer|vom|zum|zur|beim|im)\b|[äöüÄÖÜß]/gi;
17544
+ var EN_MARKERS = /\b(the|and|is|are|was|were|not|please|why|because|should|would|could|there|these|those|with|from|about|which|that|this|will|have|has|been|they|them|their|your|our|what|when|where|make|need|want|does|doesn't|don't|it's|let's)\b/gi;
17545
+ var MIN_MARKERS = 2;
17546
+ function instructionText(prompt) {
17547
+ const OUTPUT_HEAD = /^\s*(To\s+\S+|remote:|error:|fatal:|hint:|warning:|npm ERR!|Error:|Traceback|Exception|[A-Za-z]*Error\b|at\s+\S+:\d+|\s{4,}\S|[-+]{3}\s|@@\s|\$\s|>\s|\||\d+\s*\|)/i;
17548
+ const kept = [];
17549
+ let inPaste = false;
17550
+ for (const line of prompt.replace(/```[\s\S]*?```/g, "\n\n").split("\n")) {
17551
+ if (!line.trim()) {
17552
+ inPaste = false;
17553
+ kept.push(line);
17461
17554
  continue;
17462
17555
  }
17463
- if (quotes.includes(c)) {
17464
- const quote = c;
17465
- i += 1;
17466
- let closed = false;
17467
- while (i < n) {
17468
- const qc = s[i];
17469
- if (qc === quote) {
17470
- closed = true;
17471
- i += 1;
17472
- break;
17473
- }
17474
- if (escape.includes(qc) && escapedquotes.includes(quote)) {
17475
- const nxt = i + 1 < n ? s[i + 1] : null;
17476
- if (nxt !== null && (nxt === escape || nxt === quote)) {
17477
- push(nxt);
17478
- i += 2;
17479
- continue;
17480
- }
17481
- push(qc);
17482
- i += 1;
17483
- continue;
17484
- }
17485
- push(qc);
17486
- i += 1;
17487
- }
17488
- if (!closed) {
17489
- throw new ShlexError("No closing quotation");
17490
- }
17556
+ if (OUTPUT_HEAD.test(line)) {
17557
+ inPaste = true;
17491
17558
  continue;
17492
17559
  }
17493
- if (escape.includes(c)) {
17494
- const nxt = i + 1 < n ? s[i + 1] : null;
17495
- if (nxt === null) {
17496
- throw new ShlexError("No escaped character");
17497
- }
17498
- push(nxt);
17499
- i += 2;
17560
+ if (inPaste) {
17500
17561
  continue;
17501
17562
  }
17502
- push(c);
17503
- i += 1;
17563
+ kept.push(line);
17504
17564
  }
17505
- if (token !== null) {
17506
- tokens.push(token);
17507
- }
17508
- return tokens;
17565
+ return kept.join("\n");
17509
17566
  }
17510
- function _is_env_assignment(token) {
17511
- return /^[A-Za-z_][A-Za-z0-9_]*=/.test(token);
17567
+ function classify(prompt) {
17568
+ const text = instructionText(prompt);
17569
+ const de = (text.match(DE_MARKERS) ?? []).length;
17570
+ const en = (text.match(EN_MARKERS) ?? []).length;
17571
+ if (de < MIN_MARKERS && en < MIN_MARKERS) {
17572
+ return { language: "und", de_markers: de, en_markers: en };
17573
+ }
17574
+ return { language: de >= en ? "de" : "en", de_markers: de, en_markers: en };
17512
17575
  }
17513
- function _split_subcommands(tokens) {
17514
- const groups = [];
17515
- let current = [];
17516
- for (const tok of tokens) {
17517
- if (_SHELL_SEPARATORS.has(tok)) {
17518
- if (current.length) {
17519
- groups.push(current);
17520
- }
17521
- current = [];
17522
- } else {
17523
- current.push(tok);
17576
+ var LANGUAGE_NAME = {
17577
+ de: "German (Deutsch)",
17578
+ en: "English"
17579
+ };
17580
+ var LOCALE_ENV_KEYS = ["LC_ALL", "LC_MESSAGES", "LANG", "LANGUAGE"];
17581
+ function systemLocaleVerdict(env = process.env) {
17582
+ for (const key of LOCALE_ENV_KEYS) {
17583
+ const raw = (env[key] ?? "").trim();
17584
+ if (!raw) {
17585
+ continue;
17524
17586
  }
17587
+ const first = raw.split(":")[0] ?? "";
17588
+ const primary = (first.split(/[._@-]/)[0] ?? "").toLowerCase();
17589
+ if (primary === "c" || primary === "posix" || !primary) {
17590
+ continue;
17591
+ }
17592
+ if (primary === "de") {
17593
+ return "de";
17594
+ }
17595
+ if (primary === "en") {
17596
+ return "en";
17597
+ }
17598
+ return "und";
17525
17599
  }
17526
- if (current.length) {
17527
- groups.push(current);
17600
+ return "und";
17601
+ }
17602
+ function noticeText(language, source) {
17603
+ const name = LANGUAGE_NAME[language];
17604
+ if (source === "system-locale") {
17605
+ return `Reply language for this turn: ${name} \u2014 the prompt carried no language markers, so this fell back to the system locale. Write in another language and the next turn follows the prompt instead.`;
17528
17606
  }
17529
- return groups;
17607
+ return `Reply language for this turn: ${name}.`;
17530
17608
  }
17531
- function _git_base(tokens) {
17532
- let i = 0;
17533
- while (i < tokens.length && _is_env_assignment(tokens[i])) {
17534
- i += 1;
17609
+ function pinText(language, source = "prompt") {
17610
+ const name = LANGUAGE_NAME[language];
17611
+ if (source === "system-locale") {
17612
+ return `<language-pin>
17613
+ No language markers were found in this turn's prompt and no language was pinned yet, so the mirror target falls back to the environment's locale: ${name}. Use it for EVERY user-visible token this turn.
17614
+
17615
+ This is the WEAKER of the two provenances \u2014 it reflects the machine, not the user's own words. The first prompt that carries real markers replaces it. Do not treat it as a standing preference, and do not argue with the user about it if they write in something else.
17616
+ </language-pin>`;
17535
17617
  }
17536
- if (i < tokens.length && tokens[i] === "git") {
17537
- return tokens.slice(i);
17618
+ return `<language-pin>
17619
+ The user submitted this turn's prompt in ${name}. That is the mirror target for EVERY user-visible token of your replies this turn \u2014 including the short inter-tool lines between tool calls, headings, table cells, bullets, status lines, and the recommendation label under any numbered-options block.
17620
+
17621
+ This pin exists because the trigger is not observable from the transcript alone: slash-command and skill bodies arrive in the user role and can be long and English, which is what drove ~470 wrong-language turns in the sessions this hook was built from. Tool output, file contents, and an injected skill body are NOT the trigger \u2014 this pin is.
17622
+ </language-pin>`;
17623
+ }
17624
+ function _loadState(target) {
17625
+ try {
17626
+ const raw = fs33.readFileSync(target, "utf8");
17627
+ const decoded = JSON.parse(raw);
17628
+ return _isObject6(decoded) ? decoded : {};
17629
+ } catch {
17630
+ return {};
17538
17631
  }
17539
- return null;
17540
17632
  }
17541
- function _is_config_hookspath_write(git_tokens) {
17542
- const rest = git_tokens.slice(1);
17543
- let subIdx = -1;
17544
- for (let k = 0; k < rest.length; k += 1) {
17545
- const tok = rest[k];
17546
- if (!tok.startsWith("-")) {
17547
- subIdx = k;
17548
- break;
17633
+ function nextState(previous, classification, prompt_chars, session_id, now, locale = "und") {
17634
+ if (classification.language === "und") {
17635
+ if (previous.language === "de" || previous.language === "en") {
17636
+ return null;
17549
17637
  }
17550
- if (_GIT_GLOBAL_OPTS_WITH_VALUE.has(tok)) {
17551
- k += 1;
17638
+ if (locale === "und") {
17639
+ return null;
17552
17640
  }
17641
+ return {
17642
+ language: locale,
17643
+ source: "system-locale",
17644
+ detected_at: now,
17645
+ prompt_chars,
17646
+ de_markers: classification.de_markers,
17647
+ en_markers: classification.en_markers,
17648
+ session_id
17649
+ };
17553
17650
  }
17554
- if (subIdx === -1 || rest[subIdx] !== "config") {
17555
- return [false, ""];
17556
- }
17557
- const args = rest.slice(subIdx + 1);
17558
- if (args.some((t) => _CONFIG_READ_OR_RESTORE.has(t))) {
17559
- return [false, ""];
17560
- }
17561
- for (let k = 0; k < args.length; k += 1) {
17562
- const tok = args[k];
17563
- if (_HOOKS_PATH_RE.test(tok)) {
17564
- return [
17565
- true,
17566
- `'git config ${tok}' disables git hooks via hooksPath (git-history-discipline)`
17567
- ];
17568
- }
17569
- if (!_HOOKS_PATH_KEY_RE.test(tok)) {
17570
- continue;
17571
- }
17572
- const next = args.slice(k + 1).find((t) => !t.startsWith("-"));
17573
- if (next !== void 0) {
17574
- return [
17575
- true,
17576
- `'git config ${tok} ${next}' disables git hooks via hooksPath (git-history-discipline)`
17577
- ];
17651
+ return {
17652
+ language: classification.language,
17653
+ source: "prompt",
17654
+ detected_at: now,
17655
+ prompt_chars,
17656
+ de_markers: classification.de_markers,
17657
+ en_markers: classification.en_markers,
17658
+ session_id
17659
+ };
17660
+ }
17661
+ function _extractPrompt(payload) {
17662
+ for (const key of ["prompt", "userPrompt", "user_prompt", "message", "text"]) {
17663
+ const v = payload[key];
17664
+ if (typeof v === "string" && v.trim()) {
17665
+ return v;
17578
17666
  }
17579
- return [false, ""];
17580
17667
  }
17581
- return [false, ""];
17668
+ return "";
17582
17669
  }
17583
- function _is_blocked(git_tokens) {
17584
- const [cfgBlocked, cfgReason] = _is_config_hookspath_write(git_tokens);
17585
- if (cfgBlocked) {
17586
- return [cfgBlocked, cfgReason];
17670
+ function run7(stdin_text, options) {
17671
+ let envelope = {};
17672
+ if (stdin_text.trim()) {
17673
+ try {
17674
+ const decoded = JSON.parse(stdin_text);
17675
+ if (_isObject6(decoded)) {
17676
+ envelope = decoded;
17677
+ }
17678
+ } catch {
17679
+ return EXIT_ALLOW5;
17680
+ }
17587
17681
  }
17588
- let i = 1;
17682
+ const payload = _isObject6(envelope["payload"]) ? envelope["payload"] : envelope;
17683
+ const prompt = _extractPrompt(payload);
17684
+ if (!prompt) {
17685
+ return EXIT_ALLOW5;
17686
+ }
17687
+ const session_id = typeof envelope["session_id"] === "string" ? envelope["session_id"] : "";
17688
+ const target = path33.join(options.consumer_root, STATE_FILE5);
17689
+ const previous = _loadState(target);
17690
+ const classification = classify(prompt);
17691
+ const next = nextState(
17692
+ previous,
17693
+ classification,
17694
+ prompt.length,
17695
+ session_id,
17696
+ (/* @__PURE__ */ new Date()).toISOString(),
17697
+ // Injectable so the suite can pin a locale instead of inheriting the
17698
+ // machine's — a test whose verdict depends on the developer's `LANG` is a
17699
+ // test that passes here and fails in CI for reasons unrelated to the diff.
17700
+ systemLocaleVerdict(options.env ?? process.env)
17701
+ );
17702
+ const effective = next?.language ?? previous.language;
17703
+ const effectiveSource = next?.source ?? (previous.source === "system-locale" ? "system-locale" : "prompt");
17704
+ if (next) {
17705
+ try {
17706
+ atomic_write_json(target, next);
17707
+ } catch {
17708
+ }
17709
+ }
17710
+ if (effective === "de" || effective === "en") {
17711
+ process.stdout.write(
17712
+ `${JSON.stringify({ decision: "warn", reason: noticeText(effective, effectiveSource), additional_context: pinText(effective, effectiveSource) })}
17713
+ `
17714
+ );
17715
+ return EXIT_WARN3;
17716
+ }
17717
+ return EXIT_ALLOW5;
17718
+ }
17719
+ function main23(argv) {
17720
+ const args = argv ?? process.argv.slice(2);
17721
+ let consumer_root = process.cwd();
17722
+ for (let i = 0; i < args.length; i += 1) {
17723
+ const a = args[i];
17724
+ if (a === "--project-dir" && args[i + 1] !== void 0) {
17725
+ consumer_root = args[i + 1];
17726
+ i += 1;
17727
+ } else if (a !== void 0 && a.startsWith("--project-dir=")) {
17728
+ consumer_root = a.slice("--project-dir=".length);
17729
+ }
17730
+ }
17731
+ return run7(readHookStdin(), { consumer_root });
17732
+ }
17733
+ function _isCliEntry19() {
17734
+ if (true) {
17735
+ return false;
17736
+ }
17737
+ if (process.argv[1] === void 0) {
17738
+ return false;
17739
+ }
17740
+ const argvUrl = pathToFileURL20(path33.resolve(process.argv[1])).href;
17741
+ if (import.meta.url === argvUrl) {
17742
+ return true;
17743
+ }
17744
+ try {
17745
+ const here = fs33.realpathSync(fileURLToPath25(import.meta.url));
17746
+ const argv = fs33.realpathSync(path33.resolve(process.argv[1]));
17747
+ return here === argv;
17748
+ } catch {
17749
+ return false;
17750
+ }
17751
+ }
17752
+ if (_isCliEntry19()) {
17753
+ process.exit(main23());
17754
+ }
17755
+
17756
+ // src/scripts/git_authorization_hook.ts
17757
+ import fs34 from "node:fs";
17758
+ import path34 from "node:path";
17759
+ import { fileURLToPath as fileURLToPath26, pathToFileURL as pathToFileURL21 } from "node:url";
17760
+ var EXIT_ALLOW6 = 0;
17761
+ var STATE_FILE6 = path34.join("agents", "state", "git-authorization.json");
17762
+ function _isObject7(v) {
17763
+ return typeof v === "object" && v !== null && !Array.isArray(v);
17764
+ }
17765
+ var PHRASES = [
17766
+ { op: "commit", re: /\b(commit(e|et|te|ten)?|committe|einchecken)\b/i },
17767
+ { op: "push", re: /\b(push(e|en|t)?|hochladen|hochschieben|raufschieben)\b/i },
17768
+ { op: "branch", re: /\b(branch|feature-branch|zweig)\b/i },
17769
+ // A creation verb is required — "schau dir den PR an" is not "open a PR".
17770
+ {
17771
+ op: "pr-create",
17772
+ re: /\b(erstell(e|en)?|mach(e|en)?|leg(e|en)?\s+an|(er)?(ö|oe)ffne|open|create|raise|aufmachen)\b[^.\n]{0,30}\b(pr|pull[- ]request)\b|\b(pr|pull[- ]request)\b[^.\n]{0,20}\b(erstellen|aufmachen|anlegen|(er)?(ö|oe)ffnen)\b/i
17773
+ },
17774
+ // `merge` as an ACTION, never as the noun in "merge conflict" / "merge commit".
17775
+ { op: "pr-merge", re: /\b(merge|merg(e|en|st|t)|zusammenf(ü|ue)hren|reinmergen)\b(?!\s*[- ]?(conflict|konflikt|commit|base|queue|state|status))/i },
17776
+ // A tag is an ACTION here — bare "Tag" is the German word for day, and
17777
+ // "Version" is an ordinary noun. Both authorized a BLOCK op before this.
17778
+ { op: "tag", re: /\b(tagge(n|st)?|tag\s+(setzen|anlegen|erstellen)|git\s+tag|--tags|--follow-tags)\b/i },
17779
+ // "die release notes sind falsch" is a noun phrase, not an authorization.
17780
+ {
17781
+ op: "release",
17782
+ re: /\b(releasen?|ver(ö|oe)ffentlich(e|en))\b(?!\s*[- ]?(notes?|branch|candidate|pr\b|datum|date|zweig))/i
17783
+ },
17784
+ { op: "publish", re: /\b(publish(e|en)?|publiziere[n]?)\b/i }
17785
+ ];
17786
+ var OUTPUT_LINE = /^\s*(To\s+\S+|remote:|error:|fatal:|hint:|warning:|!\s|\?\?\s|\s*\^|[-+]{3}\s|@@\s|\$\s|>\s|\d+\s+(pass|fail)|npm ERR!|Error:|Traceback|at\s+\S+:\d+)/i;
17787
+ function isInterrogative(prose) {
17788
+ const t = prose.trim();
17789
+ if (!t) {
17790
+ return false;
17791
+ }
17792
+ const hasImperative = /\b(mach|mache|bitte|leg|lege|erstell|erstelle|f(ü|ue)hr|f(ü|ue)hre|setz|setze|starte|los|jetzt|go ahead|do it|ja[,.]?\s|ok[,.]?\s)\b/i.test(
17793
+ t
17794
+ );
17795
+ if (hasImperative) {
17796
+ return false;
17797
+ }
17798
+ return /\?\s*$/.test(t) || /^(was|wie|warum|wieso|weshalb|wann|wer|welche[rs]?|wo|ist|sind|kann|kannst|k(ö|oe)nnen|soll|sollen|darf|d(ü|ue)rfen|why|what|how|when|which|who|is|are|can|could|should|does|do)\b/i.test(
17799
+ t
17800
+ );
17801
+ }
17802
+ var PASTED_COMMANDS = [
17803
+ { op: "publish", re: /\bnpm\s+publish\b/i },
17804
+ { op: "tag", re: /\bgit\s+push\s+[^\n]*--tags\b|\bgit\s+tag\s+-a\b/i },
17805
+ { op: "release", re: /\bgh\s+release\s+create\b/i },
17806
+ { op: "pr-merge", re: /\bgh\s+pr\s+merge\b/i },
17807
+ { op: "pr-create", re: /\bgh\s+pr\s+create\b/i },
17808
+ { op: "push", re: /\bgit\s+push\b/i },
17809
+ { op: "commit", re: /\bgit\s+commit\b/i },
17810
+ { op: "branch", re: /\bgit\s+(checkout\s+-b|switch\s+-c|branch)\b/i }
17811
+ ];
17812
+ function splitFences(prompt) {
17813
+ const fences = [];
17814
+ const prose = prompt.replace(/```[^\n]*\n([\s\S]*?)```/g, (_m, body) => {
17815
+ fences.push(body);
17816
+ return " ";
17817
+ });
17818
+ return { prose, fences };
17819
+ }
17820
+ function _commandLines(fence) {
17821
+ return fence.split("\n").map((l) => l.trim()).filter((l) => l.length > 0).filter((l) => !/^(remote:|error:|hint:|fatal:|warning:|To |!\s|\s*\^)/i.test(l)).map((l) => l.replace(/^[$>#]\s*/, "")).filter((l) => /^(git|gh|npm|pnpm|yarn|task)\b/.test(l));
17822
+ }
17823
+ function classifyAuthorization(prompt) {
17824
+ const { prose, fences } = splitFences(prompt);
17825
+ const authorized = /* @__PURE__ */ new Set();
17826
+ const evidence = {};
17827
+ const instruction = prose.split("\n").filter((l) => !OUTPUT_LINE.test(l)).join("\n");
17828
+ for (const { op, re } of isInterrogative(instruction) ? [] : PHRASES) {
17829
+ const m = re.exec(instruction);
17830
+ if (m) {
17831
+ authorized.add(op);
17832
+ evidence[op] = `prose: "${m[0]}"`;
17833
+ }
17834
+ }
17835
+ for (const fence of fences) {
17836
+ if (fence.split("\n").some((l) => OUTPUT_LINE.test(l))) {
17837
+ continue;
17838
+ }
17839
+ for (const line of _commandLines(fence)) {
17840
+ for (const { op, re } of PASTED_COMMANDS) {
17841
+ if (re.test(line)) {
17842
+ authorized.add(op);
17843
+ evidence[op] = `pasted command: "${line.slice(0, 80)}"`;
17844
+ }
17845
+ }
17846
+ }
17847
+ }
17848
+ return { authorized: [...authorized], evidence };
17849
+ }
17850
+ function run8(stdin_text, options) {
17851
+ let envelope = {};
17852
+ if (stdin_text.trim()) {
17853
+ try {
17854
+ const decoded = JSON.parse(stdin_text);
17855
+ if (_isObject7(decoded)) {
17856
+ envelope = decoded;
17857
+ }
17858
+ } catch {
17859
+ return EXIT_ALLOW6;
17860
+ }
17861
+ }
17862
+ const payload = _isObject7(envelope["payload"]) ? envelope["payload"] : envelope;
17863
+ let prompt = "";
17864
+ for (const key of ["prompt", "userPrompt", "user_prompt", "message", "text"]) {
17865
+ const v = payload[key];
17866
+ if (typeof v === "string" && v.trim()) {
17867
+ prompt = v;
17868
+ break;
17869
+ }
17870
+ }
17871
+ if (!prompt) {
17872
+ return EXIT_ALLOW6;
17873
+ }
17874
+ const { authorized, evidence } = classifyAuthorization(prompt);
17875
+ const ledger = {
17876
+ session_id: typeof envelope["session_id"] === "string" ? envelope["session_id"] : "",
17877
+ detected_at: (/* @__PURE__ */ new Date()).toISOString(),
17878
+ authorized,
17879
+ evidence,
17880
+ prompt_chars: prompt.length
17881
+ };
17882
+ try {
17883
+ atomic_write_json(path34.join(options.consumer_root, STATE_FILE6), ledger);
17884
+ } catch {
17885
+ }
17886
+ return EXIT_ALLOW6;
17887
+ }
17888
+ function main24(argv) {
17889
+ const args = argv ?? process.argv.slice(2);
17890
+ let consumer_root = process.cwd();
17891
+ for (let i = 0; i < args.length; i += 1) {
17892
+ const a = args[i];
17893
+ if (a === "--project-dir" && args[i + 1] !== void 0) {
17894
+ consumer_root = args[i + 1];
17895
+ i += 1;
17896
+ } else if (a !== void 0 && a.startsWith("--project-dir=")) {
17897
+ consumer_root = a.slice("--project-dir=".length);
17898
+ }
17899
+ }
17900
+ return run8(readHookStdin(), { consumer_root });
17901
+ }
17902
+ function _isCliEntry20() {
17903
+ if (true) {
17904
+ return false;
17905
+ }
17906
+ if (process.argv[1] === void 0) {
17907
+ return false;
17908
+ }
17909
+ const argvUrl = pathToFileURL21(path34.resolve(process.argv[1])).href;
17910
+ if (import.meta.url === argvUrl) {
17911
+ return true;
17912
+ }
17913
+ try {
17914
+ const here = fs34.realpathSync(fileURLToPath26(import.meta.url));
17915
+ const argv = fs34.realpathSync(path34.resolve(process.argv[1]));
17916
+ return here === argv;
17917
+ } catch {
17918
+ return false;
17919
+ }
17920
+ }
17921
+ if (_isCliEntry20()) {
17922
+ process.exit(main24());
17923
+ }
17924
+
17925
+ // src/scripts/hooks/block_unauthorized_git.ts
17926
+ import fs35 from "node:fs";
17927
+ import path35 from "node:path";
17928
+ import { fileURLToPath as fileURLToPath27, pathToFileURL as pathToFileURL22 } from "node:url";
17929
+ var EXIT_ALLOW7 = 0;
17930
+ var EXIT_BLOCK = 1;
17931
+ function _isObject8(v) {
17932
+ return typeof v === "object" && v !== null && !Array.isArray(v);
17933
+ }
17934
+ var BLOCK_OPS = /* @__PURE__ */ new Set([
17935
+ "publish",
17936
+ "tag",
17937
+ "release",
17938
+ "pr-merge"
17939
+ ]);
17940
+ var WARN_OPS = /* @__PURE__ */ new Set([
17941
+ "commit",
17942
+ "push",
17943
+ "pr-create",
17944
+ "branch"
17945
+ ]);
17946
+ var G = "(?:-[A-Za-z-]+(?:=\\S+)?(?:\\s+\\S+)?\\s+)*";
17947
+ var COMMAND_OPS = [
17948
+ { op: "publish", re: new RegExp(`\\b(npm|pnpm|yarn)\\s+${G}publish\\b`, "i") },
17949
+ { op: "release", re: /\bgh\s+release\s+create\b|\bgh\s+api\b[^\n]*\/releases\b/i },
17950
+ {
17951
+ op: "tag",
17952
+ re: new RegExp(
17953
+ `\\bgit\\s+${G}push\\b[^\\n;|&]*(--tags|--follow-tags|refs\\/tags\\/)`,
17954
+ "i"
17955
+ )
17956
+ },
17957
+ { op: "pr-merge", re: /\bgh\s+pr\s+merge\b|\bgh\s+api\b[^\n]*\/pulls\/\d+\/merge\b/i },
17958
+ { op: "pr-create", re: /\bgh\s+pr\s+create\b|\bgh\s+api\b[^\n]*-X\s+POST[^\n]*\/pulls\b/i },
17959
+ { op: "push", re: new RegExp(`\\bgit\\s+${G}push\\b`, "i") },
17960
+ { op: "commit", re: new RegExp(`\\bgit\\s+${G}commit\\b`, "i") },
17961
+ { op: "branch", re: new RegExp(`\\bgit\\s+${G}(checkout\\s+-b|switch\\s+-c)\\b`, "i") }
17962
+ ];
17963
+ var COMMAND_TOOLS3 = /* @__PURE__ */ new Set([
17964
+ "launch-process",
17965
+ "launch_process",
17966
+ "Bash",
17967
+ "BashTool",
17968
+ "run-process",
17969
+ "runProcess",
17970
+ "shell",
17971
+ "execute_shell",
17972
+ "RunShellCommand"
17973
+ ]);
17974
+ function extractCommand(envelope) {
17975
+ const payload = _isObject8(envelope["payload"]) ? envelope["payload"] : envelope;
17976
+ const toolRaw = payload["tool_name"] ?? payload["toolName"] ?? payload["tool"];
17977
+ const tool = typeof toolRaw === "string" ? toolRaw : null;
17978
+ if (tool !== null && !COMMAND_TOOLS3.has(tool)) {
17979
+ return null;
17980
+ }
17981
+ const input = _isObject8(payload["tool_input"]) ? payload["tool_input"] : _isObject8(payload["toolInput"]) ? payload["toolInput"] : payload;
17982
+ for (const key of ["command", "cmd", "script"]) {
17983
+ const v = input[key];
17984
+ if (typeof v === "string" && v.trim()) {
17985
+ return v;
17986
+ }
17987
+ }
17988
+ return null;
17989
+ }
17990
+ function invokedSegments(command, depth = 0) {
17991
+ if (depth > 3) {
17992
+ return [];
17993
+ }
17994
+ const out = [];
17995
+ const withoutHeredocs = command.replace(
17996
+ /<<-?\s*(['"]?)([A-Za-z_][A-Za-z0-9_]*)\1[\s\S]*?^\s*\2\s*$/gm,
17997
+ "<<HEREDOC"
17998
+ );
17999
+ for (const raw of withoutHeredocs.split(/\n|;|&&|\|\||\||&/)) {
18000
+ let seg = raw.trim();
18001
+ if (!seg) {
18002
+ continue;
18003
+ }
18004
+ seg = seg.replace(/^(?:[A-Za-z_][A-Za-z0-9_]*=(?:"[^"]*"|'[^']*'|\S*)\s+)+/, "");
18005
+ const wrapped = /^(?:\S*\/)?(?:ba|z|k)?sh\s+-[a-z]*c\s+(?:"([^"]*)"|'([^']*)'|(\S+))/.exec(seg);
18006
+ if (wrapped) {
18007
+ out.push(...invokedSegments(wrapped[1] ?? wrapped[2] ?? wrapped[3] ?? "", depth + 1));
18008
+ continue;
18009
+ }
18010
+ out.push(seg);
18011
+ }
18012
+ return out;
18013
+ }
18014
+ function commandOp(command) {
18015
+ let found = null;
18016
+ for (const seg of invokedSegments(command)) {
18017
+ if (!/^(?:\S*\/)?(git|gh|npm|pnpm|yarn)\b/.test(seg)) {
18018
+ continue;
18019
+ }
18020
+ for (const { op, re } of COMMAND_OPS) {
18021
+ if (re.test(seg)) {
18022
+ if (BLOCK_OPS.has(op)) {
18023
+ return op;
18024
+ }
18025
+ found ??= op;
18026
+ break;
18027
+ }
18028
+ }
18029
+ }
18030
+ return found;
18031
+ }
18032
+ var LEDGER_MAX_AGE_MS = 30 * 60 * 1e3;
18033
+ function _loadLedger(consumer_root, session_id, now) {
18034
+ try {
18035
+ const raw = fs35.readFileSync(path35.join(consumer_root, STATE_FILE6), "utf8");
18036
+ const decoded = JSON.parse(raw);
18037
+ if (_isObject8(decoded) && Array.isArray(decoded["authorized"])) {
18038
+ const ledgerSession = typeof decoded["session_id"] === "string" ? decoded["session_id"] : "";
18039
+ if (session_id && ledgerSession && ledgerSession !== session_id) {
18040
+ return { authorized: /* @__PURE__ */ new Set(), present: false };
18041
+ }
18042
+ const at = Date.parse(String(decoded["detected_at"] ?? ""));
18043
+ if (Number.isFinite(at) && now - at > LEDGER_MAX_AGE_MS) {
18044
+ return { authorized: /* @__PURE__ */ new Set(), present: false };
18045
+ }
18046
+ return {
18047
+ authorized: new Set(decoded["authorized"].filter(Boolean)),
18048
+ present: true
18049
+ };
18050
+ }
18051
+ } catch {
18052
+ }
18053
+ return { authorized: /* @__PURE__ */ new Set(), present: false };
18054
+ }
18055
+ function decide(command, ledger) {
18056
+ if (command === null) {
18057
+ return { exit: EXIT_ALLOW7, stdout: "", stderr: "" };
18058
+ }
18059
+ const op = commandOp(command);
18060
+ if (op === null || ledger.authorized.has(op)) {
18061
+ return { exit: EXIT_ALLOW7, stdout: "", stderr: "" };
18062
+ }
18063
+ const shown = command.length > 120 ? `${command.slice(0, 117)}\u2026` : command;
18064
+ if (BLOCK_OPS.has(op)) {
18065
+ const reason = `Blocked: \`${op}\` with no authorization in this turn's prompt. This operation is irreversible and non-destructive-by-default already declares it never-autonomous. Command: ${shown}. Ask the user, in one numbered-options block, and run it only after they answer this turn.`;
18066
+ return { exit: EXIT_BLOCK, stdout: "", stderr: `${reason}
18067
+ ` };
18068
+ }
18069
+ if (WARN_OPS.has(op)) {
18070
+ const reason = `No \`${op}\` authorization found in this turn's prompt (commit-policy: a one-shot authorization is spent on the operation it named). If the user did authorize it this turn, proceed; otherwise stop and ask. Command: ${shown}`;
18071
+ return {
18072
+ exit: EXIT_ALLOW7,
18073
+ stdout: `${JSON.stringify({ decision: "warn", reason })}
18074
+ `,
18075
+ stderr: ""
18076
+ };
18077
+ }
18078
+ return { exit: EXIT_ALLOW7, stdout: "", stderr: "" };
18079
+ }
18080
+ function run9(stdin_text, options) {
18081
+ let envelope = {};
18082
+ if (stdin_text.trim()) {
18083
+ try {
18084
+ const decoded = JSON.parse(stdin_text);
18085
+ if (_isObject8(decoded)) {
18086
+ envelope = decoded;
18087
+ }
18088
+ } catch {
18089
+ return EXIT_ALLOW7;
18090
+ }
18091
+ }
18092
+ const session_id = typeof envelope["session_id"] === "string" ? envelope["session_id"] : "";
18093
+ const decision = decide(
18094
+ extractCommand(envelope),
18095
+ _loadLedger(options.consumer_root, session_id, Date.now())
18096
+ );
18097
+ if (decision.stdout) {
18098
+ process.stdout.write(decision.stdout);
18099
+ }
18100
+ if (decision.stderr) {
18101
+ process.stderr.write(decision.stderr);
18102
+ }
18103
+ return decision.exit;
18104
+ }
18105
+ function main25(argv) {
18106
+ const args = argv ?? process.argv.slice(2);
18107
+ let consumer_root = process.cwd();
18108
+ for (let i = 0; i < args.length; i += 1) {
18109
+ const a = args[i];
18110
+ if (a === "--project-dir" && args[i + 1] !== void 0) {
18111
+ consumer_root = args[i + 1];
18112
+ i += 1;
18113
+ } else if (a !== void 0 && a.startsWith("--project-dir=")) {
18114
+ consumer_root = a.slice("--project-dir=".length);
18115
+ }
18116
+ }
18117
+ return run9(readHookStdin(), { consumer_root });
18118
+ }
18119
+ function _isCliEntry21() {
18120
+ if (true) {
18121
+ return false;
18122
+ }
18123
+ if (process.argv[1] === void 0) {
18124
+ return false;
18125
+ }
18126
+ const argvUrl = pathToFileURL22(path35.resolve(process.argv[1])).href;
18127
+ if (import.meta.url === argvUrl) {
18128
+ return true;
18129
+ }
18130
+ try {
18131
+ const here = fs35.realpathSync(fileURLToPath27(import.meta.url));
18132
+ const argv = fs35.realpathSync(path35.resolve(process.argv[1]));
18133
+ return here === argv;
18134
+ } catch {
18135
+ return false;
18136
+ }
18137
+ }
18138
+ if (_isCliEntry21()) {
18139
+ process.exit(main25());
18140
+ }
18141
+
18142
+ // src/scripts/hooks/evidence_independence.ts
18143
+ import crypto2 from "node:crypto";
18144
+ import fs36 from "node:fs";
18145
+ import path36 from "node:path";
18146
+ import { fileURLToPath as fileURLToPath28, pathToFileURL as pathToFileURL23 } from "node:url";
18147
+ var EXIT_ALLOW8 = 0;
18148
+ var EXIT_BLOCK2 = 1;
18149
+ var STATE_FILE7 = path36.join("agents", "state", "evidence-dispatch.json");
18150
+ function _isObject9(v) {
18151
+ return typeof v === "object" && v !== null && !Array.isArray(v);
18152
+ }
18153
+ var DISPATCH_TOOLS = /* @__PURE__ */ new Set([
18154
+ "Agent",
18155
+ "Task",
18156
+ "task",
18157
+ "dispatch_agent",
18158
+ "dispatchAgent",
18159
+ "launch_agent",
18160
+ "run_subagent",
18161
+ "Subagent"
18162
+ ]);
18163
+ var EVALUATION_RE = /\b(review|reviewer|audit|auditor|judge|verdict|blind[- ]pass|blind review|adversarial|critique|assess(ment)?|verify (my|the) (work|change|diff|implementation)|find (any )?(bugs|issues|defects|problems) in (my|the)|pr(ü|ue)f(e|ung)?|begutachte|gutachten|bewerte|(gegen)?check(e)?|durchsicht|review(e|iere))\b/i;
18164
+ var PRELOADED_VERDICT_RE = [
18165
+ // German — the operator writes German, and an English-only list meant no
18166
+ // German dispatch was ever screened at all.
18167
+ /\bich erwarte (hier )?(keine|nichts)\b/i,
18168
+ /\b(du )?(wirst|solltest) (hier )?nichts finden\b/i,
18169
+ /\bbest(ä|ae)tige (nur|kurz)\b/i,
18170
+ /\b(ist|sollte) (wahrscheinlich|vermutlich|sicher) (sauber|korrekt|in ordnung|fine)\b/i,
18171
+ /\bkeine findings? (erwartet|zu erwarten)\b/i,
18172
+ // English paraphrases of the audited construct.
18173
+ /\bi am confident there is nothing\b/i,
18174
+ /\ba clean pass is the likely\b/i,
18175
+ /\bno[- ]findings? (is|are) (expected|welcome|fine|acceptable|the likely)/i,
18176
+ /\b(you )?(should|will|probably) find (nothing|no (issues|problems|bugs|findings))/i,
18177
+ /\bconfirm (that )?there (are|is) no\b/i,
18178
+ /\bi (believe|think|expect) (this|it) is (clean|correct|fine)\b/i,
18179
+ /\bexpect(ed)? (to be )?(clean|green|no findings)\b/i,
18180
+ /\bjust confirm\b/i,
18181
+ /\bit('s| is) (probably|likely) fine\b/i
18182
+ ];
18183
+ function isDispatchTool(tool) {
18184
+ return tool !== null && DISPATCH_TOOLS.has(tool);
18185
+ }
18186
+ function isEvaluationPrompt(prompt) {
18187
+ return EVALUATION_RE.test(prompt);
18188
+ }
18189
+ var SELF_SCOPE_RE = /\b(my (work|change|diff|implementation|code|fix|patch|branch|pr)|this (diff|change|branch|pr|delta|implementation|patch)|the delta|the change i|what i (wrote|built|changed|implemented)|i just (wrote|built|changed|implemented))\b/i;
18190
+ function isSelfScoped(prompt) {
18191
+ return SELF_SCOPE_RE.test(prompt);
18192
+ }
18193
+ function preloadedVerdict(prompt) {
18194
+ for (const re of PRELOADED_VERDICT_RE) {
18195
+ const m = re.exec(prompt);
18196
+ if (m) {
18197
+ return m[0];
18198
+ }
18199
+ }
18200
+ return null;
18201
+ }
18202
+ function extractDispatch(envelope) {
18203
+ const payload = _isObject9(envelope["payload"]) ? envelope["payload"] : envelope;
18204
+ const toolRaw = payload["tool_name"] ?? payload["toolName"] ?? payload["tool"];
18205
+ const tool = typeof toolRaw === "string" ? toolRaw : null;
18206
+ const input = _isObject9(payload["tool_input"]) ? payload["tool_input"] : _isObject9(payload["toolInput"]) ? payload["toolInput"] : payload;
18207
+ for (const key of ["prompt", "instructions", "task", "description"]) {
18208
+ const v = input[key];
18209
+ if (typeof v === "string" && v.trim()) {
18210
+ return [tool, v];
18211
+ }
18212
+ }
18213
+ return [tool, ""];
18214
+ }
18215
+ function _ledgerStamp(consumer_root) {
18216
+ try {
18217
+ const raw = fs36.readFileSync(
18218
+ path36.join(consumer_root, "agents", "state", "git-authorization.json"),
18219
+ "utf8"
18220
+ );
18221
+ const d = JSON.parse(raw);
18222
+ return typeof d["detected_at"] === "string" ? d["detected_at"] : "";
18223
+ } catch {
18224
+ return "";
18225
+ }
18226
+ }
18227
+ function _load(target) {
18228
+ try {
18229
+ const decoded = JSON.parse(fs36.readFileSync(target, "utf8"));
18230
+ if (_isObject9(decoded) && Array.isArray(decoded["evaluations"])) {
18231
+ return decoded;
18232
+ }
18233
+ } catch {
18234
+ }
18235
+ return { session_id: "", turn_started_at: "", evaluations: [] };
18236
+ }
18237
+ var WARN_TEXT = "First evaluation dispatch this turn. Two shapes fabricated a binding honest-null in the audited sessions \u2014 check your prompt for both before it goes out: (1) a verdict pre-loaded into the prompt, and (2) a scope narrowed to files you chose. A review you commissioned on your own work is admissible as gate evidence only when the prompt is recorded alongside the verdict.";
18238
+ function decide2(tool, prompt, priorEvaluations) {
18239
+ if (!isDispatchTool(tool) || !isEvaluationPrompt(prompt)) {
18240
+ return { exit: EXIT_ALLOW8, stdout: "", stderr: "", evaluations: priorEvaluations };
18241
+ }
18242
+ const preloaded = preloadedVerdict(prompt);
18243
+ if (preloaded !== null) {
18244
+ return {
18245
+ exit: EXIT_BLOCK2,
18246
+ stdout: "",
18247
+ stderr: `Blocked: this evaluation prompt pre-loads its verdict ("${preloaded}"). That is the construct that produced a fabricated NO-FINDINGS committed as binding gate evidence, over a delta an unsteered pass then found a live critical in. Remove the expectation from the prompt and let the evaluator reach its own verdict.
18248
+ `,
18249
+ evaluations: priorEvaluations
18250
+ };
18251
+ }
18252
+ if (!isSelfScoped(prompt)) {
18253
+ return { exit: EXIT_ALLOW8, stdout: "", stderr: "", evaluations: priorEvaluations };
18254
+ }
18255
+ if (priorEvaluations >= 1) {
18256
+ return {
18257
+ exit: EXIT_BLOCK2,
18258
+ stdout: "",
18259
+ stderr: `Blocked: second evaluation dispatch of your own work in this turn (verdict shopping). One evaluation has already run; commissioning another with a different prompt or scope selects the answer instead of measuring it. Report what the first pass returned, then re-plan.
18260
+ `,
18261
+ evaluations: priorEvaluations
18262
+ };
18263
+ }
18264
+ return {
18265
+ exit: EXIT_ALLOW8,
18266
+ stdout: `${JSON.stringify({ decision: "warn", reason: WARN_TEXT })}
18267
+ `,
18268
+ stderr: "",
18269
+ evaluations: priorEvaluations + 1
18270
+ };
18271
+ }
18272
+ function run10(stdin_text, options) {
18273
+ let envelope = {};
18274
+ if (stdin_text.trim()) {
18275
+ try {
18276
+ const decoded = JSON.parse(stdin_text);
18277
+ if (_isObject9(decoded)) {
18278
+ envelope = decoded;
18279
+ }
18280
+ } catch {
18281
+ return EXIT_ALLOW8;
18282
+ }
18283
+ }
18284
+ const target = path36.join(options.consumer_root, STATE_FILE7);
18285
+ const state = _load(target);
18286
+ const session_id = typeof envelope["session_id"] === "string" ? envelope["session_id"] : "";
18287
+ const turnMarker = `${session_id}:${_ledgerStamp(options.consumer_root)}`;
18288
+ if (state.session_id !== turnMarker) {
18289
+ state.session_id = turnMarker;
18290
+ state.turn_started_at = (/* @__PURE__ */ new Date()).toISOString();
18291
+ state.evaluations = [];
18292
+ }
18293
+ const [tool, prompt] = extractDispatch(envelope);
18294
+ const decision = decide2(tool, prompt, state.evaluations.length);
18295
+ if (decision.evaluations > state.evaluations.length) {
18296
+ state.evaluations.push({
18297
+ at: (/* @__PURE__ */ new Date()).toISOString(),
18298
+ digest: crypto2.createHash("sha256").update(prompt).digest("hex").slice(0, 16),
18299
+ prompt_chars: prompt.length
18300
+ });
18301
+ try {
18302
+ atomic_write_json(target, state);
18303
+ } catch {
18304
+ }
18305
+ }
18306
+ if (decision.stdout) {
18307
+ process.stdout.write(decision.stdout);
18308
+ }
18309
+ if (decision.stderr) {
18310
+ process.stderr.write(decision.stderr);
18311
+ }
18312
+ return decision.exit;
18313
+ }
18314
+ function main26(argv) {
18315
+ const args = argv ?? process.argv.slice(2);
18316
+ let consumer_root = process.cwd();
18317
+ for (let i = 0; i < args.length; i += 1) {
18318
+ const a = args[i];
18319
+ if (a === "--project-dir" && args[i + 1] !== void 0) {
18320
+ consumer_root = args[i + 1];
18321
+ i += 1;
18322
+ } else if (a !== void 0 && a.startsWith("--project-dir=")) {
18323
+ consumer_root = a.slice("--project-dir=".length);
18324
+ }
18325
+ }
18326
+ return run10(readHookStdin(), { consumer_root });
18327
+ }
18328
+ function _isCliEntry22() {
18329
+ if (true) {
18330
+ return false;
18331
+ }
18332
+ if (process.argv[1] === void 0) {
18333
+ return false;
18334
+ }
18335
+ const argvUrl = pathToFileURL23(path36.resolve(process.argv[1])).href;
18336
+ if (import.meta.url === argvUrl) {
18337
+ return true;
18338
+ }
18339
+ try {
18340
+ const here = fs36.realpathSync(fileURLToPath28(import.meta.url));
18341
+ const argv = fs36.realpathSync(path36.resolve(process.argv[1]));
18342
+ return here === argv;
18343
+ } catch {
18344
+ return false;
18345
+ }
18346
+ }
18347
+ if (_isCliEntry22()) {
18348
+ process.exit(main26());
18349
+ }
18350
+
18351
+ // src/scripts/hooks/block_no_verify.ts
18352
+ import * as fs37 from "node:fs";
18353
+ import { fileURLToPath as fileURLToPath29, pathToFileURL as pathToFileURL24 } from "node:url";
18354
+ import * as path37 from "node:path";
18355
+ var _HERE3 = fileURLToPath29(import.meta.url);
18356
+ var _SHELL_SEPARATORS = /* @__PURE__ */ new Set(["&&", "||", ";", "|"]);
18357
+ var _NO_VERIFY_FLAGS = /* @__PURE__ */ new Set(["--no-verify"]);
18358
+ var _NO_VERIFY_SHORT = /* @__PURE__ */ new Set(["-n"]);
18359
+ var _HOOKS_PATH_RE = /^core\.hooksPath\s*=/i;
18360
+ var _HOOKS_PATH_KEY_RE = /^core\.hooksPath$/i;
18361
+ var _GIT_GLOBAL_OPTS_WITH_VALUE = /* @__PURE__ */ new Set([
18362
+ "-C",
18363
+ "-c",
18364
+ "--config",
18365
+ "--git-dir",
18366
+ "--work-tree",
18367
+ "--namespace",
18368
+ "--exec-path",
18369
+ "--super-prefix"
18370
+ ]);
18371
+ var _CONFIG_READ_OR_RESTORE = /* @__PURE__ */ new Set([
18372
+ "--get",
18373
+ "--get-all",
18374
+ "--get-regexp",
18375
+ "--get-urlmatch",
18376
+ "--list",
18377
+ "-l",
18378
+ "--unset",
18379
+ "--unset-all"
18380
+ ]);
18381
+ var ShlexError = class extends Error {
18382
+ };
18383
+ function shlexSplit(s) {
18384
+ const whitespace = " \r\n\f\v";
18385
+ const quotes = `'"`;
18386
+ const escape = "\\";
18387
+ const escapedquotes = '"';
18388
+ const tokens = [];
18389
+ let token = null;
18390
+ let i = 0;
18391
+ const n = s.length;
18392
+ let state = "ws";
18393
+ const push = (ch) => {
18394
+ token = (token ?? "") + ch;
18395
+ };
18396
+ while (i < n) {
18397
+ const c = s[i];
18398
+ if (state === "ws") {
18399
+ if (whitespace.includes(c)) {
18400
+ i += 1;
18401
+ continue;
18402
+ }
18403
+ state = "word";
18404
+ token = "";
18405
+ }
18406
+ if (whitespace.includes(c)) {
18407
+ tokens.push(token);
18408
+ token = null;
18409
+ state = "ws";
18410
+ i += 1;
18411
+ continue;
18412
+ }
18413
+ if (quotes.includes(c)) {
18414
+ const quote = c;
18415
+ i += 1;
18416
+ let closed = false;
18417
+ while (i < n) {
18418
+ const qc = s[i];
18419
+ if (qc === quote) {
18420
+ closed = true;
18421
+ i += 1;
18422
+ break;
18423
+ }
18424
+ if (escape.includes(qc) && escapedquotes.includes(quote)) {
18425
+ const nxt = i + 1 < n ? s[i + 1] : null;
18426
+ if (nxt !== null && (nxt === escape || nxt === quote)) {
18427
+ push(nxt);
18428
+ i += 2;
18429
+ continue;
18430
+ }
18431
+ push(qc);
18432
+ i += 1;
18433
+ continue;
18434
+ }
18435
+ push(qc);
18436
+ i += 1;
18437
+ }
18438
+ if (!closed) {
18439
+ throw new ShlexError("No closing quotation");
18440
+ }
18441
+ continue;
18442
+ }
18443
+ if (escape.includes(c)) {
18444
+ const nxt = i + 1 < n ? s[i + 1] : null;
18445
+ if (nxt === null) {
18446
+ throw new ShlexError("No escaped character");
18447
+ }
18448
+ push(nxt);
18449
+ i += 2;
18450
+ continue;
18451
+ }
18452
+ push(c);
18453
+ i += 1;
18454
+ }
18455
+ if (token !== null) {
18456
+ tokens.push(token);
18457
+ }
18458
+ return tokens;
18459
+ }
18460
+ function _is_env_assignment(token) {
18461
+ return /^[A-Za-z_][A-Za-z0-9_]*=/.test(token);
18462
+ }
18463
+ function _split_subcommands(tokens) {
18464
+ const groups = [];
18465
+ let current = [];
18466
+ for (const tok of tokens) {
18467
+ if (_SHELL_SEPARATORS.has(tok)) {
18468
+ if (current.length) {
18469
+ groups.push(current);
18470
+ }
18471
+ current = [];
18472
+ } else {
18473
+ current.push(tok);
18474
+ }
18475
+ }
18476
+ if (current.length) {
18477
+ groups.push(current);
18478
+ }
18479
+ return groups;
18480
+ }
18481
+ function _git_base(tokens) {
18482
+ let i = 0;
18483
+ while (i < tokens.length && _is_env_assignment(tokens[i])) {
18484
+ i += 1;
18485
+ }
18486
+ if (i < tokens.length && tokens[i] === "git") {
18487
+ return tokens.slice(i);
18488
+ }
18489
+ return null;
18490
+ }
18491
+ function _is_config_hookspath_write(git_tokens) {
18492
+ const rest = git_tokens.slice(1);
18493
+ let subIdx = -1;
18494
+ for (let k = 0; k < rest.length; k += 1) {
18495
+ const tok = rest[k];
18496
+ if (!tok.startsWith("-")) {
18497
+ subIdx = k;
18498
+ break;
18499
+ }
18500
+ if (_GIT_GLOBAL_OPTS_WITH_VALUE.has(tok)) {
18501
+ k += 1;
18502
+ }
18503
+ }
18504
+ if (subIdx === -1 || rest[subIdx] !== "config") {
18505
+ return [false, ""];
18506
+ }
18507
+ const args = rest.slice(subIdx + 1);
18508
+ if (args.some((t) => _CONFIG_READ_OR_RESTORE.has(t))) {
18509
+ return [false, ""];
18510
+ }
18511
+ for (let k = 0; k < args.length; k += 1) {
18512
+ const tok = args[k];
18513
+ if (_HOOKS_PATH_RE.test(tok)) {
18514
+ return [
18515
+ true,
18516
+ `'git config ${tok}' disables git hooks via hooksPath (git-history-discipline)`
18517
+ ];
18518
+ }
18519
+ if (!_HOOKS_PATH_KEY_RE.test(tok)) {
18520
+ continue;
18521
+ }
18522
+ const next = args.slice(k + 1).find((t) => !t.startsWith("-"));
18523
+ if (next !== void 0) {
18524
+ return [
18525
+ true,
18526
+ `'git config ${tok} ${next}' disables git hooks via hooksPath (git-history-discipline)`
18527
+ ];
18528
+ }
18529
+ return [false, ""];
18530
+ }
18531
+ return [false, ""];
18532
+ }
18533
+ function _is_blocked(git_tokens) {
18534
+ const [cfgBlocked, cfgReason] = _is_config_hookspath_write(git_tokens);
18535
+ if (cfgBlocked) {
18536
+ return [cfgBlocked, cfgReason];
18537
+ }
18538
+ let i = 1;
17589
18539
  while (i < git_tokens.length) {
17590
18540
  const tok = git_tokens[i];
17591
18541
  if (_NO_VERIFY_FLAGS.has(tok)) {
@@ -17641,7 +18591,7 @@ function _check_command(cmd) {
17641
18591
  if (/\bgit\b/.test(cmd)) {
17642
18592
  return [
17643
18593
  true,
17644
- "command parse failed (shlex) on a git-containing command \u2014 fail-closed (git-history-discipline)"
18594
+ "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."
17645
18595
  ];
17646
18596
  }
17647
18597
  return [false, ""];
@@ -17725,7 +18675,7 @@ block_no_verify.py: error: unrecognized arguments: ${arg}
17725
18675
  function _readStdin11() {
17726
18676
  return readHookStdin();
17727
18677
  }
17728
- function main23(argv) {
18678
+ function main27(argv) {
17729
18679
  const parsed = _parseArgs4(argv ?? process.argv.slice(2));
17730
18680
  if (parsed.exitCode !== void 0) {
17731
18681
  return parsed.exitCode;
@@ -17763,33 +18713,33 @@ function main23(argv) {
17763
18713
  }
17764
18714
  return 0;
17765
18715
  }
17766
- function _isCliEntry19() {
18716
+ function _isCliEntry23() {
17767
18717
  if (true) {
17768
18718
  return false;
17769
18719
  }
17770
18720
  if (process.argv[1] === void 0) {
17771
18721
  return false;
17772
18722
  }
17773
- const argvUrl = pathToFileURL20(path33.resolve(process.argv[1])).href;
18723
+ const argvUrl = pathToFileURL24(path37.resolve(process.argv[1])).href;
17774
18724
  if (import.meta.url === argvUrl) {
17775
18725
  return true;
17776
18726
  }
17777
18727
  try {
17778
- const here = fs33.realpathSync(fileURLToPath25(import.meta.url));
17779
- const argv = fs33.realpathSync(path33.resolve(process.argv[1]));
18728
+ const here = fs37.realpathSync(fileURLToPath29(import.meta.url));
18729
+ const argv = fs37.realpathSync(path37.resolve(process.argv[1]));
17780
18730
  return here === argv;
17781
18731
  } catch {
17782
18732
  return false;
17783
18733
  }
17784
18734
  }
17785
- if (_isCliEntry19() || false) {
17786
- process.exitCode = main23();
18735
+ if (_isCliEntry23() || false) {
18736
+ process.exitCode = main27();
17787
18737
  }
17788
18738
 
17789
18739
  // src/scripts/hooks/block_kernel_rule_writes.ts
17790
- import * as fs34 from "node:fs";
17791
- import { fileURLToPath as fileURLToPath26, pathToFileURL as pathToFileURL21 } from "node:url";
17792
- import * as path34 from "node:path";
18740
+ import * as fs38 from "node:fs";
18741
+ import { fileURLToPath as fileURLToPath30, pathToFileURL as pathToFileURL25 } from "node:url";
18742
+ import * as path38 from "node:path";
17793
18743
 
17794
18744
  // src/scripts/_lib/kernel_rules.ts
17795
18745
  var KERNEL_RULE_IDS = [
@@ -17813,8 +18763,8 @@ function is_kernel_rule(name) {
17813
18763
  }
17814
18764
 
17815
18765
  // src/scripts/hooks/block_kernel_rule_writes.ts
17816
- var _HERE4 = fileURLToPath26(import.meta.url);
17817
- function _isObject6(v) {
18766
+ var _HERE4 = fileURLToPath30(import.meta.url);
18767
+ function _isObject10(v) {
17818
18768
  return v !== null && v !== void 0 && typeof v === "object" && !Array.isArray(v);
17819
18769
  }
17820
18770
  var _PATH_KEYS = [
@@ -17826,10 +18776,10 @@ var _PATH_KEYS = [
17826
18776
  "notebook_path"
17827
18777
  ];
17828
18778
  function _extract(envelope) {
17829
- const payload = _isObject6(envelope["payload"]) ? envelope["payload"] : envelope;
18779
+ const payload = _isObject10(envelope["payload"]) ? envelope["payload"] : envelope;
17830
18780
  const nameVal = payload["tool_name"] ?? payload["toolName"] ?? payload["tool"] ?? envelope["tool_name"] ?? envelope["tool"];
17831
18781
  const tool = typeof nameVal === "string" ? nameVal : "";
17832
- const ti = _isObject6(payload["tool_input"]) ? payload["tool_input"] : _isObject6(envelope["tool_input"]) ? envelope["tool_input"] : null;
18782
+ const ti = _isObject10(payload["tool_input"]) ? payload["tool_input"] : _isObject10(envelope["tool_input"]) ? envelope["tool_input"] : null;
17833
18783
  const paths = [];
17834
18784
  if (ti !== null) {
17835
18785
  for (const key of _PATH_KEYS) {
@@ -17905,7 +18855,7 @@ function _bash_targets_kernel_rule(command) {
17905
18855
  continue;
17906
18856
  }
17907
18857
  if (prevWasSeparator && !tok.startsWith("-")) {
17908
- verbs.add(path34.basename(tok));
18858
+ verbs.add(path38.basename(tok));
17909
18859
  prevWasSeparator = false;
17910
18860
  }
17911
18861
  }
@@ -17960,8 +18910,8 @@ function check_envelope(envelope) {
17960
18910
  return [false, ""];
17961
18911
  }
17962
18912
  function _extract_command3(envelope) {
17963
- const payload = _isObject6(envelope["payload"]) ? envelope["payload"] : envelope;
17964
- const ti = _isObject6(payload["tool_input"]) ? payload["tool_input"] : _isObject6(envelope["tool_input"]) ? envelope["tool_input"] : null;
18913
+ const payload = _isObject10(envelope["payload"]) ? envelope["payload"] : envelope;
18914
+ const ti = _isObject10(payload["tool_input"]) ? payload["tool_input"] : _isObject10(envelope["tool_input"]) ? envelope["tool_input"] : null;
17965
18915
  for (const src of [ti, payload]) {
17966
18916
  if (src === null) {
17967
18917
  continue;
@@ -17974,12 +18924,12 @@ function _extract_command3(envelope) {
17974
18924
  return null;
17975
18925
  }
17976
18926
  function _asObject2(v) {
17977
- return _isObject6(v) ? v : null;
18927
+ return _isObject10(v) ? v : null;
17978
18928
  }
17979
18929
  function _readStdin12() {
17980
18930
  return readHookStdin();
17981
18931
  }
17982
- function main24() {
18932
+ function main28() {
17983
18933
  const raw = _readStdin12();
17984
18934
  let envelope = {};
17985
18935
  if (raw.trim()) {
@@ -18004,45 +18954,45 @@ function main24() {
18004
18954
  }
18005
18955
  return 0;
18006
18956
  }
18007
- function _isCliEntry20() {
18957
+ function _isCliEntry24() {
18008
18958
  if (true) {
18009
18959
  return false;
18010
18960
  }
18011
18961
  if (process.argv[1] === void 0) {
18012
18962
  return false;
18013
18963
  }
18014
- const argvUrl = pathToFileURL21(path34.resolve(process.argv[1])).href;
18964
+ const argvUrl = pathToFileURL25(path38.resolve(process.argv[1])).href;
18015
18965
  if (import.meta.url === argvUrl) {
18016
18966
  return true;
18017
18967
  }
18018
18968
  try {
18019
- const here = fs34.realpathSync(fileURLToPath26(import.meta.url));
18020
- const argv = fs34.realpathSync(path34.resolve(process.argv[1]));
18969
+ const here = fs38.realpathSync(fileURLToPath30(import.meta.url));
18970
+ const argv = fs38.realpathSync(path38.resolve(process.argv[1]));
18021
18971
  return here === argv;
18022
18972
  } catch {
18023
18973
  return false;
18024
18974
  }
18025
18975
  }
18026
- if (_isCliEntry20() || false) {
18027
- process.exitCode = main24();
18976
+ if (_isCliEntry24() || false) {
18977
+ process.exitCode = main28();
18028
18978
  }
18029
18979
 
18030
18980
  // src/scripts/hooks/block_config_weakening.ts
18031
- import * as fs35 from "node:fs";
18032
- import * as path35 from "node:path";
18033
- import { fileURLToPath as fileURLToPath27, pathToFileURL as pathToFileURL22 } from "node:url";
18034
- var _HERE5 = fileURLToPath27(import.meta.url);
18035
- var EXIT_ALLOW5 = 0;
18036
- var EXIT_BLOCK = 1;
18037
- var EXIT_WARN3 = 2;
18981
+ import * as fs39 from "node:fs";
18982
+ import * as path39 from "node:path";
18983
+ import { fileURLToPath as fileURLToPath31, pathToFileURL as pathToFileURL26 } from "node:url";
18984
+ var _HERE5 = fileURLToPath31(import.meta.url);
18985
+ var EXIT_ALLOW9 = 0;
18986
+ var EXIT_BLOCK3 = 1;
18987
+ var EXIT_WARN4 = 2;
18038
18988
  var SESSION_ENTRY_CAP = 20;
18039
18989
  var SESSION_WARN_AT = 5;
18040
- function _isObject7(v) {
18990
+ function _isObject11(v) {
18041
18991
  return v !== null && v !== void 0 && typeof v === "object" && !Array.isArray(v);
18042
18992
  }
18043
18993
  var _PATH_KEYS2 = ["file_path", "path", "target_file", "filePath", "notebook_path"];
18044
18994
  function classify_target(p) {
18045
- const posix = p.split(path35.sep).join("/");
18995
+ const posix = p.split(path39.sep).join("/");
18046
18996
  const base = posix.split("/").pop() ?? "";
18047
18997
  if (/_allowlist\.(json|txt)$/.test(base) || /^allowlist[-_.]/.test(base)) {
18048
18998
  return "allowlist";
@@ -18090,7 +19040,7 @@ function added_entries(tool_input, on_disk) {
18090
19040
  }
18091
19041
  return 0;
18092
19042
  }
18093
- function decide(kind, rel_path, session_total, added) {
19043
+ function decide3(kind, rel_path, session_total, added) {
18094
19044
  if (kind === null || added <= 0) {
18095
19045
  return { action: "allow", reason: "" };
18096
19046
  }
@@ -18116,13 +19066,13 @@ function decide(kind, rel_path, session_total, added) {
18116
19066
  return { action: "allow", reason: "" };
18117
19067
  }
18118
19068
  function _state_file(root) {
18119
- return path35.join(root, "agents", "runtime", "state", "config-weakening.json");
19069
+ return path39.join(root, "agents", "runtime", "state", "config-weakening.json");
18120
19070
  }
18121
19071
  function bump_session(root, session, key, added) {
18122
19072
  const f = _state_file(root);
18123
19073
  let data = {};
18124
19074
  try {
18125
- data = JSON.parse(fs35.readFileSync(f, "utf-8"));
19075
+ data = JSON.parse(fs39.readFileSync(f, "utf-8"));
18126
19076
  } catch {
18127
19077
  data = {};
18128
19078
  }
@@ -18131,18 +19081,18 @@ function bump_session(root, session, key, added) {
18131
19081
  bucket[key] = total;
18132
19082
  data[session] = bucket;
18133
19083
  try {
18134
- fs35.mkdirSync(path35.dirname(f), { recursive: true });
18135
- fs35.writeFileSync(f, `${JSON.stringify(data, null, 2)}
19084
+ fs39.mkdirSync(path39.dirname(f), { recursive: true });
19085
+ fs39.writeFileSync(f, `${JSON.stringify(data, null, 2)}
18136
19086
  `, "utf-8");
18137
19087
  } catch {
18138
19088
  }
18139
19089
  return total;
18140
19090
  }
18141
19091
  function _extract2(envelope) {
18142
- const payload = _isObject7(envelope["payload"]) ? envelope["payload"] : envelope;
19092
+ const payload = _isObject11(envelope["payload"]) ? envelope["payload"] : envelope;
18143
19093
  const nameVal = payload["tool_name"] ?? payload["toolName"] ?? payload["tool"] ?? envelope["tool_name"] ?? envelope["tool"];
18144
19094
  const tool = typeof nameVal === "string" ? nameVal : "";
18145
- const ti = _isObject7(payload["tool_input"]) ? payload["tool_input"] : _isObject7(envelope["tool_input"]) ? envelope["tool_input"] : null;
19095
+ const ti = _isObject11(payload["tool_input"]) ? payload["tool_input"] : _isObject11(envelope["tool_input"]) ? envelope["tool_input"] : null;
18146
19096
  const paths = [];
18147
19097
  if (ti !== null) {
18148
19098
  for (const key of _PATH_KEYS2) {
@@ -18154,20 +19104,20 @@ function _extract2(envelope) {
18154
19104
  }
18155
19105
  return { tool, paths, ti };
18156
19106
  }
18157
- function main25() {
19107
+ function main29() {
18158
19108
  let envelope;
18159
19109
  try {
18160
19110
  const raw = readHookStdin();
18161
19111
  envelope = raw.trim() ? JSON.parse(raw) : {};
18162
19112
  } catch {
18163
- return EXIT_ALLOW5;
19113
+ return EXIT_ALLOW9;
18164
19114
  }
18165
- if (!_isObject7(envelope)) {
18166
- return EXIT_ALLOW5;
19115
+ if (!_isObject11(envelope)) {
19116
+ return EXIT_ALLOW9;
18167
19117
  }
18168
19118
  const { tool, paths, ti } = _extract2(envelope);
18169
19119
  if (!tool || !EDIT_TOOLS.has(tool) || ti === null) {
18170
- return EXIT_ALLOW5;
19120
+ return EXIT_ALLOW9;
18171
19121
  }
18172
19122
  const cwd = envelope["cwd"];
18173
19123
  const pr = envelope["workspace_root"] ?? envelope["project_root"];
@@ -18179,10 +19129,10 @@ function main25() {
18179
19129
  if (kind === null) {
18180
19130
  continue;
18181
19131
  }
18182
- const abs = path35.isAbsolute(p) ? p : path35.join(root, p);
19132
+ const abs = path39.isAbsolute(p) ? p : path39.join(root, p);
18183
19133
  let on_disk = null;
18184
19134
  try {
18185
- on_disk = fs35.readFileSync(abs, "utf-8");
19135
+ on_disk = fs39.readFileSync(abs, "utf-8");
18186
19136
  } catch {
18187
19137
  on_disk = null;
18188
19138
  }
@@ -18190,47 +19140,47 @@ function main25() {
18190
19140
  if (added <= 0) {
18191
19141
  continue;
18192
19142
  }
18193
- const rel = path35.relative(root, abs) || p;
19143
+ const rel = path39.relative(root, abs) || p;
18194
19144
  const total = kind === "allowlist" ? bump_session(root, session, rel, added) : added;
18195
- const d = decide(kind, rel, total, added);
19145
+ const d = decide3(kind, rel, total, added);
18196
19146
  if (d.action === "block") {
18197
19147
  process.stderr.write(`block-config-weakening: BLOCKED \u2014 ${d.reason}
18198
19148
  `);
18199
- return EXIT_BLOCK;
19149
+ return EXIT_BLOCK3;
18200
19150
  }
18201
19151
  if (d.action === "warn") {
18202
19152
  process.stdout.write(`${JSON.stringify({ decision: "warn", reason: d.reason })}
18203
19153
  `);
18204
- return EXIT_WARN3;
19154
+ return EXIT_WARN4;
18205
19155
  }
18206
19156
  }
18207
- return EXIT_ALLOW5;
19157
+ return EXIT_ALLOW9;
18208
19158
  }
18209
- function _isCliEntry21() {
19159
+ function _isCliEntry25() {
18210
19160
  if (true) {
18211
19161
  return false;
18212
19162
  }
18213
19163
  if (process.argv[1] === void 0) {
18214
19164
  return false;
18215
19165
  }
18216
- const argvUrl = pathToFileURL22(path35.resolve(process.argv[1])).href;
19166
+ const argvUrl = pathToFileURL26(path39.resolve(process.argv[1])).href;
18217
19167
  if (import.meta.url === argvUrl) {
18218
19168
  return true;
18219
19169
  }
18220
19170
  try {
18221
- return fs35.realpathSync(fileURLToPath27(import.meta.url)) === fs35.realpathSync(path35.resolve(process.argv[1]));
19171
+ return fs39.realpathSync(fileURLToPath31(import.meta.url)) === fs39.realpathSync(path39.resolve(process.argv[1]));
18222
19172
  } catch {
18223
19173
  return false;
18224
19174
  }
18225
19175
  }
18226
- if (_isCliEntry21() || process.argv[1] === _HERE5) {
18227
- process.exit(main25());
19176
+ if (_isCliEntry25() || process.argv[1] === _HERE5) {
19177
+ process.exit(main29());
18228
19178
  }
18229
19179
 
18230
19180
  // src/scripts/hooks/rtk_wrap_hook.ts
18231
- import fs36 from "node:fs";
18232
- import path36 from "node:path";
18233
- import { fileURLToPath as fileURLToPath28, pathToFileURL as pathToFileURL23 } from "node:url";
19181
+ import fs40 from "node:fs";
19182
+ import path40 from "node:path";
19183
+ import { fileURLToPath as fileURLToPath32, pathToFileURL as pathToFileURL27 } from "node:url";
18234
19184
 
18235
19185
  // src/install/rtkDetection.ts
18236
19186
  import { spawnSync as spawnSync4 } from "node:child_process";
@@ -18342,8 +19292,8 @@ function detectRtkCached(options = {}) {
18342
19292
 
18343
19293
  // src/scripts/hooks/rtk_wrap_hook.ts
18344
19294
  var SETTINGS_FILE6 = ".agent-settings.yml";
18345
- var EXIT_ALLOW6 = 0;
18346
- var EXIT_WARN4 = 2;
19295
+ var EXIT_ALLOW10 = 0;
19296
+ var EXIT_WARN5 = 2;
18347
19297
  var _RTK_PROGRAMS = /* @__PURE__ */ new Set([
18348
19298
  "git",
18349
19299
  "phpstan",
@@ -18368,19 +19318,19 @@ var _RTK_PROGRAMS = /* @__PURE__ */ new Set([
18368
19318
  "kubectl",
18369
19319
  "terraform"
18370
19320
  ]);
18371
- function _isObject8(v) {
19321
+ function _isObject12(v) {
18372
19322
  return typeof v === "object" && v !== null && !Array.isArray(v);
18373
19323
  }
18374
19324
  function _enabled2(root) {
18375
- const f = path36.join(root, SETTINGS_FILE6);
19325
+ const f = path40.join(root, SETTINGS_FILE6);
18376
19326
  try {
18377
- if (!fs36.statSync(f).isFile()) return false;
19327
+ if (!fs40.statSync(f).isFile()) return false;
18378
19328
  } catch {
18379
19329
  return false;
18380
19330
  }
18381
19331
  let text;
18382
19332
  try {
18383
- text = fs36.readFileSync(f, "utf-8");
19333
+ text = fs40.readFileSync(f, "utf-8");
18384
19334
  } catch {
18385
19335
  return false;
18386
19336
  }
@@ -18410,13 +19360,13 @@ function _enabled2(root) {
18410
19360
  function rtk_available(env = process.env) {
18411
19361
  const pathVar = env.PATH ?? env.Path ?? "";
18412
19362
  if (!pathVar) return false;
18413
- const dirs = pathVar.split(path36.delimiter).filter(Boolean);
19363
+ const dirs = pathVar.split(path40.delimiter).filter(Boolean);
18414
19364
  const exts = process.platform === "win32" ? ["", ".exe", ".cmd", ".bat"] : [""];
18415
19365
  for (const dir of dirs) {
18416
19366
  for (const ext of exts) {
18417
- const candidate = path36.join(dir, `rtk${ext}`);
19367
+ const candidate = path40.join(dir, `rtk${ext}`);
18418
19368
  try {
18419
- const st = fs36.statSync(candidate);
19369
+ const st = fs40.statSync(candidate);
18420
19370
  if (st.isFile()) {
18421
19371
  if (process.platform === "win32" || (st.mode & 73) !== 0) return true;
18422
19372
  }
@@ -18427,14 +19377,14 @@ function rtk_available(env = process.env) {
18427
19377
  return false;
18428
19378
  }
18429
19379
  function _extract_command4(envelope) {
18430
- const payload = _isObject8(envelope["payload"]) ? envelope["payload"] : {};
18431
- const tool_input = _isObject8(payload["tool_input"]) ? payload["tool_input"] : {};
19380
+ const payload = _isObject12(envelope["payload"]) ? envelope["payload"] : {};
19381
+ const tool_input = _isObject12(payload["tool_input"]) ? payload["tool_input"] : {};
18432
19382
  for (const src of [tool_input["command"], payload["command"], envelope["command"]]) {
18433
19383
  if (typeof src === "string") return src;
18434
19384
  }
18435
19385
  return null;
18436
19386
  }
18437
- function classify(command) {
19387
+ function classify2(command) {
18438
19388
  const cmd = command.trim();
18439
19389
  if (!cmd) return { eligible: false, reason_skip: "empty" };
18440
19390
  let tokens;
@@ -18464,61 +19414,61 @@ function _readStdin13() {
18464
19414
  function _jsonReason(reason) {
18465
19415
  return JSON.stringify({ decision: "warn", reason });
18466
19416
  }
18467
- function main26() {
19417
+ function main30() {
18468
19418
  let envelope;
18469
19419
  try {
18470
19420
  const raw = _readStdin13();
18471
19421
  envelope = raw.trim() ? JSON.parse(raw) : {};
18472
19422
  } catch {
18473
- return EXIT_ALLOW6;
19423
+ return EXIT_ALLOW10;
18474
19424
  }
18475
- if (!_isObject8(envelope)) return EXIT_ALLOW6;
19425
+ if (!_isObject12(envelope)) return EXIT_ALLOW10;
18476
19426
  const cwd = envelope["cwd"];
18477
19427
  const projectRoot = envelope["workspace_root"] ?? envelope["project_root"];
18478
19428
  const root = typeof cwd === "string" && cwd ? cwd : typeof projectRoot === "string" && projectRoot ? projectRoot : ".";
18479
- if (!_enabled2(root)) return EXIT_ALLOW6;
18480
- if (!rtk_available()) return EXIT_ALLOW6;
18481
- if (detectRtkCached().identity !== "token-killer") return EXIT_ALLOW6;
19429
+ if (!_enabled2(root)) return EXIT_ALLOW10;
19430
+ if (!rtk_available()) return EXIT_ALLOW10;
19431
+ if (detectRtkCached().identity !== "token-killer") return EXIT_ALLOW10;
18482
19432
  const command = _extract_command4(envelope);
18483
- if (!command) return EXIT_ALLOW6;
18484
- const verdict = classify(command);
18485
- if (!verdict.eligible) return EXIT_ALLOW6;
19433
+ if (!command) return EXIT_ALLOW10;
19434
+ const verdict = classify2(command);
19435
+ if (!verdict.eligible) return EXIT_ALLOW10;
18486
19436
  const reason = `rtk is installed and wraps verbose CLI output (upstream reports 60\u201390% fewer output tokens). Re-run wrapped: \`rtk ${command.trim()}\`. (Skip for completeness-critical output like \`git diff\`.)`;
18487
19437
  process.stdout.write(`${_jsonReason(reason)}
18488
19438
  `);
18489
- return EXIT_WARN4;
19439
+ return EXIT_WARN5;
18490
19440
  }
18491
- function _isCliEntry22() {
19441
+ function _isCliEntry26() {
18492
19442
  if (true) {
18493
19443
  return false;
18494
19444
  }
18495
19445
  if (process.argv[1] === void 0) {
18496
19446
  return false;
18497
19447
  }
18498
- const argvUrl = pathToFileURL23(path36.resolve(process.argv[1])).href;
19448
+ const argvUrl = pathToFileURL27(path40.resolve(process.argv[1])).href;
18499
19449
  if (import.meta.url === argvUrl) {
18500
19450
  return true;
18501
19451
  }
18502
19452
  try {
18503
- const here = fs36.realpathSync(fileURLToPath28(import.meta.url));
18504
- const argv = fs36.realpathSync(path36.resolve(process.argv[1]));
19453
+ const here = fs40.realpathSync(fileURLToPath32(import.meta.url));
19454
+ const argv = fs40.realpathSync(path40.resolve(process.argv[1]));
18505
19455
  return here === argv;
18506
19456
  } catch {
18507
19457
  return false;
18508
19458
  }
18509
19459
  }
18510
- if (_isCliEntry22()) {
18511
- process.exit(main26());
19460
+ if (_isCliEntry26()) {
19461
+ process.exit(main30());
18512
19462
  }
18513
19463
 
18514
19464
  // src/scripts/hooks/design_slop_hook.ts
18515
- import fs38 from "node:fs";
18516
- import path38 from "node:path";
18517
- import { fileURLToPath as fileURLToPath29, pathToFileURL as pathToFileURL24 } from "node:url";
19465
+ import fs42 from "node:fs";
19466
+ import path42 from "node:path";
19467
+ import { fileURLToPath as fileURLToPath33, pathToFileURL as pathToFileURL28 } from "node:url";
18518
19468
 
18519
19469
  // src/scripts/lint_design_slop.ts
18520
- import fs37 from "node:fs";
18521
- import path37 from "node:path";
19470
+ import fs41 from "node:fs";
19471
+ import path41 from "node:path";
18522
19472
 
18523
19473
  // src/scripts/design_slop_rules.ts
18524
19474
  function cssBlocks(content) {
@@ -18907,14 +19857,14 @@ var SLOP_RULES = [
18907
19857
  gated: (ctx) => ctx.has("brutalist", "uniform grid", "repetitive grid"),
18908
19858
  detect: ({ content }) => {
18909
19859
  const bodies = sectionBodies(content);
18910
- let run7 = 0;
19860
+ let run11 = 0;
18911
19861
  let maxRun = 0;
18912
19862
  for (const b of bodies) {
18913
19863
  if (sectionSignature(b).mediaText) {
18914
- run7 += 1;
18915
- maxRun = Math.max(maxRun, run7);
19864
+ run11 += 1;
19865
+ maxRun = Math.max(maxRun, run11);
18916
19866
  } else {
18917
- run7 = 0;
19867
+ run11 = 0;
18918
19868
  }
18919
19869
  }
18920
19870
  if (maxRun > 2) return [{ line: 1, snippet: `${maxRun} consecutive media+text sections` }];
@@ -18934,33 +19884,33 @@ function enginesForExt(ext) {
18934
19884
  return /* @__PURE__ */ new Set();
18935
19885
  }
18936
19886
  function* walkDir(dir, ext) {
18937
- if (!fs37.existsSync(dir)) return;
18938
- for (const entry of fs37.readdirSync(dir, { withFileTypes: true })) {
18939
- const full = path37.join(dir, entry.name);
19887
+ if (!fs41.existsSync(dir)) return;
19888
+ for (const entry of fs41.readdirSync(dir, { withFileTypes: true })) {
19889
+ const full = path41.join(dir, entry.name);
18940
19890
  if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
18941
19891
  if (entry.isDirectory()) yield* walkDir(full, ext);
18942
19892
  else if (ext.test(entry.name)) yield full;
18943
19893
  }
18944
19894
  }
18945
19895
  function loadConfig(dir) {
18946
- const p = path37.join(dir, ".design-quality.json");
18947
- if (!fs37.existsSync(p)) return {};
19896
+ const p = path41.join(dir, ".design-quality.json");
19897
+ if (!fs41.existsSync(p)) return {};
18948
19898
  try {
18949
- return JSON.parse(fs37.readFileSync(p, "utf-8"));
19899
+ return JSON.parse(fs41.readFileSync(p, "utf-8"));
18950
19900
  } catch {
18951
19901
  return {};
18952
19902
  }
18953
19903
  }
18954
19904
  function loadDesignContext(scanDir) {
18955
19905
  const candidates = [
18956
- path37.join(scanDir, "DESIGN.md"),
18957
- path37.join(process.cwd(), "DESIGN.md"),
18958
- path37.join(scanDir, "..", "DESIGN.md")
19906
+ path41.join(scanDir, "DESIGN.md"),
19907
+ path41.join(process.cwd(), "DESIGN.md"),
19908
+ path41.join(scanDir, "..", "DESIGN.md")
18959
19909
  ];
18960
19910
  let raw = "";
18961
19911
  for (const c of candidates) {
18962
- if (fs37.existsSync(c)) {
18963
- raw = fs37.readFileSync(c, "utf-8").toLowerCase();
19912
+ if (fs41.existsSync(c)) {
19913
+ raw = fs41.readFileSync(c, "utf-8").toLowerCase();
18964
19914
  break;
18965
19915
  }
18966
19916
  }
@@ -18991,7 +19941,7 @@ function parseIgnores(lines) {
18991
19941
  }
18992
19942
  function scanFile(content, relPath, ctx) {
18993
19943
  const lines = content.split("\n");
18994
- const ext = path37.extname(relPath).toLowerCase();
19944
+ const ext = path41.extname(relPath).toLowerCase();
18995
19945
  const fileEngines = enginesForExt(ext);
18996
19946
  if (fileEngines.size === 0) return [];
18997
19947
  const ignores = parseIgnores(lines);
@@ -19021,15 +19971,15 @@ function scanFile(content, relPath, ctx) {
19021
19971
  }
19022
19972
  return out;
19023
19973
  }
19024
- function main27() {
19974
+ function main31() {
19025
19975
  const args = process.argv.slice(2);
19026
19976
  const jsonMode = args.includes("--json");
19027
19977
  const quiet = args.includes("--quiet");
19028
19978
  const dirIdx = args.indexOf("--dir");
19029
- const scanDir = dirIdx >= 0 && args[dirIdx + 1] ? path37.resolve(args[dirIdx + 1]) : path37.resolve(process.cwd(), "src");
19979
+ const scanDir = dirIdx >= 0 && args[dirIdx + 1] ? path41.resolve(args[dirIdx + 1]) : path41.resolve(process.cwd(), "src");
19030
19980
  const failIdx = args.indexOf("--fail-on");
19031
19981
  const failOn = failIdx >= 0 ? args[failIdx + 1] : void 0;
19032
- if (!fs37.existsSync(scanDir)) {
19982
+ if (!fs41.existsSync(scanDir)) {
19033
19983
  if (!quiet) {
19034
19984
  process.stderr.write(`[lint_design_slop] scan directory not found: ${scanDir}
19035
19985
  `);
@@ -19063,9 +20013,9 @@ function main27() {
19063
20013
  }
19064
20014
  const findings = [];
19065
20015
  for (const fp of files) {
19066
- const rel = path37.relative(process.cwd(), fp);
20016
+ const rel = path41.relative(process.cwd(), fp);
19067
20017
  try {
19068
- const fileFindings = scanFile(fs37.readFileSync(fp, "utf-8"), rel, ctx).filter(
20018
+ const fileFindings = scanFile(fs41.readFileSync(fp, "utf-8"), rel, ctx).filter(
19069
20019
  (f) => !ignoreRules.has(f.rule.toLowerCase())
19070
20020
  );
19071
20021
  findings.push(...fileFindings);
@@ -19098,23 +20048,23 @@ lint_design_slop: ${findings.length} tell(s) flagged (rebuttable \u2014 declare
19098
20048
  process.exit(overThreshold.length > 0 ? 2 : 0);
19099
20049
  }
19100
20050
  var invokedDirectly = process.argv[1] !== void 0 && /lint_design_slop\.ts$/.test(process.argv[1]);
19101
- if (invokedDirectly) main27();
20051
+ if (invokedDirectly) main31();
19102
20052
 
19103
20053
  // src/scripts/hooks/design_slop_hook.ts
19104
20054
  var SETTINGS_FILE7 = ".agent-settings.yml";
19105
- var EXIT_ALLOW7 = 0;
19106
- var EXIT_WARN5 = 2;
20055
+ var EXIT_ALLOW11 = 0;
20056
+ var EXIT_WARN6 = 2;
19107
20057
  var DEGRADE_AFTER = 3;
19108
20058
  var UI_EXT = /\.(html|htm|css|scss|sass|less|vue|svelte|astro|jsx|tsx)$/i;
19109
20059
  function isObject(v) {
19110
20060
  return typeof v === "object" && v !== null && !Array.isArray(v);
19111
20061
  }
19112
20062
  function enabled2(root) {
19113
- const f = path38.join(root, SETTINGS_FILE7);
20063
+ const f = path42.join(root, SETTINGS_FILE7);
19114
20064
  let text;
19115
20065
  try {
19116
- if (!fs38.statSync(f).isFile()) return false;
19117
- text = fs38.readFileSync(f, "utf-8");
20066
+ if (!fs42.statSync(f).isFile()) return false;
20067
+ text = fs42.readFileSync(f, "utf-8");
19118
20068
  } catch {
19119
20069
  return false;
19120
20070
  }
@@ -19139,7 +20089,12 @@ function enabled2(root) {
19139
20089
  }
19140
20090
  return false;
19141
20091
  }
19142
- function extract(envelope) {
20092
+ function _unwrap2(envelope) {
20093
+ const inner = envelope["payload"];
20094
+ return isObject(inner) ? inner : envelope;
20095
+ }
20096
+ function extract(outer) {
20097
+ const envelope = _unwrap2(outer);
19143
20098
  const ti = envelope["tool_input"] ?? envelope["toolInput"] ?? envelope["input"];
19144
20099
  if (!isObject(ti)) return null;
19145
20100
  const fileVal = ti["file_path"] ?? ti["path"] ?? ti["filePath"];
@@ -19151,11 +20106,11 @@ function extract(envelope) {
19151
20106
  return null;
19152
20107
  }
19153
20108
  function stateFile(root) {
19154
- return path38.join(root, "agents", "runtime", "state", "design-slop-hook.json");
20109
+ return path42.join(root, "agents", "runtime", "state", "design-slop-hook.json");
19155
20110
  }
19156
20111
  function readState(root) {
19157
20112
  try {
19158
- const t = fs38.readFileSync(stateFile(root), "utf-8");
20113
+ const t = fs42.readFileSync(stateFile(root), "utf-8");
19159
20114
  const parsed = JSON.parse(t);
19160
20115
  return isObject(parsed) ? parsed : {};
19161
20116
  } catch {
@@ -19165,31 +20120,31 @@ function readState(root) {
19165
20120
  function writeState(root, state) {
19166
20121
  try {
19167
20122
  const sf = stateFile(root);
19168
- fs38.mkdirSync(path38.dirname(sf), { recursive: true });
19169
- fs38.writeFileSync(sf, JSON.stringify(state, null, 2) + "\n");
20123
+ fs42.mkdirSync(path42.dirname(sf), { recursive: true });
20124
+ fs42.writeFileSync(sf, JSON.stringify(state, null, 2) + "\n");
19170
20125
  } catch {
19171
20126
  }
19172
20127
  }
19173
20128
  function readStdin() {
19174
20129
  return readHookStdin();
19175
20130
  }
19176
- function main28() {
20131
+ function main32() {
19177
20132
  let envelope;
19178
20133
  try {
19179
20134
  const raw = readStdin();
19180
20135
  envelope = raw.trim() ? JSON.parse(raw) : {};
19181
20136
  } catch {
19182
- return EXIT_ALLOW7;
20137
+ return EXIT_ALLOW11;
19183
20138
  }
19184
- if (!isObject(envelope)) return EXIT_ALLOW7;
20139
+ if (!isObject(envelope)) return EXIT_ALLOW11;
19185
20140
  const rootVal = envelope["cwd"] ?? envelope["project_root"] ?? ".";
19186
20141
  const root = typeof rootVal === "string" && rootVal ? rootVal : ".";
19187
- if (!enabled2(root)) return EXIT_ALLOW7;
20142
+ if (!enabled2(root)) return EXIT_ALLOW11;
19188
20143
  const ex = extract(envelope);
19189
- if (!ex || !ex.file || !UI_EXT.test(ex.file)) return EXIT_ALLOW7;
20144
+ if (!ex || !ex.file || !UI_EXT.test(ex.file)) return EXIT_ALLOW11;
19190
20145
  let ctx;
19191
20146
  try {
19192
- ctx = loadDesignContext(path38.dirname(path38.resolve(root, ex.file)));
20147
+ ctx = loadDesignContext(path42.dirname(path42.resolve(root, ex.file)));
19193
20148
  } catch {
19194
20149
  ctx = { raw: "", has: () => false };
19195
20150
  }
@@ -19199,9 +20154,9 @@ function main28() {
19199
20154
  (f) => f.severity === "P0" || f.severity === "P1"
19200
20155
  );
19201
20156
  } catch {
19202
- return EXIT_ALLOW7;
20157
+ return EXIT_ALLOW11;
19203
20158
  }
19204
- if (findings.length === 0) return EXIT_ALLOW7;
20159
+ if (findings.length === 0) return EXIT_ALLOW11;
19205
20160
  const state = readState(root);
19206
20161
  const surfaced = findings.filter((f) => {
19207
20162
  const sig = `${ex.file}::${f.rule}`;
@@ -19211,43 +20166,43 @@ function main28() {
19211
20166
  return true;
19212
20167
  });
19213
20168
  writeState(root, state);
19214
- if (surfaced.length === 0) return EXIT_ALLOW7;
20169
+ if (surfaced.length === 0) return EXIT_ALLOW11;
19215
20170
  const lines = surfaced.map((f) => `${f.catalogId} (${f.rule}) ${f.file}:${f.line} \u2014 ${f.message}`).join("; ");
19216
20171
  const reason = "\u26A0\uFE0F Anti-slop: high-severity aesthetic tell(s) in the proposed UI \u2014 " + lines + ". Rebuttable: declare intent in DESIGN.md, add design-slop-disable-next-line, or proceed if deliberate (this is a flag, not a block).";
19217
20172
  process.stdout.write(JSON.stringify({ decision: "warn", reason }) + "\n");
19218
- return EXIT_WARN5;
20173
+ return EXIT_WARN6;
19219
20174
  }
19220
- function _isCliEntry23() {
20175
+ function _isCliEntry27() {
19221
20176
  if (true) {
19222
20177
  return false;
19223
20178
  }
19224
20179
  if (process.argv[1] === void 0) {
19225
20180
  return false;
19226
20181
  }
19227
- const argvUrl = pathToFileURL24(path38.resolve(process.argv[1])).href;
20182
+ const argvUrl = pathToFileURL28(path42.resolve(process.argv[1])).href;
19228
20183
  if (import.meta.url === argvUrl) {
19229
20184
  return true;
19230
20185
  }
19231
20186
  try {
19232
- const here = fs38.realpathSync(fileURLToPath29(import.meta.url));
19233
- const argv = fs38.realpathSync(path38.resolve(process.argv[1]));
20187
+ const here = fs42.realpathSync(fileURLToPath33(import.meta.url));
20188
+ const argv = fs42.realpathSync(path42.resolve(process.argv[1]));
19234
20189
  return here === argv;
19235
20190
  } catch {
19236
20191
  return false;
19237
20192
  }
19238
20193
  }
19239
- var isCliEntry9 = _isCliEntry23();
19240
- if (isCliEntry9) process.exit(main28());
20194
+ var isCliEntry9 = _isCliEntry27();
20195
+ if (isCliEntry9) process.exit(main32());
19241
20196
 
19242
20197
  // src/scripts/hooks/code_graph_nudge_hook.ts
19243
- import fs40 from "node:fs";
19244
- import path40 from "node:path";
19245
- import { fileURLToPath as fileURLToPath30, pathToFileURL as pathToFileURL25 } from "node:url";
20198
+ import fs44 from "node:fs";
20199
+ import path44 from "node:path";
20200
+ import { fileURLToPath as fileURLToPath34, pathToFileURL as pathToFileURL29 } from "node:url";
19246
20201
 
19247
20202
  // src/scripts/code_graph/detect.ts
19248
20203
  import { execFileSync } from "node:child_process";
19249
- import * as fs39 from "node:fs";
19250
- import * as path39 from "node:path";
20204
+ import * as fs43 from "node:fs";
20205
+ import * as path43 from "node:path";
19251
20206
 
19252
20207
  // src/scripts/code_graph/validate.ts
19253
20208
  var RELATIONS = /* @__PURE__ */ new Set(["calls", "imports", "uses", "inherits", "member"]);
@@ -19328,7 +20283,7 @@ function freshness(root, file, embeddedSha) {
19328
20283
  const last = gitLastCommitEpoch(root);
19329
20284
  if (last === null) return {};
19330
20285
  try {
19331
- const mtime = Math.floor(fs39.statSync(file).mtimeMs / 1e3);
20286
+ const mtime = Math.floor(fs43.statSync(file).mtimeMs / 1e3);
19332
20287
  return { stale: mtime < last };
19333
20288
  } catch {
19334
20289
  return {};
@@ -19336,7 +20291,7 @@ function freshness(root, file, embeddedSha) {
19336
20291
  }
19337
20292
  function looksLikeGraph(p) {
19338
20293
  try {
19339
- const raw = JSON.parse(fs39.readFileSync(p, "utf-8"));
20294
+ const raw = JSON.parse(fs43.readFileSync(p, "utf-8"));
19340
20295
  if (validateGraph(raw).ok) return { ok: true, sha: raw["head_at_build"] ?? null };
19341
20296
  const nodes = raw["nodes"];
19342
20297
  const edges = raw["edges"] ?? raw["links"];
@@ -19347,23 +20302,23 @@ function looksLikeGraph(p) {
19347
20302
  }
19348
20303
  }
19349
20304
  function detectSources(root, nativeCache) {
19350
- const abs = path39.resolve(root);
20305
+ const abs = path43.resolve(root);
19351
20306
  const out = [];
19352
20307
  for (const rel of CONSUMER_CANDIDATES) {
19353
- const p = path39.join(abs, rel);
19354
- if (fs39.existsSync(p)) {
20308
+ const p = path43.join(abs, rel);
20309
+ if (fs43.existsSync(p)) {
19355
20310
  const { ok, sha } = looksLikeGraph(p);
19356
20311
  if (ok) out.push({ kind: "consumer", path: p, present: true, ...freshness(abs, p, sha) });
19357
20312
  }
19358
20313
  }
19359
- const scipCandidates = [path39.join(abs, "index.scip")];
20314
+ const scipCandidates = [path43.join(abs, "index.scip")];
19360
20315
  try {
19361
- for (const e of fs39.readdirSync(abs)) if (e.endsWith(".scip")) scipCandidates.push(path39.join(abs, e));
20316
+ for (const e of fs43.readdirSync(abs)) if (e.endsWith(".scip")) scipCandidates.push(path43.join(abs, e));
19362
20317
  } catch {
19363
20318
  }
19364
- const scip = scipCandidates.find((p) => fs39.existsSync(p));
20319
+ const scip = scipCandidates.find((p) => fs43.existsSync(p));
19365
20320
  if (scip) out.push({ kind: "scip", path: scip, present: true, note: "SCIP detected \u2014 peer tooling required (no owned reader)" });
19366
- if (fs39.existsSync(nativeCache)) out.push({ kind: "native", path: nativeCache, present: true, ...freshness(abs, nativeCache, null) });
20321
+ if (fs43.existsSync(nativeCache)) out.push({ kind: "native", path: nativeCache, present: true, ...freshness(abs, nativeCache, null) });
19367
20322
  return out;
19368
20323
  }
19369
20324
  function pickSource(verdicts) {
@@ -19376,18 +20331,18 @@ function pickSource(verdicts) {
19376
20331
 
19377
20332
  // src/scripts/hooks/code_graph_nudge_hook.ts
19378
20333
  var SETTINGS_FILE8 = ".agent-settings.yml";
19379
- var EXIT_ALLOW8 = 0;
19380
- var EXIT_WARN6 = 2;
20334
+ var EXIT_ALLOW12 = 0;
20335
+ var EXIT_WARN7 = 2;
19381
20336
  var CODE_EXT = /\.(php|ts|tsx|mts|cts|js|jsx|mjs|cjs)$/i;
19382
20337
  function isObject2(v) {
19383
20338
  return typeof v === "object" && v !== null && !Array.isArray(v);
19384
20339
  }
19385
20340
  function enabled3(root) {
19386
- const f = path40.join(root, SETTINGS_FILE8);
20341
+ const f = path44.join(root, SETTINGS_FILE8);
19387
20342
  let text;
19388
20343
  try {
19389
- if (!fs40.statSync(f).isFile()) return false;
19390
- text = fs40.readFileSync(f, "utf-8");
20344
+ if (!fs44.statSync(f).isFile()) return false;
20345
+ text = fs44.readFileSync(f, "utf-8");
19391
20346
  } catch {
19392
20347
  return false;
19393
20348
  }
@@ -19430,11 +20385,11 @@ function sessionId(envelope) {
19430
20385
  return typeof s === "string" && s ? s : "default";
19431
20386
  }
19432
20387
  function latchFile(root) {
19433
- return path40.join(root, "agents", "runtime", "state", "code-graph-nudge.json");
20388
+ return path44.join(root, "agents", "runtime", "state", "code-graph-nudge.json");
19434
20389
  }
19435
20390
  function alreadyNudged(root, session) {
19436
20391
  try {
19437
- const state = JSON.parse(fs40.readFileSync(latchFile(root), "utf-8"));
20392
+ const state = JSON.parse(fs44.readFileSync(latchFile(root), "utf-8"));
19438
20393
  return state[session] === true;
19439
20394
  } catch {
19440
20395
  return false;
@@ -19445,18 +20400,18 @@ function latch(root, session) {
19445
20400
  const p = latchFile(root);
19446
20401
  let state = {};
19447
20402
  try {
19448
- state = JSON.parse(fs40.readFileSync(p, "utf-8"));
20403
+ state = JSON.parse(fs44.readFileSync(p, "utf-8"));
19449
20404
  } catch {
19450
20405
  }
19451
20406
  state[session] = true;
19452
- fs40.mkdirSync(path40.dirname(p), { recursive: true });
19453
- fs40.writeFileSync(p, JSON.stringify(state));
20407
+ fs44.mkdirSync(path44.dirname(p), { recursive: true });
20408
+ fs44.writeFileSync(p, JSON.stringify(state));
19454
20409
  } catch {
19455
20410
  }
19456
20411
  }
19457
- var NATIVE_CACHE = path40.join("agents", "runtime", "state", "code-graph-v1.json");
20412
+ var NATIVE_CACHE = path44.join("agents", "runtime", "state", "code-graph-v1.json");
19458
20413
  function nudgeReason(root) {
19459
- const verdicts = detectSources(root, path40.join(root, NATIVE_CACHE));
20414
+ const verdicts = detectSources(root, path44.join(root, NATIVE_CACHE));
19460
20415
  const picked = pickSource(verdicts);
19461
20416
  if (!picked) {
19462
20417
  return 'No code-graph found. For "who calls / where used / impact" run `agent-config code-graph refresh` once, then `agent-config code-graph query <symbol>` instead of grepping blind.';
@@ -19466,48 +20421,48 @@ function nudgeReason(root) {
19466
20421
  }
19467
20422
  return "A fresh code-graph is present \u2014 for structure questions run `agent-config code-graph query|affected <symbol>` first; grep is the fallback (say which answered).";
19468
20423
  }
19469
- function main29() {
20424
+ function main33() {
19470
20425
  let envelope;
19471
20426
  try {
19472
20427
  const raw = readHookStdin();
19473
20428
  envelope = raw.trim() ? JSON.parse(raw) : {};
19474
20429
  } catch {
19475
- return EXIT_ALLOW8;
20430
+ return EXIT_ALLOW12;
19476
20431
  }
19477
- if (!isObject2(envelope)) return EXIT_ALLOW8;
20432
+ if (!isObject2(envelope)) return EXIT_ALLOW12;
19478
20433
  const cwd = envelope["cwd"];
19479
20434
  const pr = envelope["workspace_root"] ?? envelope["project_root"];
19480
20435
  const root = typeof cwd === "string" && cwd ? cwd : typeof pr === "string" && pr ? pr : ".";
19481
- if (!enabled3(root)) return EXIT_ALLOW8;
20436
+ if (!enabled3(root)) return EXIT_ALLOW12;
19482
20437
  const { isSearch, isCodeRead } = classifyTool(envelope);
19483
- if (!isSearch && !isCodeRead) return EXIT_ALLOW8;
20438
+ if (!isSearch && !isCodeRead) return EXIT_ALLOW12;
19484
20439
  const session = sessionId(envelope);
19485
- if (alreadyNudged(root, session)) return EXIT_ALLOW8;
20440
+ if (alreadyNudged(root, session)) return EXIT_ALLOW12;
19486
20441
  let reason;
19487
20442
  try {
19488
20443
  reason = nudgeReason(root);
19489
20444
  } catch {
19490
- return EXIT_ALLOW8;
20445
+ return EXIT_ALLOW12;
19491
20446
  }
19492
20447
  latch(root, session);
19493
20448
  process.stdout.write(`${JSON.stringify({ decision: "warn", reason })}
19494
20449
  `);
19495
- return EXIT_WARN6;
20450
+ return EXIT_WARN7;
19496
20451
  }
19497
20452
  function isCliEntry10() {
19498
20453
  if (true) {
19499
20454
  return false;
19500
20455
  }
19501
20456
  if (process.argv[1] === void 0) return false;
19502
- const argvUrl = pathToFileURL25(path40.resolve(process.argv[1])).href;
20457
+ const argvUrl = pathToFileURL29(path44.resolve(process.argv[1])).href;
19503
20458
  if (import.meta.url === argvUrl) return true;
19504
20459
  try {
19505
- return fs40.realpathSync(fileURLToPath30(import.meta.url)) === fs40.realpathSync(path40.resolve(process.argv[1]));
20460
+ return fs44.realpathSync(fileURLToPath34(import.meta.url)) === fs44.realpathSync(path44.resolve(process.argv[1]));
19506
20461
  } catch {
19507
20462
  return false;
19508
20463
  }
19509
20464
  }
19510
- if (isCliEntry10()) process.exit(main29());
20465
+ if (isCliEntry10()) process.exit(main33());
19511
20466
 
19512
20467
  // src/scripts/hooks/concern_registry.ts
19513
20468
  var CONCERN_REGISTRY = {
@@ -19528,12 +20483,16 @@ var CONCERN_REGISTRY = {
19528
20483
  "src/scripts/team_review_gate_hook.ts": main20,
19529
20484
  "src/scripts/pr_url_reminder_hook.ts": main21,
19530
20485
  "src/scripts/session_canary_hook.ts": main22,
19531
- "src/scripts/hooks/block_no_verify.ts": main23,
19532
- "src/scripts/hooks/block_kernel_rule_writes.ts": main24,
19533
- "src/scripts/hooks/block_config_weakening.ts": main25,
19534
- "src/scripts/hooks/rtk_wrap_hook.ts": main26,
19535
- "src/scripts/hooks/design_slop_hook.ts": main28,
19536
- "src/scripts/hooks/code_graph_nudge_hook.ts": main29
20486
+ "src/scripts/language_mirror_hook.ts": main23,
20487
+ "src/scripts/git_authorization_hook.ts": main24,
20488
+ "src/scripts/hooks/block_unauthorized_git.ts": main25,
20489
+ "src/scripts/hooks/evidence_independence.ts": main26,
20490
+ "src/scripts/hooks/block_no_verify.ts": main27,
20491
+ "src/scripts/hooks/block_kernel_rule_writes.ts": main28,
20492
+ "src/scripts/hooks/block_config_weakening.ts": main29,
20493
+ "src/scripts/hooks/rtk_wrap_hook.ts": main30,
20494
+ "src/scripts/hooks/design_slop_hook.ts": main32,
20495
+ "src/scripts/hooks/code_graph_nudge_hook.ts": main33
19537
20496
  };
19538
20497
 
19539
20498
  // src/scripts/hooks/host_semantics.ts
@@ -19587,14 +20546,14 @@ function emitFor(platform, event, severity, reasons, legacyExit) {
19587
20546
 
19588
20547
  // src/scripts/hooks/dispatch_hook.ts
19589
20548
  var _IN_BUNDLE = true;
19590
- var REPO_ROOT = path41.resolve(
19591
- path41.dirname(fileURLToPath31(import.meta.url)),
20549
+ var REPO_ROOT = path45.resolve(
20550
+ path45.dirname(fileURLToPath35(import.meta.url)),
19592
20551
  ..._IN_BUNDLE ? ["..", ".."] : ["..", "..", ".."]
19593
20552
  );
19594
- var MANIFEST_PATH = path41.join(REPO_ROOT, "src", "scripts", "hook_manifest.yaml");
19595
- var EXIT_ALLOW9 = 0;
19596
- var EXIT_BLOCK2 = 1;
19597
- var EXIT_WARN7 = 2;
20553
+ var MANIFEST_PATH = path45.join(REPO_ROOT, "src", "scripts", "hook_manifest.yaml");
20554
+ var EXIT_ALLOW13 = 0;
20555
+ var EXIT_BLOCK4 = 1;
20556
+ var EXIT_WARN8 = 2;
19598
20557
  var EVENT_VOCABULARY = /* @__PURE__ */ new Set([
19599
20558
  "session_start",
19600
20559
  "session_end",
@@ -19606,11 +20565,11 @@ var EVENT_VOCABULARY = /* @__PURE__ */ new Set([
19606
20565
  "agent_error"
19607
20566
  ]);
19608
20567
  var _SEVERITY_BY_EXIT = {
19609
- [EXIT_ALLOW9]: "allow",
19610
- [EXIT_BLOCK2]: "block",
19611
- [EXIT_WARN7]: "warn"
20568
+ [EXIT_ALLOW13]: "allow",
20569
+ [EXIT_BLOCK4]: "block",
20570
+ [EXIT_WARN8]: "warn"
19612
20571
  };
19613
- function _isObject9(v) {
20572
+ function _isObject13(v) {
19614
20573
  return typeof v === "object" && v !== null && !Array.isArray(v);
19615
20574
  }
19616
20575
  function _severity_for(rc) {
@@ -19640,33 +20599,58 @@ function _parse_concern_stdout(stdout_text) {
19640
20599
  } catch {
19641
20600
  return { _raw_stdout: text.slice(0, 500) };
19642
20601
  }
19643
- return _isObject9(parsed) ? parsed : { _raw: parsed };
20602
+ return _isObject13(parsed) ? parsed : { _raw: parsed };
19644
20603
  }
19645
20604
  function _load_yaml3(p) {
19646
- const text = fs41.readFileSync(p, "utf-8");
20605
+ const text = fs45.readFileSync(p, "utf-8");
19647
20606
  const data = (0, import_yaml6.parse)(text, { version: "1.1" });
19648
- return _isObject9(data) ? data : {};
20607
+ return _isObject13(data) ? data : {};
20608
+ }
20609
+ function _payload_tool_name(envelope) {
20610
+ const payload = envelope["payload"];
20611
+ if (!_isObject13(payload)) {
20612
+ return "";
20613
+ }
20614
+ const raw = payload["tool_name"];
20615
+ return typeof raw === "string" ? raw : "";
20616
+ }
20617
+ function _concern_matches_tool(concern, tool_name) {
20618
+ const raw = concern["tools"];
20619
+ if (raw === void 0 || raw === null) {
20620
+ return true;
20621
+ }
20622
+ if (!Array.isArray(raw) || raw.length === 0) {
20623
+ return true;
20624
+ }
20625
+ const names = raw.filter((t) => typeof t === "string");
20626
+ if (names.length === 0 || names.includes("*")) {
20627
+ return true;
20628
+ }
20629
+ if (tool_name === "") {
20630
+ return true;
20631
+ }
20632
+ return names.includes(tool_name);
19649
20633
  }
19650
20634
  function _resolve_concerns(manifest, platform, event) {
19651
20635
  const platformsRaw = manifest["platforms"];
19652
- const platforms = _isObject9(platformsRaw) ? platformsRaw : {};
20636
+ const platforms = _isObject13(platformsRaw) ? platformsRaw : {};
19653
20637
  const block = platforms[platform];
19654
20638
  if (!block) {
19655
20639
  return [];
19656
20640
  }
19657
- if (_isObject9(block) && block["fallback_only"]) {
20641
+ if (_isObject13(block) && block["fallback_only"]) {
19658
20642
  return [];
19659
20643
  }
19660
- const names = _isObject9(block) ? block[event] : null;
20644
+ const names = _isObject13(block) ? block[event] : null;
19661
20645
  if (!Array.isArray(names)) {
19662
20646
  return [];
19663
20647
  }
19664
20648
  const concernsRaw = manifest["concerns"];
19665
- const concerns_def = _isObject9(concernsRaw) ? concernsRaw : {};
20649
+ const concerns_def = _isObject13(concernsRaw) ? concernsRaw : {};
19666
20650
  const out = [];
19667
20651
  for (const name of names) {
19668
20652
  const spec = typeof name === "string" ? concerns_def[name] : void 0;
19669
- if (!spec || !_isObject9(spec)) {
20653
+ if (!spec || !_isObject13(spec)) {
19670
20654
  process.stderr.write(
19671
20655
  `dispatch_hook: unknown concern '${String(name)}' in manifest
19672
20656
  `
@@ -19756,7 +20740,7 @@ function _maybe_capture_payload(args, payload_text) {
19756
20740
  }
19757
20741
  try {
19758
20742
  const target = _expanduser2(capture_dir);
19759
- fs41.mkdirSync(target, { recursive: true });
20743
+ fs45.mkdirSync(target, { recursive: true });
19760
20744
  let payload;
19761
20745
  try {
19762
20746
  payload = payload_text.trim() ? JSON.parse(payload_text) : {};
@@ -19773,8 +20757,8 @@ function _maybe_capture_payload(args, payload_text) {
19773
20757
  const ts = Date.now();
19774
20758
  const native = (args.native_event || args.event).replace(/\//g, "_");
19775
20759
  const fname = `${args.platform}__${native}__${ts}__${process.pid}.json`;
19776
- fs41.writeFileSync(
19777
- path41.join(target, fname),
20760
+ fs45.writeFileSync(
20761
+ path45.join(target, fname),
19778
20762
  _py_json_dumps2(record, 2) + "\n",
19779
20763
  { encoding: "utf-8" }
19780
20764
  );
@@ -19785,7 +20769,7 @@ function _maybe_capture_payload(args, payload_text) {
19785
20769
  function _expanduser2(p) {
19786
20770
  if (p === "~" || p.startsWith("~/")) {
19787
20771
  const home = process.env["HOME"] || process.env["USERPROFILE"] || "";
19788
- return path41.join(home, p.slice(1));
20772
+ return path45.join(home, p.slice(1));
19789
20773
  }
19790
20774
  return p;
19791
20775
  }
@@ -19793,7 +20777,7 @@ function _build_envelope(args, payload_text) {
19793
20777
  let payload;
19794
20778
  try {
19795
20779
  payload = payload_text.trim() ? JSON.parse(payload_text) : {};
19796
- if (!_isObject9(payload)) {
20780
+ if (!_isObject13(payload)) {
19797
20781
  payload = { _raw: payload };
19798
20782
  }
19799
20783
  } catch {
@@ -19817,25 +20801,25 @@ function _resolve_tsx_invocation2(scriptPath, scriptArgs) {
19817
20801
  const walkUp = (start) => {
19818
20802
  let dir = start;
19819
20803
  for (; ; ) {
19820
- const candidate = path41.join(dir, "node_modules", ".bin", binName);
20804
+ const candidate = path45.join(dir, "node_modules", ".bin", binName);
19821
20805
  if (_isFile7(candidate)) {
19822
20806
  return candidate;
19823
20807
  }
19824
- const parent = path41.dirname(dir);
20808
+ const parent = path45.dirname(dir);
19825
20809
  if (parent === dir) {
19826
20810
  return null;
19827
20811
  }
19828
20812
  dir = parent;
19829
20813
  }
19830
20814
  };
19831
- const tsx = walkUp(path41.dirname(scriptPath)) ?? walkUp(path41.dirname(fileURLToPath31(import.meta.url)));
20815
+ const tsx = walkUp(path45.dirname(scriptPath)) ?? walkUp(path45.dirname(fileURLToPath35(import.meta.url)));
19832
20816
  if (tsx !== null) {
19833
20817
  return { command: tsx, args: [scriptPath, ...scriptArgs] };
19834
20818
  }
19835
20819
  return { command: "npx", args: ["tsx", scriptPath, ...scriptArgs] };
19836
20820
  }
19837
20821
  function _run_concern_inproc(main_fn, concern, envelope) {
19838
- const scriptAbs = path41.join(REPO_ROOT, String(concern["script"]));
20822
+ const scriptAbs = path45.join(REPO_ROOT, String(concern["script"]));
19839
20823
  const argsList = Array.isArray(concern["args"]) ? concern["args"].map((a) => String(a)) : [];
19840
20824
  argsList.push("--platform", String(envelope["platform"] || "generic"));
19841
20825
  const workspace = String(envelope["workspace_root"] || process.cwd());
@@ -19912,7 +20896,7 @@ function _run_concern(concern, envelope) {
19912
20896
  return _run_concern_inproc(inproc, concern, envelope);
19913
20897
  }
19914
20898
  }
19915
- const script = path41.join(REPO_ROOT, String(concern["script"]));
20899
+ const script = path45.join(REPO_ROOT, String(concern["script"]));
19916
20900
  const argsList = Array.isArray(concern["args"]) ? concern["args"].map((a) => String(a)) : [];
19917
20901
  const cmd = [script, ...argsList];
19918
20902
  cmd.push("--platform", String(envelope["platform"] || "generic"));
@@ -19969,7 +20953,7 @@ function _run_concern(concern, envelope) {
19969
20953
  }
19970
20954
  function _isFile7(p) {
19971
20955
  try {
19972
- return fs41.statSync(p).isFile();
20956
+ return fs45.statSync(p).isFile();
19973
20957
  } catch {
19974
20958
  return false;
19975
20959
  }
@@ -19978,23 +20962,23 @@ function _compactJsonDumps(value) {
19978
20962
  return JSON.stringify(value);
19979
20963
  }
19980
20964
  function _reduce(rcs) {
19981
- if (rcs.some((rc) => rc === EXIT_BLOCK2)) {
19982
- return EXIT_BLOCK2;
20965
+ if (rcs.some((rc) => rc === EXIT_BLOCK4)) {
20966
+ return EXIT_BLOCK4;
19983
20967
  }
19984
- if (rcs.some((rc) => rc === EXIT_WARN7)) {
19985
- return EXIT_WARN7;
20968
+ if (rcs.some((rc) => rc === EXIT_WARN8)) {
20969
+ return EXIT_WARN8;
19986
20970
  }
19987
- return EXIT_ALLOW9;
20971
+ return EXIT_ALLOW13;
19988
20972
  }
19989
20973
  function _write_feedback(envelope, session_id, entries, final_rc, started_at) {
19990
20974
  if (is_replay_mode()) {
19991
20975
  return;
19992
20976
  }
19993
20977
  const workspace = String(envelope["workspace_root"] || process.cwd());
19994
- const state_root = path41.join(workspace, "agents", "runtime", "state");
20978
+ const state_root = path45.join(workspace, "agents", "runtime", "state");
19995
20979
  const fb_dir = feedback_dir(state_root, session_id);
19996
20980
  try {
19997
- fs41.mkdirSync(fb_dir, { recursive: true });
20981
+ fs45.mkdirSync(fb_dir, { recursive: true });
19998
20982
  } catch (exc) {
19999
20983
  const msg = exc instanceof Error ? exc.message : String(exc);
20000
20984
  process.stderr.write(`dispatch_hook: feedback dir unavailable: ${msg}
@@ -20002,7 +20986,7 @@ function _write_feedback(envelope, session_id, entries, final_rc, started_at) {
20002
20986
  return;
20003
20987
  }
20004
20988
  for (const entry of entries) {
20005
- const target = path41.join(fb_dir, `${entry["concern"]}.json`);
20989
+ const target = path45.join(fb_dir, `${entry["concern"]}.json`);
20006
20990
  try {
20007
20991
  atomic_write_json(target, entry);
20008
20992
  } catch (exc) {
@@ -20042,7 +21026,7 @@ function _write_feedback(envelope, session_id, entries, final_rc, started_at) {
20042
21026
  })
20043
21027
  };
20044
21028
  try {
20045
- atomic_write_json(path41.join(fb_dir, "summary.json"), summary);
21029
+ atomic_write_json(path45.join(fb_dir, "summary.json"), summary);
20046
21030
  } catch (exc) {
20047
21031
  const msg = exc instanceof Error ? exc.message : String(exc);
20048
21032
  process.stderr.write(`dispatch_hook: summary write failed: ${msg}
@@ -20052,17 +21036,17 @@ function _write_feedback(envelope, session_id, entries, final_rc, started_at) {
20052
21036
  function _record_rule_trips(envelope, entries) {
20053
21037
  if (is_replay_mode()) return;
20054
21038
  const tripped = entries.filter(
20055
- (e) => e["exit_code"] === EXIT_BLOCK2 || e["exit_code"] === EXIT_WARN7
21039
+ (e) => e["exit_code"] === EXIT_BLOCK4 || e["exit_code"] === EXIT_WARN8
20056
21040
  );
20057
21041
  if (tripped.length === 0) return;
20058
21042
  try {
20059
21043
  const workspace = String(envelope["workspace_root"] || process.cwd());
20060
- const state_dir = path41.join(workspace, "agents", "runtime", "state");
20061
- const target = path41.join(state_dir, "rule-trips.json");
20062
- fs41.mkdirSync(state_dir, { recursive: true });
21044
+ const state_dir = path45.join(workspace, "agents", "runtime", "state");
21045
+ const target = path45.join(state_dir, "rule-trips.json");
21046
+ fs45.mkdirSync(state_dir, { recursive: true });
20063
21047
  let doc = { schema_version: 1, concerns: {} };
20064
21048
  try {
20065
- const parsed = JSON.parse(fs41.readFileSync(target, "utf-8"));
21049
+ const parsed = JSON.parse(fs45.readFileSync(target, "utf-8"));
20066
21050
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) doc = parsed;
20067
21051
  } catch {
20068
21052
  }
@@ -20072,8 +21056,8 @@ function _record_rule_trips(envelope, entries) {
20072
21056
  const name = String(e["concern"]);
20073
21057
  const prev = concerns[name] ?? { block: 0, warn: 0 };
20074
21058
  concerns[name] = {
20075
- block: (Number(prev["block"]) || 0) + (e["exit_code"] === EXIT_BLOCK2 ? 1 : 0),
20076
- warn: (Number(prev["warn"]) || 0) + (e["exit_code"] === EXIT_WARN7 ? 1 : 0),
21059
+ block: (Number(prev["block"]) || 0) + (e["exit_code"] === EXIT_BLOCK4 ? 1 : 0),
21060
+ warn: (Number(prev["warn"]) || 0) + (e["exit_code"] === EXIT_WARN8 ? 1 : 0),
20077
21061
  last_trip: today
20078
21062
  };
20079
21063
  }
@@ -20161,7 +21145,7 @@ function _parse_args(argv) {
20161
21145
  }
20162
21146
  return args;
20163
21147
  }
20164
- function main30(argv) {
21148
+ function main34(argv) {
20165
21149
  const args = _parse_args(argv ?? process.argv.slice(2));
20166
21150
  if (args.project_dir) {
20167
21151
  const project_dir = _expanduser2(args.project_dir);
@@ -20179,13 +21163,13 @@ function main30(argv) {
20179
21163
  `dispatch_hook: unknown event '${args.event}'; allowed: ${_sortedRepr(EVENT_VOCABULARY)}
20180
21164
  `
20181
21165
  );
20182
- return EXIT_ALLOW9;
21166
+ return EXIT_ALLOW13;
20183
21167
  }
20184
21168
  const manifest_path = args.manifest;
20185
- if (!fs41.existsSync(manifest_path)) {
21169
+ if (!fs45.existsSync(manifest_path)) {
20186
21170
  process.stderr.write(`dispatch_hook: manifest missing at ${manifest_path}
20187
21171
  `);
20188
- return EXIT_ALLOW9;
21172
+ return EXIT_ALLOW13;
20189
21173
  }
20190
21174
  const manifest = _load_yaml3(manifest_path);
20191
21175
  if (args.min_version) {
@@ -20207,10 +21191,10 @@ function main30(argv) {
20207
21191
  concerns: concerns.map((c) => c["name"])
20208
21192
  };
20209
21193
  process.stdout.write(_py_json_dumps2(plan, 2) + "\n");
20210
- return EXIT_ALLOW9;
21194
+ return EXIT_ALLOW13;
20211
21195
  }
20212
21196
  if (concerns.length === 0) {
20213
- return EXIT_ALLOW9;
21197
+ return EXIT_ALLOW13;
20214
21198
  }
20215
21199
  const envelope = _build_envelope(args, payload_text);
20216
21200
  const session_id = _resolve_session_id(envelope);
@@ -20219,35 +21203,41 @@ function main30(argv) {
20219
21203
  const feedback_entries = [];
20220
21204
  const context_blocks = [];
20221
21205
  const concern_messages = [];
21206
+ const tool_name = _payload_tool_name(envelope);
20222
21207
  for (const concern of concerns) {
21208
+ if (!_concern_matches_tool(concern, tool_name)) {
21209
+ continue;
21210
+ }
20223
21211
  const concern_started = _now_iso3();
20224
21212
  const { rc: rawRcResult, stderr: stderr_text, stdout: stdout_text, duration_ms } = _run_concern(concern, envelope);
20225
21213
  let rc = rawRcResult;
20226
21214
  const raw_rc = rc;
20227
21215
  if (rc >= 3) {
20228
21216
  if (!concern["fail_closed"]) {
20229
- rc = EXIT_ALLOW9;
21217
+ rc = EXIT_ALLOW13;
20230
21218
  } else {
20231
- rc = EXIT_BLOCK2;
21219
+ rc = EXIT_BLOCK4;
20232
21220
  }
20233
21221
  if (stderr_text) {
20234
21222
  process.stderr.write(stderr_text);
20235
21223
  }
20236
21224
  }
20237
- if (rc === EXIT_BLOCK2 && _is_advisory(concern)) {
21225
+ if (rc === EXIT_BLOCK4 && _is_advisory(concern)) {
20238
21226
  process.stderr.write(
20239
21227
  `dispatch_hook: concern '${String(concern["name"])}' is declared severity: advisory but returned BLOCK \u2014 downgraded to warn.
20240
21228
  `
20241
21229
  );
20242
- rc = EXIT_WARN7;
21230
+ rc = EXIT_WARN8;
20243
21231
  }
20244
21232
  rcs.push(rc);
20245
21233
  const reply = _parse_concern_stdout(stdout_text);
20246
21234
  const stated = typeof reply["reason"] === "string" && reply["reason"].trim() ? reply["reason"].trim() : stderr_text.trim();
20247
- if (stated) {
20248
- concern_messages.push({ rc, text: stated });
21235
+ const extra = typeof reply["additional_context"] === "string" && reply["additional_context"].trim() ? reply["additional_context"].trim() : "";
21236
+ const message = [stated, extra].filter(Boolean).join("\n\n");
21237
+ if (message) {
21238
+ concern_messages.push({ rc, text: message });
20249
21239
  }
20250
- if (args.event === "session_start" && rc === EXIT_ALLOW9 && typeof reply["context"] === "string" && reply["context"].trim()) {
21240
+ if (args.event === "session_start" && rc === EXIT_ALLOW13 && typeof reply["context"] === "string" && reply["context"].trim()) {
20251
21241
  context_blocks.push(reply["context"].trim());
20252
21242
  }
20253
21243
  feedback_entries.push({
@@ -20266,7 +21256,7 @@ function main30(argv) {
20266
21256
  const final_rc = _reduce(rcs);
20267
21257
  _write_feedback(envelope, session_id, feedback_entries, final_rc, started_at);
20268
21258
  _record_rule_trips(envelope, feedback_entries);
20269
- if (context_blocks.length > 0 && final_rc === EXIT_ALLOW9) {
21259
+ if (context_blocks.length > 0 && final_rc === EXIT_ALLOW13) {
20270
21260
  process.stdout.write(context_blocks.join("\n\n") + "\n");
20271
21261
  }
20272
21262
  const decidingReasons = concern_messages.filter((m) => m.rc === final_rc).map((m) => m.text);
@@ -20287,7 +21277,7 @@ function main30(argv) {
20287
21277
  }
20288
21278
  function _isDir4(p) {
20289
21279
  try {
20290
- return fs41.statSync(p).isDirectory();
21280
+ return fs45.statSync(p).isDirectory();
20291
21281
  } catch {
20292
21282
  return false;
20293
21283
  }
@@ -20298,41 +21288,41 @@ function _sortedRepr(s) {
20298
21288
  }
20299
21289
  function _readStdin14() {
20300
21290
  try {
20301
- return fs41.readFileSync(0, "utf-8");
21291
+ return fs45.readFileSync(0, "utf-8");
20302
21292
  } catch {
20303
21293
  return "";
20304
21294
  }
20305
21295
  }
20306
- function _isCliEntry24() {
21296
+ function _isCliEntry28() {
20307
21297
  if (true) {
20308
21298
  return false;
20309
21299
  }
20310
21300
  if (process.argv[1] === void 0) {
20311
21301
  return false;
20312
21302
  }
20313
- const argvUrl = pathToFileURL26(path41.resolve(process.argv[1])).href;
21303
+ const argvUrl = pathToFileURL30(path45.resolve(process.argv[1])).href;
20314
21304
  if (import.meta.url === argvUrl) {
20315
21305
  return true;
20316
21306
  }
20317
21307
  try {
20318
- const here = fs41.realpathSync(fileURLToPath31(import.meta.url));
20319
- const argv = fs41.realpathSync(path41.resolve(process.argv[1]));
21308
+ const here = fs45.realpathSync(fileURLToPath35(import.meta.url));
21309
+ const argv = fs45.realpathSync(path45.resolve(process.argv[1]));
20320
21310
  return here === argv;
20321
21311
  } catch {
20322
21312
  return false;
20323
21313
  }
20324
21314
  }
20325
- var isCliEntry11 = _isCliEntry24();
21315
+ var isCliEntry11 = _isCliEntry28();
20326
21316
  if (isCliEntry11) {
20327
- process.exit(main30(process.argv.slice(2)));
21317
+ process.exit(main34(process.argv.slice(2)));
20328
21318
  }
20329
21319
 
20330
21320
  // src/scripts/hooks/dispatch_entry.ts
20331
- var _selfPath = fileURLToPath32(import.meta.url);
20332
- var _invokedDirectly2 = globalThis.__AC_HOOKS_BUNDLE_DIRECT === true || process.argv[1] !== void 0 && path42.resolve(process.argv[1]) === path42.resolve(_selfPath);
21321
+ var _selfPath = fileURLToPath36(import.meta.url);
21322
+ var _invokedDirectly2 = globalThis.__AC_HOOKS_BUNDLE_DIRECT === true || process.argv[1] !== void 0 && path46.resolve(process.argv[1]) === path46.resolve(_selfPath);
20333
21323
  if (_invokedDirectly2) {
20334
- process.exitCode = main30(process.argv.slice(2));
21324
+ process.exitCode = main34(process.argv.slice(2));
20335
21325
  }
20336
21326
  export {
20337
- main30 as main
21327
+ main34 as main
20338
21328
  };