@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.
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +136 -0
- package/README.md +1 -1
- package/dist/agent-src/commands/analyze/conformance.md +182 -0
- package/dist/agent-src/commands/analyze/inbox.md +33 -2
- package/dist/agent-src/commands/review/changes.md +6 -5
- package/dist/agent-src/commands/roadmap/next.md +194 -0
- package/dist/agent-src/commands/roadmap.md +12 -4
- package/dist/agent-src/contexts/execution/subagent-routing.md +4 -1
- package/dist/agent-src/rules/decision-revisit-gate.md +2 -0
- package/dist/agent-src/rules/delegation-policy.md +3 -2
- package/dist/agent-src/rules/design-fidelity.md +17 -1
- package/dist/agent-src/rules/design-review-after-ui-write.md +116 -0
- package/dist/agent-src/rules/evaluator-independence.md +111 -0
- package/dist/agent-src/rules/session-canary.md +15 -1
- package/dist/agent-src/rules/settings-ask-protocol.md +176 -0
- package/dist/agent-src/rules/token-budget-discipline.md +6 -3
- package/dist/agent-src/rules/ui-audit-gate.md +3 -0
- package/dist/agent-src/rules/user-interaction.md +23 -0
- package/dist/agent-src/skills/finishing-a-development-branch/SKILL.md +1 -1
- package/dist/agent-src/skills/recursive-verification/SKILL.md +13 -0
- package/dist/agent-src/skills/rule-writing/SKILL.md +45 -0
- package/dist/agent-src/skills/skill-writing/SKILL.md +114 -0
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/cli/registry.js +1 -0
- package/dist/cli/registry.js.map +1 -1
- package/dist/cli-delegate/cmd_route_audit.js +4 -1
- package/dist/cli-delegate/cmd_route_explain.js +4 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +146 -28
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +5 -5
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +16 -11
- package/dist/discovery/trust-report.md +3 -3
- package/dist/discovery/workspaces.json +12 -7
- package/dist/hooks/dispatch.js +1501 -511
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +2 -2
- package/dist/router.json +1 -1
- package/dist/server/nicknameResolver.js +116 -0
- package/dist/server/nicknameResolver.js.map +1 -0
- package/dist/server/routes/ping.js +29 -11
- package/dist/server/routes/ping.js.map +1 -1
- package/dist/shared/interactiveContext.js +73 -0
- package/dist/shared/interactiveContext.js.map +1 -0
- package/dist/shared/nicknamePrefill.js +59 -0
- package/dist/shared/nicknamePrefill.js.map +1 -0
- package/dist/shared/settingsAsks.js +128 -0
- package/dist/shared/settingsAsks.js.map +1 -0
- package/dist/shared/settingsConsent.js +93 -0
- package/dist/shared/settingsConsent.js.map +1 -0
- package/package.json +1 -1
- package/src/config/agents-paths.yml +15 -0
- package/src/config/evaluator-budgets.json +68 -68
- package/src/config/gate-coverage.yml +131 -5
- package/src/config/gate-violation-baselines.json +11 -0
- package/src/scripts/_cli/cmd_route_audit.ts +4 -1
- package/src/scripts/_cli/cmd_route_explain.ts +9 -1
- package/src/scripts/_dispatch.bash +12 -0
- package/src/scripts/ai-video/stitch.sh +27 -9
- package/src/scripts/before_complete_hook.ts +146 -5
- package/src/scripts/bench_ab_v2_run.ts +272 -16
- package/src/scripts/bench_ab_v2_stats.ts +156 -3
- package/src/scripts/check_completion_review.ts +80 -3
- package/src/scripts/check_corpus_staleness.ts +692 -0
- package/src/scripts/check_depth_budget.ts +295 -0
- package/src/scripts/check_gate_coverage.ts +67 -0
- package/src/scripts/check_hook_bundle_freshness.ts +183 -0
- package/src/scripts/conformance_scan.ts +422 -0
- package/src/scripts/dispatch_r2_reviewer.ts +31 -2
- package/src/scripts/git_authorization_hook.ts +328 -0
- package/src/scripts/hook_manifest.yaml +69 -9
- package/src/scripts/hooks/block_no_verify.ts +3 -1
- package/src/scripts/hooks/block_unauthorized_git.ts +371 -0
- package/src/scripts/hooks/concern_registry.ts +8 -0
- package/src/scripts/hooks/design_slop_hook.ts +13 -1
- package/src/scripts/hooks/dispatch_hook.ts +97 -2
- package/src/scripts/hooks/evidence_independence.ts +368 -0
- package/src/scripts/language_mirror_hook.ts +456 -0
- package/src/scripts/lint_abstraction_thresholds.ts +41 -8
- package/src/scripts/lint_agents_layout.ts +2 -0
- package/src/scripts/lint_decision_impact.ts +246 -0
- package/src/scripts/lint_example_fences.ts +609 -0
- package/src/scripts/lint_hook_manifest.ts +29 -0
- package/src/scripts/lint_rule_interactions.ts +90 -0
- package/src/scripts/lint_rule_migration_ledger.ts +480 -0
- package/src/scripts/lint_skill_descriptions.ts +86 -2
- package/src/scripts/memory_learn_hook.ts +109 -6
- package/src/scripts/pr_url_reminder_hook.ts +17 -2
- package/src/scripts/release.ts +38 -1
- package/src/scripts/schemas/review-findings.schema.json +99 -0
- package/src/scripts/schemas/rule.schema.json +10 -0
- package/src/shared/interactiveContext.ts +98 -0
- package/src/shared/nicknamePrefill.ts +96 -0
- package/src/shared/settingsAsks.ts +176 -0
- package/src/shared/settingsConsent.ts +136 -0
package/dist/hooks/dispatch.js
CHANGED
|
@@ -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,
|
|
116
|
-
const ctrl = callVisitor(key, node, visitor,
|
|
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,
|
|
119
|
-
return visit_(key, ctrl, visitor,
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
137
|
-
const ck = visit_("key", node.key, visitor,
|
|
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,
|
|
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,
|
|
164
|
-
const ctrl = await callVisitor(key, node, visitor,
|
|
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,
|
|
167
|
-
return visitAsync_(key, ctrl, visitor,
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
185
|
-
const ck = await visitAsync_("key", node.key, visitor,
|
|
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,
|
|
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,
|
|
217
|
+
function callVisitor(key, node, visitor, path47) {
|
|
218
218
|
if (typeof visitor === "function")
|
|
219
|
-
return visitor(key, node,
|
|
219
|
+
return visitor(key, node, path47);
|
|
220
220
|
if (identity.isMap(node))
|
|
221
|
-
return visitor.Map?.(key, node,
|
|
221
|
+
return visitor.Map?.(key, node, path47);
|
|
222
222
|
if (identity.isSeq(node))
|
|
223
|
-
return visitor.Seq?.(key, node,
|
|
223
|
+
return visitor.Seq?.(key, node, path47);
|
|
224
224
|
if (identity.isPair(node))
|
|
225
|
-
return visitor.Pair?.(key, node,
|
|
225
|
+
return visitor.Pair?.(key, node, path47);
|
|
226
226
|
if (identity.isScalar(node))
|
|
227
|
-
return visitor.Scalar?.(key, node,
|
|
227
|
+
return visitor.Scalar?.(key, node, path47);
|
|
228
228
|
if (identity.isAlias(node))
|
|
229
|
-
return visitor.Alias?.(key, node,
|
|
229
|
+
return visitor.Alias?.(key, node, path47);
|
|
230
230
|
return void 0;
|
|
231
231
|
}
|
|
232
|
-
function replaceNode(key,
|
|
233
|
-
const parent =
|
|
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,
|
|
843
|
+
function collectionFromPath(schema, path47, value) {
|
|
844
844
|
let v = value;
|
|
845
|
-
for (let i =
|
|
846
|
-
const k =
|
|
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 = (
|
|
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(
|
|
896
|
-
if (isEmptyPath(
|
|
895
|
+
addIn(path47, value) {
|
|
896
|
+
if (isEmptyPath(path47))
|
|
897
897
|
this.add(value);
|
|
898
898
|
else {
|
|
899
|
-
const [key, ...rest] =
|
|
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(
|
|
914
|
-
const [key, ...rest] =
|
|
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(
|
|
929
|
-
const [key, ...rest] =
|
|
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(
|
|
948
|
-
const [key, ...rest] =
|
|
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(
|
|
959
|
-
const [key, ...rest] =
|
|
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(
|
|
3474
|
+
addIn(path47, value) {
|
|
3475
3475
|
if (assertCollection(this.contents))
|
|
3476
|
-
this.contents.addIn(
|
|
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(
|
|
3552
|
-
if (Collection.isEmptyPath(
|
|
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(
|
|
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(
|
|
3574
|
-
if (Collection.isEmptyPath(
|
|
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(
|
|
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(
|
|
3588
|
-
if (Collection.isEmptyPath(
|
|
3587
|
+
hasIn(path47) {
|
|
3588
|
+
if (Collection.isEmptyPath(path47))
|
|
3589
3589
|
return this.contents !== void 0;
|
|
3590
|
-
return identity.isCollection(this.contents) ? this.contents.hasIn(
|
|
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(
|
|
3608
|
-
if (Collection.isEmptyPath(
|
|
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(
|
|
3611
|
+
this.contents = Collection.collectionFromPath(this.schema, Array.from(path47), value);
|
|
3612
3612
|
} else if (assertCollection(this.contents)) {
|
|
3613
|
-
this.contents.setIn(
|
|
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,
|
|
5573
|
+
visit.itemAtPath = (cst, path47) => {
|
|
5574
5574
|
let item = cst;
|
|
5575
|
-
for (const [field, index] of
|
|
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,
|
|
5585
|
-
const parent = visit.itemAtPath(cst,
|
|
5586
|
-
const field =
|
|
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(
|
|
5593
|
-
let ctrl = visitor(item,
|
|
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(
|
|
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,
|
|
5611
|
+
ctrl = ctrl(item, path47);
|
|
5612
5612
|
}
|
|
5613
5613
|
}
|
|
5614
|
-
return typeof ctrl === "function" ? ctrl(item,
|
|
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
|
|
6916
|
+
const fs46 = this.flowScalar(this.type);
|
|
6917
6917
|
if (atNextItem || it.value) {
|
|
6918
|
-
map.items.push({ start, key:
|
|
6918
|
+
map.items.push({ start, key: fs46, sep: [] });
|
|
6919
6919
|
this.onKeyLine = true;
|
|
6920
6920
|
} else if (it.sep) {
|
|
6921
|
-
this.stack.push(
|
|
6921
|
+
this.stack.push(fs46);
|
|
6922
6922
|
} else {
|
|
6923
|
-
Object.assign(it, { key:
|
|
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
|
|
7051
|
+
const fs46 = this.flowScalar(this.type);
|
|
7052
7052
|
if (!it || it.value)
|
|
7053
|
-
fc.items.push({ start: [], key:
|
|
7053
|
+
fc.items.push({ start: [], key: fs46, sep: [] });
|
|
7054
7054
|
else if (it.sep)
|
|
7055
|
-
this.stack.push(
|
|
7055
|
+
this.stack.push(fs46);
|
|
7056
7056
|
else
|
|
7057
|
-
Object.assign(it, { key:
|
|
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
|
|
7367
|
-
import { fileURLToPath as
|
|
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
|
|
7373
|
-
import
|
|
7374
|
-
import { fileURLToPath as
|
|
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
|
-
|
|
15153
|
-
|
|
15154
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
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/
|
|
17402
|
-
import
|
|
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
|
-
|
|
17405
|
-
var
|
|
17406
|
-
var
|
|
17407
|
-
|
|
17408
|
-
|
|
17409
|
-
|
|
17410
|
-
var
|
|
17411
|
-
var
|
|
17412
|
-
|
|
17413
|
-
|
|
17414
|
-
|
|
17415
|
-
|
|
17416
|
-
|
|
17417
|
-
"
|
|
17418
|
-
|
|
17419
|
-
|
|
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 (
|
|
17464
|
-
|
|
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 (
|
|
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(
|
|
17503
|
-
i += 1;
|
|
17563
|
+
kept.push(line);
|
|
17504
17564
|
}
|
|
17505
|
-
|
|
17506
|
-
tokens.push(token);
|
|
17507
|
-
}
|
|
17508
|
-
return tokens;
|
|
17565
|
+
return kept.join("\n");
|
|
17509
17566
|
}
|
|
17510
|
-
function
|
|
17511
|
-
|
|
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
|
-
|
|
17514
|
-
|
|
17515
|
-
|
|
17516
|
-
|
|
17517
|
-
|
|
17518
|
-
|
|
17519
|
-
|
|
17520
|
-
|
|
17521
|
-
|
|
17522
|
-
|
|
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
|
-
|
|
17527
|
-
|
|
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
|
|
17607
|
+
return `Reply language for this turn: ${name}.`;
|
|
17530
17608
|
}
|
|
17531
|
-
function
|
|
17532
|
-
|
|
17533
|
-
|
|
17534
|
-
|
|
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
|
-
|
|
17537
|
-
|
|
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
|
|
17542
|
-
|
|
17543
|
-
|
|
17544
|
-
|
|
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 (
|
|
17551
|
-
|
|
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
|
-
|
|
17555
|
-
|
|
17556
|
-
|
|
17557
|
-
|
|
17558
|
-
|
|
17559
|
-
|
|
17560
|
-
|
|
17561
|
-
|
|
17562
|
-
|
|
17563
|
-
|
|
17564
|
-
|
|
17565
|
-
|
|
17566
|
-
|
|
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
|
|
17668
|
+
return "";
|
|
17582
17669
|
}
|
|
17583
|
-
function
|
|
17584
|
-
|
|
17585
|
-
if (
|
|
17586
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
17779
|
-
const argv =
|
|
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 (
|
|
17786
|
-
process.exitCode =
|
|
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
|
|
17791
|
-
import { fileURLToPath as
|
|
17792
|
-
import * as
|
|
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 =
|
|
17817
|
-
function
|
|
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 =
|
|
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 =
|
|
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(
|
|
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 =
|
|
17964
|
-
const ti =
|
|
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
|
|
18927
|
+
return _isObject10(v) ? v : null;
|
|
17978
18928
|
}
|
|
17979
18929
|
function _readStdin12() {
|
|
17980
18930
|
return readHookStdin();
|
|
17981
18931
|
}
|
|
17982
|
-
function
|
|
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
|
|
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 =
|
|
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 =
|
|
18020
|
-
const argv =
|
|
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 (
|
|
18027
|
-
process.exitCode =
|
|
18976
|
+
if (_isCliEntry24() || false) {
|
|
18977
|
+
process.exitCode = main28();
|
|
18028
18978
|
}
|
|
18029
18979
|
|
|
18030
18980
|
// src/scripts/hooks/block_config_weakening.ts
|
|
18031
|
-
import * as
|
|
18032
|
-
import * as
|
|
18033
|
-
import { fileURLToPath as
|
|
18034
|
-
var _HERE5 =
|
|
18035
|
-
var
|
|
18036
|
-
var
|
|
18037
|
-
var
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
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(
|
|
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
|
-
|
|
18135
|
-
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
|
19113
|
+
return EXIT_ALLOW9;
|
|
18164
19114
|
}
|
|
18165
|
-
if (!
|
|
18166
|
-
return
|
|
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
|
|
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 =
|
|
19132
|
+
const abs = path39.isAbsolute(p) ? p : path39.join(root, p);
|
|
18183
19133
|
let on_disk = null;
|
|
18184
19134
|
try {
|
|
18185
|
-
on_disk =
|
|
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 =
|
|
19143
|
+
const rel = path39.relative(root, abs) || p;
|
|
18194
19144
|
const total = kind === "allowlist" ? bump_session(root, session, rel, added) : added;
|
|
18195
|
-
const d =
|
|
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
|
|
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
|
|
19154
|
+
return EXIT_WARN4;
|
|
18205
19155
|
}
|
|
18206
19156
|
}
|
|
18207
|
-
return
|
|
19157
|
+
return EXIT_ALLOW9;
|
|
18208
19158
|
}
|
|
18209
|
-
function
|
|
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 =
|
|
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
|
|
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 (
|
|
18227
|
-
process.exit(
|
|
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
|
|
18232
|
-
import
|
|
18233
|
-
import { fileURLToPath as
|
|
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
|
|
18346
|
-
var
|
|
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
|
|
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 =
|
|
19325
|
+
const f = path40.join(root, SETTINGS_FILE6);
|
|
18376
19326
|
try {
|
|
18377
|
-
if (!
|
|
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 =
|
|
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(
|
|
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 =
|
|
19367
|
+
const candidate = path40.join(dir, `rtk${ext}`);
|
|
18418
19368
|
try {
|
|
18419
|
-
const st =
|
|
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 =
|
|
18431
|
-
const 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
|
|
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
|
|
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
|
|
19423
|
+
return EXIT_ALLOW10;
|
|
18474
19424
|
}
|
|
18475
|
-
if (!
|
|
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
|
|
18480
|
-
if (!rtk_available()) return
|
|
18481
|
-
if (detectRtkCached().identity !== "token-killer") return
|
|
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
|
|
18484
|
-
const verdict =
|
|
18485
|
-
if (!verdict.eligible) return
|
|
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
|
|
19439
|
+
return EXIT_WARN5;
|
|
18490
19440
|
}
|
|
18491
|
-
function
|
|
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 =
|
|
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 =
|
|
18504
|
-
const argv =
|
|
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 (
|
|
18511
|
-
process.exit(
|
|
19460
|
+
if (_isCliEntry26()) {
|
|
19461
|
+
process.exit(main30());
|
|
18512
19462
|
}
|
|
18513
19463
|
|
|
18514
19464
|
// src/scripts/hooks/design_slop_hook.ts
|
|
18515
|
-
import
|
|
18516
|
-
import
|
|
18517
|
-
import { fileURLToPath as
|
|
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
|
|
18521
|
-
import
|
|
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
|
|
19860
|
+
let run11 = 0;
|
|
18911
19861
|
let maxRun = 0;
|
|
18912
19862
|
for (const b of bodies) {
|
|
18913
19863
|
if (sectionSignature(b).mediaText) {
|
|
18914
|
-
|
|
18915
|
-
maxRun = Math.max(maxRun,
|
|
19864
|
+
run11 += 1;
|
|
19865
|
+
maxRun = Math.max(maxRun, run11);
|
|
18916
19866
|
} else {
|
|
18917
|
-
|
|
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 (!
|
|
18938
|
-
for (const entry of
|
|
18939
|
-
const full =
|
|
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 =
|
|
18947
|
-
if (!
|
|
19896
|
+
const p = path41.join(dir, ".design-quality.json");
|
|
19897
|
+
if (!fs41.existsSync(p)) return {};
|
|
18948
19898
|
try {
|
|
18949
|
-
return JSON.parse(
|
|
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
|
-
|
|
18957
|
-
|
|
18958
|
-
|
|
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 (
|
|
18963
|
-
raw =
|
|
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 =
|
|
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
|
|
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] ?
|
|
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 (!
|
|
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 =
|
|
20016
|
+
const rel = path41.relative(process.cwd(), fp);
|
|
19067
20017
|
try {
|
|
19068
|
-
const fileFindings = scanFile(
|
|
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)
|
|
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
|
|
19106
|
-
var
|
|
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 =
|
|
20063
|
+
const f = path42.join(root, SETTINGS_FILE7);
|
|
19114
20064
|
let text;
|
|
19115
20065
|
try {
|
|
19116
|
-
if (!
|
|
19117
|
-
text =
|
|
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
|
|
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
|
|
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 =
|
|
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
|
-
|
|
19169
|
-
|
|
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
|
|
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
|
|
20137
|
+
return EXIT_ALLOW11;
|
|
19183
20138
|
}
|
|
19184
|
-
if (!isObject(envelope)) return
|
|
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
|
|
20142
|
+
if (!enabled2(root)) return EXIT_ALLOW11;
|
|
19188
20143
|
const ex = extract(envelope);
|
|
19189
|
-
if (!ex || !ex.file || !UI_EXT.test(ex.file)) return
|
|
20144
|
+
if (!ex || !ex.file || !UI_EXT.test(ex.file)) return EXIT_ALLOW11;
|
|
19190
20145
|
let ctx;
|
|
19191
20146
|
try {
|
|
19192
|
-
ctx = loadDesignContext(
|
|
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
|
|
20157
|
+
return EXIT_ALLOW11;
|
|
19203
20158
|
}
|
|
19204
|
-
if (findings.length === 0) return
|
|
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
|
|
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
|
|
20173
|
+
return EXIT_WARN6;
|
|
19219
20174
|
}
|
|
19220
|
-
function
|
|
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 =
|
|
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 =
|
|
19233
|
-
const argv =
|
|
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 =
|
|
19240
|
-
if (isCliEntry9) process.exit(
|
|
20194
|
+
var isCliEntry9 = _isCliEntry27();
|
|
20195
|
+
if (isCliEntry9) process.exit(main32());
|
|
19241
20196
|
|
|
19242
20197
|
// src/scripts/hooks/code_graph_nudge_hook.ts
|
|
19243
|
-
import
|
|
19244
|
-
import
|
|
19245
|
-
import { fileURLToPath as
|
|
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
|
|
19250
|
-
import * as
|
|
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(
|
|
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(
|
|
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 =
|
|
20305
|
+
const abs = path43.resolve(root);
|
|
19351
20306
|
const out = [];
|
|
19352
20307
|
for (const rel of CONSUMER_CANDIDATES) {
|
|
19353
|
-
const p =
|
|
19354
|
-
if (
|
|
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 = [
|
|
20314
|
+
const scipCandidates = [path43.join(abs, "index.scip")];
|
|
19360
20315
|
try {
|
|
19361
|
-
for (const e of
|
|
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) =>
|
|
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 (
|
|
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
|
|
19380
|
-
var
|
|
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 =
|
|
20341
|
+
const f = path44.join(root, SETTINGS_FILE8);
|
|
19387
20342
|
let text;
|
|
19388
20343
|
try {
|
|
19389
|
-
if (!
|
|
19390
|
-
text =
|
|
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
|
|
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(
|
|
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(
|
|
20403
|
+
state = JSON.parse(fs44.readFileSync(p, "utf-8"));
|
|
19449
20404
|
} catch {
|
|
19450
20405
|
}
|
|
19451
20406
|
state[session] = true;
|
|
19452
|
-
|
|
19453
|
-
|
|
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 =
|
|
20412
|
+
var NATIVE_CACHE = path44.join("agents", "runtime", "state", "code-graph-v1.json");
|
|
19458
20413
|
function nudgeReason(root) {
|
|
19459
|
-
const verdicts = detectSources(root,
|
|
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
|
|
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
|
|
20430
|
+
return EXIT_ALLOW12;
|
|
19476
20431
|
}
|
|
19477
|
-
if (!isObject2(envelope)) return
|
|
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
|
|
20436
|
+
if (!enabled3(root)) return EXIT_ALLOW12;
|
|
19482
20437
|
const { isSearch, isCodeRead } = classifyTool(envelope);
|
|
19483
|
-
if (!isSearch && !isCodeRead) return
|
|
20438
|
+
if (!isSearch && !isCodeRead) return EXIT_ALLOW12;
|
|
19484
20439
|
const session = sessionId(envelope);
|
|
19485
|
-
if (alreadyNudged(root, session)) return
|
|
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
|
|
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
|
|
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 =
|
|
20457
|
+
const argvUrl = pathToFileURL29(path44.resolve(process.argv[1])).href;
|
|
19503
20458
|
if (import.meta.url === argvUrl) return true;
|
|
19504
20459
|
try {
|
|
19505
|
-
return
|
|
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(
|
|
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/
|
|
19532
|
-
"src/scripts/
|
|
19533
|
-
"src/scripts/hooks/
|
|
19534
|
-
"src/scripts/hooks/
|
|
19535
|
-
"src/scripts/hooks/
|
|
19536
|
-
"src/scripts/hooks/
|
|
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 =
|
|
19591
|
-
|
|
20549
|
+
var REPO_ROOT = path45.resolve(
|
|
20550
|
+
path45.dirname(fileURLToPath35(import.meta.url)),
|
|
19592
20551
|
..._IN_BUNDLE ? ["..", ".."] : ["..", "..", ".."]
|
|
19593
20552
|
);
|
|
19594
|
-
var MANIFEST_PATH =
|
|
19595
|
-
var
|
|
19596
|
-
var
|
|
19597
|
-
var
|
|
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
|
-
[
|
|
19610
|
-
[
|
|
19611
|
-
[
|
|
20568
|
+
[EXIT_ALLOW13]: "allow",
|
|
20569
|
+
[EXIT_BLOCK4]: "block",
|
|
20570
|
+
[EXIT_WARN8]: "warn"
|
|
19612
20571
|
};
|
|
19613
|
-
function
|
|
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
|
|
20602
|
+
return _isObject13(parsed) ? parsed : { _raw: parsed };
|
|
19644
20603
|
}
|
|
19645
20604
|
function _load_yaml3(p) {
|
|
19646
|
-
const text =
|
|
20605
|
+
const text = fs45.readFileSync(p, "utf-8");
|
|
19647
20606
|
const data = (0, import_yaml6.parse)(text, { version: "1.1" });
|
|
19648
|
-
return
|
|
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 =
|
|
20636
|
+
const platforms = _isObject13(platformsRaw) ? platformsRaw : {};
|
|
19653
20637
|
const block = platforms[platform];
|
|
19654
20638
|
if (!block) {
|
|
19655
20639
|
return [];
|
|
19656
20640
|
}
|
|
19657
|
-
if (
|
|
20641
|
+
if (_isObject13(block) && block["fallback_only"]) {
|
|
19658
20642
|
return [];
|
|
19659
20643
|
}
|
|
19660
|
-
const names =
|
|
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 =
|
|
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 || !
|
|
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
|
-
|
|
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
|
-
|
|
19777
|
-
|
|
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
|
|
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 (!
|
|
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 =
|
|
20804
|
+
const candidate = path45.join(dir, "node_modules", ".bin", binName);
|
|
19821
20805
|
if (_isFile7(candidate)) {
|
|
19822
20806
|
return candidate;
|
|
19823
20807
|
}
|
|
19824
|
-
const parent =
|
|
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(
|
|
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 =
|
|
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 =
|
|
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
|
|
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 ===
|
|
19982
|
-
return
|
|
20965
|
+
if (rcs.some((rc) => rc === EXIT_BLOCK4)) {
|
|
20966
|
+
return EXIT_BLOCK4;
|
|
19983
20967
|
}
|
|
19984
|
-
if (rcs.some((rc) => rc ===
|
|
19985
|
-
return
|
|
20968
|
+
if (rcs.some((rc) => rc === EXIT_WARN8)) {
|
|
20969
|
+
return EXIT_WARN8;
|
|
19986
20970
|
}
|
|
19987
|
-
return
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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(
|
|
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"] ===
|
|
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 =
|
|
20061
|
-
const target =
|
|
20062
|
-
|
|
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(
|
|
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"] ===
|
|
20076
|
-
warn: (Number(prev["warn"]) || 0) + (e["exit_code"] ===
|
|
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
|
|
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
|
|
21166
|
+
return EXIT_ALLOW13;
|
|
20183
21167
|
}
|
|
20184
21168
|
const manifest_path = args.manifest;
|
|
20185
|
-
if (!
|
|
21169
|
+
if (!fs45.existsSync(manifest_path)) {
|
|
20186
21170
|
process.stderr.write(`dispatch_hook: manifest missing at ${manifest_path}
|
|
20187
21171
|
`);
|
|
20188
|
-
return
|
|
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
|
|
21194
|
+
return EXIT_ALLOW13;
|
|
20211
21195
|
}
|
|
20212
21196
|
if (concerns.length === 0) {
|
|
20213
|
-
return
|
|
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 =
|
|
21217
|
+
rc = EXIT_ALLOW13;
|
|
20230
21218
|
} else {
|
|
20231
|
-
rc =
|
|
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 ===
|
|
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 =
|
|
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
|
-
|
|
20248
|
-
|
|
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 ===
|
|
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 ===
|
|
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
|
|
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
|
|
21291
|
+
return fs45.readFileSync(0, "utf-8");
|
|
20302
21292
|
} catch {
|
|
20303
21293
|
return "";
|
|
20304
21294
|
}
|
|
20305
21295
|
}
|
|
20306
|
-
function
|
|
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 =
|
|
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 =
|
|
20319
|
-
const argv =
|
|
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 =
|
|
21315
|
+
var isCliEntry11 = _isCliEntry28();
|
|
20326
21316
|
if (isCliEntry11) {
|
|
20327
|
-
process.exit(
|
|
21317
|
+
process.exit(main34(process.argv.slice(2)));
|
|
20328
21318
|
}
|
|
20329
21319
|
|
|
20330
21320
|
// src/scripts/hooks/dispatch_entry.ts
|
|
20331
|
-
var _selfPath =
|
|
20332
|
-
var _invokedDirectly2 = globalThis.__AC_HOOKS_BUNDLE_DIRECT === true || process.argv[1] !== void 0 &&
|
|
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 =
|
|
21324
|
+
process.exitCode = main34(process.argv.slice(2));
|
|
20335
21325
|
}
|
|
20336
21326
|
export {
|
|
20337
|
-
|
|
21327
|
+
main34 as main
|
|
20338
21328
|
};
|