@event4u/agent-config 14.16.0 → 14.18.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/.augment-plugin/marketplace.json +3 -3
- package/.augment-plugin/plugin.json +1 -1
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +177 -213
- package/README.md +2 -2
- package/dist/agent-src/commands/analyze/inbox.md +172 -6
- package/dist/agent-src/commands/fix/commit-messages.md +336 -0
- package/dist/agent-src/commands/fix.md +5 -3
- package/dist/agent-src/commands/pr/merge.md +35 -44
- package/dist/agent-src/rules/commit-conventions.md +1 -1
- package/dist/agent-src/skills/accessibility-auditor/SKILL.md +2 -0
- package/dist/agent-src/skills/ai-code-blindspots/SKILL.md +27 -1
- package/dist/agent-src/skills/aws-infrastructure/SKILL.md +41 -0
- package/dist/agent-src/skills/code-intelligence/SKILL.md +60 -12
- package/dist/agent-src/skills/complexity-first-planning/SKILL.md +27 -0
- package/dist/agent-src/skills/conventional-commits-writing/SKILL.md +234 -4
- package/dist/agent-src/skills/design-review/SKILL.md +2 -0
- package/dist/agent-src/skills/feature-planning/SKILL.md +34 -0
- package/dist/agent-src/skills/git-workflow/SKILL.md +37 -12
- package/dist/agent-src/skills/git-workflow/references/push-closes-its-loop.md +176 -0
- package/dist/agent-src/skills/laravel-mail/SKILL.md +44 -0
- package/dist/agent-src/skills/terraform/SKILL.md +29 -0
- package/dist/agent-src/skills/testing-anti-patterns/SKILL.md +40 -0
- package/dist/agent-src/skills/threat-modeling/data/reasoning.csv +1 -0
- package/dist/agent-src/skills/threat-modeling/data/surfaces.csv +1 -0
- package/dist/agent-src/skills/threat-modeling/data/threats.csv +5 -0
- package/dist/agent-src/skills/using-git-worktrees/SKILL.md +12 -0
- package/dist/agent-src/skills/verify-repair-loop/SKILL.md +53 -8
- package/dist/agent-src/skills/worktree-lifecycle/SKILL.md +3 -1
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/cli-delegate/cmd_conformance.js +335 -659
- package/dist/cli-delegate/cmd_explain.js +24 -112
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +55 -29
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +3 -3
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +6 -5
- package/dist/discovery/trust-report.md +2 -2
- package/dist/discovery/workspaces.json +5 -4
- package/dist/hooks/dispatch.js +959 -1304
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +671 -1002
- package/dist/shared/settingsConsent.js +1 -1
- package/package.json +1 -1
- package/src/config/conformance-claim-baseline.json +9 -0
- package/src/config/gate-violation-baselines.json +3 -3
- package/src/config/release-gate-locality.yml +129 -0
- package/src/config/web-launch-readiness.json +1 -1
- package/src/scripts/_cli/explain_last/index.ts +1 -1
- package/src/scripts/_cli/explain_last/memory.ts +8 -104
- package/src/scripts/_lib/release_highlights.ts +172 -1
- package/src/scripts/_lib/release_material.ts +66 -0
- package/src/scripts/_lib/repeated_run.ts +77 -0
- package/src/scripts/_lib/tamper_vocabulary.ts +242 -0
- package/src/scripts/_lib/unified_diff.ts +121 -0
- package/src/scripts/check_artefact_count_messaging.ts +9 -0
- package/src/scripts/check_finding_dispositions.ts +179 -3
- package/src/scripts/check_installed_hooks_fresh.ts +381 -0
- package/src/scripts/check_release_highlights.ts +89 -4
- package/src/scripts/check_suppression_hygiene.ts +11 -0
- package/src/scripts/check_web_launch_readiness.ts +295 -15
- package/src/scripts/code_graph/build.ts +230 -33
- package/src/scripts/code_graph/extract.ts +168 -33
- package/src/scripts/code_graph/types.ts +37 -2
- package/src/scripts/code_graph/validate.ts +12 -1
- package/src/scripts/conformance_scan.ts +2 -2
- package/src/scripts/detect_silent_catch.ts +403 -0
- package/src/scripts/detect_verification_tampering.ts +538 -0
- package/src/scripts/git_authorization_hook.ts +153 -17
- package/src/scripts/hook_manifest.json +1 -1
- package/src/scripts/hook_manifest.yaml +33 -19
- package/src/scripts/hooks/block_no_verify.ts +3 -3
- package/src/scripts/hooks/concern_registry.ts +2 -2
- package/src/scripts/hooks/evidence_independence.ts +21 -2
- package/src/scripts/hooks/{block_unauthorized_git.ts → git_command_classifier.ts} +25 -369
- package/src/scripts/hooks/push_settle_hook.ts +250 -0
- package/src/scripts/hooks/ship_diff_volume_hook.ts +1 -1
- package/src/scripts/install-hooks.sh +134 -1
- package/src/scripts/language_mirror_hook.ts +27 -5
- package/src/scripts/measure_release_mix.ts +384 -0
- package/src/scripts/release.ts +31 -143
- package/src/scripts/release_drill.ts +71 -1
- package/src/scripts/release_mix_taxonomy.json +172 -0
- package/src/scripts/release_publication.ts +243 -3
- package/src/scripts/release_verify.ts +220 -0
- package/src/scripts/schemas/review-findings.schema.json +1 -1
- package/src/scripts/schemas/skill.schema.json +11 -1
- package/src/scripts/self_review_gate.ts +10 -1
- package/src/shared/settingsConsent.ts +1 -1
- package/src/scripts/attest_artifact.ts +0 -193
|
@@ -78,12 +78,12 @@ import {
|
|
|
78
78
|
|
|
79
79
|
// src/scripts/_cli/cmd_conformance.ts
|
|
80
80
|
var YAML = __toESM(require_dist(), 1);
|
|
81
|
-
import * as
|
|
81
|
+
import * as fs13 from "node:fs";
|
|
82
82
|
import * as os7 from "node:os";
|
|
83
|
-
import * as
|
|
83
|
+
import * as path13 from "node:path";
|
|
84
84
|
import process6 from "node:process";
|
|
85
85
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
86
|
-
import { fileURLToPath as
|
|
86
|
+
import { fileURLToPath as fileURLToPath13, pathToFileURL as pathToFileURL13 } from "node:url";
|
|
87
87
|
|
|
88
88
|
// src/install/txlog.ts
|
|
89
89
|
import { createReadStream, createWriteStream, existsSync, readFileSync, renameSync, statSync, unlinkSync } from "node:fs";
|
|
@@ -144,18 +144,18 @@ function routeTargetPathsPosix(target) {
|
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
// src/scripts/report_conformance_funnel.ts
|
|
147
|
-
import * as
|
|
147
|
+
import * as fs12 from "node:fs";
|
|
148
148
|
import * as os6 from "node:os";
|
|
149
|
-
import * as
|
|
149
|
+
import * as path12 from "node:path";
|
|
150
150
|
import process5 from "node:process";
|
|
151
|
-
import { fileURLToPath as
|
|
151
|
+
import { fileURLToPath as fileURLToPath12, pathToFileURL as pathToFileURL12 } from "node:url";
|
|
152
152
|
|
|
153
153
|
// src/scripts/conformance_scan.ts
|
|
154
154
|
import { createHash as createHash3 } from "node:crypto";
|
|
155
|
-
import
|
|
155
|
+
import fs8 from "node:fs";
|
|
156
156
|
import os2 from "node:os";
|
|
157
|
-
import
|
|
158
|
-
import { fileURLToPath as
|
|
157
|
+
import path8 from "node:path";
|
|
158
|
+
import { fileURLToPath as fileURLToPath8, pathToFileURL as pathToFileURL8 } from "node:url";
|
|
159
159
|
|
|
160
160
|
// src/scripts/_lib/transcript_entry.ts
|
|
161
161
|
function _isObject(v) {
|
|
@@ -432,7 +432,11 @@ function _setPinLost(consumer_root, session_id) {
|
|
|
432
432
|
_migrateLegacyMarker(consumer_root);
|
|
433
433
|
try {
|
|
434
434
|
atomic_write_text(path.join(consumer_root, pinLostMarker(session_id)), (/* @__PURE__ */ new Date()).toISOString());
|
|
435
|
-
} catch {
|
|
435
|
+
} catch (err) {
|
|
436
|
+
process.stderr.write(
|
|
437
|
+
`language-mirror: pin-lost marker write failed (${_errText(err)}) \u2014 the pin will NOT be re-emitted after this compaction. Turn outcome unchanged.
|
|
438
|
+
`
|
|
439
|
+
);
|
|
436
440
|
}
|
|
437
441
|
}
|
|
438
442
|
function _pinLost(consumer_root, session_id) {
|
|
@@ -658,7 +662,11 @@ function run(stdin_text, options) {
|
|
|
658
662
|
atomic_write_json(target, next);
|
|
659
663
|
_pruneLegacyState(options.consumer_root);
|
|
660
664
|
_pruneStaleSessions(options.consumer_root, Date.now());
|
|
661
|
-
} catch {
|
|
665
|
+
} catch (err) {
|
|
666
|
+
process.stderr.write(
|
|
667
|
+
`language-mirror: pin-state write failed (${_errText(err)}) \u2014 the language pin did NOT persist and the next turn re-derives it. This turn's notice is unchanged.
|
|
668
|
+
`
|
|
669
|
+
);
|
|
662
670
|
}
|
|
663
671
|
}
|
|
664
672
|
if (effective === "de" || effective === "en") {
|
|
@@ -670,6 +678,10 @@ function run(stdin_text, options) {
|
|
|
670
678
|
}
|
|
671
679
|
return EXIT_ALLOW;
|
|
672
680
|
}
|
|
681
|
+
function _errText(err) {
|
|
682
|
+
const t = err instanceof Error ? err.message : String(err);
|
|
683
|
+
return t.replace(/\s+/g, " ").trim().slice(0, 200);
|
|
684
|
+
}
|
|
673
685
|
function main(argv) {
|
|
674
686
|
const args = argv ?? process.argv.slice(2);
|
|
675
687
|
let consumer_root = process.cwd();
|
|
@@ -1000,7 +1012,7 @@ function splitFences(prompt) {
|
|
|
1000
1012
|
function _commandLines(fence) {
|
|
1001
1013
|
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));
|
|
1002
1014
|
}
|
|
1003
|
-
function
|
|
1015
|
+
function _errText2(err) {
|
|
1004
1016
|
const t = err instanceof Error ? err.message : String(err);
|
|
1005
1017
|
return t.replace(/\s+/g, " ").trim().slice(0, 200);
|
|
1006
1018
|
}
|
|
@@ -1017,9 +1029,20 @@ function extractMergeTargets(prompt) {
|
|
|
1017
1029
|
}
|
|
1018
1030
|
return [...out].sort((a, b) => a - b);
|
|
1019
1031
|
}
|
|
1020
|
-
var
|
|
1032
|
+
var REVOKE_STOP_WORD = /\b(stop|stopp|halt|abbrechen|abbruch|cancel|revoke|widerruf(en)?|zur(ü|ue)ck(nehmen|ziehen)|hold\s+(everything|on|the\s+merge)|warte|wait)\b/iu;
|
|
1033
|
+
var MERGE_VERB = /\b(merg(e|en|ing)|zusammenf(ü|ue)hren)\b/giu;
|
|
1021
1034
|
function isRevocation(prompt) {
|
|
1022
|
-
|
|
1035
|
+
if (REVOKE_STOP_WORD.test(prompt) || isBareRefusal(prompt)) {
|
|
1036
|
+
return true;
|
|
1037
|
+
}
|
|
1038
|
+
MERGE_VERB.lastIndex = 0;
|
|
1039
|
+
let m;
|
|
1040
|
+
while ((m = MERGE_VERB.exec(prompt)) !== null) {
|
|
1041
|
+
if (negatedBefore(prompt, m.index, m[0])) {
|
|
1042
|
+
return true;
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
return false;
|
|
1023
1046
|
}
|
|
1024
1047
|
function _grantId(session_id, at, targets) {
|
|
1025
1048
|
return `${sessionSlug(session_id) || "nosession"}:${at}:${targets.join(",")}`;
|
|
@@ -1054,8 +1077,12 @@ function foldGrants(prior, prompt, authorized, session_id, now) {
|
|
|
1054
1077
|
}
|
|
1055
1078
|
];
|
|
1056
1079
|
}
|
|
1057
|
-
var
|
|
1058
|
-
var
|
|
1080
|
+
var APOSTROPHE = "'\u2019\u2018\u02BC";
|
|
1081
|
+
var NEGATION_ALTERNATION = `nicht|nichts|kein(?:e|en|em|er|es)?|niemals|nie|no|not|don[${APOSTROPHE}]?t|never|without|ohne`;
|
|
1082
|
+
var NEGATION_WORD = new RegExp(`\\b(${NEGATION_ALTERNATION})\\b`, "i");
|
|
1083
|
+
var NEGATION_TOKEN = new RegExp(`^(?:${NEGATION_ALTERNATION})$`, "i");
|
|
1084
|
+
var CONTRAST_ALTERNATION = "aber|sondern|jedoch|but|however|instead";
|
|
1085
|
+
var CONTRAST_CUE = new RegExp(`\\b(${CONTRAST_ALTERNATION})\\b`, "gi");
|
|
1059
1086
|
var ABBREVIATION_BEFORE_DOT = /(?:^|[\s("'\u2018\u201c])(?:[a-z]|z\.b|bzw|ca|usw|d\.h|u\.a|evtl|ggf|inkl|max|min|nr|abb|e\.g|i\.e|etc|vs|approx|fig|no|st|dr|prof)\.$/i;
|
|
1060
1087
|
function isSentenceBoundary(text, at) {
|
|
1061
1088
|
const mark = text[at];
|
|
@@ -1142,6 +1169,19 @@ function negatedBefore(text, index, matched = "") {
|
|
|
1142
1169
|
const after = afterFrom < end ? text.slice(afterFrom, clauseEnd(text, afterFrom, end)) : "";
|
|
1143
1170
|
return NEGATION_WORD.test(before) || NEGATION_WORD.test(matched) || NEGATION_WORD.test(after);
|
|
1144
1171
|
}
|
|
1172
|
+
var WORD_TOKEN = new RegExp(`[\\p{L}\\p{N}${APOSTROPHE}]+`, "gu");
|
|
1173
|
+
var CLAUSE_SPLIT = new RegExp(`[,;:]|\\b(?:${CONTRAST_ALTERNATION})\\b`, "iu");
|
|
1174
|
+
function isBareRefusal(text) {
|
|
1175
|
+
for (const sentence of _sentences(text)) {
|
|
1176
|
+
for (const clause of sentence.split(CLAUSE_SPLIT)) {
|
|
1177
|
+
const tokens = (clause ?? "").match(WORD_TOKEN) ?? [];
|
|
1178
|
+
if (tokens.length > 0 && tokens.every((t) => NEGATION_TOKEN.test(t))) {
|
|
1179
|
+
return true;
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
return false;
|
|
1184
|
+
}
|
|
1145
1185
|
function classifyAuthorization(prompt) {
|
|
1146
1186
|
const { prose, fences } = splitFences(prompt);
|
|
1147
1187
|
const authorized = /* @__PURE__ */ new Set();
|
|
@@ -1209,40 +1249,6 @@ function readGrants(consumer_root, session_id) {
|
|
|
1209
1249
|
return [];
|
|
1210
1250
|
}
|
|
1211
1251
|
}
|
|
1212
|
-
function consumeGrantTarget(consumer_root, session_id, target) {
|
|
1213
|
-
const file = path2.join(consumer_root, ledgerFileFor(session_id));
|
|
1214
|
-
let decoded;
|
|
1215
|
-
try {
|
|
1216
|
-
decoded = JSON.parse(fs2.readFileSync(file, "utf8"));
|
|
1217
|
-
} catch {
|
|
1218
|
-
return;
|
|
1219
|
-
}
|
|
1220
|
-
if (!_isObject3(decoded) || !Array.isArray(decoded["grants"])) {
|
|
1221
|
-
return;
|
|
1222
|
-
}
|
|
1223
|
-
let touched = false;
|
|
1224
|
-
for (const g of decoded["grants"]) {
|
|
1225
|
-
if (!_isObject3(g) || !Array.isArray(g["targets"]) || !Array.isArray(g["consumed"])) {
|
|
1226
|
-
continue;
|
|
1227
|
-
}
|
|
1228
|
-
const targets = g["targets"];
|
|
1229
|
-
const consumed = g["consumed"];
|
|
1230
|
-
if (targets.includes(target) && !consumed.includes(target)) {
|
|
1231
|
-
consumed.push(target);
|
|
1232
|
-
touched = true;
|
|
1233
|
-
}
|
|
1234
|
-
}
|
|
1235
|
-
if (touched) {
|
|
1236
|
-
try {
|
|
1237
|
-
atomic_write_json(file, decoded);
|
|
1238
|
-
} catch (err) {
|
|
1239
|
-
process.stderr.write(
|
|
1240
|
-
`git-authorization: grant-consumption write failed (${_errText(err)}) \u2014 the target stays UNSPENT, so one further merge of a PR the user named will still be authorized. Authorization outcome unchanged.
|
|
1241
|
-
`
|
|
1242
|
-
);
|
|
1243
|
-
}
|
|
1244
|
-
}
|
|
1245
|
-
}
|
|
1246
1252
|
function takePending(consumer_root, session_id, now) {
|
|
1247
1253
|
const file = path2.join(consumer_root, pendingFileFor(session_id));
|
|
1248
1254
|
let raw;
|
|
@@ -1334,7 +1340,7 @@ function run2(stdin_text, options) {
|
|
|
1334
1340
|
atomic_write_json(path2.join(options.consumer_root, ledgerFileFor(session)), ledger);
|
|
1335
1341
|
} catch (err) {
|
|
1336
1342
|
process.stderr.write(
|
|
1337
|
-
`git-authorization: session-ledger write failed (${
|
|
1343
|
+
`git-authorization: session-ledger write failed (${_errText2(err)}) \u2014 the gate degrades to "no ledger" for this session, which denies the irreversible subset and warns on the rest. Authorization outcome unchanged.
|
|
1338
1344
|
`
|
|
1339
1345
|
);
|
|
1340
1346
|
}
|
|
@@ -1377,125 +1383,7 @@ if (_isCliEntry2()) {
|
|
|
1377
1383
|
process.exit(main2());
|
|
1378
1384
|
}
|
|
1379
1385
|
|
|
1380
|
-
// src/scripts/hooks/
|
|
1381
|
-
import fs3 from "node:fs";
|
|
1382
|
-
import path3 from "node:path";
|
|
1383
|
-
import { fileURLToPath as fileURLToPath3, pathToFileURL as pathToFileURL3 } from "node:url";
|
|
1384
|
-
|
|
1385
|
-
// src/scripts/hooks/merge_impact.ts
|
|
1386
|
-
import { execFileSync } from "node:child_process";
|
|
1387
|
-
var DESTRUCTIVE_MARKERS = [
|
|
1388
|
-
// Schema removal. Matched on ADDED lines only — a migration that *removes* a
|
|
1389
|
-
// dropColumn call is the opposite of destructive, and matching the raw patch
|
|
1390
|
-
// would score it the same way.
|
|
1391
|
-
{ label: "migration drops a column or table", re: /^\+.*\b(dropColumn|dropTable|dropIfExists|removeColumn|drop_column|drop_table)\b/im },
|
|
1392
|
-
{ label: "raw DROP or TRUNCATE in a migration", re: /^\+.*\b(DROP\s+(TABLE|COLUMN|INDEX|CONSTRAINT)|TRUNCATE\s+TABLE)\b/im },
|
|
1393
|
-
// The author said so themselves. Conventional Commits marks a breaking change
|
|
1394
|
-
// with a `!` before the colon or a body trailer.
|
|
1395
|
-
{ label: "author marked a BREAKING CHANGE", re: /^\+.*BREAKING[ -]CHANGE/m },
|
|
1396
|
-
// A removed export is the shape most likely to break an importer.
|
|
1397
|
-
{ label: "an exported symbol was removed", re: /^-\s*export\s+(default\s+|const\s+|function\s+|class\s+|interface\s+|type\s+|async\s+)/m },
|
|
1398
|
-
{ label: "a public PHP or Python symbol was removed", re: /^-\s*(public\s+function|def\s+[a-z_]+\s*\()/m },
|
|
1399
|
-
// Route removal breaks callers that never imported anything.
|
|
1400
|
-
{ label: "a route or endpoint was removed", re: /^-.*\b(Route::(get|post|put|patch|delete)|@(Get|Post|Put|Patch|Delete)Mapping|app\.(get|post|put|patch|delete)\s*\()/m },
|
|
1401
|
-
{ label: "a whole file was deleted", re: /^deleted file mode /m }
|
|
1402
|
-
];
|
|
1403
|
-
var SCHEMA_REMOVAL_BODY = /\b(dropColumn|dropTable|dropIfExists|removeColumn|drop_column|drop_table|DROP\s+(TABLE|COLUMN|INDEX|CONSTRAINT)|TRUNCATE\s+TABLE)\b/i;
|
|
1404
|
-
var RENAME_METADATA = /^rename (?:from|to) /m;
|
|
1405
|
-
function fileBlocks(patch) {
|
|
1406
|
-
return patch.split(/^(?=diff --git )/m).filter((b) => b.startsWith("diff --git "));
|
|
1407
|
-
}
|
|
1408
|
-
function renamedSchemaRemoval(patch) {
|
|
1409
|
-
for (const block of fileBlocks(patch)) {
|
|
1410
|
-
if (!RENAME_METADATA.test(block)) {
|
|
1411
|
-
continue;
|
|
1412
|
-
}
|
|
1413
|
-
for (const line of block.split("\n")) {
|
|
1414
|
-
if (line.startsWith("-") && !line.startsWith("---") && SCHEMA_REMOVAL_BODY.test(line)) {
|
|
1415
|
-
return true;
|
|
1416
|
-
}
|
|
1417
|
-
}
|
|
1418
|
-
}
|
|
1419
|
-
return false;
|
|
1420
|
-
}
|
|
1421
|
-
var MAJOR_BUMP = /^-\s*"version"\s*:\s*"(\d+)\.[^"]*"[\s\S]{0,200}?^\+\s*"version"\s*:\s*"(\d+)\./m;
|
|
1422
|
-
function classifyDiff(patch) {
|
|
1423
|
-
if (patch.trim() === "") {
|
|
1424
|
-
return { verdict: "undecidable", markers: [], reason: "empty diff" };
|
|
1425
|
-
}
|
|
1426
|
-
const markers = [];
|
|
1427
|
-
for (const { label, re } of DESTRUCTIVE_MARKERS) {
|
|
1428
|
-
if (re.test(patch)) {
|
|
1429
|
-
markers.push(label);
|
|
1430
|
-
}
|
|
1431
|
-
}
|
|
1432
|
-
if (renamedSchemaRemoval(patch)) {
|
|
1433
|
-
markers.push("a renamed file drops a column or table");
|
|
1434
|
-
}
|
|
1435
|
-
const bump = MAJOR_BUMP.exec(patch);
|
|
1436
|
-
if (bump && bump[1] !== bump[2]) {
|
|
1437
|
-
markers.push(`major version bump ${bump[1]}.x to ${bump[2]}.x`);
|
|
1438
|
-
}
|
|
1439
|
-
const filesChanged = (patch.match(/^diff --git /gm) ?? []).length;
|
|
1440
|
-
if (markers.length > 0) {
|
|
1441
|
-
return { verdict: "destructive", markers, filesChanged };
|
|
1442
|
-
}
|
|
1443
|
-
return { verdict: "additive", markers: [], filesChanged };
|
|
1444
|
-
}
|
|
1445
|
-
function fetchPatch(pr, opts = {}) {
|
|
1446
|
-
const run5 = opts.exec ?? execFileSync;
|
|
1447
|
-
const cwd = opts.cwd ?? process.cwd();
|
|
1448
|
-
const capture = (file, args) => run5(file, args, { cwd, encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"], timeout: 15e3 });
|
|
1449
|
-
for (const ref of [`refs/pull/${pr}/head`, `pull/${pr}/head`]) {
|
|
1450
|
-
try {
|
|
1451
|
-
const base = capture("git", ["merge-base", "HEAD", ref]).trim();
|
|
1452
|
-
if (base) {
|
|
1453
|
-
const patch = capture("git", ["diff", `${base}...${ref}`]);
|
|
1454
|
-
if (patch.trim() !== "") {
|
|
1455
|
-
return { patch, source: "local" };
|
|
1456
|
-
}
|
|
1457
|
-
}
|
|
1458
|
-
} catch {
|
|
1459
|
-
}
|
|
1460
|
-
}
|
|
1461
|
-
if (opts.allowNetwork === false) {
|
|
1462
|
-
return { patch: "", source: "none", reason: "no local ref and network reads disabled" };
|
|
1463
|
-
}
|
|
1464
|
-
try {
|
|
1465
|
-
const patch = capture("gh", ["pr", "diff", String(pr), "--patch"]);
|
|
1466
|
-
if (patch.trim() !== "") {
|
|
1467
|
-
return { patch, source: "gh" };
|
|
1468
|
-
}
|
|
1469
|
-
return { patch: "", source: "none", reason: "gh returned an empty diff" };
|
|
1470
|
-
} catch {
|
|
1471
|
-
return { patch: "", source: "none", reason: "no local ref, and gh pr diff failed" };
|
|
1472
|
-
}
|
|
1473
|
-
}
|
|
1474
|
-
function analyseMergeImpact(pr, opts = {}) {
|
|
1475
|
-
const got = fetchPatch(pr, opts);
|
|
1476
|
-
if (got.source === "none") {
|
|
1477
|
-
return { verdict: "undecidable", markers: [], ...got.reason ? { reason: got.reason } : {} };
|
|
1478
|
-
}
|
|
1479
|
-
return classifyDiff(got.patch);
|
|
1480
|
-
}
|
|
1481
|
-
function describeImpact(pr, impact) {
|
|
1482
|
-
const say = `Say "merge #${pr}" to authorize it.`;
|
|
1483
|
-
switch (impact.verdict) {
|
|
1484
|
-
case "additive":
|
|
1485
|
-
return `Impact scan: PR #${pr} touches ${impact.filesChanged ?? 0} file(s) and trips no destructive marker \u2014 no schema drop, no removed export or route, no major bump, no BREAKING CHANGE. Additive as far as the diff can show, which is not the same as safe to merge: the base has moved since review and merging may trigger a deploy. ${say}`;
|
|
1486
|
-
case "destructive":
|
|
1487
|
-
return `Impact scan: PR #${pr} is NOT additive \u2014 ${impact.markers.join("; ")}. Read the diff before authorizing. ${say}`;
|
|
1488
|
-
default:
|
|
1489
|
-
return `Impact scan: could not read the diff for PR #${pr} (${impact.reason ?? "unknown"}), so nothing is known about what it changes. ${say}`;
|
|
1490
|
-
}
|
|
1491
|
-
}
|
|
1492
|
-
|
|
1493
|
-
// src/scripts/hooks/block_unauthorized_git.ts
|
|
1494
|
-
var EXIT_ALLOW3 = 0;
|
|
1495
|
-
var EXIT_BLOCK = 1;
|
|
1496
|
-
function _isObject4(v) {
|
|
1497
|
-
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
1498
|
-
}
|
|
1386
|
+
// src/scripts/hooks/git_command_classifier.ts
|
|
1499
1387
|
var BLOCK_OPS = /* @__PURE__ */ new Set([
|
|
1500
1388
|
"publish",
|
|
1501
1389
|
"tag",
|
|
@@ -1529,27 +1417,6 @@ var BLOCK_OPS = /* @__PURE__ */ new Set([
|
|
|
1529
1417
|
/** `-x` is the flag that takes `.env` and local certificates. */
|
|
1530
1418
|
"clean-ignored"
|
|
1531
1419
|
]);
|
|
1532
|
-
var WARN_OPS = /* @__PURE__ */ new Set([
|
|
1533
|
-
"commit",
|
|
1534
|
-
"push",
|
|
1535
|
-
"pr-create",
|
|
1536
|
-
"branch",
|
|
1537
|
-
// ── Added 2026-09-03, deliberately at warn rather than block.
|
|
1538
|
-
//
|
|
1539
|
-
// Each is destructive in some reading, and each is also routine enough that
|
|
1540
|
-
// blocking it would be the friction that gets the whole guard routed around —
|
|
1541
|
-
// the failure mode this estate has already recorded twice. `reset-hard` is the
|
|
1542
|
-
// sharpest case and stays here for a decidable reason: the Hard Floor's
|
|
1543
|
-
// qualifier is "past unpushed work", and the command text cannot say whether
|
|
1544
|
-
// the work was pushed.
|
|
1545
|
-
"tag-force",
|
|
1546
|
-
"rebase",
|
|
1547
|
-
"reset-hard",
|
|
1548
|
-
"clean",
|
|
1549
|
-
"stash-drop",
|
|
1550
|
-
"branch-delete",
|
|
1551
|
-
"close"
|
|
1552
|
-
]);
|
|
1553
1420
|
var G = "(?:-[A-Za-z-]+(?:=\\S+)?(?:\\s+\\S+)?\\s+)*";
|
|
1554
1421
|
var P = "^(?:\\S*\\/)?";
|
|
1555
1422
|
function ghApiWrite(pathRe) {
|
|
@@ -1664,33 +1531,6 @@ var COMMAND_OPS = [
|
|
|
1664
1531
|
{ op: "commit", re: new RegExp(`${P}git\\s+${G}commit\\b`, "i") },
|
|
1665
1532
|
{ op: "branch", re: new RegExp(`${P}git\\s+${G}(checkout\\s+-b|switch\\s+-c)\\b`, "i") }
|
|
1666
1533
|
];
|
|
1667
|
-
var COMMAND_TOOLS = /* @__PURE__ */ new Set([
|
|
1668
|
-
"launch-process",
|
|
1669
|
-
"launch_process",
|
|
1670
|
-
"Bash",
|
|
1671
|
-
"BashTool",
|
|
1672
|
-
"run-process",
|
|
1673
|
-
"runProcess",
|
|
1674
|
-
"shell",
|
|
1675
|
-
"execute_shell",
|
|
1676
|
-
"RunShellCommand"
|
|
1677
|
-
]);
|
|
1678
|
-
function extractCommand(envelope) {
|
|
1679
|
-
const payload = _isObject4(envelope["payload"]) ? envelope["payload"] : envelope;
|
|
1680
|
-
const toolRaw = payload["tool_name"] ?? payload["toolName"] ?? payload["tool"];
|
|
1681
|
-
const tool = typeof toolRaw === "string" ? toolRaw : null;
|
|
1682
|
-
if (tool !== null && !COMMAND_TOOLS.has(tool)) {
|
|
1683
|
-
return null;
|
|
1684
|
-
}
|
|
1685
|
-
const input = _isObject4(payload["tool_input"]) ? payload["tool_input"] : _isObject4(payload["toolInput"]) ? payload["toolInput"] : payload;
|
|
1686
|
-
for (const key of ["command", "cmd", "script"]) {
|
|
1687
|
-
const v = input[key];
|
|
1688
|
-
if (typeof v === "string" && v.trim()) {
|
|
1689
|
-
return v;
|
|
1690
|
-
}
|
|
1691
|
-
}
|
|
1692
|
-
return null;
|
|
1693
|
-
}
|
|
1694
1534
|
function splitOutsideQuotes(command) {
|
|
1695
1535
|
const parts = [];
|
|
1696
1536
|
let cur = "";
|
|
@@ -1852,191 +1692,19 @@ function commandOp(command) {
|
|
|
1852
1692
|
}
|
|
1853
1693
|
return found;
|
|
1854
1694
|
}
|
|
1855
|
-
function mergeTargetOf(command) {
|
|
1856
|
-
const gh = /\bgh\s+pr\s+merge\s+(?:-{1,2}\S+\s+)*?(\d{1,10})\b/i.exec(command);
|
|
1857
|
-
if (gh) {
|
|
1858
|
-
return _boundedTarget(gh[1]);
|
|
1859
|
-
}
|
|
1860
|
-
const api = /\/pulls\/(\d{1,10})\/merge\b/i.exec(command);
|
|
1861
|
-
return api ? _boundedTarget(api[1]) : null;
|
|
1862
|
-
}
|
|
1863
|
-
function _boundedTarget(digits) {
|
|
1864
|
-
const n = Number.parseInt(digits, 10);
|
|
1865
|
-
return Number.isSafeInteger(n) && n > 0 && n <= PR_NUMBER_MAX ? n : null;
|
|
1866
|
-
}
|
|
1867
|
-
function grantCovers(grants, op, target) {
|
|
1868
|
-
if (op !== "pr-merge" || target === null) {
|
|
1869
|
-
return null;
|
|
1870
|
-
}
|
|
1871
|
-
return grants.find(
|
|
1872
|
-
(g) => g.op === "pr-merge" && g.targets.includes(target) && !g.consumed.includes(target)
|
|
1873
|
-
) ?? null;
|
|
1874
|
-
}
|
|
1875
|
-
var LEDGER_MAX_AGE_MS = 30 * 60 * 1e3;
|
|
1876
|
-
function _loadLedger(consumer_root, session_id, now) {
|
|
1877
|
-
const grants = readGrants(consumer_root, session_id);
|
|
1878
|
-
const candidates = [ledgerFileFor(session_id)];
|
|
1879
|
-
if (!candidates.includes(STATE_FILE2)) {
|
|
1880
|
-
candidates.push(STATE_FILE2);
|
|
1881
|
-
}
|
|
1882
|
-
for (const rel of candidates) {
|
|
1883
|
-
const found = _readLedgerFile(path3.join(consumer_root, rel), session_id, now);
|
|
1884
|
-
if (found !== null) {
|
|
1885
|
-
return { ...found, grants };
|
|
1886
|
-
}
|
|
1887
|
-
}
|
|
1888
|
-
return { authorized: /* @__PURE__ */ new Set(), present: false, grants };
|
|
1889
|
-
}
|
|
1890
|
-
function _readLedgerFile(file, session_id, now) {
|
|
1891
|
-
try {
|
|
1892
|
-
const raw = fs3.readFileSync(file, "utf8");
|
|
1893
|
-
const decoded = JSON.parse(raw);
|
|
1894
|
-
if (_isObject4(decoded) && Array.isArray(decoded["authorized"])) {
|
|
1895
|
-
const ledgerSession = typeof decoded["session_id"] === "string" ? decoded["session_id"] : "";
|
|
1896
|
-
if (session_id && ledgerSession && ledgerSession !== session_id) {
|
|
1897
|
-
return null;
|
|
1898
|
-
}
|
|
1899
|
-
const at = Date.parse(String(decoded["detected_at"] ?? ""));
|
|
1900
|
-
if (Number.isFinite(at) && now - at > LEDGER_MAX_AGE_MS) {
|
|
1901
|
-
return null;
|
|
1902
|
-
}
|
|
1903
|
-
return {
|
|
1904
|
-
authorized: new Set(decoded["authorized"].filter(Boolean)),
|
|
1905
|
-
present: true
|
|
1906
|
-
};
|
|
1907
|
-
}
|
|
1908
|
-
} catch {
|
|
1909
|
-
}
|
|
1910
|
-
return null;
|
|
1911
|
-
}
|
|
1912
|
-
function decide(command, ledger, impact) {
|
|
1913
|
-
if (command === null) {
|
|
1914
|
-
return { exit: EXIT_ALLOW3, stdout: "", stderr: "" };
|
|
1915
|
-
}
|
|
1916
|
-
const op = commandOp(command);
|
|
1917
|
-
if (op === null || ledger.authorized.has(op)) {
|
|
1918
|
-
return { exit: EXIT_ALLOW3, stdout: "", stderr: "" };
|
|
1919
|
-
}
|
|
1920
|
-
const target = mergeTargetOf(command);
|
|
1921
|
-
if (grantCovers(ledger.grants ?? [], op, target) && target !== null) {
|
|
1922
|
-
return { exit: EXIT_ALLOW3, stdout: "", stderr: "", consumedTarget: target };
|
|
1923
|
-
}
|
|
1924
|
-
const shown = command.length > 120 ? `${command.slice(0, 117)}\u2026` : command;
|
|
1925
|
-
if (BLOCK_OPS.has(op)) {
|
|
1926
|
-
const scan = op === "pr-merge" && target !== null && impact ? ` ${impact}` : "";
|
|
1927
|
-
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}.${scan} Ask the user, in one numbered-options block, and run it only after they answer this turn.`;
|
|
1928
|
-
return { exit: EXIT_BLOCK, stdout: "", stderr: `${reason}
|
|
1929
|
-
`, blockedOp: op };
|
|
1930
|
-
}
|
|
1931
|
-
if (WARN_OPS.has(op)) {
|
|
1932
|
-
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}`;
|
|
1933
|
-
return {
|
|
1934
|
-
exit: EXIT_ALLOW3,
|
|
1935
|
-
stdout: `${JSON.stringify({ decision: "warn", reason })}
|
|
1936
|
-
`,
|
|
1937
|
-
stderr: ""
|
|
1938
|
-
};
|
|
1939
|
-
}
|
|
1940
|
-
return { exit: EXIT_ALLOW3, stdout: "", stderr: "" };
|
|
1941
|
-
}
|
|
1942
|
-
function run3(stdin_text, options) {
|
|
1943
|
-
let envelope = {};
|
|
1944
|
-
if (stdin_text.trim()) {
|
|
1945
|
-
try {
|
|
1946
|
-
const decoded = JSON.parse(stdin_text);
|
|
1947
|
-
if (_isObject4(decoded)) {
|
|
1948
|
-
envelope = decoded;
|
|
1949
|
-
}
|
|
1950
|
-
} catch {
|
|
1951
|
-
return EXIT_ALLOW3;
|
|
1952
|
-
}
|
|
1953
|
-
}
|
|
1954
|
-
const session_id = typeof envelope["session_id"] === "string" ? envelope["session_id"] : "";
|
|
1955
|
-
const command = extractCommand(envelope);
|
|
1956
|
-
const ledger = _loadLedger(options.consumer_root, session_id, Date.now());
|
|
1957
|
-
let impact;
|
|
1958
|
-
const stage1 = command === null ? null : commandOp(command);
|
|
1959
|
-
const stage2Target = command === null ? null : mergeTargetOf(command);
|
|
1960
|
-
if (stage1 === "pr-merge" && stage2Target !== null && !ledger.authorized.has("pr-merge") && !grantCovers(ledger.grants ?? [], "pr-merge", stage2Target)) {
|
|
1961
|
-
try {
|
|
1962
|
-
impact = describeImpact(
|
|
1963
|
-
stage2Target,
|
|
1964
|
-
analyseMergeImpact(stage2Target, { cwd: options.consumer_root })
|
|
1965
|
-
);
|
|
1966
|
-
} catch {
|
|
1967
|
-
}
|
|
1968
|
-
}
|
|
1969
|
-
const decision = decide(command, ledger, impact);
|
|
1970
|
-
if (decision.consumedTarget !== void 0) {
|
|
1971
|
-
consumeGrantTarget(options.consumer_root, session_id, decision.consumedTarget);
|
|
1972
|
-
}
|
|
1973
|
-
if (decision.blockedOp) {
|
|
1974
|
-
try {
|
|
1975
|
-
atomic_write_json(path3.join(options.consumer_root, pendingFileFor(session_id)), {
|
|
1976
|
-
op: decision.blockedOp,
|
|
1977
|
-
session_id,
|
|
1978
|
-
refused_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
1979
|
-
});
|
|
1980
|
-
} catch {
|
|
1981
|
-
}
|
|
1982
|
-
}
|
|
1983
|
-
if (decision.stdout) {
|
|
1984
|
-
process.stdout.write(decision.stdout);
|
|
1985
|
-
}
|
|
1986
|
-
if (decision.stderr) {
|
|
1987
|
-
process.stderr.write(decision.stderr);
|
|
1988
|
-
}
|
|
1989
|
-
return decision.exit;
|
|
1990
|
-
}
|
|
1991
|
-
function main3(argv) {
|
|
1992
|
-
const args = argv ?? process.argv.slice(2);
|
|
1993
|
-
let consumer_root = process.cwd();
|
|
1994
|
-
for (let i = 0; i < args.length; i += 1) {
|
|
1995
|
-
const a = args[i];
|
|
1996
|
-
if (a === "--project-dir" && args[i + 1] !== void 0) {
|
|
1997
|
-
consumer_root = args[i + 1];
|
|
1998
|
-
i += 1;
|
|
1999
|
-
} else if (a !== void 0 && a.startsWith("--project-dir=")) {
|
|
2000
|
-
consumer_root = a.slice("--project-dir=".length);
|
|
2001
|
-
}
|
|
2002
|
-
}
|
|
2003
|
-
return run3(readHookStdin(), { consumer_root });
|
|
2004
|
-
}
|
|
2005
|
-
function _isCliEntry3() {
|
|
2006
|
-
if (true) {
|
|
2007
|
-
return false;
|
|
2008
|
-
}
|
|
2009
|
-
if (process.argv[1] === void 0) {
|
|
2010
|
-
return false;
|
|
2011
|
-
}
|
|
2012
|
-
const argvUrl = pathToFileURL3(path3.resolve(process.argv[1])).href;
|
|
2013
|
-
if (import.meta.url === argvUrl) {
|
|
2014
|
-
return true;
|
|
2015
|
-
}
|
|
2016
|
-
try {
|
|
2017
|
-
const here = fs3.realpathSync(fileURLToPath3(import.meta.url));
|
|
2018
|
-
const argv = fs3.realpathSync(path3.resolve(process.argv[1]));
|
|
2019
|
-
return here === argv;
|
|
2020
|
-
} catch {
|
|
2021
|
-
return false;
|
|
2022
|
-
}
|
|
2023
|
-
}
|
|
2024
|
-
if (_isCliEntry3()) {
|
|
2025
|
-
process.exit(main3());
|
|
2026
|
-
}
|
|
2027
1695
|
|
|
2028
1696
|
// src/scripts/hooks/turn_end_gate_hook.ts
|
|
2029
|
-
import * as
|
|
2030
|
-
import * as
|
|
2031
|
-
import { fileURLToPath as
|
|
1697
|
+
import * as fs5 from "node:fs";
|
|
1698
|
+
import * as path5 from "node:path";
|
|
1699
|
+
import { fileURLToPath as fileURLToPath5, pathToFileURL as pathToFileURL5 } from "node:url";
|
|
2032
1700
|
|
|
2033
1701
|
// src/scripts/hooks/end_review_nudge_hook.ts
|
|
2034
1702
|
import { spawnSync } from "node:child_process";
|
|
2035
1703
|
import * as crypto from "node:crypto";
|
|
2036
|
-
import * as
|
|
1704
|
+
import * as fs3 from "node:fs";
|
|
2037
1705
|
import * as os from "node:os";
|
|
2038
|
-
import * as
|
|
2039
|
-
import { fileURLToPath as
|
|
1706
|
+
import * as path3 from "node:path";
|
|
1707
|
+
import { fileURLToPath as fileURLToPath3, pathToFileURL as pathToFileURL3 } from "node:url";
|
|
2040
1708
|
|
|
2041
1709
|
// src/scripts/_lib/review_skipped_record.ts
|
|
2042
1710
|
var PRODUCER_PRIVACY_CLASS = "ids-only";
|
|
@@ -2091,11 +1759,11 @@ var ENVELOPE_KEYS = [
|
|
|
2091
1759
|
"event",
|
|
2092
1760
|
"payload"
|
|
2093
1761
|
];
|
|
2094
|
-
function
|
|
1762
|
+
function _isObject4(obj) {
|
|
2095
1763
|
return typeof obj === "object" && obj !== null && !Array.isArray(obj);
|
|
2096
1764
|
}
|
|
2097
1765
|
function looks_like_envelope(obj) {
|
|
2098
|
-
if (!
|
|
1766
|
+
if (!_isObject4(obj)) {
|
|
2099
1767
|
return false;
|
|
2100
1768
|
}
|
|
2101
1769
|
return ENVELOPE_KEYS.every((key) => key in obj);
|
|
@@ -2114,14 +1782,14 @@ function unwrap(stdin_text, default_platform = "generic") {
|
|
|
2114
1782
|
if (looks_like_envelope(decoded)) {
|
|
2115
1783
|
const env = decoded;
|
|
2116
1784
|
let payload2 = env["payload"];
|
|
2117
|
-
if (!payload2 || !
|
|
1785
|
+
if (!payload2 || !_isObject4(payload2)) {
|
|
2118
1786
|
payload2 = {};
|
|
2119
1787
|
}
|
|
2120
1788
|
const platRaw = env["platform"];
|
|
2121
1789
|
const platform = String(platRaw || default_platform);
|
|
2122
1790
|
return [env, payload2, platform];
|
|
2123
1791
|
}
|
|
2124
|
-
const payload =
|
|
1792
|
+
const payload = _isObject4(decoded) ? decoded : {};
|
|
2125
1793
|
return [
|
|
2126
1794
|
{
|
|
2127
1795
|
schema_version: 1,
|
|
@@ -2147,13 +1815,13 @@ function isSafeTranscriptPath(rawPath, opts = {}) {
|
|
|
2147
1815
|
const homeDir = opts.homeDir ?? os.homedir();
|
|
2148
1816
|
const maxBytes = opts.maxBytes ?? TRANSCRIPT_SCAN_MAX_BYTES;
|
|
2149
1817
|
try {
|
|
2150
|
-
const realHome =
|
|
2151
|
-
const realPath =
|
|
2152
|
-
const relative2 =
|
|
2153
|
-
if (relative2 === "" || relative2.startsWith("..") ||
|
|
1818
|
+
const realHome = fs3.realpathSync(homeDir);
|
|
1819
|
+
const realPath = fs3.realpathSync(rawPath);
|
|
1820
|
+
const relative2 = path3.relative(realHome, realPath);
|
|
1821
|
+
if (relative2 === "" || relative2.startsWith("..") || path3.isAbsolute(relative2)) {
|
|
2154
1822
|
return false;
|
|
2155
1823
|
}
|
|
2156
|
-
const { size } =
|
|
1824
|
+
const { size } = fs3.statSync(realPath);
|
|
2157
1825
|
return size <= maxBytes;
|
|
2158
1826
|
} catch {
|
|
2159
1827
|
return false;
|
|
@@ -2212,13 +1880,13 @@ var BINARY_PROBE_BYTES = 8e3;
|
|
|
2212
1880
|
var UNTRACKED_FILE_READ_CAP_BYTES = 8 * 1024 * 1024;
|
|
2213
1881
|
function untrackedFileLineCount(cwd, relPath) {
|
|
2214
1882
|
try {
|
|
2215
|
-
const abs =
|
|
2216
|
-
const size =
|
|
1883
|
+
const abs = path3.resolve(cwd, relPath);
|
|
1884
|
+
const size = fs3.statSync(abs).size;
|
|
2217
1885
|
if (size === 0) return 0;
|
|
2218
1886
|
if (size > UNTRACKED_FILE_READ_CAP_BYTES) {
|
|
2219
1887
|
return MUTATION_LINE_THRESHOLD + 1;
|
|
2220
1888
|
}
|
|
2221
|
-
const buf =
|
|
1889
|
+
const buf = fs3.readFileSync(abs);
|
|
2222
1890
|
if (buf.length === 0) return 0;
|
|
2223
1891
|
const probe = buf.subarray(0, Math.min(buf.length, BINARY_PROBE_BYTES));
|
|
2224
1892
|
if (probe.includes(0)) return 0;
|
|
@@ -2308,19 +1976,19 @@ function appendReviewSkippedTelemetry(workspaceRoot, diffLines, mutationMeasure)
|
|
|
2308
1976
|
});
|
|
2309
1977
|
if (errors.length || line === null) return;
|
|
2310
1978
|
try {
|
|
2311
|
-
const dir =
|
|
2312
|
-
|
|
2313
|
-
const file =
|
|
2314
|
-
|
|
1979
|
+
const dir = path3.join(workspaceRoot, "agents", "runtime", "state", "audit");
|
|
1980
|
+
fs3.mkdirSync(dir, { recursive: true });
|
|
1981
|
+
const file = path3.join(dir, `${ts.slice(0, 7)}.jsonl`);
|
|
1982
|
+
fs3.appendFileSync(file, `${JSON.stringify(line)}
|
|
2315
1983
|
`, "utf8");
|
|
2316
1984
|
} catch {
|
|
2317
1985
|
}
|
|
2318
1986
|
}
|
|
2319
1987
|
function sessionStateDir(workspaceRoot) {
|
|
2320
|
-
return
|
|
1988
|
+
return path3.join(workspaceRoot, "agents", "runtime", "state", "end-review-nudge");
|
|
2321
1989
|
}
|
|
2322
1990
|
function sessionStateFile(workspaceRoot, sessionKey) {
|
|
2323
|
-
return
|
|
1991
|
+
return path3.join(sessionStateDir(workspaceRoot), `${sessionKey}.json`);
|
|
2324
1992
|
}
|
|
2325
1993
|
function deriveSessionKey2(envelope, payload) {
|
|
2326
1994
|
const raw = str(envelope["session_id"]) || str(payload["transcript_path"] ?? payload["transcriptPath"]);
|
|
@@ -2329,7 +1997,7 @@ function deriveSessionKey2(envelope, payload) {
|
|
|
2329
1997
|
}
|
|
2330
1998
|
function hasFiredThisSession(workspaceRoot, sessionKey) {
|
|
2331
1999
|
try {
|
|
2332
|
-
return
|
|
2000
|
+
return fs3.existsSync(sessionStateFile(workspaceRoot, sessionKey));
|
|
2333
2001
|
} catch {
|
|
2334
2002
|
return false;
|
|
2335
2003
|
}
|
|
@@ -2343,7 +2011,7 @@ function markFiredThisSession(workspaceRoot, sessionKey, ts) {
|
|
|
2343
2011
|
function _read_stdin() {
|
|
2344
2012
|
return readHookStdin();
|
|
2345
2013
|
}
|
|
2346
|
-
function
|
|
2014
|
+
function main3() {
|
|
2347
2015
|
const [envelope, payload] = unwrap(_read_stdin(), "claude");
|
|
2348
2016
|
const event = String(envelope["event"] ?? "");
|
|
2349
2017
|
if (event !== "" && event !== "stop") {
|
|
@@ -2372,7 +2040,7 @@ function main4() {
|
|
|
2372
2040
|
let reviewerRan = false;
|
|
2373
2041
|
if (transcriptPath && isSafeTranscriptPath(transcriptPath)) {
|
|
2374
2042
|
try {
|
|
2375
|
-
reviewerRan = scanTranscriptForReviewer(
|
|
2043
|
+
reviewerRan = scanTranscriptForReviewer(fs3.readFileSync(transcriptPath, "utf-8"));
|
|
2376
2044
|
} catch {
|
|
2377
2045
|
reviewerRan = false;
|
|
2378
2046
|
}
|
|
@@ -2395,34 +2063,34 @@ function main4() {
|
|
|
2395
2063
|
);
|
|
2396
2064
|
return EXIT_WARN2;
|
|
2397
2065
|
}
|
|
2398
|
-
function
|
|
2066
|
+
function _isCliEntry3() {
|
|
2399
2067
|
if (true) {
|
|
2400
2068
|
return false;
|
|
2401
2069
|
}
|
|
2402
2070
|
if (process.argv[1] === void 0) {
|
|
2403
2071
|
return false;
|
|
2404
2072
|
}
|
|
2405
|
-
const argvUrl =
|
|
2073
|
+
const argvUrl = pathToFileURL3(path3.resolve(process.argv[1])).href;
|
|
2406
2074
|
if (import.meta.url === argvUrl) {
|
|
2407
2075
|
return true;
|
|
2408
2076
|
}
|
|
2409
2077
|
try {
|
|
2410
|
-
const here =
|
|
2411
|
-
const argv =
|
|
2078
|
+
const here = fs3.realpathSync(fileURLToPath3(import.meta.url));
|
|
2079
|
+
const argv = fs3.realpathSync(path3.resolve(process.argv[1]));
|
|
2412
2080
|
return here === argv;
|
|
2413
2081
|
} catch {
|
|
2414
2082
|
return false;
|
|
2415
2083
|
}
|
|
2416
2084
|
}
|
|
2417
|
-
if (
|
|
2418
|
-
process.exit(
|
|
2085
|
+
if (_isCliEntry3()) {
|
|
2086
|
+
process.exit(main3());
|
|
2419
2087
|
}
|
|
2420
2088
|
|
|
2421
2089
|
// src/scripts/hooks/subagent_ledger_hook.ts
|
|
2422
2090
|
import * as crypto2 from "node:crypto";
|
|
2423
|
-
import * as
|
|
2424
|
-
import * as
|
|
2425
|
-
import { fileURLToPath as
|
|
2091
|
+
import * as fs4 from "node:fs";
|
|
2092
|
+
import * as path4 from "node:path";
|
|
2093
|
+
import { fileURLToPath as fileURLToPath4, pathToFileURL as pathToFileURL4 } from "node:url";
|
|
2426
2094
|
|
|
2427
2095
|
// src/scripts/_lib/subagent_response.ts
|
|
2428
2096
|
var MAX_SUMMARY_CHARS = 2e3;
|
|
@@ -2524,11 +2192,11 @@ function validateResponse(input) {
|
|
|
2524
2192
|
}
|
|
2525
2193
|
|
|
2526
2194
|
// src/scripts/hooks/subagent_ledger_hook.ts
|
|
2527
|
-
var
|
|
2195
|
+
var EXIT_ALLOW3 = 0;
|
|
2528
2196
|
function isObject2(v) {
|
|
2529
2197
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
2530
2198
|
}
|
|
2531
|
-
var LEDGER_DIR =
|
|
2199
|
+
var LEDGER_DIR = path4.join("agents", "runtime", "state", "subagent-ledger");
|
|
2532
2200
|
var OPEN_SUBDIR = "open";
|
|
2533
2201
|
var OPEN_RECORD_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
2534
2202
|
function refFor(agentId) {
|
|
@@ -2618,10 +2286,10 @@ function _jsonObjectCandidates(message) {
|
|
|
2618
2286
|
return out;
|
|
2619
2287
|
}
|
|
2620
2288
|
function openDir(root) {
|
|
2621
|
-
return
|
|
2289
|
+
return path4.join(root, LEDGER_DIR, OPEN_SUBDIR);
|
|
2622
2290
|
}
|
|
2623
2291
|
function openFile(root, ref) {
|
|
2624
|
-
return
|
|
2292
|
+
return path4.join(openDir(root), `${ref}.json`);
|
|
2625
2293
|
}
|
|
2626
2294
|
var DEPTH_BASES = /* @__PURE__ */ new Set(["observed", "asserted-parent", "assumed-root"]);
|
|
2627
2295
|
function _asOpenRecord(value, expectedRef) {
|
|
@@ -2648,7 +2316,7 @@ function readOpenRecords(root) {
|
|
|
2648
2316
|
const out = /* @__PURE__ */ new Map();
|
|
2649
2317
|
let names;
|
|
2650
2318
|
try {
|
|
2651
|
-
names =
|
|
2319
|
+
names = fs4.readdirSync(openDir(root));
|
|
2652
2320
|
} catch {
|
|
2653
2321
|
return out;
|
|
2654
2322
|
}
|
|
@@ -2656,7 +2324,7 @@ function readOpenRecords(root) {
|
|
|
2656
2324
|
if (!name.endsWith(".json")) continue;
|
|
2657
2325
|
const expectedRef = name.slice(0, -".json".length);
|
|
2658
2326
|
try {
|
|
2659
|
-
const raw =
|
|
2327
|
+
const raw = fs4.readFileSync(path4.join(openDir(root), name), "utf8");
|
|
2660
2328
|
const rec = _asOpenRecord(JSON.parse(raw), expectedRef);
|
|
2661
2329
|
if (rec) out.set(rec.ref, rec);
|
|
2662
2330
|
} catch {
|
|
@@ -2671,13 +2339,13 @@ function resolveDepth(parentRef, open) {
|
|
|
2671
2339
|
return { depth: parent.depth + 1, depth_basis: "observed" };
|
|
2672
2340
|
}
|
|
2673
2341
|
function ledgerFileFor2(root, ts) {
|
|
2674
|
-
return
|
|
2342
|
+
return path4.join(root, LEDGER_DIR, `${ts.slice(0, 7)}.jsonl`);
|
|
2675
2343
|
}
|
|
2676
2344
|
function appendLedgerLine(root, ts, line) {
|
|
2677
2345
|
if (is_replay_mode()) return;
|
|
2678
2346
|
const file = ledgerFileFor2(root, ts);
|
|
2679
|
-
|
|
2680
|
-
|
|
2347
|
+
fs4.mkdirSync(path4.dirname(file), { recursive: true });
|
|
2348
|
+
fs4.appendFileSync(file, `${JSON.stringify(line)}
|
|
2681
2349
|
`, "utf8");
|
|
2682
2350
|
}
|
|
2683
2351
|
var WALL_CLOCK_ARMS_MS = [
|
|
@@ -2691,7 +2359,7 @@ function armsExceeded(elapsedMs) {
|
|
|
2691
2359
|
return WALL_CLOCK_ARMS_MS.filter((a) => elapsedMs >= a.ms).map((a) => a.label);
|
|
2692
2360
|
}
|
|
2693
2361
|
function openRecordStats(root, nowMs = Date.now()) {
|
|
2694
|
-
const ledgerPresent =
|
|
2362
|
+
const ledgerPresent = fs4.existsSync(path4.join(root, LEDGER_DIR));
|
|
2695
2363
|
const open = readOpenRecords(root);
|
|
2696
2364
|
let maxDepth = 0;
|
|
2697
2365
|
let counted = 0;
|
|
@@ -2719,13 +2387,13 @@ function writeOpenRecord(root, rec) {
|
|
|
2719
2387
|
function removeOpenRecord(root, ref) {
|
|
2720
2388
|
if (is_replay_mode()) return;
|
|
2721
2389
|
try {
|
|
2722
|
-
|
|
2390
|
+
fs4.unlinkSync(openFile(root, ref));
|
|
2723
2391
|
} catch {
|
|
2724
2392
|
}
|
|
2725
2393
|
}
|
|
2726
2394
|
function countOpen(root) {
|
|
2727
2395
|
try {
|
|
2728
|
-
return
|
|
2396
|
+
return fs4.readdirSync(openDir(root)).filter((n) => n.endsWith(".json")).length;
|
|
2729
2397
|
} catch {
|
|
2730
2398
|
return 0;
|
|
2731
2399
|
}
|
|
@@ -2852,9 +2520,9 @@ function handleStop(root, payload, nowIso, sessionId) {
|
|
|
2852
2520
|
}
|
|
2853
2521
|
function processEnvelope(envelope, consumerRoot) {
|
|
2854
2522
|
try {
|
|
2855
|
-
if (!isObject2(envelope)) return
|
|
2523
|
+
if (!isObject2(envelope)) return EXIT_ALLOW3;
|
|
2856
2524
|
const event = envelope["event"];
|
|
2857
|
-
if (event !== "subagent_start" && event !== "subagent_stop") return
|
|
2525
|
+
if (event !== "subagent_start" && event !== "subagent_stop") return EXIT_ALLOW3;
|
|
2858
2526
|
const payload = unwrapPayload(envelope);
|
|
2859
2527
|
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
2860
2528
|
const sessionId = str2(payload, "session_id", "sessionId") ?? str2(envelope, "session_id", "sessionId");
|
|
@@ -2862,9 +2530,9 @@ function processEnvelope(envelope, consumerRoot) {
|
|
|
2862
2530
|
if (event === "subagent_start") handleStart(consumerRoot, payload, nowIso, sessionId);
|
|
2863
2531
|
else handleStop(consumerRoot, payload, nowIso, sessionId);
|
|
2864
2532
|
} catch {
|
|
2865
|
-
return
|
|
2533
|
+
return EXIT_ALLOW3;
|
|
2866
2534
|
}
|
|
2867
|
-
return
|
|
2535
|
+
return EXIT_ALLOW3;
|
|
2868
2536
|
}
|
|
2869
2537
|
function resolveConsumerRoot(envelope) {
|
|
2870
2538
|
if (isObject2(envelope)) {
|
|
@@ -2876,34 +2544,34 @@ function resolveConsumerRoot(envelope) {
|
|
|
2876
2544
|
}
|
|
2877
2545
|
return process.cwd();
|
|
2878
2546
|
}
|
|
2879
|
-
function
|
|
2547
|
+
function main4() {
|
|
2880
2548
|
const raw = readHookStdin();
|
|
2881
2549
|
let envelope = {};
|
|
2882
2550
|
try {
|
|
2883
2551
|
envelope = raw.trim() ? JSON.parse(raw) : {};
|
|
2884
2552
|
} catch {
|
|
2885
|
-
return
|
|
2553
|
+
return EXIT_ALLOW3;
|
|
2886
2554
|
}
|
|
2887
2555
|
return processEnvelope(envelope, resolveConsumerRoot(envelope));
|
|
2888
2556
|
}
|
|
2889
|
-
function
|
|
2557
|
+
function _isCliEntry4() {
|
|
2890
2558
|
if (true) {
|
|
2891
2559
|
return false;
|
|
2892
2560
|
}
|
|
2893
2561
|
if (process.argv[1] === void 0) return false;
|
|
2894
|
-
const argvUrl =
|
|
2562
|
+
const argvUrl = pathToFileURL4(path4.resolve(process.argv[1])).href;
|
|
2895
2563
|
if (import.meta.url === argvUrl) return true;
|
|
2896
2564
|
try {
|
|
2897
|
-
return
|
|
2565
|
+
return fs4.realpathSync(fileURLToPath4(import.meta.url)) === fs4.realpathSync(path4.resolve(process.argv[1]));
|
|
2898
2566
|
} catch {
|
|
2899
2567
|
return false;
|
|
2900
2568
|
}
|
|
2901
2569
|
}
|
|
2902
|
-
if (
|
|
2570
|
+
if (_isCliEntry4()) process.exit(main4());
|
|
2903
2571
|
|
|
2904
2572
|
// src/scripts/hooks/turn_end_gate_hook.ts
|
|
2905
|
-
var
|
|
2906
|
-
var
|
|
2573
|
+
var EXIT_BLOCK = 1;
|
|
2574
|
+
var EXIT_ALLOW4 = 0;
|
|
2907
2575
|
var TRANSCRIPT_READ_MAX_BYTES = 8 * 1024 * 1024;
|
|
2908
2576
|
function stripFencedBlocks(text) {
|
|
2909
2577
|
const out = [];
|
|
@@ -3008,7 +2676,7 @@ function detectPromissory(reply) {
|
|
|
3008
2676
|
function readCiSettled(workspaceRoot, session_id) {
|
|
3009
2677
|
if (!hasStableSessionId(session_id)) return { seen: false, settled: false };
|
|
3010
2678
|
try {
|
|
3011
|
-
const raw =
|
|
2679
|
+
const raw = fs5.readFileSync(path5.join(workspaceRoot, statePathFor(session_id)), "utf-8");
|
|
3012
2680
|
const decoded = JSON.parse(raw);
|
|
3013
2681
|
if (!owns_session_state(decoded, session_id)) return { seen: false, settled: false };
|
|
3014
2682
|
if (typeof decoded === "object" && decoded !== null && !Array.isArray(decoded)) {
|
|
@@ -3044,8 +2712,8 @@ function detectCompletionClaim(reply, ci) {
|
|
|
3044
2712
|
function readLanguagePin(workspaceRoot, session_id) {
|
|
3045
2713
|
if (!hasStableSessionId(session_id)) return "und";
|
|
3046
2714
|
try {
|
|
3047
|
-
const raw =
|
|
3048
|
-
|
|
2715
|
+
const raw = fs5.readFileSync(
|
|
2716
|
+
path5.join(workspaceRoot, statePathFor2(session_id)),
|
|
3049
2717
|
"utf-8"
|
|
3050
2718
|
);
|
|
3051
2719
|
const decoded = JSON.parse(raw);
|
|
@@ -3101,7 +2769,7 @@ function sessionStateFile2(workspaceRoot, sessionKey) {
|
|
|
3101
2769
|
}
|
|
3102
2770
|
function alreadyRefusedTurn(workspaceRoot, sessionKey, turnOrdinal) {
|
|
3103
2771
|
try {
|
|
3104
|
-
const raw =
|
|
2772
|
+
const raw = fs5.readFileSync(sessionStateFile2(workspaceRoot, sessionKey), "utf-8");
|
|
3105
2773
|
const decoded = JSON.parse(raw);
|
|
3106
2774
|
if (typeof decoded === "object" && decoded !== null && !Array.isArray(decoded)) {
|
|
3107
2775
|
return decoded["refused_turn"] === turnOrdinal;
|
|
@@ -3115,7 +2783,7 @@ function markRefusedTurn(workspaceRoot, sessionKey, turnOrdinal, detectors) {
|
|
|
3115
2783
|
const file = sessionStateFile2(workspaceRoot, sessionKey);
|
|
3116
2784
|
let prev = null;
|
|
3117
2785
|
try {
|
|
3118
|
-
prev = parseRecord(
|
|
2786
|
+
prev = parseRecord(fs5.readFileSync(file, "utf-8"));
|
|
3119
2787
|
} catch {
|
|
3120
2788
|
}
|
|
3121
2789
|
let version;
|
|
@@ -3142,10 +2810,10 @@ function readTranscriptTail(transcriptPath, opts = {}) {
|
|
|
3142
2810
|
if (!transcriptPath || !isSafeTranscriptPath(transcriptPath, opts)) return empty;
|
|
3143
2811
|
let lines;
|
|
3144
2812
|
try {
|
|
3145
|
-
if (opts.maxBytes !== void 0 &&
|
|
2813
|
+
if (opts.maxBytes !== void 0 && fs5.statSync(transcriptPath).size > opts.maxBytes) {
|
|
3146
2814
|
return empty;
|
|
3147
2815
|
}
|
|
3148
|
-
lines =
|
|
2816
|
+
lines = fs5.readFileSync(transcriptPath, "utf-8").split("\n");
|
|
3149
2817
|
} catch {
|
|
3150
2818
|
return empty;
|
|
3151
2819
|
}
|
|
@@ -3221,15 +2889,15 @@ function _messageText(content) {
|
|
|
3221
2889
|
function str3(v) {
|
|
3222
2890
|
return typeof v === "string" ? v : "";
|
|
3223
2891
|
}
|
|
3224
|
-
function
|
|
2892
|
+
function main5() {
|
|
3225
2893
|
let envelope;
|
|
3226
2894
|
let payload;
|
|
3227
2895
|
try {
|
|
3228
2896
|
[envelope, payload] = unwrap(readHookStdin(), "claude");
|
|
3229
2897
|
} catch {
|
|
3230
|
-
return
|
|
2898
|
+
return EXIT_ALLOW4;
|
|
3231
2899
|
}
|
|
3232
|
-
if (payload["stop_hook_active"] === true) return
|
|
2900
|
+
if (payload["stop_hook_active"] === true) return EXIT_ALLOW4;
|
|
3233
2901
|
const workspaceRoot = str3(envelope["workspace_root"]) || process.cwd();
|
|
3234
2902
|
let dispatchOpen = false;
|
|
3235
2903
|
try {
|
|
@@ -3242,10 +2910,10 @@ function main6() {
|
|
|
3242
2910
|
const { lastAssistant, turnOrdinal, toolCalls } = readTranscriptTail(transcriptPath, {
|
|
3243
2911
|
maxBytes: TRANSCRIPT_READ_MAX_BYTES
|
|
3244
2912
|
});
|
|
3245
|
-
if (!lastAssistant) return
|
|
2913
|
+
if (!lastAssistant) return EXIT_ALLOW4;
|
|
3246
2914
|
const rawSessionId = str3(envelope["session_id"]) || "";
|
|
3247
2915
|
const sessionKey = deriveSessionKey(rawSessionId || "unknown-session");
|
|
3248
|
-
if (alreadyRefusedTurn(workspaceRoot, sessionKey, turnOrdinal)) return
|
|
2916
|
+
if (alreadyRefusedTurn(workspaceRoot, sessionKey, turnOrdinal)) return EXIT_ALLOW4;
|
|
3249
2917
|
const findings = [];
|
|
3250
2918
|
for (const f of [
|
|
3251
2919
|
// A and D are the completion-adjacent pair a pending dispatch excuses
|
|
@@ -3268,7 +2936,7 @@ function main6() {
|
|
|
3268
2936
|
]) {
|
|
3269
2937
|
if (f) findings.push(f);
|
|
3270
2938
|
}
|
|
3271
|
-
if (findings.length === 0) return
|
|
2939
|
+
if (findings.length === 0) return EXIT_ALLOW4;
|
|
3272
2940
|
markRefusedTurn(
|
|
3273
2941
|
workspaceRoot,
|
|
3274
2942
|
sessionKey,
|
|
@@ -3286,40 +2954,40 @@ ${lines.join("\n")}
|
|
|
3286
2954
|
This turn will not be refused a second time.
|
|
3287
2955
|
`
|
|
3288
2956
|
);
|
|
3289
|
-
return
|
|
2957
|
+
return EXIT_BLOCK;
|
|
3290
2958
|
}
|
|
3291
|
-
function
|
|
2959
|
+
function _isCliEntry5() {
|
|
3292
2960
|
if (true) {
|
|
3293
2961
|
return false;
|
|
3294
2962
|
}
|
|
3295
2963
|
if (process.argv[1] === void 0) {
|
|
3296
2964
|
return false;
|
|
3297
2965
|
}
|
|
3298
|
-
const argvUrl =
|
|
2966
|
+
const argvUrl = pathToFileURL5(path5.resolve(process.argv[1])).href;
|
|
3299
2967
|
if (import.meta.url === argvUrl) {
|
|
3300
2968
|
return true;
|
|
3301
2969
|
}
|
|
3302
2970
|
try {
|
|
3303
|
-
const here =
|
|
3304
|
-
const argv =
|
|
2971
|
+
const here = fs5.realpathSync(fileURLToPath5(import.meta.url));
|
|
2972
|
+
const argv = fs5.realpathSync(path5.resolve(process.argv[1]));
|
|
3305
2973
|
return here === argv;
|
|
3306
2974
|
} catch {
|
|
3307
2975
|
return false;
|
|
3308
2976
|
}
|
|
3309
2977
|
}
|
|
3310
|
-
if (
|
|
3311
|
-
process.exit(
|
|
2978
|
+
if (_isCliEntry5()) {
|
|
2979
|
+
process.exit(main5());
|
|
3312
2980
|
}
|
|
3313
2981
|
|
|
3314
2982
|
// src/scripts/hooks/evidence_independence.ts
|
|
3315
2983
|
import crypto3 from "node:crypto";
|
|
3316
|
-
import
|
|
3317
|
-
import
|
|
3318
|
-
import { fileURLToPath as
|
|
3319
|
-
var
|
|
3320
|
-
var
|
|
3321
|
-
var STATE_FILE3 =
|
|
3322
|
-
function
|
|
2984
|
+
import fs6 from "node:fs";
|
|
2985
|
+
import path6 from "node:path";
|
|
2986
|
+
import { fileURLToPath as fileURLToPath6, pathToFileURL as pathToFileURL6 } from "node:url";
|
|
2987
|
+
var EXIT_ALLOW5 = 0;
|
|
2988
|
+
var EXIT_BLOCK2 = 1;
|
|
2989
|
+
var STATE_FILE3 = path6.join("agents", "state", "evidence-dispatch.json");
|
|
2990
|
+
function _isObject5(v) {
|
|
3323
2991
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
3324
2992
|
}
|
|
3325
2993
|
var DISPATCH_TOOLS = /* @__PURE__ */ new Set([
|
|
@@ -3372,10 +3040,10 @@ function preloadedVerdict(prompt) {
|
|
|
3372
3040
|
return null;
|
|
3373
3041
|
}
|
|
3374
3042
|
function extractDispatch(envelope) {
|
|
3375
|
-
const payload =
|
|
3043
|
+
const payload = _isObject5(envelope["payload"]) ? envelope["payload"] : envelope;
|
|
3376
3044
|
const toolRaw = payload["tool_name"] ?? payload["toolName"] ?? payload["tool"];
|
|
3377
3045
|
const tool = typeof toolRaw === "string" ? toolRaw : null;
|
|
3378
|
-
const input =
|
|
3046
|
+
const input = _isObject5(payload["tool_input"]) ? payload["tool_input"] : _isObject5(payload["toolInput"]) ? payload["toolInput"] : payload;
|
|
3379
3047
|
for (const key of ["prompt", "instructions", "task", "description"]) {
|
|
3380
3048
|
const v = input[key];
|
|
3381
3049
|
if (typeof v === "string" && v.trim()) {
|
|
@@ -3386,8 +3054,8 @@ function extractDispatch(envelope) {
|
|
|
3386
3054
|
}
|
|
3387
3055
|
function _ledgerStamp(consumer_root) {
|
|
3388
3056
|
try {
|
|
3389
|
-
const raw =
|
|
3390
|
-
|
|
3057
|
+
const raw = fs6.readFileSync(
|
|
3058
|
+
path6.join(consumer_root, "agents", "state", "git-authorization.json"),
|
|
3391
3059
|
"utf8"
|
|
3392
3060
|
);
|
|
3393
3061
|
const d = JSON.parse(raw);
|
|
@@ -3398,8 +3066,8 @@ function _ledgerStamp(consumer_root) {
|
|
|
3398
3066
|
}
|
|
3399
3067
|
function _load(target) {
|
|
3400
3068
|
try {
|
|
3401
|
-
const decoded = JSON.parse(
|
|
3402
|
-
if (
|
|
3069
|
+
const decoded = JSON.parse(fs6.readFileSync(target, "utf8"));
|
|
3070
|
+
if (_isObject5(decoded) && Array.isArray(decoded["evaluations"])) {
|
|
3403
3071
|
return decoded;
|
|
3404
3072
|
}
|
|
3405
3073
|
} catch {
|
|
@@ -3407,14 +3075,14 @@ function _load(target) {
|
|
|
3407
3075
|
return { session_id: "", turn_started_at: "", evaluations: [] };
|
|
3408
3076
|
}
|
|
3409
3077
|
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.";
|
|
3410
|
-
function
|
|
3078
|
+
function decide(tool, prompt, priorEvaluations) {
|
|
3411
3079
|
if (!isDispatchTool(tool) || !isEvaluationPrompt(prompt)) {
|
|
3412
|
-
return { exit:
|
|
3080
|
+
return { exit: EXIT_ALLOW5, stdout: "", stderr: "", evaluations: priorEvaluations };
|
|
3413
3081
|
}
|
|
3414
3082
|
const preloaded = preloadedVerdict(prompt);
|
|
3415
3083
|
if (preloaded !== null) {
|
|
3416
3084
|
return {
|
|
3417
|
-
exit:
|
|
3085
|
+
exit: EXIT_BLOCK2,
|
|
3418
3086
|
stdout: "",
|
|
3419
3087
|
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.
|
|
3420
3088
|
`,
|
|
@@ -3422,11 +3090,11 @@ function decide2(tool, prompt, priorEvaluations) {
|
|
|
3422
3090
|
};
|
|
3423
3091
|
}
|
|
3424
3092
|
if (!isSelfScoped(prompt)) {
|
|
3425
|
-
return { exit:
|
|
3093
|
+
return { exit: EXIT_ALLOW5, stdout: "", stderr: "", evaluations: priorEvaluations };
|
|
3426
3094
|
}
|
|
3427
3095
|
if (priorEvaluations >= 1) {
|
|
3428
3096
|
return {
|
|
3429
|
-
exit:
|
|
3097
|
+
exit: EXIT_ALLOW5,
|
|
3430
3098
|
stdout: `${JSON.stringify({
|
|
3431
3099
|
decision: "warn",
|
|
3432
3100
|
reason: `Second evaluation dispatch of your own work in this turn. If both passes judge the SAME subject, that is verdict shopping \u2014 commissioning another with a different prompt or scope selects the answer instead of measuring it. Report what the first pass returned, then re-plan. If this is an implementation fan-out rather than a second review, carry on: this check reads prose and cannot tell the two apart with certainty.`
|
|
@@ -3437,26 +3105,26 @@ function decide2(tool, prompt, priorEvaluations) {
|
|
|
3437
3105
|
};
|
|
3438
3106
|
}
|
|
3439
3107
|
return {
|
|
3440
|
-
exit:
|
|
3108
|
+
exit: EXIT_ALLOW5,
|
|
3441
3109
|
stdout: `${JSON.stringify({ decision: "warn", reason: WARN_TEXT })}
|
|
3442
3110
|
`,
|
|
3443
3111
|
stderr: "",
|
|
3444
3112
|
evaluations: priorEvaluations + 1
|
|
3445
3113
|
};
|
|
3446
3114
|
}
|
|
3447
|
-
function
|
|
3115
|
+
function run3(stdin_text, options) {
|
|
3448
3116
|
let envelope = {};
|
|
3449
3117
|
if (stdin_text.trim()) {
|
|
3450
3118
|
try {
|
|
3451
3119
|
const decoded = JSON.parse(stdin_text);
|
|
3452
|
-
if (
|
|
3120
|
+
if (_isObject5(decoded)) {
|
|
3453
3121
|
envelope = decoded;
|
|
3454
3122
|
}
|
|
3455
3123
|
} catch {
|
|
3456
|
-
return
|
|
3124
|
+
return EXIT_ALLOW5;
|
|
3457
3125
|
}
|
|
3458
3126
|
}
|
|
3459
|
-
const target =
|
|
3127
|
+
const target = path6.join(options.consumer_root, STATE_FILE3);
|
|
3460
3128
|
const state = _load(target);
|
|
3461
3129
|
const session_id = typeof envelope["session_id"] === "string" ? envelope["session_id"] : "";
|
|
3462
3130
|
const turnMarker = `${session_id}:${_ledgerStamp(options.consumer_root)}`;
|
|
@@ -3466,7 +3134,7 @@ function run4(stdin_text, options) {
|
|
|
3466
3134
|
state.evaluations = [];
|
|
3467
3135
|
}
|
|
3468
3136
|
const [tool, prompt] = extractDispatch(envelope);
|
|
3469
|
-
const decision =
|
|
3137
|
+
const decision = decide(tool, prompt, state.evaluations.length);
|
|
3470
3138
|
if (decision.evaluations > state.evaluations.length) {
|
|
3471
3139
|
state.evaluations.push({
|
|
3472
3140
|
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -3475,7 +3143,11 @@ function run4(stdin_text, options) {
|
|
|
3475
3143
|
});
|
|
3476
3144
|
try {
|
|
3477
3145
|
atomic_write_json(target, state);
|
|
3478
|
-
} catch {
|
|
3146
|
+
} catch (err) {
|
|
3147
|
+
process.stderr.write(
|
|
3148
|
+
`evidence-independence: evaluation-count write failed (${_errText3(err)}) \u2014 this turn's count did NOT advance, so a second self-scoped evaluation will not be warned about. The pre-loaded-verdict block is unaffected.
|
|
3149
|
+
`
|
|
3150
|
+
);
|
|
3479
3151
|
}
|
|
3480
3152
|
}
|
|
3481
3153
|
if (decision.stdout) {
|
|
@@ -3486,7 +3158,11 @@ function run4(stdin_text, options) {
|
|
|
3486
3158
|
}
|
|
3487
3159
|
return decision.exit;
|
|
3488
3160
|
}
|
|
3489
|
-
function
|
|
3161
|
+
function _errText3(err) {
|
|
3162
|
+
const t = err instanceof Error ? err.message : String(err);
|
|
3163
|
+
return t.replace(/\s+/g, " ").trim().slice(0, 200);
|
|
3164
|
+
}
|
|
3165
|
+
function main6(argv) {
|
|
3490
3166
|
const args = argv ?? process.argv.slice(2);
|
|
3491
3167
|
let consumer_root = process.cwd();
|
|
3492
3168
|
for (let i = 0; i < args.length; i += 1) {
|
|
@@ -3498,35 +3174,35 @@ function main7(argv) {
|
|
|
3498
3174
|
consumer_root = a.slice("--project-dir=".length);
|
|
3499
3175
|
}
|
|
3500
3176
|
}
|
|
3501
|
-
return
|
|
3177
|
+
return run3(readHookStdin(), { consumer_root });
|
|
3502
3178
|
}
|
|
3503
|
-
function
|
|
3179
|
+
function _isCliEntry6() {
|
|
3504
3180
|
if (true) {
|
|
3505
3181
|
return false;
|
|
3506
3182
|
}
|
|
3507
3183
|
if (process.argv[1] === void 0) {
|
|
3508
3184
|
return false;
|
|
3509
3185
|
}
|
|
3510
|
-
const argvUrl =
|
|
3186
|
+
const argvUrl = pathToFileURL6(path6.resolve(process.argv[1])).href;
|
|
3511
3187
|
if (import.meta.url === argvUrl) {
|
|
3512
3188
|
return true;
|
|
3513
3189
|
}
|
|
3514
3190
|
try {
|
|
3515
|
-
const here =
|
|
3516
|
-
const argv =
|
|
3191
|
+
const here = fs6.realpathSync(fileURLToPath6(import.meta.url));
|
|
3192
|
+
const argv = fs6.realpathSync(path6.resolve(process.argv[1]));
|
|
3517
3193
|
return here === argv;
|
|
3518
3194
|
} catch {
|
|
3519
3195
|
return false;
|
|
3520
3196
|
}
|
|
3521
3197
|
}
|
|
3522
|
-
if (
|
|
3523
|
-
process.exit(
|
|
3198
|
+
if (_isCliEntry6()) {
|
|
3199
|
+
process.exit(main6());
|
|
3524
3200
|
}
|
|
3525
3201
|
|
|
3526
3202
|
// src/scripts/hooks/delegation_nudge_hook.ts
|
|
3527
|
-
import
|
|
3528
|
-
import
|
|
3529
|
-
import { fileURLToPath as
|
|
3203
|
+
import fs7 from "node:fs";
|
|
3204
|
+
import path7 from "node:path";
|
|
3205
|
+
import { fileURLToPath as fileURLToPath7, pathToFileURL as pathToFileURL7 } from "node:url";
|
|
3530
3206
|
|
|
3531
3207
|
// src/scripts/_lib/host_capability.ts
|
|
3532
3208
|
import process2 from "node:process";
|
|
@@ -3855,9 +3531,9 @@ function resolveSubagentRouting(inp) {
|
|
|
3855
3531
|
}
|
|
3856
3532
|
|
|
3857
3533
|
// src/scripts/hooks/delegation_nudge_hook.ts
|
|
3858
|
-
var
|
|
3534
|
+
var EXIT_ALLOW6 = 0;
|
|
3859
3535
|
var EXIT_WARN3 = 2;
|
|
3860
|
-
function
|
|
3536
|
+
function _isObject6(v) {
|
|
3861
3537
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
3862
3538
|
}
|
|
3863
3539
|
var FILE_TOKEN_RE = /`?\b[\w][\w.\-]{0,80}\.(ts|tsx|js|jsx|mjs|cjs|py|php|rb|go|rs|java|kt|swift|md|mdx|json|ya?ml|css|scss|less|html|vue|svelte|sql|sh|bash|c|cpp|h|hpp|cs|toml|xml)\b`?/gi;
|
|
@@ -4016,34 +3692,34 @@ function _workspaceRoot(envelope) {
|
|
|
4016
3692
|
}
|
|
4017
3693
|
return process.cwd();
|
|
4018
3694
|
}
|
|
4019
|
-
function
|
|
3695
|
+
function main7() {
|
|
4020
3696
|
let envelope = {};
|
|
4021
3697
|
try {
|
|
4022
3698
|
const raw = readHookStdin();
|
|
4023
3699
|
envelope = raw.trim() ? JSON.parse(raw) : {};
|
|
4024
3700
|
} catch {
|
|
4025
|
-
return
|
|
3701
|
+
return EXIT_ALLOW6;
|
|
4026
3702
|
}
|
|
4027
|
-
const env =
|
|
3703
|
+
const env = _isObject6(envelope) ? envelope : {};
|
|
4028
3704
|
const event = env["event"];
|
|
4029
3705
|
const slot = typeof event === "string" && event !== "" ? event : "user_prompt_submit";
|
|
4030
3706
|
if (slot !== "user_prompt_submit") {
|
|
4031
|
-
return
|
|
3707
|
+
return EXIT_ALLOW6;
|
|
4032
3708
|
}
|
|
4033
|
-
const payload =
|
|
3709
|
+
const payload = _isObject6(env["payload"]) ? env["payload"] : env;
|
|
4034
3710
|
const prompt = _extractPrompt2(payload);
|
|
4035
3711
|
if (!prompt) {
|
|
4036
|
-
return
|
|
3712
|
+
return EXIT_ALLOW6;
|
|
4037
3713
|
}
|
|
4038
3714
|
if (isSyntheticPrompt(prompt)) {
|
|
4039
|
-
return
|
|
3715
|
+
return EXIT_ALLOW6;
|
|
4040
3716
|
}
|
|
4041
3717
|
const root = _workspaceRoot(env);
|
|
4042
3718
|
const platform = env["platform"];
|
|
4043
3719
|
const hostId = typeof platform === "string" && platform ? platform : null;
|
|
4044
3720
|
const result = classifyPrompt(prompt, root, hostId);
|
|
4045
3721
|
if (!result) {
|
|
4046
|
-
return
|
|
3722
|
+
return EXIT_ALLOW6;
|
|
4047
3723
|
}
|
|
4048
3724
|
process.stdout.write(
|
|
4049
3725
|
`${JSON.stringify({
|
|
@@ -4055,31 +3731,31 @@ function main8() {
|
|
|
4055
3731
|
);
|
|
4056
3732
|
return EXIT_WARN3;
|
|
4057
3733
|
}
|
|
4058
|
-
function
|
|
3734
|
+
function _isCliEntry7() {
|
|
4059
3735
|
if (true) {
|
|
4060
3736
|
return false;
|
|
4061
3737
|
}
|
|
4062
3738
|
if (process.argv[1] === void 0) {
|
|
4063
3739
|
return false;
|
|
4064
3740
|
}
|
|
4065
|
-
const argvUrl =
|
|
3741
|
+
const argvUrl = pathToFileURL7(path7.resolve(process.argv[1])).href;
|
|
4066
3742
|
if (import.meta.url === argvUrl) {
|
|
4067
3743
|
return true;
|
|
4068
3744
|
}
|
|
4069
3745
|
try {
|
|
4070
|
-
const here =
|
|
4071
|
-
const argv =
|
|
3746
|
+
const here = fs7.realpathSync(fileURLToPath7(import.meta.url));
|
|
3747
|
+
const argv = fs7.realpathSync(path7.resolve(process.argv[1]));
|
|
4072
3748
|
return here === argv;
|
|
4073
3749
|
} catch {
|
|
4074
3750
|
return false;
|
|
4075
3751
|
}
|
|
4076
3752
|
}
|
|
4077
|
-
if (
|
|
4078
|
-
process.exit(
|
|
3753
|
+
if (_isCliEntry7()) {
|
|
3754
|
+
process.exit(main7());
|
|
4079
3755
|
}
|
|
4080
3756
|
|
|
4081
3757
|
// src/scripts/conformance_scan.ts
|
|
4082
|
-
var REPO_ROOT =
|
|
3758
|
+
var REPO_ROOT = path8.resolve(path8.dirname(fileURLToPath8(import.meta.url)), "..", "..");
|
|
4083
3759
|
var OBSERVED_BAND = { low: 9.1, high: 39.2 };
|
|
4084
3760
|
var BAND_MIN_TURNS = 1978;
|
|
4085
3761
|
var CARRIER_CHANGES = [
|
|
@@ -4163,7 +3839,7 @@ function renderWhy(report, id) {
|
|
|
4163
3839
|
}
|
|
4164
3840
|
return lines.join("\n");
|
|
4165
3841
|
}
|
|
4166
|
-
function
|
|
3842
|
+
function _isObject7(v) {
|
|
4167
3843
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
4168
3844
|
}
|
|
4169
3845
|
function userText(entry) {
|
|
@@ -4187,15 +3863,15 @@ function assistantText(entry) {
|
|
|
4187
3863
|
}
|
|
4188
3864
|
function toolUses2(entry) {
|
|
4189
3865
|
const msg = entry["message"];
|
|
4190
|
-
const content =
|
|
3866
|
+
const content = _isObject7(msg) ? msg["content"] : void 0;
|
|
4191
3867
|
if (!Array.isArray(content)) {
|
|
4192
3868
|
return [];
|
|
4193
3869
|
}
|
|
4194
|
-
return content.filter((b) =>
|
|
3870
|
+
return content.filter((b) => _isObject7(b) && b["type"] === "tool_use").map((b) => {
|
|
4195
3871
|
const o = b;
|
|
4196
3872
|
return {
|
|
4197
3873
|
name: String(o["name"] ?? ""),
|
|
4198
|
-
input:
|
|
3874
|
+
input: _isObject7(o["input"]) ? o["input"] : {}
|
|
4199
3875
|
};
|
|
4200
3876
|
});
|
|
4201
3877
|
}
|
|
@@ -4429,7 +4105,7 @@ function scanSession(sessionId, lines) {
|
|
|
4429
4105
|
closeWindow();
|
|
4430
4106
|
return report;
|
|
4431
4107
|
}
|
|
4432
|
-
var DEFAULT_RATE_SERIES =
|
|
4108
|
+
var DEFAULT_RATE_SERIES = path8.join(
|
|
4433
4109
|
REPO_ROOT,
|
|
4434
4110
|
"agents",
|
|
4435
4111
|
"runtime",
|
|
@@ -4438,7 +4114,7 @@ var DEFAULT_RATE_SERIES = path9.join(
|
|
|
4438
4114
|
);
|
|
4439
4115
|
function defaultStore(projectDir) {
|
|
4440
4116
|
const slug = projectStoreSlug(projectDir);
|
|
4441
|
-
return
|
|
4117
|
+
return path8.join(process.env["HOME"] ?? "", ".claude", "projects", slug);
|
|
4442
4118
|
}
|
|
4443
4119
|
function _tokens(chars) {
|
|
4444
4120
|
return Math.round(chars / 4);
|
|
@@ -4449,13 +4125,13 @@ function measureDelivered(projectRulesDir, globalRulesDir) {
|
|
|
4449
4125
|
return {
|
|
4450
4126
|
project: {
|
|
4451
4127
|
dir: projectRulesDir,
|
|
4452
|
-
present:
|
|
4128
|
+
present: fs8.existsSync(projectRulesDir),
|
|
4453
4129
|
files: p.files,
|
|
4454
4130
|
tokens: _tokens(p.chars)
|
|
4455
4131
|
},
|
|
4456
4132
|
global: {
|
|
4457
4133
|
dir: globalRulesDir,
|
|
4458
|
-
present:
|
|
4134
|
+
present: fs8.existsSync(globalRulesDir),
|
|
4459
4135
|
files: g.files,
|
|
4460
4136
|
tokens: _tokens(g.chars)
|
|
4461
4137
|
},
|
|
@@ -4463,13 +4139,13 @@ function measureDelivered(projectRulesDir, globalRulesDir) {
|
|
|
4463
4139
|
};
|
|
4464
4140
|
}
|
|
4465
4141
|
function storeKey(store) {
|
|
4466
|
-
return createHash3("sha256").update(
|
|
4142
|
+
return createHash3("sha256").update(path8.resolve(store)).digest("hex").slice(0, 12);
|
|
4467
4143
|
}
|
|
4468
4144
|
function scanStore(store, limit) {
|
|
4469
|
-
const files =
|
|
4145
|
+
const files = fs8.readdirSync(store).filter((f) => f.endsWith(".jsonl")).map((f) => ({ f, m: fs8.statSync(path8.join(store, f)).mtimeMs })).sort((a, b) => b.m - a.m).slice(0, limit).map((x) => x.f);
|
|
4470
4146
|
const per_session = [];
|
|
4471
4147
|
for (const f of files) {
|
|
4472
|
-
const lines =
|
|
4148
|
+
const lines = fs8.readFileSync(path8.join(store, f), "utf8").split("\n");
|
|
4473
4149
|
const r = scanSession(f.replace(/\.jsonl$/, "").slice(0, 8), lines);
|
|
4474
4150
|
if (r.assistant_turns > 0) {
|
|
4475
4151
|
per_session.push(r);
|
|
@@ -4497,10 +4173,10 @@ function scanStore(store, limit) {
|
|
|
4497
4173
|
const task_completeness_rate_pct = completeness_windows === 0 ? 0 : Number((100 * task_completeness / completeness_windows).toFixed(1));
|
|
4498
4174
|
const era = spansCarrierChange(per_session.map((s) => s.first_at));
|
|
4499
4175
|
const delivered = measureDelivered(
|
|
4500
|
-
|
|
4501
|
-
|
|
4176
|
+
path8.join(REPO_ROOT, ".claude", "rules"),
|
|
4177
|
+
path8.join(process.env["HOME"] ?? os2.homedir(), ".claude", "rules")
|
|
4502
4178
|
);
|
|
4503
|
-
const ownStore =
|
|
4179
|
+
const ownStore = path8.resolve(store) === path8.resolve(defaultStore(REPO_ROOT));
|
|
4504
4180
|
return {
|
|
4505
4181
|
scanned_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4506
4182
|
store,
|
|
@@ -4530,8 +4206,8 @@ function scanStore(store, limit) {
|
|
|
4530
4206
|
};
|
|
4531
4207
|
}
|
|
4532
4208
|
function recordRate(file, scanned_at, rate) {
|
|
4533
|
-
|
|
4534
|
-
|
|
4209
|
+
fs8.mkdirSync(path8.dirname(file), { recursive: true });
|
|
4210
|
+
fs8.appendFileSync(file, `${JSON.stringify({ measured_at: scanned_at, ...rate })}
|
|
4535
4211
|
`, "utf8");
|
|
4536
4212
|
}
|
|
4537
4213
|
function render(report) {
|
|
@@ -4630,7 +4306,7 @@ function render(report) {
|
|
|
4630
4306
|
lines.push(" checkbox batching \u2014 measured NOWHERE. ~5 low-severity findings.");
|
|
4631
4307
|
return lines.join("\n");
|
|
4632
4308
|
}
|
|
4633
|
-
function
|
|
4309
|
+
function main8(argv) {
|
|
4634
4310
|
const args = argv ?? process.argv.slice(2);
|
|
4635
4311
|
let store = null;
|
|
4636
4312
|
let limit = 30;
|
|
@@ -4662,14 +4338,14 @@ function main9(argv) {
|
|
|
4662
4338
|
return 2;
|
|
4663
4339
|
}
|
|
4664
4340
|
const resolved = store ?? defaultStore(process.cwd());
|
|
4665
|
-
if (!
|
|
4341
|
+
if (!fs8.existsSync(resolved)) {
|
|
4666
4342
|
process.stderr.write(`conformance:behavior: no transcript store at ${resolved}
|
|
4667
4343
|
`);
|
|
4668
4344
|
return 1;
|
|
4669
4345
|
}
|
|
4670
4346
|
const report = scanStore(resolved, Number.isFinite(limit) && limit > 0 ? limit : 30);
|
|
4671
4347
|
if (out) {
|
|
4672
|
-
|
|
4348
|
+
fs8.writeFileSync(out, `${JSON.stringify(report, null, 2)}
|
|
4673
4349
|
`, "utf8");
|
|
4674
4350
|
}
|
|
4675
4351
|
if (record) {
|
|
@@ -4677,7 +4353,7 @@ function main9(argv) {
|
|
|
4677
4353
|
}
|
|
4678
4354
|
if (why !== null) {
|
|
4679
4355
|
const id = why;
|
|
4680
|
-
|
|
4356
|
+
fs8.writeSync(
|
|
4681
4357
|
1,
|
|
4682
4358
|
json ? `${JSON.stringify(
|
|
4683
4359
|
{
|
|
@@ -4697,48 +4373,48 @@ function main9(argv) {
|
|
|
4697
4373
|
);
|
|
4698
4374
|
return 0;
|
|
4699
4375
|
}
|
|
4700
|
-
|
|
4376
|
+
fs8.writeSync(1, json ? `${JSON.stringify(report, null, 2)}
|
|
4701
4377
|
` : `${render(report)}
|
|
4702
4378
|
`);
|
|
4703
4379
|
return 0;
|
|
4704
4380
|
}
|
|
4705
|
-
function
|
|
4381
|
+
function _isCliEntry8() {
|
|
4706
4382
|
if (true) {
|
|
4707
4383
|
return false;
|
|
4708
4384
|
}
|
|
4709
4385
|
if (process.argv[1] === void 0) {
|
|
4710
4386
|
return false;
|
|
4711
4387
|
}
|
|
4712
|
-
const argvUrl =
|
|
4388
|
+
const argvUrl = pathToFileURL8(path8.resolve(process.argv[1])).href;
|
|
4713
4389
|
if (import.meta.url === argvUrl) {
|
|
4714
4390
|
return true;
|
|
4715
4391
|
}
|
|
4716
4392
|
try {
|
|
4717
|
-
const here =
|
|
4718
|
-
const argv =
|
|
4393
|
+
const here = fs8.realpathSync(fileURLToPath8(import.meta.url));
|
|
4394
|
+
const argv = fs8.realpathSync(path8.resolve(process.argv[1]));
|
|
4719
4395
|
return here === argv;
|
|
4720
4396
|
} catch {
|
|
4721
4397
|
return false;
|
|
4722
4398
|
}
|
|
4723
4399
|
}
|
|
4724
|
-
if (
|
|
4725
|
-
process.exit(
|
|
4400
|
+
if (_isCliEntry8()) {
|
|
4401
|
+
process.exit(main8());
|
|
4726
4402
|
}
|
|
4727
4403
|
|
|
4728
4404
|
// src/scripts/report_carrier_divergence.ts
|
|
4729
|
-
import * as
|
|
4405
|
+
import * as fs9 from "node:fs";
|
|
4730
4406
|
import * as os3 from "node:os";
|
|
4731
|
-
import * as
|
|
4407
|
+
import * as path9 from "node:path";
|
|
4732
4408
|
import process3 from "node:process";
|
|
4733
|
-
import { fileURLToPath as
|
|
4734
|
-
var _HERE =
|
|
4735
|
-
var REPO_ROOT2 =
|
|
4736
|
-
var PROJECT_RULES =
|
|
4737
|
-
var PROJECTION_SOURCE =
|
|
4738
|
-
var GLOBAL_RULES =
|
|
4409
|
+
import { fileURLToPath as fileURLToPath9, pathToFileURL as pathToFileURL9 } from "node:url";
|
|
4410
|
+
var _HERE = fileURLToPath9(import.meta.url);
|
|
4411
|
+
var REPO_ROOT2 = path9.resolve(path9.dirname(_HERE), "..", "..");
|
|
4412
|
+
var PROJECT_RULES = path9.join(".claude", "rules");
|
|
4413
|
+
var PROJECTION_SOURCE = path9.join("dist", "agent-src", "rules");
|
|
4414
|
+
var GLOBAL_RULES = path9.join(".claude", "rules");
|
|
4739
4415
|
function _listRules(dir) {
|
|
4740
4416
|
try {
|
|
4741
|
-
return
|
|
4417
|
+
return fs9.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
|
|
4742
4418
|
} catch {
|
|
4743
4419
|
return [];
|
|
4744
4420
|
}
|
|
@@ -4746,7 +4422,7 @@ function _listRules(dir) {
|
|
|
4746
4422
|
function _ruleType(file) {
|
|
4747
4423
|
let text;
|
|
4748
4424
|
try {
|
|
4749
|
-
text =
|
|
4425
|
+
text = fs9.readFileSync(file, "utf-8");
|
|
4750
4426
|
} catch {
|
|
4751
4427
|
return "";
|
|
4752
4428
|
}
|
|
@@ -4757,8 +4433,8 @@ function compareCarriers(projectDir, globalDir, sourceDir) {
|
|
|
4757
4433
|
const out = {
|
|
4758
4434
|
projectDir,
|
|
4759
4435
|
globalDir,
|
|
4760
|
-
globalPresent:
|
|
4761
|
-
projectPresent:
|
|
4436
|
+
globalPresent: fs9.existsSync(globalDir),
|
|
4437
|
+
projectPresent: fs9.existsSync(projectDir),
|
|
4762
4438
|
shared: 0,
|
|
4763
4439
|
identical: [],
|
|
4764
4440
|
provenanceOnly: [],
|
|
@@ -4781,7 +4457,7 @@ function compareCarriers(projectDir, globalDir, sourceDir) {
|
|
|
4781
4457
|
}
|
|
4782
4458
|
if (!inP && inG) {
|
|
4783
4459
|
out.globalOnly.push(rule);
|
|
4784
|
-
if (sourceDir !== void 0 && _ruleType(
|
|
4460
|
+
if (sourceDir !== void 0 && _ruleType(path9.join(sourceDir, rule)) === "manual") {
|
|
4785
4461
|
out.manualOnlyGlobal.push(rule);
|
|
4786
4462
|
}
|
|
4787
4463
|
continue;
|
|
@@ -4791,8 +4467,8 @@ function compareCarriers(projectDir, globalDir, sourceDir) {
|
|
|
4791
4467
|
let projectCopy;
|
|
4792
4468
|
let globalCopy;
|
|
4793
4469
|
try {
|
|
4794
|
-
projectCopy =
|
|
4795
|
-
globalCopy =
|
|
4470
|
+
projectCopy = fs9.readFileSync(path9.join(projectDir, rule));
|
|
4471
|
+
globalCopy = fs9.readFileSync(path9.join(globalDir, rule));
|
|
4796
4472
|
verdict = comparePair(projectCopy, globalCopy);
|
|
4797
4473
|
} catch {
|
|
4798
4474
|
out.shared -= 1;
|
|
@@ -4937,11 +4613,11 @@ function render2(d) {
|
|
|
4937
4613
|
}
|
|
4938
4614
|
return lines.join("\n");
|
|
4939
4615
|
}
|
|
4940
|
-
function
|
|
4616
|
+
function main9(argv) {
|
|
4941
4617
|
const args = argv ?? process3.argv.slice(2);
|
|
4942
|
-
let projectDir =
|
|
4943
|
-
let globalDir =
|
|
4944
|
-
let sourceDir =
|
|
4618
|
+
let projectDir = path9.join(REPO_ROOT2, PROJECT_RULES);
|
|
4619
|
+
let globalDir = path9.join(os3.homedir(), GLOBAL_RULES);
|
|
4620
|
+
let sourceDir = path9.join(REPO_ROOT2, PROJECTION_SOURCE);
|
|
4945
4621
|
const value = (i) => {
|
|
4946
4622
|
const v = args[i + 1];
|
|
4947
4623
|
return v === void 0 || v.startsWith("-") ? null : v;
|
|
@@ -4955,7 +4631,7 @@ function main10(argv) {
|
|
|
4955
4631
|
`);
|
|
4956
4632
|
return 1;
|
|
4957
4633
|
}
|
|
4958
|
-
const resolved =
|
|
4634
|
+
const resolved = path9.resolve(v);
|
|
4959
4635
|
if (a === "--project") projectDir = resolved;
|
|
4960
4636
|
else if (a === "--global") globalDir = resolved;
|
|
4961
4637
|
else sourceDir = resolved;
|
|
@@ -4975,44 +4651,44 @@ function main10(argv) {
|
|
|
4975
4651
|
`);
|
|
4976
4652
|
return 0;
|
|
4977
4653
|
}
|
|
4978
|
-
function
|
|
4654
|
+
function _isCliEntry9() {
|
|
4979
4655
|
if (process3.argv[1] === void 0) return false;
|
|
4980
|
-
if (import.meta.url ===
|
|
4656
|
+
if (import.meta.url === pathToFileURL9(path9.resolve(process3.argv[1])).href) return true;
|
|
4981
4657
|
try {
|
|
4982
|
-
return
|
|
4658
|
+
return fs9.realpathSync(_HERE) === fs9.realpathSync(path9.resolve(process3.argv[1]));
|
|
4983
4659
|
} catch {
|
|
4984
4660
|
return false;
|
|
4985
4661
|
}
|
|
4986
4662
|
}
|
|
4987
|
-
if (
|
|
4988
|
-
process3.exit(
|
|
4663
|
+
if (_isCliEntry9()) {
|
|
4664
|
+
process3.exit(main9());
|
|
4989
4665
|
}
|
|
4990
4666
|
|
|
4991
4667
|
// src/scripts/report_skill_activation.ts
|
|
4992
|
-
import * as
|
|
4668
|
+
import * as fs10 from "node:fs";
|
|
4993
4669
|
import * as os4 from "node:os";
|
|
4994
|
-
import * as
|
|
4995
|
-
import { fileURLToPath as
|
|
4996
|
-
var _HERE2 =
|
|
4997
|
-
var REPO_ROOT3 =
|
|
4670
|
+
import * as path10 from "node:path";
|
|
4671
|
+
import { fileURLToPath as fileURLToPath10, pathToFileURL as pathToFileURL10 } from "node:url";
|
|
4672
|
+
var _HERE2 = fileURLToPath10(import.meta.url);
|
|
4673
|
+
var REPO_ROOT3 = path10.resolve(path10.dirname(_HERE2), "..", "..");
|
|
4998
4674
|
var SKILLS_ROOT = "src/skills";
|
|
4999
4675
|
var TRIGGER_KEYS = ["triggers:", "trigger_description:", "file_pattern:", "path_prefix:"];
|
|
5000
4676
|
var DETERMINISTIC_RE = /^\s*(?:[-*]\s*)?(?:\*\*)?(MUST|NEVER|ALWAYS)\b/m;
|
|
5001
4677
|
function censusSkills(root) {
|
|
5002
4678
|
const out = { total: 0, withTriggerKey: [], withDeterministicObligation: [] };
|
|
5003
|
-
if (!
|
|
4679
|
+
if (!fs10.existsSync(root)) {
|
|
5004
4680
|
return out;
|
|
5005
4681
|
}
|
|
5006
|
-
for (const entry of
|
|
4682
|
+
for (const entry of fs10.readdirSync(root, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
5007
4683
|
if (!entry.isDirectory()) {
|
|
5008
4684
|
continue;
|
|
5009
4685
|
}
|
|
5010
|
-
const file =
|
|
5011
|
-
if (!
|
|
4686
|
+
const file = path10.join(root, entry.name, "SKILL.md");
|
|
4687
|
+
if (!fs10.existsSync(file)) {
|
|
5012
4688
|
continue;
|
|
5013
4689
|
}
|
|
5014
4690
|
out.total += 1;
|
|
5015
|
-
const text =
|
|
4691
|
+
const text = fs10.readFileSync(file, "utf8");
|
|
5016
4692
|
const fmEnd = text.startsWith("---") ? text.indexOf("\n---", 3) : -1;
|
|
5017
4693
|
const fm = fmEnd === -1 ? "" : text.slice(0, fmEnd);
|
|
5018
4694
|
if (TRIGGER_KEYS.some((k) => new RegExp(`^${k}`, "m").test(fm))) {
|
|
@@ -5026,17 +4702,17 @@ function censusSkills(root) {
|
|
|
5026
4702
|
return out;
|
|
5027
4703
|
}
|
|
5028
4704
|
function defaultStore2(cwd) {
|
|
5029
|
-
return
|
|
4705
|
+
return path10.join(os4.homedir(), ".claude", "projects", projectStoreSlug(cwd));
|
|
5030
4706
|
}
|
|
5031
4707
|
function measureUsage(store, limit) {
|
|
5032
4708
|
const rep = { store, sessions: 0, assistantTurns: 0, invocations: 0, bySkill: {} };
|
|
5033
|
-
if (!
|
|
4709
|
+
if (!fs10.existsSync(store)) {
|
|
5034
4710
|
return rep;
|
|
5035
4711
|
}
|
|
5036
|
-
const files =
|
|
4712
|
+
const files = fs10.readdirSync(store).filter((f) => f.endsWith(".jsonl")).map((f) => path10.join(store, f)).sort((a, b) => fs10.statSync(b).mtimeMs - fs10.statSync(a).mtimeMs).slice(0, limit);
|
|
5037
4713
|
rep.sessions = files.length;
|
|
5038
4714
|
for (const file of files) {
|
|
5039
|
-
for (const line of
|
|
4715
|
+
for (const line of fs10.readFileSync(file, "utf8").split("\n")) {
|
|
5040
4716
|
if (!line.trim()) {
|
|
5041
4717
|
continue;
|
|
5042
4718
|
}
|
|
@@ -5099,7 +4775,7 @@ function render3(census, usage) {
|
|
|
5099
4775
|
}
|
|
5100
4776
|
totalInv += u.invocations;
|
|
5101
4777
|
lines.push(
|
|
5102
|
-
` ${
|
|
4778
|
+
` ${path10.basename(u.store).slice(-38).padEnd(38)} sessions=${String(u.sessions).padStart(3)} asst=${String(u.assistantTurns).padStart(6)} Skill calls=${String(u.invocations).padStart(3)}`
|
|
5103
4779
|
);
|
|
5104
4780
|
}
|
|
5105
4781
|
lines.push("");
|
|
@@ -5124,7 +4800,7 @@ function render3(census, usage) {
|
|
|
5124
4800
|
lines.push(" catalogue once per session, then count descriptions against bare names.");
|
|
5125
4801
|
return lines.join("\n");
|
|
5126
4802
|
}
|
|
5127
|
-
function
|
|
4803
|
+
function main10(argv) {
|
|
5128
4804
|
let limit = 30;
|
|
5129
4805
|
const stores = [];
|
|
5130
4806
|
for (let i = 0; i < argv.length; i += 1) {
|
|
@@ -5147,24 +4823,24 @@ function main11(argv) {
|
|
|
5147
4823
|
if (stores.length === 0) {
|
|
5148
4824
|
stores.push(defaultStore2(REPO_ROOT3));
|
|
5149
4825
|
}
|
|
5150
|
-
const census = censusSkills(
|
|
4826
|
+
const census = censusSkills(path10.join(REPO_ROOT3, SKILLS_ROOT));
|
|
5151
4827
|
const usage = stores.map((s) => measureUsage(s, limit));
|
|
5152
4828
|
process.stdout.write(`${render3(census, usage)}
|
|
5153
4829
|
`);
|
|
5154
4830
|
return 0;
|
|
5155
4831
|
}
|
|
5156
|
-
if (process.argv[1] !== void 0 && import.meta.url ===
|
|
5157
|
-
process.exit(
|
|
4832
|
+
if (process.argv[1] !== void 0 && import.meta.url === pathToFileURL10(path10.resolve(process.argv[1])).href) {
|
|
4833
|
+
process.exit(main10(process.argv.slice(2)));
|
|
5158
4834
|
}
|
|
5159
4835
|
|
|
5160
4836
|
// src/scripts/report_skill_obligation_violations.ts
|
|
5161
|
-
import * as
|
|
4837
|
+
import * as fs11 from "node:fs";
|
|
5162
4838
|
import * as os5 from "node:os";
|
|
5163
|
-
import * as
|
|
4839
|
+
import * as path11 from "node:path";
|
|
5164
4840
|
import process4 from "node:process";
|
|
5165
|
-
import { fileURLToPath as
|
|
5166
|
-
var _HERE3 =
|
|
5167
|
-
var REPO_ROOT4 =
|
|
4841
|
+
import { fileURLToPath as fileURLToPath11, pathToFileURL as pathToFileURL11 } from "node:url";
|
|
4842
|
+
var _HERE3 = fileURLToPath11(import.meta.url);
|
|
4843
|
+
var REPO_ROOT4 = path11.resolve(path11.dirname(_HERE3), "..", "..");
|
|
5168
4844
|
var OBLIGATION_LINE_RE = new RegExp(`${DETERMINISTIC_RE.source}.*`, "gm");
|
|
5169
4845
|
var PATH_RE = /`([A-Za-z0-9_./-]*\/[A-Za-z0-9_.-]+\.[a-z]{2,6})`/g;
|
|
5170
4846
|
var CMD_RE = /`([a-z][a-z0-9-]*(?: [a-z][a-z0-9:._-]*){1,3})`/g;
|
|
@@ -5202,7 +4878,7 @@ function _artefacts(line) {
|
|
|
5202
4878
|
return out;
|
|
5203
4879
|
}
|
|
5204
4880
|
function extractObligations(repoRoot) {
|
|
5205
|
-
const skillsRoot =
|
|
4881
|
+
const skillsRoot = path11.join(repoRoot, SKILLS_ROOT);
|
|
5206
4882
|
const census = censusSkills(skillsRoot);
|
|
5207
4883
|
const out = {
|
|
5208
4884
|
skills: census.withDeterministicObligation,
|
|
@@ -5216,7 +4892,7 @@ function extractObligations(repoRoot) {
|
|
|
5216
4892
|
for (const skill of census.withDeterministicObligation) {
|
|
5217
4893
|
let text;
|
|
5218
4894
|
try {
|
|
5219
|
-
text =
|
|
4895
|
+
text = fs11.readFileSync(path11.join(skillsRoot, skill, "SKILL.md"), "utf-8");
|
|
5220
4896
|
} catch {
|
|
5221
4897
|
continue;
|
|
5222
4898
|
}
|
|
@@ -5332,7 +5008,7 @@ function scanSessionForViolations(session, lines, forbidden, parsed) {
|
|
|
5332
5008
|
return flags;
|
|
5333
5009
|
}
|
|
5334
5010
|
function defaultStore3(cwd) {
|
|
5335
|
-
return
|
|
5011
|
+
return path11.join(os5.homedir(), ".claude", "projects", projectStoreSlug(cwd));
|
|
5336
5012
|
}
|
|
5337
5013
|
function scanStore2(repoRoot, store, limit) {
|
|
5338
5014
|
const census = extractObligations(repoRoot);
|
|
@@ -5345,14 +5021,14 @@ function scanStore2(repoRoot, store, limit) {
|
|
|
5345
5021
|
};
|
|
5346
5022
|
let files;
|
|
5347
5023
|
try {
|
|
5348
|
-
files =
|
|
5024
|
+
files = fs11.readdirSync(store).filter((f) => f.endsWith(".jsonl")).map((f) => ({ p: path11.join(store, f), m: fs11.statSync(path11.join(store, f)).mtimeMs })).sort((a, b) => b.m - a.m).slice(0, limit).map((x) => x.p);
|
|
5349
5025
|
} catch {
|
|
5350
5026
|
return report;
|
|
5351
5027
|
}
|
|
5352
5028
|
report.sessions = files.length;
|
|
5353
5029
|
for (const file of files) {
|
|
5354
|
-
const lines =
|
|
5355
|
-
const id =
|
|
5030
|
+
const lines = fs11.readFileSync(file, "utf-8").split("\n");
|
|
5031
|
+
const id = path11.basename(file).replace(/\.jsonl$/, "").slice(0, 8);
|
|
5356
5032
|
const entries = _parseSession(lines);
|
|
5357
5033
|
if (loadedSkillsFrom(entries).size > 0) report.sessionsWithASkill += 1;
|
|
5358
5034
|
report.flags.push(...scanSessionForViolations(id, lines, census.forbidden, entries));
|
|
@@ -5422,7 +5098,7 @@ function render4(r) {
|
|
|
5422
5098
|
lines.push(" ships as detection-only, and this one says so.");
|
|
5423
5099
|
return lines.join("\n");
|
|
5424
5100
|
}
|
|
5425
|
-
function
|
|
5101
|
+
function main11(argv) {
|
|
5426
5102
|
const args = argv ?? process4.argv.slice(2);
|
|
5427
5103
|
let limit = 30;
|
|
5428
5104
|
let json = false;
|
|
@@ -5475,35 +5151,35 @@ function main12(argv) {
|
|
|
5475
5151
|
}
|
|
5476
5152
|
return 0;
|
|
5477
5153
|
}
|
|
5478
|
-
function
|
|
5154
|
+
function _isCliEntry10() {
|
|
5479
5155
|
if (process4.argv[1] === void 0) return false;
|
|
5480
|
-
if (import.meta.url ===
|
|
5156
|
+
if (import.meta.url === pathToFileURL11(path11.resolve(process4.argv[1])).href) return true;
|
|
5481
5157
|
try {
|
|
5482
|
-
return
|
|
5158
|
+
return fs11.realpathSync(_HERE3) === fs11.realpathSync(path11.resolve(process4.argv[1]));
|
|
5483
5159
|
} catch {
|
|
5484
5160
|
return false;
|
|
5485
5161
|
}
|
|
5486
5162
|
}
|
|
5487
|
-
if (
|
|
5488
|
-
process4.exit(
|
|
5163
|
+
if (_isCliEntry10()) {
|
|
5164
|
+
process4.exit(main11());
|
|
5489
5165
|
}
|
|
5490
5166
|
|
|
5491
5167
|
// src/scripts/report_conformance_funnel.ts
|
|
5492
|
-
var _HERE4 =
|
|
5493
|
-
var REPO_ROOT5 =
|
|
5168
|
+
var _HERE4 = fileURLToPath12(import.meta.url);
|
|
5169
|
+
var REPO_ROOT5 = path12.resolve(path12.dirname(_HERE4), "..", "..");
|
|
5494
5170
|
function buildFunnel(opts = {}) {
|
|
5495
5171
|
const repoRoot = opts.repoRoot ?? REPO_ROOT5;
|
|
5496
|
-
const projectRulesDir = opts.projectRulesDir ??
|
|
5497
|
-
const globalRulesDir = opts.globalRulesDir ??
|
|
5498
|
-
const sourceDir = opts.sourceDir ??
|
|
5172
|
+
const projectRulesDir = opts.projectRulesDir ?? path12.join(repoRoot, PROJECT_RULES);
|
|
5173
|
+
const globalRulesDir = opts.globalRulesDir ?? path12.join(os6.homedir(), GLOBAL_RULES);
|
|
5174
|
+
const sourceDir = opts.sourceDir ?? path12.join(repoRoot, PROJECTION_SOURCE);
|
|
5499
5175
|
const store = opts.store ?? defaultStore(repoRoot);
|
|
5500
5176
|
const limit = opts.limit ?? 30;
|
|
5501
5177
|
return {
|
|
5502
5178
|
delivered: measureDelivered(projectRulesDir, globalRulesDir),
|
|
5503
5179
|
divergence: compareCarriers(projectRulesDir, globalRulesDir, sourceDir),
|
|
5504
|
-
skills: censusSkills(
|
|
5180
|
+
skills: censusSkills(path12.join(repoRoot, SKILLS_ROOT)),
|
|
5505
5181
|
usage: measureUsage(store, limit),
|
|
5506
|
-
storePresent:
|
|
5182
|
+
storePresent: fs12.existsSync(store),
|
|
5507
5183
|
sk2: scanStore2(repoRoot, store, limit)
|
|
5508
5184
|
};
|
|
5509
5185
|
}
|
|
@@ -5628,7 +5304,7 @@ function render5(r) {
|
|
|
5628
5304
|
lines.push("workflow without a measured false-positive rate first (locked policy).");
|
|
5629
5305
|
return lines.join("\n");
|
|
5630
5306
|
}
|
|
5631
|
-
function
|
|
5307
|
+
function main12(argv) {
|
|
5632
5308
|
const args = argv ?? process5.argv.slice(2);
|
|
5633
5309
|
const opts = {};
|
|
5634
5310
|
const value = (i) => {
|
|
@@ -5644,7 +5320,7 @@ function main13(argv) {
|
|
|
5644
5320
|
`);
|
|
5645
5321
|
return 1;
|
|
5646
5322
|
}
|
|
5647
|
-
const resolved =
|
|
5323
|
+
const resolved = path12.resolve(v);
|
|
5648
5324
|
if (a === "--store") opts.store = resolved;
|
|
5649
5325
|
else if (a === "--project") opts.projectRulesDir = resolved;
|
|
5650
5326
|
else if (a === "--global") opts.globalRulesDir = resolved;
|
|
@@ -5674,21 +5350,21 @@ function main13(argv) {
|
|
|
5674
5350
|
`);
|
|
5675
5351
|
return 0;
|
|
5676
5352
|
}
|
|
5677
|
-
function
|
|
5353
|
+
function _isCliEntry11() {
|
|
5678
5354
|
if (process5.argv[1] === void 0) return false;
|
|
5679
|
-
if (import.meta.url ===
|
|
5355
|
+
if (import.meta.url === pathToFileURL12(path12.resolve(process5.argv[1])).href) return true;
|
|
5680
5356
|
try {
|
|
5681
|
-
return
|
|
5357
|
+
return fs12.realpathSync(_HERE4) === fs12.realpathSync(path12.resolve(process5.argv[1]));
|
|
5682
5358
|
} catch {
|
|
5683
5359
|
return false;
|
|
5684
5360
|
}
|
|
5685
5361
|
}
|
|
5686
|
-
if (
|
|
5687
|
-
process5.exit(
|
|
5362
|
+
if (_isCliEntry11()) {
|
|
5363
|
+
process5.exit(main12());
|
|
5688
5364
|
}
|
|
5689
5365
|
|
|
5690
5366
|
// src/scripts/_cli/cmd_conformance.ts
|
|
5691
|
-
var _HERE5 =
|
|
5367
|
+
var _HERE5 = fileURLToPath13(import.meta.url);
|
|
5692
5368
|
var PACKAGE_ROOT = resolvePackageRoot(import.meta.url);
|
|
5693
5369
|
var CONFORMANCE_CHECK_IDS = [
|
|
5694
5370
|
"txlog-clean",
|
|
@@ -5711,17 +5387,17 @@ function conformanceLogPath() {
|
|
|
5711
5387
|
if (override && override.trim().length > 0) {
|
|
5712
5388
|
return override;
|
|
5713
5389
|
}
|
|
5714
|
-
return
|
|
5390
|
+
return path13.join(os7.homedir(), ".event4u", "agent-config", "conformance-log.jsonl");
|
|
5715
5391
|
}
|
|
5716
5392
|
function installLogPath() {
|
|
5717
5393
|
const override = process6.env["AGENT_CONFIG_INSTALL_LOG"];
|
|
5718
5394
|
if (override && override.trim().length > 0) {
|
|
5719
5395
|
return override;
|
|
5720
5396
|
}
|
|
5721
|
-
return
|
|
5397
|
+
return path13.join(os7.homedir(), ".event4u", "agent-config", "install-log.jsonl");
|
|
5722
5398
|
}
|
|
5723
5399
|
function _check_txlog_clean(logPath = installLogPath()) {
|
|
5724
|
-
if (!
|
|
5400
|
+
if (!fs13.existsSync(logPath)) {
|
|
5725
5401
|
return {
|
|
5726
5402
|
id: "txlog-clean",
|
|
5727
5403
|
status: "ok",
|
|
@@ -5755,11 +5431,11 @@ function _check_txlog_clean(logPath = installLogPath()) {
|
|
|
5755
5431
|
};
|
|
5756
5432
|
}
|
|
5757
5433
|
function routeTargetPaths(target) {
|
|
5758
|
-
return routeTargetPathsPosix(target).map((rel) =>
|
|
5434
|
+
return routeTargetPathsPosix(target).map((rel) => path13.join(...rel.split("/")));
|
|
5759
5435
|
}
|
|
5760
5436
|
function _check_router_pointers(packageRoot = PACKAGE_ROOT) {
|
|
5761
|
-
const routerPath =
|
|
5762
|
-
if (!
|
|
5437
|
+
const routerPath = path13.join(packageRoot, "dist", "router.json");
|
|
5438
|
+
if (!fs13.existsSync(routerPath)) {
|
|
5763
5439
|
return {
|
|
5764
5440
|
id: "router-pointers",
|
|
5765
5441
|
status: "fail",
|
|
@@ -5769,7 +5445,7 @@ function _check_router_pointers(packageRoot = PACKAGE_ROOT) {
|
|
|
5769
5445
|
}
|
|
5770
5446
|
let router;
|
|
5771
5447
|
try {
|
|
5772
|
-
router = JSON.parse(
|
|
5448
|
+
router = JSON.parse(fs13.readFileSync(routerPath, "utf8"));
|
|
5773
5449
|
} catch (exc) {
|
|
5774
5450
|
return {
|
|
5775
5451
|
id: "router-pointers",
|
|
@@ -5778,13 +5454,13 @@ function _check_router_pointers(packageRoot = PACKAGE_ROOT) {
|
|
|
5778
5454
|
remedy: "reinstall the package \u2014 dist/router.json is corrupt"
|
|
5779
5455
|
};
|
|
5780
5456
|
}
|
|
5781
|
-
const rulesDir =
|
|
5457
|
+
const rulesDir = path13.join(packageRoot, "dist", "agent-src", "rules");
|
|
5782
5458
|
const broken = [];
|
|
5783
5459
|
let ids = 0;
|
|
5784
5460
|
let targets = 0;
|
|
5785
5461
|
for (const kernelId of router["kernel"] ?? []) {
|
|
5786
5462
|
ids += 1;
|
|
5787
|
-
if (!
|
|
5463
|
+
if (!fs13.existsSync(path13.join(rulesDir, `${kernelId}.md`))) {
|
|
5788
5464
|
broken.push(`kernel:${kernelId} \u2192 rules/${kernelId}.md missing`);
|
|
5789
5465
|
}
|
|
5790
5466
|
}
|
|
@@ -5792,7 +5468,7 @@ function _check_router_pointers(packageRoot = PACKAGE_ROOT) {
|
|
|
5792
5468
|
for (const entry of router[tier] ?? []) {
|
|
5793
5469
|
const ruleId = String(entry["id"] ?? "");
|
|
5794
5470
|
ids += 1;
|
|
5795
|
-
if (!
|
|
5471
|
+
if (!fs13.existsSync(path13.join(rulesDir, `${ruleId}.md`))) {
|
|
5796
5472
|
broken.push(`${tier}:${ruleId} \u2192 rules/${ruleId}.md missing`);
|
|
5797
5473
|
}
|
|
5798
5474
|
for (const target of entry["routes_to"] ?? []) {
|
|
@@ -5802,7 +5478,7 @@ function _check_router_pointers(packageRoot = PACKAGE_ROOT) {
|
|
|
5802
5478
|
broken.push(`${ruleId} \u2192 unparseable routes_to ${JSON.stringify(target)}`);
|
|
5803
5479
|
continue;
|
|
5804
5480
|
}
|
|
5805
|
-
if (!candidates.some((rel) =>
|
|
5481
|
+
if (!candidates.some((rel) => fs13.existsSync(path13.join(packageRoot, rel)))) {
|
|
5806
5482
|
broken.push(`${ruleId} \u2192 ${target} (${candidates[0]} missing)`);
|
|
5807
5483
|
}
|
|
5808
5484
|
}
|
|
@@ -5834,9 +5510,9 @@ function detectSmokePlatform(projectRoot) {
|
|
|
5834
5510
|
return "claude";
|
|
5835
5511
|
}
|
|
5836
5512
|
function dispatcherRunner(packageRoot) {
|
|
5837
|
-
const localTsx =
|
|
5838
|
-
const script =
|
|
5839
|
-
if (
|
|
5513
|
+
const localTsx = path13.join(packageRoot, "node_modules", ".bin", "tsx");
|
|
5514
|
+
const script = path13.join(packageRoot, "src", "scripts", "hooks", "dispatch_hook.ts");
|
|
5515
|
+
if (fs13.existsSync(localTsx)) {
|
|
5840
5516
|
return [localTsx, script];
|
|
5841
5517
|
}
|
|
5842
5518
|
return ["npx", "tsx", script];
|
|
@@ -5886,12 +5562,12 @@ function _check_hook_dispatcher(projectRoot, packageRoot = PACKAGE_ROOT, opts =
|
|
|
5886
5562
|
};
|
|
5887
5563
|
}
|
|
5888
5564
|
function readSettingsMode(projectRoot) {
|
|
5889
|
-
const settingsPath =
|
|
5890
|
-
if (!
|
|
5565
|
+
const settingsPath = path13.join(projectRoot, ".agent-settings.yml");
|
|
5566
|
+
if (!fs13.existsSync(settingsPath)) {
|
|
5891
5567
|
return "eager-all";
|
|
5892
5568
|
}
|
|
5893
5569
|
try {
|
|
5894
|
-
const parsed = YAML.parse(
|
|
5570
|
+
const parsed = YAML.parse(fs13.readFileSync(settingsPath, "utf8"));
|
|
5895
5571
|
const lean = parsed?.["lean_projection"] ?? null;
|
|
5896
5572
|
const mode = lean?.["mode"];
|
|
5897
5573
|
return typeof mode === "string" && mode.length > 0 ? mode : "eager-all";
|
|
@@ -5902,7 +5578,7 @@ function readSettingsMode(projectRoot) {
|
|
|
5902
5578
|
function kernelIdsFromRouter(packageRoot) {
|
|
5903
5579
|
try {
|
|
5904
5580
|
const router = JSON.parse(
|
|
5905
|
-
|
|
5581
|
+
fs13.readFileSync(path13.join(packageRoot, "dist", "router.json"), "utf8")
|
|
5906
5582
|
);
|
|
5907
5583
|
return new Set((router["kernel"] ?? []).map(String));
|
|
5908
5584
|
} catch {
|
|
@@ -5919,8 +5595,8 @@ function _check_lean_projection(projectRoot, packageRoot = PACKAGE_ROOT, project
|
|
|
5919
5595
|
remedy: "set lean_projection.mode to 'eager-all' or 'thin' in .agent-settings.yml"
|
|
5920
5596
|
};
|
|
5921
5597
|
}
|
|
5922
|
-
const rulesDir = projectedRulesDir ??
|
|
5923
|
-
if (!
|
|
5598
|
+
const rulesDir = projectedRulesDir ?? path13.join(projectRoot, ".augment", "rules");
|
|
5599
|
+
if (!fs13.existsSync(rulesDir)) {
|
|
5924
5600
|
return {
|
|
5925
5601
|
id: "lean-projection",
|
|
5926
5602
|
status: "skipped",
|
|
@@ -5929,7 +5605,7 @@ function _check_lean_projection(projectRoot, packageRoot = PACKAGE_ROOT, project
|
|
|
5929
5605
|
};
|
|
5930
5606
|
}
|
|
5931
5607
|
const kernel = kernelIdsFromRouter(packageRoot);
|
|
5932
|
-
const files =
|
|
5608
|
+
const files = fs13.readdirSync(rulesDir).filter((f) => f.endsWith(".md") && f !== "INDEX.md").sort();
|
|
5933
5609
|
const nonKernel = files.filter((f) => !kernel.has(f.replace(/\.md$/, "")));
|
|
5934
5610
|
if (nonKernel.length === 0) {
|
|
5935
5611
|
return {
|
|
@@ -5943,7 +5619,7 @@ function _check_lean_projection(projectRoot, packageRoot = PACKAGE_ROOT, project
|
|
|
5943
5619
|
for (const f of nonKernel) {
|
|
5944
5620
|
let text = "";
|
|
5945
5621
|
try {
|
|
5946
|
-
text =
|
|
5622
|
+
text = fs13.readFileSync(path13.join(rulesDir, f), "utf8");
|
|
5947
5623
|
} catch {
|
|
5948
5624
|
continue;
|
|
5949
5625
|
}
|
|
@@ -5974,8 +5650,8 @@ function _check_lean_projection(projectRoot, packageRoot = PACKAGE_ROOT, project
|
|
|
5974
5650
|
function _check_host_manifest(projectRoot) {
|
|
5975
5651
|
const detected = Object.entries(detectToolPresence(projectRoot)).filter(([, v]) => v === true).map(([k]) => k);
|
|
5976
5652
|
const detectedNote = detected.length > 0 ? `detected surfaces: ${detected.join(", ")}` : "no surfaces detected";
|
|
5977
|
-
const settingsPath =
|
|
5978
|
-
if (!
|
|
5653
|
+
const settingsPath = path13.join(projectRoot, ".agent-settings.yml");
|
|
5654
|
+
if (!fs13.existsSync(settingsPath)) {
|
|
5979
5655
|
return {
|
|
5980
5656
|
id: "host-manifest",
|
|
5981
5657
|
status: "ok",
|
|
@@ -5985,7 +5661,7 @@ function _check_host_manifest(projectRoot) {
|
|
|
5985
5661
|
}
|
|
5986
5662
|
let parsed = null;
|
|
5987
5663
|
try {
|
|
5988
|
-
parsed = YAML.parse(
|
|
5664
|
+
parsed = YAML.parse(fs13.readFileSync(settingsPath, "utf8"));
|
|
5989
5665
|
} catch (exc) {
|
|
5990
5666
|
return {
|
|
5991
5667
|
id: "host-manifest",
|
|
@@ -6084,7 +5760,7 @@ function _parse(argv) {
|
|
|
6084
5760
|
}
|
|
6085
5761
|
return opts;
|
|
6086
5762
|
}
|
|
6087
|
-
function
|
|
5763
|
+
function main13(argv = null) {
|
|
6088
5764
|
const opts = _parse(argv !== null ? Array.from(argv) : process6.argv.slice(2));
|
|
6089
5765
|
if (opts.funnel) {
|
|
6090
5766
|
print(render5(buildFunnel()));
|
|
@@ -6155,25 +5831,25 @@ function main14(argv = null) {
|
|
|
6155
5831
|
}
|
|
6156
5832
|
return failed ? 1 : 0;
|
|
6157
5833
|
}
|
|
6158
|
-
function
|
|
5834
|
+
function _isCliEntry12() {
|
|
6159
5835
|
if (process6.argv[1] === void 0) {
|
|
6160
5836
|
return false;
|
|
6161
5837
|
}
|
|
6162
|
-
const argvUrl =
|
|
5838
|
+
const argvUrl = pathToFileURL13(path13.resolve(process6.argv[1])).href;
|
|
6163
5839
|
if (import.meta.url === argvUrl) {
|
|
6164
5840
|
return true;
|
|
6165
5841
|
}
|
|
6166
5842
|
try {
|
|
6167
|
-
const here =
|
|
6168
|
-
const argv =
|
|
5843
|
+
const here = fs13.realpathSync(fileURLToPath13(import.meta.url));
|
|
5844
|
+
const argv = fs13.realpathSync(path13.resolve(process6.argv[1]));
|
|
6169
5845
|
return here === argv;
|
|
6170
5846
|
} catch {
|
|
6171
5847
|
return false;
|
|
6172
5848
|
}
|
|
6173
5849
|
}
|
|
6174
|
-
if (
|
|
5850
|
+
if (_isCliEntry12() || process6.argv[1] === _HERE5) {
|
|
6175
5851
|
try {
|
|
6176
|
-
process6.exitCode =
|
|
5852
|
+
process6.exitCode = main13(process6.argv.slice(2));
|
|
6177
5853
|
} catch (e) {
|
|
6178
5854
|
if (e instanceof ArgparseExit) {
|
|
6179
5855
|
process6.exitCode = e.code;
|
|
@@ -6196,7 +5872,7 @@ export {
|
|
|
6196
5872
|
conformanceLogPath,
|
|
6197
5873
|
detectSmokePlatform,
|
|
6198
5874
|
installLogPath,
|
|
6199
|
-
|
|
5875
|
+
main13 as main,
|
|
6200
5876
|
routeTargetPaths,
|
|
6201
5877
|
runConformanceChecks
|
|
6202
5878
|
};
|