@event4u/agent-config 10.3.0 → 11.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +147 -0
- package/README.md +1 -1
- package/dist/agent-src/commands/analyze.md +2 -1
- package/dist/agent-src/commands/council/debate.md +13 -4
- package/dist/agent-src/commands/council/default.md +26 -11
- package/dist/agent-src/commands/council.md +1 -1
- package/dist/agent-src/commands/design-system/capture.md +44 -0
- package/dist/agent-src/commands/design-system/generate.md +75 -0
- package/dist/agent-src/commands/design-system/import.md +63 -0
- package/dist/agent-src/commands/design-system.md +66 -0
- package/dist/agent-src/commands/pr/create.md +51 -26
- package/dist/agent-src/commands/worktree/create.md +5 -3
- package/dist/agent-src/rules/settings-ask-protocol.md +14 -9
- package/dist/agent-src/skills/ai-council/SKILL.md +24 -6
- package/dist/agent-src/skills/corpus-grounding/SKILL.md +12 -1
- package/dist/agent-src/skills/corpus-grounding/scripts/decision_engine.ts +215 -7
- package/dist/agent-src/skills/corpus-grounding/scripts/ground.ts +39 -1
- package/dist/agent-src/skills/design-intelligence/ATTRIBUTION.md +19 -2
- package/dist/agent-src/skills/design-intelligence/data/manifest.json +36 -1
- package/dist/agent-src/skills/design-intelligence/data/motion.csv +17 -0
- package/dist/agent-src/skills/design-system-capture/SKILL.md +9 -0
- package/dist/agent-src/skills/design-system-capture/references/design-system-json.md +70 -0
- package/dist/agent-src/skills/git-workflow/SKILL.md +9 -3
- package/dist/agent-src/skills/subagent-orchestration/SKILL.md +9 -6
- package/dist/agent-src/skills/using-git-worktrees/SKILL.md +25 -21
- package/dist/agent-src/templates/agent-settings.md +0 -1
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/scripts/work_engine/directives/ui/design.ts +4 -1
- package/dist/cli-delegate/{chunk-BV3WR67D.js → chunk-55WZN5VF.js} +3 -6
- package/dist/cli-delegate/{chunk-X3VOARZD.js → chunk-L565YFXH.js} +3 -3
- package/dist/cli-delegate/{chunk-JMQZ7MM5.js → chunk-MNWRDMR5.js} +1 -1
- package/dist/cli-delegate/{chunk-IR3IVRVC.js → chunk-NLP54U3J.js} +2 -1
- package/dist/cli-delegate/{chunk-FV34EGEX.js → chunk-NN4KW4HZ.js} +1 -1
- package/dist/cli-delegate/{chunk-6ENSXSBW.js → chunk-PPQO4NGR.js} +1 -1
- package/dist/cli-delegate/chunk-RLN73PR5.js +157 -0
- package/dist/cli-delegate/{chunk-6LOPHJLD.js → chunk-RYNADUFG.js} +1 -1
- package/dist/cli-delegate/{chunk-I5EAFRII.js → chunk-ZPSXJTLI.js} +2 -154
- package/dist/cli-delegate/cmd_analyze_session.js +1 -1
- package/dist/cli-delegate/cmd_brand_status.js +1 -1
- package/dist/cli-delegate/cmd_conformance.js +673 -215
- package/dist/cli-delegate/cmd_doctor.js +2 -2
- package/dist/cli-delegate/cmd_explain.js +2 -2
- package/dist/cli-delegate/cmd_export.js +4 -4
- package/dist/cli-delegate/cmd_handoff.js +10 -8
- package/dist/cli-delegate/cmd_mcp_available.js +1 -1
- package/dist/cli-delegate/cmd_migrate.js +2 -2
- package/dist/cli-delegate/cmd_packs_active.js +2 -2
- package/dist/cli-delegate/cmd_prune.js +4 -4
- package/dist/cli-delegate/cmd_route_audit.js +2 -2
- package/dist/cli-delegate/cmd_route_explain.js +1 -1
- package/dist/cli-delegate/cmd_session_recycle.js +6 -4
- package/dist/cli-delegate/cmd_settings_get.js +1 -1
- package/dist/cli-delegate/cmd_settings_migrate.js +4 -4
- package/dist/cli-delegate/cmd_settings_set.js +1 -1
- package/dist/cli-delegate/cmd_sync.js +4 -4
- package/dist/cli-delegate/cmd_uninstall.js +4 -4
- package/dist/cli-delegate/cmd_update.js +1 -1
- package/dist/cli-delegate/cmd_upgrade.js +1 -1
- package/dist/cli-delegate/cmd_validate.js +4 -4
- package/dist/cli-delegate/cmd_versions.js +1 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +127 -22
- 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 +9 -5
- package/dist/discovery/trust-report.md +2 -2
- package/dist/discovery/workspaces.json +8 -4
- package/dist/hooks/dispatch.js +994 -399
- package/dist/install/install.mjs +5 -7
- package/dist/mcp/registry-manifest.json +2 -2
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +1104 -593
- package/dist/scripts/_lib/agent_settings.js +8 -0
- package/dist/scripts/_lib/agent_settings.js.map +1 -1
- package/dist/server/schemas/settings.js +3 -4
- package/dist/server/schemas/settings.js.map +1 -1
- package/dist/ui/assets/{index-5fXOHoVh.js → index-B0aMJnuz.js} +2 -2
- package/dist/ui/assets/{index-5fXOHoVh.js.map → index-B0aMJnuz.js.map} +1 -1
- package/dist/ui/index.html +1 -1
- package/docs/contracts/settings-classes.md +12 -9
- package/package.json +1 -1
- package/src/agent-src/templates/scripts/work_engine/directives/ui/design.ts +4 -1
- package/src/config/agent-settings.template.yml +15 -18
- package/src/config/gate-coverage.yml +33 -2
- package/src/config/gate-violation-baselines.json +2 -2
- package/src/config/pack-size-budget.json +3 -2
- package/src/scripts/_lib/agent_settings.ts +8 -0
- package/src/scripts/_lib/design_system_import.ts +987 -0
- package/src/scripts/check_branch_freshness.ts +238 -6
- package/src/scripts/design_system_import.ts +264 -0
- package/src/scripts/external_sources_denylist.json +7 -2
- package/src/scripts/hook_manifest.yaml +71 -2
- package/src/scripts/hooks/concern_registry.ts +4 -0
- package/src/scripts/hooks/dispatch_hook.ts +10 -0
- package/src/scripts/hooks/host_semantics.ts +2 -0
- package/src/scripts/hooks/spawn_guard_shadow_hook.ts +212 -0
- package/src/scripts/hooks/subagent_ledger_hook.ts +723 -0
- package/src/scripts/hooks/turn_end_gate_hook.ts +39 -2
- package/src/scripts/lint_hook_manifest.ts +2 -0
- package/src/scripts/lint_rule_skill_pack_reach.ts +194 -13
- package/src/scripts/session_register_hook.ts +120 -10
- package/src/server/schemas/settings.ts +3 -6
- package/tests/fixtures/hooks/subagent_start.json +7 -0
- package/tests/fixtures/hooks/subagent_stop.json +8 -0
|
@@ -2,6 +2,9 @@ import { createRequire as __acCreateRequire } from 'node:module'; const require
|
|
|
2
2
|
import {
|
|
3
3
|
readHookStdin
|
|
4
4
|
} from "./chunk-MMJL4TIX.js";
|
|
5
|
+
import {
|
|
6
|
+
validateAssumption
|
|
7
|
+
} from "./chunk-ZPSXJTLI.js";
|
|
5
8
|
import {
|
|
6
9
|
ArgparseExit,
|
|
7
10
|
STATUS_SYMBOLS,
|
|
@@ -20,7 +23,7 @@ import {
|
|
|
20
23
|
proseEqual,
|
|
21
24
|
resolveSessionRole,
|
|
22
25
|
splitFrontmatter
|
|
23
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-NN4KW4HZ.js";
|
|
24
27
|
import "./chunk-FTAISGDQ.js";
|
|
25
28
|
import {
|
|
26
29
|
atomic_write_json,
|
|
@@ -42,7 +45,7 @@ import "./chunk-GRRPEPRN.js";
|
|
|
42
45
|
import "./chunk-NXFWFAYV.js";
|
|
43
46
|
import {
|
|
44
47
|
load_agent_settings
|
|
45
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-NLP54U3J.js";
|
|
46
49
|
import "./chunk-NDJLNC6Q.js";
|
|
47
50
|
import {
|
|
48
51
|
detectToolPresence
|
|
@@ -59,12 +62,12 @@ import {
|
|
|
59
62
|
|
|
60
63
|
// src/scripts/_cli/cmd_conformance.ts
|
|
61
64
|
var YAML = __toESM(require_dist(), 1);
|
|
62
|
-
import * as
|
|
65
|
+
import * as fs15 from "node:fs";
|
|
63
66
|
import * as os7 from "node:os";
|
|
64
|
-
import * as
|
|
67
|
+
import * as path15 from "node:path";
|
|
65
68
|
import process6 from "node:process";
|
|
66
69
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
67
|
-
import { fileURLToPath as
|
|
70
|
+
import { fileURLToPath as fileURLToPath15, pathToFileURL as pathToFileURL15 } from "node:url";
|
|
68
71
|
|
|
69
72
|
// src/install/txlog.ts
|
|
70
73
|
import { createReadStream, createWriteStream, existsSync, readFileSync, renameSync, statSync, unlinkSync } from "node:fs";
|
|
@@ -125,18 +128,18 @@ function routeTargetPathsPosix(target) {
|
|
|
125
128
|
}
|
|
126
129
|
|
|
127
130
|
// src/scripts/report_conformance_funnel.ts
|
|
128
|
-
import * as
|
|
131
|
+
import * as fs14 from "node:fs";
|
|
129
132
|
import * as os6 from "node:os";
|
|
130
|
-
import * as
|
|
133
|
+
import * as path14 from "node:path";
|
|
131
134
|
import process5 from "node:process";
|
|
132
|
-
import { fileURLToPath as
|
|
135
|
+
import { fileURLToPath as fileURLToPath14, pathToFileURL as pathToFileURL14 } from "node:url";
|
|
133
136
|
|
|
134
137
|
// src/scripts/conformance_scan.ts
|
|
135
|
-
import { createHash as
|
|
136
|
-
import
|
|
138
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
139
|
+
import fs10 from "node:fs";
|
|
137
140
|
import os2 from "node:os";
|
|
138
|
-
import
|
|
139
|
-
import { fileURLToPath as
|
|
141
|
+
import path10 from "node:path";
|
|
142
|
+
import { fileURLToPath as fileURLToPath10, pathToFileURL as pathToFileURL10 } from "node:url";
|
|
140
143
|
|
|
141
144
|
// src/scripts/_lib/transcript_entry.ts
|
|
142
145
|
function _isObject(v) {
|
|
@@ -1339,10 +1342,10 @@ if (isCliEntry) {
|
|
|
1339
1342
|
}
|
|
1340
1343
|
|
|
1341
1344
|
// src/scripts/hooks/turn_end_gate_hook.ts
|
|
1342
|
-
import * as
|
|
1343
|
-
import * as
|
|
1344
|
-
import * as
|
|
1345
|
-
import { fileURLToPath as
|
|
1345
|
+
import * as crypto3 from "node:crypto";
|
|
1346
|
+
import * as fs7 from "node:fs";
|
|
1347
|
+
import * as path7 from "node:path";
|
|
1348
|
+
import { fileURLToPath as fileURLToPath7, pathToFileURL as pathToFileURL7 } from "node:url";
|
|
1346
1349
|
|
|
1347
1350
|
// src/scripts/hooks/end_review_nudge_hook.ts
|
|
1348
1351
|
import { spawnSync } from "node:child_process";
|
|
@@ -1710,9 +1713,456 @@ if (_isCliEntry5()) {
|
|
|
1710
1713
|
process.exit(main5());
|
|
1711
1714
|
}
|
|
1712
1715
|
|
|
1716
|
+
// src/scripts/hooks/subagent_ledger_hook.ts
|
|
1717
|
+
import * as crypto2 from "node:crypto";
|
|
1718
|
+
import * as fs6 from "node:fs";
|
|
1719
|
+
import * as path6 from "node:path";
|
|
1720
|
+
import { fileURLToPath as fileURLToPath6, pathToFileURL as pathToFileURL6 } from "node:url";
|
|
1721
|
+
|
|
1722
|
+
// src/scripts/_lib/subagent_response.ts
|
|
1723
|
+
var MAX_SUMMARY_CHARS = 2e3;
|
|
1724
|
+
var MAX_RESPONSE_LINE_CHARS = 240;
|
|
1725
|
+
var MAX_RESPONSE_ENTRIES = 40;
|
|
1726
|
+
var MAX_ARTIFACT_REF_CHARS = 200;
|
|
1727
|
+
var MAX_ENVELOPE_CHARS = 12e3;
|
|
1728
|
+
var CONFIDENCE = /* @__PURE__ */ new Set(["low", "medium", "high"]);
|
|
1729
|
+
function validateResponse(input) {
|
|
1730
|
+
const errors = [];
|
|
1731
|
+
if (input === null || typeof input !== "object") {
|
|
1732
|
+
return { valid: false, errors: ["response is not an object"] };
|
|
1733
|
+
}
|
|
1734
|
+
const r = input;
|
|
1735
|
+
if (typeof r.summary !== "string") errors.push("summary missing or not a string");
|
|
1736
|
+
if (typeof r.handoff !== "string") errors.push("handoff missing or not a string");
|
|
1737
|
+
if (!CONFIDENCE.has(r.confidence)) errors.push(`confidence must be low|medium|high (got ${String(r.confidence)})`);
|
|
1738
|
+
if (!Array.isArray(r.findings)) errors.push("findings missing or not an array");
|
|
1739
|
+
if (!Array.isArray(r.risks)) errors.push("risks missing or not an array");
|
|
1740
|
+
if (Array.isArray(r.findings)) {
|
|
1741
|
+
for (const [i, f] of r.findings.entries()) {
|
|
1742
|
+
if (!f || typeof f.title !== "string") errors.push(`finding[${i}] missing title`);
|
|
1743
|
+
const refs = f?.evidence_refs;
|
|
1744
|
+
if (refs && refs.some((x) => typeof x !== "string" || x.includes("\n"))) {
|
|
1745
|
+
errors.push(`finding[${i}] evidence_refs must be ref tokens, not bodies`);
|
|
1746
|
+
}
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1749
|
+
if (r.assumptions !== void 0) {
|
|
1750
|
+
if (!Array.isArray(r.assumptions)) {
|
|
1751
|
+
errors.push("assumptions must be an array of {statement, basis, epistemic_state}");
|
|
1752
|
+
} else {
|
|
1753
|
+
for (const [i, a] of r.assumptions.entries()) {
|
|
1754
|
+
errors.push(...validateAssumption(a, `assumptions[${i}]`));
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1757
|
+
}
|
|
1758
|
+
if (typeof r.summary === "string" && r.summary.length > MAX_SUMMARY_CHARS) {
|
|
1759
|
+
errors.push(`summary is ${r.summary.length} chars (max ${MAX_SUMMARY_CHARS}) \u2014 the envelope carries a bounded summary; the full result belongs on disk (artifact_paths)`);
|
|
1760
|
+
}
|
|
1761
|
+
if (typeof r.handoff === "string" && r.handoff.length > MAX_RESPONSE_LINE_CHARS) {
|
|
1762
|
+
errors.push(`handoff is ${r.handoff.length} chars (max ${MAX_RESPONSE_LINE_CHARS})`);
|
|
1763
|
+
}
|
|
1764
|
+
for (const [key, arr] of [
|
|
1765
|
+
["findings", r.findings],
|
|
1766
|
+
["risks", r.risks],
|
|
1767
|
+
["artifact_paths", r.artifact_paths]
|
|
1768
|
+
]) {
|
|
1769
|
+
if (Array.isArray(arr) && arr.length > MAX_RESPONSE_ENTRIES) {
|
|
1770
|
+
errors.push(`${key} carries ${arr.length} entries (max ${MAX_RESPONSE_ENTRIES}) \u2014 an envelope is a handoff, not a transcript`);
|
|
1771
|
+
}
|
|
1772
|
+
}
|
|
1773
|
+
if (Array.isArray(r.risks)) {
|
|
1774
|
+
for (const [i, risk] of r.risks.entries()) {
|
|
1775
|
+
if (typeof risk === "string" && risk.length > MAX_RESPONSE_LINE_CHARS) {
|
|
1776
|
+
errors.push(`risks[${i}] is ${risk.length} chars (max ${MAX_RESPONSE_LINE_CHARS})`);
|
|
1777
|
+
}
|
|
1778
|
+
}
|
|
1779
|
+
}
|
|
1780
|
+
if (Array.isArray(r.findings)) {
|
|
1781
|
+
for (const [i, f] of r.findings.entries()) {
|
|
1782
|
+
if (f && typeof f.title === "string" && f.title.length > MAX_RESPONSE_LINE_CHARS) {
|
|
1783
|
+
errors.push(`finding[${i}] title is ${f.title.length} chars (max ${MAX_RESPONSE_LINE_CHARS})`);
|
|
1784
|
+
}
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1787
|
+
if (r.artifact_paths !== void 0) {
|
|
1788
|
+
if (!Array.isArray(r.artifact_paths)) {
|
|
1789
|
+
errors.push("artifact_paths must be an array of path ref tokens");
|
|
1790
|
+
} else {
|
|
1791
|
+
for (const [i, p] of r.artifact_paths.entries()) {
|
|
1792
|
+
if (typeof p !== "string" || p.includes("\n") || p.length > MAX_ARTIFACT_REF_CHARS) {
|
|
1793
|
+
errors.push(`artifact_paths[${i}] must be a single-line path ref \u2264 ${MAX_ARTIFACT_REF_CHARS} chars`);
|
|
1794
|
+
}
|
|
1795
|
+
}
|
|
1796
|
+
}
|
|
1797
|
+
}
|
|
1798
|
+
try {
|
|
1799
|
+
const serialized = JSON.stringify(input);
|
|
1800
|
+
if (serialized.length > MAX_ENVELOPE_CHARS) {
|
|
1801
|
+
errors.push(`envelope serializes to ${serialized.length} chars (max ${MAX_ENVELOPE_CHARS}) \u2014 move content to disk and reference it via artifact_paths`);
|
|
1802
|
+
}
|
|
1803
|
+
} catch {
|
|
1804
|
+
errors.push("envelope is not JSON-serializable");
|
|
1805
|
+
}
|
|
1806
|
+
return { valid: errors.length === 0, errors };
|
|
1807
|
+
}
|
|
1808
|
+
|
|
1809
|
+
// src/scripts/hooks/subagent_ledger_hook.ts
|
|
1810
|
+
var EXIT_ALLOW4 = 0;
|
|
1811
|
+
function isObject2(v) {
|
|
1812
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
1813
|
+
}
|
|
1814
|
+
var LEDGER_DIR = path6.join("agents", "runtime", "state", "subagent-ledger");
|
|
1815
|
+
var OPEN_SUBDIR = "open";
|
|
1816
|
+
var OPEN_RECORD_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
1817
|
+
function refFor(agentId) {
|
|
1818
|
+
return crypto2.createHash("sha256").update(agentId, "utf8").digest("hex").slice(0, 12);
|
|
1819
|
+
}
|
|
1820
|
+
function unwrapPayload(envelope) {
|
|
1821
|
+
const inner = envelope["payload"];
|
|
1822
|
+
return isObject2(inner) ? inner : envelope;
|
|
1823
|
+
}
|
|
1824
|
+
function str2(payload, ...keys) {
|
|
1825
|
+
for (const k of keys) {
|
|
1826
|
+
const v = payload[k];
|
|
1827
|
+
if (typeof v === "string" && v) return v;
|
|
1828
|
+
}
|
|
1829
|
+
return null;
|
|
1830
|
+
}
|
|
1831
|
+
function extractParentId(payload, ownId) {
|
|
1832
|
+
const explicit = str2(payload, "parent_agent_id", "parentAgentId");
|
|
1833
|
+
if (explicit) return explicit;
|
|
1834
|
+
const session = payload["session"];
|
|
1835
|
+
if (isObject2(session)) {
|
|
1836
|
+
const sessionAgent = str2(session, "agent_id", "agentId");
|
|
1837
|
+
if (sessionAgent && sessionAgent !== ownId) return sessionAgent;
|
|
1838
|
+
}
|
|
1839
|
+
return null;
|
|
1840
|
+
}
|
|
1841
|
+
function classifyEnvelope(message) {
|
|
1842
|
+
if (message === null || !message.trim()) return { verdict: "absent", error_count: 0 };
|
|
1843
|
+
const candidates = _jsonObjectCandidates(message);
|
|
1844
|
+
if (candidates.length === 0) return { verdict: "absent", error_count: 0 };
|
|
1845
|
+
let best = null;
|
|
1846
|
+
for (const candidate of candidates) {
|
|
1847
|
+
const result = validateResponse(candidate);
|
|
1848
|
+
if (result.valid) return { verdict: "ok", error_count: 0 };
|
|
1849
|
+
if (best === null) best = { verdict: "fail", error_count: result.errors.length };
|
|
1850
|
+
}
|
|
1851
|
+
return best ?? { verdict: "absent", error_count: 0 };
|
|
1852
|
+
}
|
|
1853
|
+
function _jsonObjectCandidates(message) {
|
|
1854
|
+
const texts = [];
|
|
1855
|
+
for (const match of message.matchAll(/^[ \t]*```[ \t]*(?:json)?[ \t]*\r?\n([\s\S]*?)^[ \t]*```/gm)) {
|
|
1856
|
+
if (match[1]) texts.push(match[1]);
|
|
1857
|
+
}
|
|
1858
|
+
let depth = 0;
|
|
1859
|
+
let start = -1;
|
|
1860
|
+
let inString = false;
|
|
1861
|
+
let escaped = false;
|
|
1862
|
+
for (let i = 0; i < message.length; i++) {
|
|
1863
|
+
const ch = message[i];
|
|
1864
|
+
if (inString) {
|
|
1865
|
+
if (escaped) escaped = false;
|
|
1866
|
+
else if (ch === "\\") escaped = true;
|
|
1867
|
+
else if (ch === '"') inString = false;
|
|
1868
|
+
continue;
|
|
1869
|
+
}
|
|
1870
|
+
if (ch === '"') inString = true;
|
|
1871
|
+
else if (ch === "{") {
|
|
1872
|
+
if (depth === 0) start = i;
|
|
1873
|
+
depth++;
|
|
1874
|
+
} else if (ch === "}") {
|
|
1875
|
+
if (depth > 0) {
|
|
1876
|
+
depth--;
|
|
1877
|
+
if (depth === 0 && start !== -1) {
|
|
1878
|
+
texts.push(message.slice(start, i + 1));
|
|
1879
|
+
start = -1;
|
|
1880
|
+
}
|
|
1881
|
+
}
|
|
1882
|
+
}
|
|
1883
|
+
}
|
|
1884
|
+
const out = [];
|
|
1885
|
+
for (const text of texts) {
|
|
1886
|
+
try {
|
|
1887
|
+
const parsed = JSON.parse(text.trim());
|
|
1888
|
+
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) out.push(parsed);
|
|
1889
|
+
} catch {
|
|
1890
|
+
}
|
|
1891
|
+
}
|
|
1892
|
+
return out;
|
|
1893
|
+
}
|
|
1894
|
+
function openDir(root) {
|
|
1895
|
+
return path6.join(root, LEDGER_DIR, OPEN_SUBDIR);
|
|
1896
|
+
}
|
|
1897
|
+
function openFile(root, ref) {
|
|
1898
|
+
return path6.join(openDir(root), `${ref}.json`);
|
|
1899
|
+
}
|
|
1900
|
+
var DEPTH_BASES = /* @__PURE__ */ new Set(["observed", "asserted-parent", "assumed-root"]);
|
|
1901
|
+
function _asOpenRecord(value, expectedRef) {
|
|
1902
|
+
if (!isObject2(value)) return null;
|
|
1903
|
+
const ref = value["ref"];
|
|
1904
|
+
if (typeof ref !== "string" || ref !== expectedRef) return null;
|
|
1905
|
+
if (typeof value["started_at"] !== "string") return null;
|
|
1906
|
+
if (typeof value["depth"] !== "number" || !Number.isFinite(value["depth"])) return null;
|
|
1907
|
+
if (typeof value["depth_basis"] !== "string" || !DEPTH_BASES.has(value["depth_basis"])) return null;
|
|
1908
|
+
const agentType = value["agent_type"];
|
|
1909
|
+
const parentRef = value["parent_ref"];
|
|
1910
|
+
const sessionId = value["session_id"];
|
|
1911
|
+
return {
|
|
1912
|
+
ref,
|
|
1913
|
+
agent_type: typeof agentType === "string" ? agentType : null,
|
|
1914
|
+
started_at: value["started_at"],
|
|
1915
|
+
parent_ref: typeof parentRef === "string" ? parentRef : null,
|
|
1916
|
+
depth: value["depth"],
|
|
1917
|
+
depth_basis: value["depth_basis"],
|
|
1918
|
+
session_id: typeof sessionId === "string" ? sessionId : null
|
|
1919
|
+
};
|
|
1920
|
+
}
|
|
1921
|
+
function readOpenRecords(root) {
|
|
1922
|
+
const out = /* @__PURE__ */ new Map();
|
|
1923
|
+
let names;
|
|
1924
|
+
try {
|
|
1925
|
+
names = fs6.readdirSync(openDir(root));
|
|
1926
|
+
} catch {
|
|
1927
|
+
return out;
|
|
1928
|
+
}
|
|
1929
|
+
for (const name of names) {
|
|
1930
|
+
if (!name.endsWith(".json")) continue;
|
|
1931
|
+
const expectedRef = name.slice(0, -".json".length);
|
|
1932
|
+
try {
|
|
1933
|
+
const raw = fs6.readFileSync(path6.join(openDir(root), name), "utf8");
|
|
1934
|
+
const rec = _asOpenRecord(JSON.parse(raw), expectedRef);
|
|
1935
|
+
if (rec) out.set(rec.ref, rec);
|
|
1936
|
+
} catch {
|
|
1937
|
+
}
|
|
1938
|
+
}
|
|
1939
|
+
return out;
|
|
1940
|
+
}
|
|
1941
|
+
function resolveDepth(parentRef, open) {
|
|
1942
|
+
if (parentRef === null) return { depth: 1, depth_basis: "assumed-root" };
|
|
1943
|
+
const parent = open.get(parentRef);
|
|
1944
|
+
if (!parent) return { depth: 2, depth_basis: "asserted-parent" };
|
|
1945
|
+
return { depth: parent.depth + 1, depth_basis: "observed" };
|
|
1946
|
+
}
|
|
1947
|
+
function ledgerFileFor(root, ts) {
|
|
1948
|
+
return path6.join(root, LEDGER_DIR, `${ts.slice(0, 7)}.jsonl`);
|
|
1949
|
+
}
|
|
1950
|
+
function appendLedgerLine(root, ts, line) {
|
|
1951
|
+
if (is_replay_mode()) return;
|
|
1952
|
+
const file = ledgerFileFor(root, ts);
|
|
1953
|
+
fs6.mkdirSync(path6.dirname(file), { recursive: true });
|
|
1954
|
+
fs6.appendFileSync(file, `${JSON.stringify(line)}
|
|
1955
|
+
`, "utf8");
|
|
1956
|
+
}
|
|
1957
|
+
var WALL_CLOCK_ARMS_MS = [
|
|
1958
|
+
{ label: "5m", ms: 5 * 60 * 1e3 },
|
|
1959
|
+
{ label: "15m", ms: 15 * 60 * 1e3 },
|
|
1960
|
+
{ label: "30m", ms: 30 * 60 * 1e3 },
|
|
1961
|
+
{ label: "2h", ms: 2 * 60 * 60 * 1e3 }
|
|
1962
|
+
];
|
|
1963
|
+
function armsExceeded(elapsedMs) {
|
|
1964
|
+
if (elapsedMs === null || !Number.isFinite(elapsedMs)) return [];
|
|
1965
|
+
return WALL_CLOCK_ARMS_MS.filter((a) => elapsedMs >= a.ms).map((a) => a.label);
|
|
1966
|
+
}
|
|
1967
|
+
function openRecordStats(root, nowMs = Date.now()) {
|
|
1968
|
+
const ledgerPresent = fs6.existsSync(path6.join(root, LEDGER_DIR));
|
|
1969
|
+
const open = readOpenRecords(root);
|
|
1970
|
+
let maxDepth = 0;
|
|
1971
|
+
let counted = 0;
|
|
1972
|
+
let stale = 0;
|
|
1973
|
+
for (const rec of open.values()) {
|
|
1974
|
+
const started = Date.parse(rec.started_at);
|
|
1975
|
+
const isStale = Number.isFinite(started) && nowMs - started >= OPEN_RECORD_TTL_MS;
|
|
1976
|
+
if (isStale) {
|
|
1977
|
+
stale++;
|
|
1978
|
+
continue;
|
|
1979
|
+
}
|
|
1980
|
+
counted++;
|
|
1981
|
+
if (rec.depth > maxDepth) maxDepth = rec.depth;
|
|
1982
|
+
}
|
|
1983
|
+
return {
|
|
1984
|
+
open_count: counted,
|
|
1985
|
+
max_depth: maxDepth,
|
|
1986
|
+
stale_excluded: stale,
|
|
1987
|
+
ledger_present: ledgerPresent
|
|
1988
|
+
};
|
|
1989
|
+
}
|
|
1990
|
+
function writeOpenRecord(root, rec) {
|
|
1991
|
+
atomic_write_json(openFile(root, rec.ref), rec);
|
|
1992
|
+
}
|
|
1993
|
+
function removeOpenRecord(root, ref) {
|
|
1994
|
+
if (is_replay_mode()) return;
|
|
1995
|
+
try {
|
|
1996
|
+
fs6.unlinkSync(openFile(root, ref));
|
|
1997
|
+
} catch {
|
|
1998
|
+
}
|
|
1999
|
+
}
|
|
2000
|
+
function countOpen(root) {
|
|
2001
|
+
try {
|
|
2002
|
+
return fs6.readdirSync(openDir(root)).filter((n) => n.endsWith(".json")).length;
|
|
2003
|
+
} catch {
|
|
2004
|
+
return 0;
|
|
2005
|
+
}
|
|
2006
|
+
}
|
|
2007
|
+
function reapStaleOpenRecords(root, nowIso) {
|
|
2008
|
+
const now = Date.parse(nowIso);
|
|
2009
|
+
if (!Number.isFinite(now)) return 0;
|
|
2010
|
+
let reaped = 0;
|
|
2011
|
+
for (const rec of readOpenRecords(root).values()) {
|
|
2012
|
+
const started = Date.parse(rec.started_at);
|
|
2013
|
+
if (!Number.isFinite(started) || now - started < OPEN_RECORD_TTL_MS) continue;
|
|
2014
|
+
removeOpenRecord(root, rec.ref);
|
|
2015
|
+
reaped++;
|
|
2016
|
+
appendLedgerLine(root, nowIso, {
|
|
2017
|
+
event: "subagent_reaped",
|
|
2018
|
+
ts: nowIso,
|
|
2019
|
+
ref: rec.ref,
|
|
2020
|
+
agent_type: rec.agent_type,
|
|
2021
|
+
depth: rec.depth,
|
|
2022
|
+
depth_basis: rec.depth_basis,
|
|
2023
|
+
// R2 round 2, finding 5: the arm list is NOT repeated here. A reap
|
|
2024
|
+
// fires only past OPEN_RECORD_TTL_MS (24 h), which exceeds every
|
|
2025
|
+
// arm (largest: 2 h), so `stop_loss_arms_exceeded` would be a
|
|
2026
|
+
// constant on this line — a field that cannot vary answers no
|
|
2027
|
+
// question. `age_ms` carries strictly more information and is what
|
|
2028
|
+
// a reader should aggregate over.
|
|
2029
|
+
age_ms: now - started,
|
|
2030
|
+
reason: "open record exceeded OPEN_RECORD_TTL_MS without a stop"
|
|
2031
|
+
});
|
|
2032
|
+
}
|
|
2033
|
+
return reaped;
|
|
2034
|
+
}
|
|
2035
|
+
function appendUnidentified(root, event, nowIso, payload) {
|
|
2036
|
+
appendLedgerLine(root, nowIso, {
|
|
2037
|
+
event,
|
|
2038
|
+
ts: nowIso,
|
|
2039
|
+
ref: null,
|
|
2040
|
+
unidentified: true,
|
|
2041
|
+
// The agent TYPE is an id-shaped enum and may still be present; it is
|
|
2042
|
+
// the only thing salvageable from a payload with no id.
|
|
2043
|
+
agent_type: str2(payload, "agent_type", "agentType", "subagent_type", "subagentType"),
|
|
2044
|
+
reason: "payload carried no agent id \u2014 nothing to correlate start with stop"
|
|
2045
|
+
});
|
|
2046
|
+
}
|
|
2047
|
+
function handleStart(root, payload, nowIso, sessionId) {
|
|
2048
|
+
const agentId = str2(payload, "agent_id", "agentId");
|
|
2049
|
+
if (agentId === null) {
|
|
2050
|
+
appendUnidentified(root, "subagent_start", nowIso, payload);
|
|
2051
|
+
return;
|
|
2052
|
+
}
|
|
2053
|
+
const ref = refFor(agentId);
|
|
2054
|
+
const parentId = extractParentId(payload, agentId);
|
|
2055
|
+
const parentRef = parentId ? refFor(parentId) : null;
|
|
2056
|
+
const { depth, depth_basis } = resolveDepth(parentRef, readOpenRecords(root));
|
|
2057
|
+
const rec = {
|
|
2058
|
+
ref,
|
|
2059
|
+
agent_type: str2(payload, "agent_type", "agentType", "subagent_type", "subagentType"),
|
|
2060
|
+
started_at: nowIso,
|
|
2061
|
+
parent_ref: parentRef,
|
|
2062
|
+
depth,
|
|
2063
|
+
depth_basis,
|
|
2064
|
+
session_id: sessionId
|
|
2065
|
+
};
|
|
2066
|
+
writeOpenRecord(root, rec);
|
|
2067
|
+
appendLedgerLine(root, nowIso, {
|
|
2068
|
+
event: "subagent_start",
|
|
2069
|
+
ts: nowIso,
|
|
2070
|
+
ref,
|
|
2071
|
+
agent_type: rec.agent_type,
|
|
2072
|
+
parent_ref: parentRef,
|
|
2073
|
+
depth,
|
|
2074
|
+
depth_basis,
|
|
2075
|
+
concurrent_open: countOpen(root)
|
|
2076
|
+
});
|
|
2077
|
+
}
|
|
2078
|
+
function handleStop(root, payload, nowIso) {
|
|
2079
|
+
const agentId = str2(payload, "agent_id", "agentId");
|
|
2080
|
+
if (agentId === null) {
|
|
2081
|
+
appendUnidentified(root, "subagent_stop", nowIso, payload);
|
|
2082
|
+
return;
|
|
2083
|
+
}
|
|
2084
|
+
const ref = refFor(agentId);
|
|
2085
|
+
const rec = readOpenRecords(root).get(ref) ?? null;
|
|
2086
|
+
let durationMs = null;
|
|
2087
|
+
if (rec) {
|
|
2088
|
+
const started = Date.parse(rec.started_at);
|
|
2089
|
+
if (Number.isFinite(started)) durationMs = Math.max(0, Date.parse(nowIso) - started);
|
|
2090
|
+
}
|
|
2091
|
+
const parse2 = classifyEnvelope(str2(payload, "last_assistant_message", "lastAssistantMessage"));
|
|
2092
|
+
removeOpenRecord(root, ref);
|
|
2093
|
+
appendLedgerLine(root, nowIso, {
|
|
2094
|
+
event: "subagent_stop",
|
|
2095
|
+
ts: nowIso,
|
|
2096
|
+
ref,
|
|
2097
|
+
agent_type: rec?.agent_type ?? str2(payload, "agent_type", "agentType", "subagent_type", "subagentType"),
|
|
2098
|
+
depth: rec?.depth ?? null,
|
|
2099
|
+
depth_basis: rec?.depth_basis ?? null,
|
|
2100
|
+
// `null` = the matching start was never seen. That is a finding about
|
|
2101
|
+
// the instrument's own coverage and is recorded as such, not as 0.
|
|
2102
|
+
duration_ms: durationMs,
|
|
2103
|
+
// Phase 3 Step 3, shadow: which wall-clock arms this dispatch would
|
|
2104
|
+
// have tripped. Recorded, never acted on.
|
|
2105
|
+
stop_loss_arms_exceeded: armsExceeded(durationMs),
|
|
2106
|
+
start_seen: rec !== null,
|
|
2107
|
+
envelope_parse: parse2.verdict,
|
|
2108
|
+
envelope_error_count: parse2.error_count,
|
|
2109
|
+
concurrent_open: countOpen(root)
|
|
2110
|
+
});
|
|
2111
|
+
}
|
|
2112
|
+
function processEnvelope(envelope, consumerRoot) {
|
|
2113
|
+
try {
|
|
2114
|
+
if (!isObject2(envelope)) return EXIT_ALLOW4;
|
|
2115
|
+
const event = envelope["event"];
|
|
2116
|
+
if (event !== "subagent_start" && event !== "subagent_stop") return EXIT_ALLOW4;
|
|
2117
|
+
const payload = unwrapPayload(envelope);
|
|
2118
|
+
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
2119
|
+
const sessionId = str2(payload, "session_id", "sessionId") ?? str2(envelope, "session_id", "sessionId");
|
|
2120
|
+
reapStaleOpenRecords(consumerRoot, nowIso);
|
|
2121
|
+
if (event === "subagent_start") handleStart(consumerRoot, payload, nowIso, sessionId);
|
|
2122
|
+
else handleStop(consumerRoot, payload, nowIso);
|
|
2123
|
+
} catch {
|
|
2124
|
+
return EXIT_ALLOW4;
|
|
2125
|
+
}
|
|
2126
|
+
return EXIT_ALLOW4;
|
|
2127
|
+
}
|
|
2128
|
+
function resolveConsumerRoot(envelope) {
|
|
2129
|
+
if (isObject2(envelope)) {
|
|
2130
|
+
const pr = str2(envelope, "workspace_root", "project_root");
|
|
2131
|
+
if (pr) return pr;
|
|
2132
|
+
const payload = unwrapPayload(envelope);
|
|
2133
|
+
const cwd = str2(payload, "cwd");
|
|
2134
|
+
if (cwd) return cwd;
|
|
2135
|
+
}
|
|
2136
|
+
return process.cwd();
|
|
2137
|
+
}
|
|
2138
|
+
function main6() {
|
|
2139
|
+
const raw = readHookStdin();
|
|
2140
|
+
let envelope = {};
|
|
2141
|
+
try {
|
|
2142
|
+
envelope = raw.trim() ? JSON.parse(raw) : {};
|
|
2143
|
+
} catch {
|
|
2144
|
+
return EXIT_ALLOW4;
|
|
2145
|
+
}
|
|
2146
|
+
return processEnvelope(envelope, resolveConsumerRoot(envelope));
|
|
2147
|
+
}
|
|
2148
|
+
function _isCliEntry6() {
|
|
2149
|
+
if (true) {
|
|
2150
|
+
return false;
|
|
2151
|
+
}
|
|
2152
|
+
if (process.argv[1] === void 0) return false;
|
|
2153
|
+
const argvUrl = pathToFileURL6(path6.resolve(process.argv[1])).href;
|
|
2154
|
+
if (import.meta.url === argvUrl) return true;
|
|
2155
|
+
try {
|
|
2156
|
+
return fs6.realpathSync(fileURLToPath6(import.meta.url)) === fs6.realpathSync(path6.resolve(process.argv[1]));
|
|
2157
|
+
} catch {
|
|
2158
|
+
return false;
|
|
2159
|
+
}
|
|
2160
|
+
}
|
|
2161
|
+
if (_isCliEntry6()) process.exit(main6());
|
|
2162
|
+
|
|
1713
2163
|
// src/scripts/hooks/turn_end_gate_hook.ts
|
|
1714
2164
|
var EXIT_BLOCK2 = 1;
|
|
1715
|
-
var
|
|
2165
|
+
var EXIT_ALLOW5 = 0;
|
|
1716
2166
|
var TRANSCRIPT_READ_MAX_BYTES = 8 * 1024 * 1024;
|
|
1717
2167
|
function stripFencedBlocks(text) {
|
|
1718
2168
|
const out = [];
|
|
@@ -1816,7 +2266,7 @@ function detectPromissory(reply) {
|
|
|
1816
2266
|
}
|
|
1817
2267
|
function readCiSettled(workspaceRoot) {
|
|
1818
2268
|
try {
|
|
1819
|
-
const raw =
|
|
2269
|
+
const raw = fs7.readFileSync(path7.join(workspaceRoot, STATE_FILE3), "utf-8");
|
|
1820
2270
|
const decoded = JSON.parse(raw);
|
|
1821
2271
|
if (typeof decoded === "object" && decoded !== null && !Array.isArray(decoded)) {
|
|
1822
2272
|
const ci = decoded["ci_last"];
|
|
@@ -1850,7 +2300,7 @@ function detectCompletionClaim(reply, ci) {
|
|
|
1850
2300
|
}
|
|
1851
2301
|
function readLanguagePin(workspaceRoot) {
|
|
1852
2302
|
try {
|
|
1853
|
-
const raw =
|
|
2303
|
+
const raw = fs7.readFileSync(path7.join(workspaceRoot, STATE_FILE), "utf-8");
|
|
1854
2304
|
const decoded = JSON.parse(raw);
|
|
1855
2305
|
if (typeof decoded === "object" && decoded !== null && !Array.isArray(decoded)) {
|
|
1856
2306
|
const lang = decoded["language"];
|
|
@@ -1899,17 +2349,17 @@ function detectUnverifiedEdit(toolCalls) {
|
|
|
1899
2349
|
};
|
|
1900
2350
|
}
|
|
1901
2351
|
function stateDir(workspaceRoot) {
|
|
1902
|
-
return
|
|
2352
|
+
return path7.join(workspaceRoot, "agents", "runtime", "state", "turn-end-gate");
|
|
1903
2353
|
}
|
|
1904
2354
|
function sessionStateFile2(workspaceRoot, sessionKey) {
|
|
1905
|
-
return
|
|
2355
|
+
return path7.join(stateDir(workspaceRoot), `${sessionKey}.json`);
|
|
1906
2356
|
}
|
|
1907
2357
|
function deriveSessionKey2(sessionId) {
|
|
1908
|
-
return
|
|
2358
|
+
return crypto3.createHash("sha256").update(sessionId).digest("hex").slice(0, 32);
|
|
1909
2359
|
}
|
|
1910
2360
|
function alreadyRefusedTurn(workspaceRoot, sessionKey, turnOrdinal) {
|
|
1911
2361
|
try {
|
|
1912
|
-
const raw =
|
|
2362
|
+
const raw = fs7.readFileSync(sessionStateFile2(workspaceRoot, sessionKey), "utf-8");
|
|
1913
2363
|
const decoded = JSON.parse(raw);
|
|
1914
2364
|
if (typeof decoded === "object" && decoded !== null && !Array.isArray(decoded)) {
|
|
1915
2365
|
return decoded["refused_turn"] === turnOrdinal;
|
|
@@ -1934,10 +2384,10 @@ function readTranscriptTail(transcriptPath, opts = {}) {
|
|
|
1934
2384
|
if (!transcriptPath || !isSafeTranscriptPath(transcriptPath, opts)) return empty;
|
|
1935
2385
|
let lines;
|
|
1936
2386
|
try {
|
|
1937
|
-
if (opts.maxBytes !== void 0 &&
|
|
2387
|
+
if (opts.maxBytes !== void 0 && fs7.statSync(transcriptPath).size > opts.maxBytes) {
|
|
1938
2388
|
return empty;
|
|
1939
2389
|
}
|
|
1940
|
-
lines =
|
|
2390
|
+
lines = fs7.readFileSync(transcriptPath, "utf-8").split("\n");
|
|
1941
2391
|
} catch {
|
|
1942
2392
|
return empty;
|
|
1943
2393
|
}
|
|
@@ -2010,33 +2460,41 @@ function _messageText(content) {
|
|
|
2010
2460
|
}
|
|
2011
2461
|
return parts.length > 0 ? parts.join("\n") : null;
|
|
2012
2462
|
}
|
|
2013
|
-
function
|
|
2463
|
+
function str3(v) {
|
|
2014
2464
|
return typeof v === "string" ? v : "";
|
|
2015
2465
|
}
|
|
2016
|
-
function
|
|
2466
|
+
function main7() {
|
|
2017
2467
|
let envelope;
|
|
2018
2468
|
let payload;
|
|
2019
2469
|
try {
|
|
2020
2470
|
[envelope, payload] = unwrap(readHookStdin(), "claude");
|
|
2021
2471
|
} catch {
|
|
2022
|
-
return
|
|
2472
|
+
return EXIT_ALLOW5;
|
|
2473
|
+
}
|
|
2474
|
+
if (payload["stop_hook_active"] === true) return EXIT_ALLOW5;
|
|
2475
|
+
const workspaceRoot = str3(envelope["workspace_root"]) || process.cwd();
|
|
2476
|
+
let dispatchOpen = false;
|
|
2477
|
+
try {
|
|
2478
|
+
dispatchOpen = openRecordStats(workspaceRoot).open_count > 0;
|
|
2479
|
+
} catch {
|
|
2023
2480
|
}
|
|
2024
|
-
|
|
2025
|
-
const workspaceRoot = str2(envelope["workspace_root"]) || process.cwd();
|
|
2026
|
-
const transcriptPath = str2(
|
|
2481
|
+
const transcriptPath = str3(
|
|
2027
2482
|
payload["transcript_path"] ?? payload["transcriptPath"]
|
|
2028
2483
|
);
|
|
2029
2484
|
const { lastAssistant, turnOrdinal, toolCalls } = readTranscriptTail(transcriptPath, {
|
|
2030
2485
|
maxBytes: TRANSCRIPT_READ_MAX_BYTES
|
|
2031
2486
|
});
|
|
2032
|
-
if (!lastAssistant) return
|
|
2487
|
+
if (!lastAssistant) return EXIT_ALLOW5;
|
|
2033
2488
|
const sessionKey = deriveSessionKey2(
|
|
2034
|
-
|
|
2489
|
+
str3(envelope["session_id"]) || "unknown-session"
|
|
2035
2490
|
);
|
|
2036
|
-
if (alreadyRefusedTurn(workspaceRoot, sessionKey, turnOrdinal)) return
|
|
2491
|
+
if (alreadyRefusedTurn(workspaceRoot, sessionKey, turnOrdinal)) return EXIT_ALLOW5;
|
|
2037
2492
|
const findings = [];
|
|
2038
2493
|
for (const f of [
|
|
2039
|
-
|
|
2494
|
+
// A and D are the completion-adjacent pair a pending dispatch excuses
|
|
2495
|
+
// (Phase 3 Step 2, narrowed by R2 round 2 finding 2). B and C are not
|
|
2496
|
+
// excused by anything about a dispatch and run unchanged.
|
|
2497
|
+
dispatchOpen ? null : detectPromissory(lastAssistant),
|
|
2040
2498
|
detectLanguage(lastAssistant, readLanguagePin(workspaceRoot)),
|
|
2041
2499
|
detectUnverifiedEdit(toolCalls),
|
|
2042
2500
|
// Round 7 § Phase 1 — detector D, in the same unconditional list as the
|
|
@@ -2046,11 +2504,11 @@ function main6() {
|
|
|
2046
2504
|
// gating is where the comment above says gating belongs — inside the
|
|
2047
2505
|
// detector: no CI observed, or a settled read, or no completion claim
|
|
2048
2506
|
// ⇒ no finding.
|
|
2049
|
-
detectCompletionClaim(lastAssistant, readCiSettled(workspaceRoot))
|
|
2507
|
+
dispatchOpen ? null : detectCompletionClaim(lastAssistant, readCiSettled(workspaceRoot))
|
|
2050
2508
|
]) {
|
|
2051
2509
|
if (f) findings.push(f);
|
|
2052
2510
|
}
|
|
2053
|
-
if (findings.length === 0) return
|
|
2511
|
+
if (findings.length === 0) return EXIT_ALLOW5;
|
|
2054
2512
|
markRefusedTurn(workspaceRoot, sessionKey, turnOrdinal, findings[0].detector);
|
|
2055
2513
|
const lines = findings.map(
|
|
2056
2514
|
(f) => ` \xB7 ${f.detector}: ${f.reason}
|
|
@@ -2065,37 +2523,37 @@ ${lines.join("\n")}
|
|
|
2065
2523
|
);
|
|
2066
2524
|
return EXIT_BLOCK2;
|
|
2067
2525
|
}
|
|
2068
|
-
function
|
|
2526
|
+
function _isCliEntry7() {
|
|
2069
2527
|
if (true) {
|
|
2070
2528
|
return false;
|
|
2071
2529
|
}
|
|
2072
2530
|
if (process.argv[1] === void 0) {
|
|
2073
2531
|
return false;
|
|
2074
2532
|
}
|
|
2075
|
-
const argvUrl =
|
|
2533
|
+
const argvUrl = pathToFileURL7(path7.resolve(process.argv[1])).href;
|
|
2076
2534
|
if (import.meta.url === argvUrl) {
|
|
2077
2535
|
return true;
|
|
2078
2536
|
}
|
|
2079
2537
|
try {
|
|
2080
|
-
const here =
|
|
2081
|
-
const argv =
|
|
2538
|
+
const here = fs7.realpathSync(fileURLToPath7(import.meta.url));
|
|
2539
|
+
const argv = fs7.realpathSync(path7.resolve(process.argv[1]));
|
|
2082
2540
|
return here === argv;
|
|
2083
2541
|
} catch {
|
|
2084
2542
|
return false;
|
|
2085
2543
|
}
|
|
2086
2544
|
}
|
|
2087
|
-
if (
|
|
2088
|
-
process.exit(
|
|
2545
|
+
if (_isCliEntry7()) {
|
|
2546
|
+
process.exit(main7());
|
|
2089
2547
|
}
|
|
2090
2548
|
|
|
2091
2549
|
// src/scripts/hooks/evidence_independence.ts
|
|
2092
|
-
import
|
|
2093
|
-
import
|
|
2094
|
-
import
|
|
2095
|
-
import { fileURLToPath as
|
|
2096
|
-
var
|
|
2550
|
+
import crypto4 from "node:crypto";
|
|
2551
|
+
import fs8 from "node:fs";
|
|
2552
|
+
import path8 from "node:path";
|
|
2553
|
+
import { fileURLToPath as fileURLToPath8, pathToFileURL as pathToFileURL8 } from "node:url";
|
|
2554
|
+
var EXIT_ALLOW6 = 0;
|
|
2097
2555
|
var EXIT_BLOCK3 = 1;
|
|
2098
|
-
var STATE_FILE4 =
|
|
2556
|
+
var STATE_FILE4 = path8.join("agents", "state", "evidence-dispatch.json");
|
|
2099
2557
|
function _isObject6(v) {
|
|
2100
2558
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
2101
2559
|
}
|
|
@@ -2163,8 +2621,8 @@ function extractDispatch(envelope) {
|
|
|
2163
2621
|
}
|
|
2164
2622
|
function _ledgerStamp(consumer_root) {
|
|
2165
2623
|
try {
|
|
2166
|
-
const raw =
|
|
2167
|
-
|
|
2624
|
+
const raw = fs8.readFileSync(
|
|
2625
|
+
path8.join(consumer_root, "agents", "state", "git-authorization.json"),
|
|
2168
2626
|
"utf8"
|
|
2169
2627
|
);
|
|
2170
2628
|
const d = JSON.parse(raw);
|
|
@@ -2175,7 +2633,7 @@ function _ledgerStamp(consumer_root) {
|
|
|
2175
2633
|
}
|
|
2176
2634
|
function _load(target) {
|
|
2177
2635
|
try {
|
|
2178
|
-
const decoded = JSON.parse(
|
|
2636
|
+
const decoded = JSON.parse(fs8.readFileSync(target, "utf8"));
|
|
2179
2637
|
if (_isObject6(decoded) && Array.isArray(decoded["evaluations"])) {
|
|
2180
2638
|
return decoded;
|
|
2181
2639
|
}
|
|
@@ -2186,7 +2644,7 @@ function _load(target) {
|
|
|
2186
2644
|
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.";
|
|
2187
2645
|
function decide2(tool, prompt, priorEvaluations) {
|
|
2188
2646
|
if (!isDispatchTool(tool) || !isEvaluationPrompt(prompt)) {
|
|
2189
|
-
return { exit:
|
|
2647
|
+
return { exit: EXIT_ALLOW6, stdout: "", stderr: "", evaluations: priorEvaluations };
|
|
2190
2648
|
}
|
|
2191
2649
|
const preloaded = preloadedVerdict(prompt);
|
|
2192
2650
|
if (preloaded !== null) {
|
|
@@ -2199,11 +2657,11 @@ function decide2(tool, prompt, priorEvaluations) {
|
|
|
2199
2657
|
};
|
|
2200
2658
|
}
|
|
2201
2659
|
if (!isSelfScoped(prompt)) {
|
|
2202
|
-
return { exit:
|
|
2660
|
+
return { exit: EXIT_ALLOW6, stdout: "", stderr: "", evaluations: priorEvaluations };
|
|
2203
2661
|
}
|
|
2204
2662
|
if (priorEvaluations >= 1) {
|
|
2205
2663
|
return {
|
|
2206
|
-
exit:
|
|
2664
|
+
exit: EXIT_ALLOW6,
|
|
2207
2665
|
stdout: `${JSON.stringify({
|
|
2208
2666
|
decision: "warn",
|
|
2209
2667
|
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.`
|
|
@@ -2214,7 +2672,7 @@ function decide2(tool, prompt, priorEvaluations) {
|
|
|
2214
2672
|
};
|
|
2215
2673
|
}
|
|
2216
2674
|
return {
|
|
2217
|
-
exit:
|
|
2675
|
+
exit: EXIT_ALLOW6,
|
|
2218
2676
|
stdout: `${JSON.stringify({ decision: "warn", reason: WARN_TEXT })}
|
|
2219
2677
|
`,
|
|
2220
2678
|
stderr: "",
|
|
@@ -2230,10 +2688,10 @@ function run5(stdin_text, options) {
|
|
|
2230
2688
|
envelope = decoded;
|
|
2231
2689
|
}
|
|
2232
2690
|
} catch {
|
|
2233
|
-
return
|
|
2691
|
+
return EXIT_ALLOW6;
|
|
2234
2692
|
}
|
|
2235
2693
|
}
|
|
2236
|
-
const target =
|
|
2694
|
+
const target = path8.join(options.consumer_root, STATE_FILE4);
|
|
2237
2695
|
const state = _load(target);
|
|
2238
2696
|
const session_id = typeof envelope["session_id"] === "string" ? envelope["session_id"] : "";
|
|
2239
2697
|
const turnMarker = `${session_id}:${_ledgerStamp(options.consumer_root)}`;
|
|
@@ -2247,7 +2705,7 @@ function run5(stdin_text, options) {
|
|
|
2247
2705
|
if (decision.evaluations > state.evaluations.length) {
|
|
2248
2706
|
state.evaluations.push({
|
|
2249
2707
|
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2250
|
-
digest:
|
|
2708
|
+
digest: crypto4.createHash("sha256").update(prompt).digest("hex").slice(0, 16),
|
|
2251
2709
|
prompt_chars: prompt.length
|
|
2252
2710
|
});
|
|
2253
2711
|
try {
|
|
@@ -2263,7 +2721,7 @@ function run5(stdin_text, options) {
|
|
|
2263
2721
|
}
|
|
2264
2722
|
return decision.exit;
|
|
2265
2723
|
}
|
|
2266
|
-
function
|
|
2724
|
+
function main8(argv) {
|
|
2267
2725
|
const args = argv ?? process.argv.slice(2);
|
|
2268
2726
|
let consumer_root = process.cwd();
|
|
2269
2727
|
for (let i = 0; i < args.length; i += 1) {
|
|
@@ -2277,33 +2735,33 @@ function main7(argv) {
|
|
|
2277
2735
|
}
|
|
2278
2736
|
return run5(readHookStdin(), { consumer_root });
|
|
2279
2737
|
}
|
|
2280
|
-
function
|
|
2738
|
+
function _isCliEntry8() {
|
|
2281
2739
|
if (true) {
|
|
2282
2740
|
return false;
|
|
2283
2741
|
}
|
|
2284
2742
|
if (process.argv[1] === void 0) {
|
|
2285
2743
|
return false;
|
|
2286
2744
|
}
|
|
2287
|
-
const argvUrl =
|
|
2745
|
+
const argvUrl = pathToFileURL8(path8.resolve(process.argv[1])).href;
|
|
2288
2746
|
if (import.meta.url === argvUrl) {
|
|
2289
2747
|
return true;
|
|
2290
2748
|
}
|
|
2291
2749
|
try {
|
|
2292
|
-
const here =
|
|
2293
|
-
const argv =
|
|
2750
|
+
const here = fs8.realpathSync(fileURLToPath8(import.meta.url));
|
|
2751
|
+
const argv = fs8.realpathSync(path8.resolve(process.argv[1]));
|
|
2294
2752
|
return here === argv;
|
|
2295
2753
|
} catch {
|
|
2296
2754
|
return false;
|
|
2297
2755
|
}
|
|
2298
2756
|
}
|
|
2299
|
-
if (
|
|
2300
|
-
process.exit(
|
|
2757
|
+
if (_isCliEntry8()) {
|
|
2758
|
+
process.exit(main8());
|
|
2301
2759
|
}
|
|
2302
2760
|
|
|
2303
2761
|
// src/scripts/hooks/delegation_nudge_hook.ts
|
|
2304
|
-
import
|
|
2305
|
-
import
|
|
2306
|
-
import { fileURLToPath as
|
|
2762
|
+
import fs9 from "node:fs";
|
|
2763
|
+
import path9 from "node:path";
|
|
2764
|
+
import { fileURLToPath as fileURLToPath9, pathToFileURL as pathToFileURL9 } from "node:url";
|
|
2307
2765
|
|
|
2308
2766
|
// src/scripts/_lib/host_capability.ts
|
|
2309
2767
|
import process2 from "node:process";
|
|
@@ -2630,7 +3088,7 @@ function resolveSubagentRouting(inp) {
|
|
|
2630
3088
|
}
|
|
2631
3089
|
|
|
2632
3090
|
// src/scripts/hooks/delegation_nudge_hook.ts
|
|
2633
|
-
var
|
|
3091
|
+
var EXIT_ALLOW7 = 0;
|
|
2634
3092
|
var EXIT_WARN3 = 2;
|
|
2635
3093
|
function _isObject7(v) {
|
|
2636
3094
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
@@ -2791,34 +3249,34 @@ function _workspaceRoot(envelope) {
|
|
|
2791
3249
|
}
|
|
2792
3250
|
return process.cwd();
|
|
2793
3251
|
}
|
|
2794
|
-
function
|
|
3252
|
+
function main9() {
|
|
2795
3253
|
let envelope = {};
|
|
2796
3254
|
try {
|
|
2797
3255
|
const raw = readHookStdin();
|
|
2798
3256
|
envelope = raw.trim() ? JSON.parse(raw) : {};
|
|
2799
3257
|
} catch {
|
|
2800
|
-
return
|
|
3258
|
+
return EXIT_ALLOW7;
|
|
2801
3259
|
}
|
|
2802
3260
|
const env = _isObject7(envelope) ? envelope : {};
|
|
2803
3261
|
const event = env["event"];
|
|
2804
3262
|
const slot = typeof event === "string" && event !== "" ? event : "user_prompt_submit";
|
|
2805
3263
|
if (slot !== "user_prompt_submit") {
|
|
2806
|
-
return
|
|
3264
|
+
return EXIT_ALLOW7;
|
|
2807
3265
|
}
|
|
2808
3266
|
const payload = _isObject7(env["payload"]) ? env["payload"] : env;
|
|
2809
3267
|
const prompt = _extractPrompt2(payload);
|
|
2810
3268
|
if (!prompt) {
|
|
2811
|
-
return
|
|
3269
|
+
return EXIT_ALLOW7;
|
|
2812
3270
|
}
|
|
2813
3271
|
if (isSyntheticPrompt(prompt)) {
|
|
2814
|
-
return
|
|
3272
|
+
return EXIT_ALLOW7;
|
|
2815
3273
|
}
|
|
2816
3274
|
const root = _workspaceRoot(env);
|
|
2817
3275
|
const platform = env["platform"];
|
|
2818
3276
|
const hostId = typeof platform === "string" && platform ? platform : null;
|
|
2819
3277
|
const result = classifyPrompt(prompt, root, hostId);
|
|
2820
3278
|
if (!result) {
|
|
2821
|
-
return
|
|
3279
|
+
return EXIT_ALLOW7;
|
|
2822
3280
|
}
|
|
2823
3281
|
process.stdout.write(
|
|
2824
3282
|
`${JSON.stringify({
|
|
@@ -2830,31 +3288,31 @@ function main8() {
|
|
|
2830
3288
|
);
|
|
2831
3289
|
return EXIT_WARN3;
|
|
2832
3290
|
}
|
|
2833
|
-
function
|
|
3291
|
+
function _isCliEntry9() {
|
|
2834
3292
|
if (true) {
|
|
2835
3293
|
return false;
|
|
2836
3294
|
}
|
|
2837
3295
|
if (process.argv[1] === void 0) {
|
|
2838
3296
|
return false;
|
|
2839
3297
|
}
|
|
2840
|
-
const argvUrl =
|
|
3298
|
+
const argvUrl = pathToFileURL9(path9.resolve(process.argv[1])).href;
|
|
2841
3299
|
if (import.meta.url === argvUrl) {
|
|
2842
3300
|
return true;
|
|
2843
3301
|
}
|
|
2844
3302
|
try {
|
|
2845
|
-
const here =
|
|
2846
|
-
const argv =
|
|
3303
|
+
const here = fs9.realpathSync(fileURLToPath9(import.meta.url));
|
|
3304
|
+
const argv = fs9.realpathSync(path9.resolve(process.argv[1]));
|
|
2847
3305
|
return here === argv;
|
|
2848
3306
|
} catch {
|
|
2849
3307
|
return false;
|
|
2850
3308
|
}
|
|
2851
3309
|
}
|
|
2852
|
-
if (
|
|
2853
|
-
process.exit(
|
|
3310
|
+
if (_isCliEntry9()) {
|
|
3311
|
+
process.exit(main9());
|
|
2854
3312
|
}
|
|
2855
3313
|
|
|
2856
3314
|
// src/scripts/conformance_scan.ts
|
|
2857
|
-
var REPO_ROOT =
|
|
3315
|
+
var REPO_ROOT = path10.resolve(path10.dirname(fileURLToPath10(import.meta.url)), "..", "..");
|
|
2858
3316
|
var OBSERVED_BAND = { low: 9.1, high: 39.2 };
|
|
2859
3317
|
var BAND_MIN_TURNS = 1978;
|
|
2860
3318
|
var CARRIER_CHANGES = [
|
|
@@ -3204,7 +3662,7 @@ function scanSession(sessionId, lines) {
|
|
|
3204
3662
|
closeWindow();
|
|
3205
3663
|
return report;
|
|
3206
3664
|
}
|
|
3207
|
-
var DEFAULT_RATE_SERIES =
|
|
3665
|
+
var DEFAULT_RATE_SERIES = path10.join(
|
|
3208
3666
|
REPO_ROOT,
|
|
3209
3667
|
"agents",
|
|
3210
3668
|
"runtime",
|
|
@@ -3213,7 +3671,7 @@ var DEFAULT_RATE_SERIES = path9.join(
|
|
|
3213
3671
|
);
|
|
3214
3672
|
function defaultStore(projectDir) {
|
|
3215
3673
|
const slug = projectStoreSlug(projectDir);
|
|
3216
|
-
return
|
|
3674
|
+
return path10.join(process.env["HOME"] ?? "", ".claude", "projects", slug);
|
|
3217
3675
|
}
|
|
3218
3676
|
function _tokens(chars) {
|
|
3219
3677
|
return Math.round(chars / 4);
|
|
@@ -3224,13 +3682,13 @@ function measureDelivered(projectRulesDir, globalRulesDir) {
|
|
|
3224
3682
|
return {
|
|
3225
3683
|
project: {
|
|
3226
3684
|
dir: projectRulesDir,
|
|
3227
|
-
present:
|
|
3685
|
+
present: fs10.existsSync(projectRulesDir),
|
|
3228
3686
|
files: p.files,
|
|
3229
3687
|
tokens: _tokens(p.chars)
|
|
3230
3688
|
},
|
|
3231
3689
|
global: {
|
|
3232
3690
|
dir: globalRulesDir,
|
|
3233
|
-
present:
|
|
3691
|
+
present: fs10.existsSync(globalRulesDir),
|
|
3234
3692
|
files: g.files,
|
|
3235
3693
|
tokens: _tokens(g.chars)
|
|
3236
3694
|
},
|
|
@@ -3238,13 +3696,13 @@ function measureDelivered(projectRulesDir, globalRulesDir) {
|
|
|
3238
3696
|
};
|
|
3239
3697
|
}
|
|
3240
3698
|
function storeKey(store) {
|
|
3241
|
-
return
|
|
3699
|
+
return createHash4("sha256").update(path10.resolve(store)).digest("hex").slice(0, 12);
|
|
3242
3700
|
}
|
|
3243
3701
|
function scanStore(store, limit) {
|
|
3244
|
-
const files =
|
|
3702
|
+
const files = fs10.readdirSync(store).filter((f) => f.endsWith(".jsonl")).map((f) => ({ f, m: fs10.statSync(path10.join(store, f)).mtimeMs })).sort((a, b) => b.m - a.m).slice(0, limit).map((x) => x.f);
|
|
3245
3703
|
const per_session = [];
|
|
3246
3704
|
for (const f of files) {
|
|
3247
|
-
const lines =
|
|
3705
|
+
const lines = fs10.readFileSync(path10.join(store, f), "utf8").split("\n");
|
|
3248
3706
|
const r = scanSession(f.replace(/\.jsonl$/, "").slice(0, 8), lines);
|
|
3249
3707
|
if (r.assistant_turns > 0) {
|
|
3250
3708
|
per_session.push(r);
|
|
@@ -3272,10 +3730,10 @@ function scanStore(store, limit) {
|
|
|
3272
3730
|
const task_completeness_rate_pct = completeness_windows === 0 ? 0 : Number((100 * task_completeness / completeness_windows).toFixed(1));
|
|
3273
3731
|
const era = spansCarrierChange(per_session.map((s) => s.first_at));
|
|
3274
3732
|
const delivered = measureDelivered(
|
|
3275
|
-
|
|
3276
|
-
|
|
3733
|
+
path10.join(REPO_ROOT, ".claude", "rules"),
|
|
3734
|
+
path10.join(process.env["HOME"] ?? os2.homedir(), ".claude", "rules")
|
|
3277
3735
|
);
|
|
3278
|
-
const ownStore =
|
|
3736
|
+
const ownStore = path10.resolve(store) === path10.resolve(defaultStore(REPO_ROOT));
|
|
3279
3737
|
return {
|
|
3280
3738
|
scanned_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3281
3739
|
store,
|
|
@@ -3305,8 +3763,8 @@ function scanStore(store, limit) {
|
|
|
3305
3763
|
};
|
|
3306
3764
|
}
|
|
3307
3765
|
function recordRate(file, scanned_at, rate) {
|
|
3308
|
-
|
|
3309
|
-
|
|
3766
|
+
fs10.mkdirSync(path10.dirname(file), { recursive: true });
|
|
3767
|
+
fs10.appendFileSync(file, `${JSON.stringify({ measured_at: scanned_at, ...rate })}
|
|
3310
3768
|
`, "utf8");
|
|
3311
3769
|
}
|
|
3312
3770
|
function render(report) {
|
|
@@ -3405,7 +3863,7 @@ function render(report) {
|
|
|
3405
3863
|
lines.push(" checkbox batching \u2014 measured NOWHERE. ~5 low-severity findings.");
|
|
3406
3864
|
return lines.join("\n");
|
|
3407
3865
|
}
|
|
3408
|
-
function
|
|
3866
|
+
function main10(argv) {
|
|
3409
3867
|
const args = argv ?? process.argv.slice(2);
|
|
3410
3868
|
let store = null;
|
|
3411
3869
|
let limit = 30;
|
|
@@ -3437,14 +3895,14 @@ function main9(argv) {
|
|
|
3437
3895
|
return 2;
|
|
3438
3896
|
}
|
|
3439
3897
|
const resolved = store ?? defaultStore(process.cwd());
|
|
3440
|
-
if (!
|
|
3898
|
+
if (!fs10.existsSync(resolved)) {
|
|
3441
3899
|
process.stderr.write(`conformance:behavior: no transcript store at ${resolved}
|
|
3442
3900
|
`);
|
|
3443
3901
|
return 1;
|
|
3444
3902
|
}
|
|
3445
3903
|
const report = scanStore(resolved, Number.isFinite(limit) && limit > 0 ? limit : 30);
|
|
3446
3904
|
if (out) {
|
|
3447
|
-
|
|
3905
|
+
fs10.writeFileSync(out, `${JSON.stringify(report, null, 2)}
|
|
3448
3906
|
`, "utf8");
|
|
3449
3907
|
}
|
|
3450
3908
|
if (record) {
|
|
@@ -3452,7 +3910,7 @@ function main9(argv) {
|
|
|
3452
3910
|
}
|
|
3453
3911
|
if (why !== null) {
|
|
3454
3912
|
const id = why;
|
|
3455
|
-
|
|
3913
|
+
fs10.writeSync(
|
|
3456
3914
|
1,
|
|
3457
3915
|
json ? `${JSON.stringify(
|
|
3458
3916
|
{
|
|
@@ -3472,48 +3930,48 @@ function main9(argv) {
|
|
|
3472
3930
|
);
|
|
3473
3931
|
return 0;
|
|
3474
3932
|
}
|
|
3475
|
-
|
|
3933
|
+
fs10.writeSync(1, json ? `${JSON.stringify(report, null, 2)}
|
|
3476
3934
|
` : `${render(report)}
|
|
3477
3935
|
`);
|
|
3478
3936
|
return 0;
|
|
3479
3937
|
}
|
|
3480
|
-
function
|
|
3938
|
+
function _isCliEntry10() {
|
|
3481
3939
|
if (true) {
|
|
3482
3940
|
return false;
|
|
3483
3941
|
}
|
|
3484
3942
|
if (process.argv[1] === void 0) {
|
|
3485
3943
|
return false;
|
|
3486
3944
|
}
|
|
3487
|
-
const argvUrl =
|
|
3945
|
+
const argvUrl = pathToFileURL10(path10.resolve(process.argv[1])).href;
|
|
3488
3946
|
if (import.meta.url === argvUrl) {
|
|
3489
3947
|
return true;
|
|
3490
3948
|
}
|
|
3491
3949
|
try {
|
|
3492
|
-
const here =
|
|
3493
|
-
const argv =
|
|
3950
|
+
const here = fs10.realpathSync(fileURLToPath10(import.meta.url));
|
|
3951
|
+
const argv = fs10.realpathSync(path10.resolve(process.argv[1]));
|
|
3494
3952
|
return here === argv;
|
|
3495
3953
|
} catch {
|
|
3496
3954
|
return false;
|
|
3497
3955
|
}
|
|
3498
3956
|
}
|
|
3499
|
-
if (
|
|
3500
|
-
process.exit(
|
|
3957
|
+
if (_isCliEntry10()) {
|
|
3958
|
+
process.exit(main10());
|
|
3501
3959
|
}
|
|
3502
3960
|
|
|
3503
3961
|
// src/scripts/report_carrier_divergence.ts
|
|
3504
|
-
import * as
|
|
3962
|
+
import * as fs11 from "node:fs";
|
|
3505
3963
|
import * as os3 from "node:os";
|
|
3506
|
-
import * as
|
|
3964
|
+
import * as path11 from "node:path";
|
|
3507
3965
|
import process3 from "node:process";
|
|
3508
|
-
import { fileURLToPath as
|
|
3509
|
-
var _HERE =
|
|
3510
|
-
var REPO_ROOT2 =
|
|
3511
|
-
var PROJECT_RULES =
|
|
3512
|
-
var PROJECTION_SOURCE =
|
|
3513
|
-
var GLOBAL_RULES =
|
|
3966
|
+
import { fileURLToPath as fileURLToPath11, pathToFileURL as pathToFileURL11 } from "node:url";
|
|
3967
|
+
var _HERE = fileURLToPath11(import.meta.url);
|
|
3968
|
+
var REPO_ROOT2 = path11.resolve(path11.dirname(_HERE), "..", "..");
|
|
3969
|
+
var PROJECT_RULES = path11.join(".claude", "rules");
|
|
3970
|
+
var PROJECTION_SOURCE = path11.join("dist", "agent-src", "rules");
|
|
3971
|
+
var GLOBAL_RULES = path11.join(".claude", "rules");
|
|
3514
3972
|
function _listRules(dir) {
|
|
3515
3973
|
try {
|
|
3516
|
-
return
|
|
3974
|
+
return fs11.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
|
|
3517
3975
|
} catch {
|
|
3518
3976
|
return [];
|
|
3519
3977
|
}
|
|
@@ -3521,7 +3979,7 @@ function _listRules(dir) {
|
|
|
3521
3979
|
function _ruleType(file) {
|
|
3522
3980
|
let text;
|
|
3523
3981
|
try {
|
|
3524
|
-
text =
|
|
3982
|
+
text = fs11.readFileSync(file, "utf-8");
|
|
3525
3983
|
} catch {
|
|
3526
3984
|
return "";
|
|
3527
3985
|
}
|
|
@@ -3532,8 +3990,8 @@ function compareCarriers(projectDir, globalDir, sourceDir) {
|
|
|
3532
3990
|
const out = {
|
|
3533
3991
|
projectDir,
|
|
3534
3992
|
globalDir,
|
|
3535
|
-
globalPresent:
|
|
3536
|
-
projectPresent:
|
|
3993
|
+
globalPresent: fs11.existsSync(globalDir),
|
|
3994
|
+
projectPresent: fs11.existsSync(projectDir),
|
|
3537
3995
|
shared: 0,
|
|
3538
3996
|
identical: [],
|
|
3539
3997
|
provenanceOnly: [],
|
|
@@ -3556,7 +4014,7 @@ function compareCarriers(projectDir, globalDir, sourceDir) {
|
|
|
3556
4014
|
}
|
|
3557
4015
|
if (!inP && inG) {
|
|
3558
4016
|
out.globalOnly.push(rule);
|
|
3559
|
-
if (sourceDir !== void 0 && _ruleType(
|
|
4017
|
+
if (sourceDir !== void 0 && _ruleType(path11.join(sourceDir, rule)) === "manual") {
|
|
3560
4018
|
out.manualOnlyGlobal.push(rule);
|
|
3561
4019
|
}
|
|
3562
4020
|
continue;
|
|
@@ -3566,8 +4024,8 @@ function compareCarriers(projectDir, globalDir, sourceDir) {
|
|
|
3566
4024
|
let projectCopy;
|
|
3567
4025
|
let globalCopy;
|
|
3568
4026
|
try {
|
|
3569
|
-
projectCopy =
|
|
3570
|
-
globalCopy =
|
|
4027
|
+
projectCopy = fs11.readFileSync(path11.join(projectDir, rule));
|
|
4028
|
+
globalCopy = fs11.readFileSync(path11.join(globalDir, rule));
|
|
3571
4029
|
verdict = comparePair(projectCopy, globalCopy);
|
|
3572
4030
|
} catch {
|
|
3573
4031
|
out.shared -= 1;
|
|
@@ -3712,11 +4170,11 @@ function render2(d) {
|
|
|
3712
4170
|
}
|
|
3713
4171
|
return lines.join("\n");
|
|
3714
4172
|
}
|
|
3715
|
-
function
|
|
4173
|
+
function main11(argv) {
|
|
3716
4174
|
const args = argv ?? process3.argv.slice(2);
|
|
3717
|
-
let projectDir =
|
|
3718
|
-
let globalDir =
|
|
3719
|
-
let sourceDir =
|
|
4175
|
+
let projectDir = path11.join(REPO_ROOT2, PROJECT_RULES);
|
|
4176
|
+
let globalDir = path11.join(os3.homedir(), GLOBAL_RULES);
|
|
4177
|
+
let sourceDir = path11.join(REPO_ROOT2, PROJECTION_SOURCE);
|
|
3720
4178
|
const value = (i) => {
|
|
3721
4179
|
const v = args[i + 1];
|
|
3722
4180
|
return v === void 0 || v.startsWith("-") ? null : v;
|
|
@@ -3730,7 +4188,7 @@ function main10(argv) {
|
|
|
3730
4188
|
`);
|
|
3731
4189
|
return 1;
|
|
3732
4190
|
}
|
|
3733
|
-
const resolved =
|
|
4191
|
+
const resolved = path11.resolve(v);
|
|
3734
4192
|
if (a === "--project") projectDir = resolved;
|
|
3735
4193
|
else if (a === "--global") globalDir = resolved;
|
|
3736
4194
|
else sourceDir = resolved;
|
|
@@ -3750,44 +4208,44 @@ function main10(argv) {
|
|
|
3750
4208
|
`);
|
|
3751
4209
|
return 0;
|
|
3752
4210
|
}
|
|
3753
|
-
function
|
|
4211
|
+
function _isCliEntry11() {
|
|
3754
4212
|
if (process3.argv[1] === void 0) return false;
|
|
3755
|
-
if (import.meta.url ===
|
|
4213
|
+
if (import.meta.url === pathToFileURL11(path11.resolve(process3.argv[1])).href) return true;
|
|
3756
4214
|
try {
|
|
3757
|
-
return
|
|
4215
|
+
return fs11.realpathSync(_HERE) === fs11.realpathSync(path11.resolve(process3.argv[1]));
|
|
3758
4216
|
} catch {
|
|
3759
4217
|
return false;
|
|
3760
4218
|
}
|
|
3761
4219
|
}
|
|
3762
|
-
if (
|
|
3763
|
-
process3.exit(
|
|
4220
|
+
if (_isCliEntry11()) {
|
|
4221
|
+
process3.exit(main11());
|
|
3764
4222
|
}
|
|
3765
4223
|
|
|
3766
4224
|
// src/scripts/report_skill_activation.ts
|
|
3767
|
-
import * as
|
|
4225
|
+
import * as fs12 from "node:fs";
|
|
3768
4226
|
import * as os4 from "node:os";
|
|
3769
|
-
import * as
|
|
3770
|
-
import { fileURLToPath as
|
|
3771
|
-
var _HERE2 =
|
|
3772
|
-
var REPO_ROOT3 =
|
|
4227
|
+
import * as path12 from "node:path";
|
|
4228
|
+
import { fileURLToPath as fileURLToPath12, pathToFileURL as pathToFileURL12 } from "node:url";
|
|
4229
|
+
var _HERE2 = fileURLToPath12(import.meta.url);
|
|
4230
|
+
var REPO_ROOT3 = path12.resolve(path12.dirname(_HERE2), "..", "..");
|
|
3773
4231
|
var SKILLS_ROOT = "src/skills";
|
|
3774
4232
|
var TRIGGER_KEYS = ["triggers:", "trigger_description:", "file_pattern:", "path_prefix:"];
|
|
3775
4233
|
var DETERMINISTIC_RE = /^\s*(?:[-*]\s*)?(?:\*\*)?(MUST|NEVER|ALWAYS)\b/m;
|
|
3776
4234
|
function censusSkills(root) {
|
|
3777
4235
|
const out = { total: 0, withTriggerKey: [], withDeterministicObligation: [] };
|
|
3778
|
-
if (!
|
|
4236
|
+
if (!fs12.existsSync(root)) {
|
|
3779
4237
|
return out;
|
|
3780
4238
|
}
|
|
3781
|
-
for (const entry of
|
|
4239
|
+
for (const entry of fs12.readdirSync(root, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
3782
4240
|
if (!entry.isDirectory()) {
|
|
3783
4241
|
continue;
|
|
3784
4242
|
}
|
|
3785
|
-
const file =
|
|
3786
|
-
if (!
|
|
4243
|
+
const file = path12.join(root, entry.name, "SKILL.md");
|
|
4244
|
+
if (!fs12.existsSync(file)) {
|
|
3787
4245
|
continue;
|
|
3788
4246
|
}
|
|
3789
4247
|
out.total += 1;
|
|
3790
|
-
const text =
|
|
4248
|
+
const text = fs12.readFileSync(file, "utf8");
|
|
3791
4249
|
const fmEnd = text.startsWith("---") ? text.indexOf("\n---", 3) : -1;
|
|
3792
4250
|
const fm = fmEnd === -1 ? "" : text.slice(0, fmEnd);
|
|
3793
4251
|
if (TRIGGER_KEYS.some((k) => new RegExp(`^${k}`, "m").test(fm))) {
|
|
@@ -3801,17 +4259,17 @@ function censusSkills(root) {
|
|
|
3801
4259
|
return out;
|
|
3802
4260
|
}
|
|
3803
4261
|
function defaultStore2(cwd) {
|
|
3804
|
-
return
|
|
4262
|
+
return path12.join(os4.homedir(), ".claude", "projects", projectStoreSlug(cwd));
|
|
3805
4263
|
}
|
|
3806
4264
|
function measureUsage(store, limit) {
|
|
3807
4265
|
const rep = { store, sessions: 0, assistantTurns: 0, invocations: 0, bySkill: {} };
|
|
3808
|
-
if (!
|
|
4266
|
+
if (!fs12.existsSync(store)) {
|
|
3809
4267
|
return rep;
|
|
3810
4268
|
}
|
|
3811
|
-
const files =
|
|
4269
|
+
const files = fs12.readdirSync(store).filter((f) => f.endsWith(".jsonl")).map((f) => path12.join(store, f)).sort((a, b) => fs12.statSync(b).mtimeMs - fs12.statSync(a).mtimeMs).slice(0, limit);
|
|
3812
4270
|
rep.sessions = files.length;
|
|
3813
4271
|
for (const file of files) {
|
|
3814
|
-
for (const line of
|
|
4272
|
+
for (const line of fs12.readFileSync(file, "utf8").split("\n")) {
|
|
3815
4273
|
if (!line.trim()) {
|
|
3816
4274
|
continue;
|
|
3817
4275
|
}
|
|
@@ -3874,7 +4332,7 @@ function render3(census, usage) {
|
|
|
3874
4332
|
}
|
|
3875
4333
|
totalInv += u.invocations;
|
|
3876
4334
|
lines.push(
|
|
3877
|
-
` ${
|
|
4335
|
+
` ${path12.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)}`
|
|
3878
4336
|
);
|
|
3879
4337
|
}
|
|
3880
4338
|
lines.push("");
|
|
@@ -3899,7 +4357,7 @@ function render3(census, usage) {
|
|
|
3899
4357
|
lines.push(" catalogue once per session, then count descriptions against bare names.");
|
|
3900
4358
|
return lines.join("\n");
|
|
3901
4359
|
}
|
|
3902
|
-
function
|
|
4360
|
+
function main12(argv) {
|
|
3903
4361
|
let limit = 30;
|
|
3904
4362
|
const stores = [];
|
|
3905
4363
|
for (let i = 0; i < argv.length; i += 1) {
|
|
@@ -3922,24 +4380,24 @@ function main11(argv) {
|
|
|
3922
4380
|
if (stores.length === 0) {
|
|
3923
4381
|
stores.push(defaultStore2(REPO_ROOT3));
|
|
3924
4382
|
}
|
|
3925
|
-
const census = censusSkills(
|
|
4383
|
+
const census = censusSkills(path12.join(REPO_ROOT3, SKILLS_ROOT));
|
|
3926
4384
|
const usage = stores.map((s) => measureUsage(s, limit));
|
|
3927
4385
|
process.stdout.write(`${render3(census, usage)}
|
|
3928
4386
|
`);
|
|
3929
4387
|
return 0;
|
|
3930
4388
|
}
|
|
3931
|
-
if (process.argv[1] !== void 0 && import.meta.url ===
|
|
3932
|
-
process.exit(
|
|
4389
|
+
if (process.argv[1] !== void 0 && import.meta.url === pathToFileURL12(path12.resolve(process.argv[1])).href) {
|
|
4390
|
+
process.exit(main12(process.argv.slice(2)));
|
|
3933
4391
|
}
|
|
3934
4392
|
|
|
3935
4393
|
// src/scripts/report_skill_obligation_violations.ts
|
|
3936
|
-
import * as
|
|
4394
|
+
import * as fs13 from "node:fs";
|
|
3937
4395
|
import * as os5 from "node:os";
|
|
3938
|
-
import * as
|
|
4396
|
+
import * as path13 from "node:path";
|
|
3939
4397
|
import process4 from "node:process";
|
|
3940
|
-
import { fileURLToPath as
|
|
3941
|
-
var _HERE3 =
|
|
3942
|
-
var REPO_ROOT4 =
|
|
4398
|
+
import { fileURLToPath as fileURLToPath13, pathToFileURL as pathToFileURL13 } from "node:url";
|
|
4399
|
+
var _HERE3 = fileURLToPath13(import.meta.url);
|
|
4400
|
+
var REPO_ROOT4 = path13.resolve(path13.dirname(_HERE3), "..", "..");
|
|
3943
4401
|
var OBLIGATION_LINE_RE = new RegExp(`${DETERMINISTIC_RE.source}.*`, "gm");
|
|
3944
4402
|
var PATH_RE = /`([A-Za-z0-9_./-]*\/[A-Za-z0-9_.-]+\.[a-z]{2,6})`/g;
|
|
3945
4403
|
var CMD_RE = /`([a-z][a-z0-9-]*(?: [a-z][a-z0-9:._-]*){1,3})`/g;
|
|
@@ -3977,7 +4435,7 @@ function _artefacts(line) {
|
|
|
3977
4435
|
return out;
|
|
3978
4436
|
}
|
|
3979
4437
|
function extractObligations(repoRoot) {
|
|
3980
|
-
const skillsRoot =
|
|
4438
|
+
const skillsRoot = path13.join(repoRoot, SKILLS_ROOT);
|
|
3981
4439
|
const census = censusSkills(skillsRoot);
|
|
3982
4440
|
const out = {
|
|
3983
4441
|
skills: census.withDeterministicObligation,
|
|
@@ -3991,7 +4449,7 @@ function extractObligations(repoRoot) {
|
|
|
3991
4449
|
for (const skill of census.withDeterministicObligation) {
|
|
3992
4450
|
let text;
|
|
3993
4451
|
try {
|
|
3994
|
-
text =
|
|
4452
|
+
text = fs13.readFileSync(path13.join(skillsRoot, skill, "SKILL.md"), "utf-8");
|
|
3995
4453
|
} catch {
|
|
3996
4454
|
continue;
|
|
3997
4455
|
}
|
|
@@ -4107,7 +4565,7 @@ function scanSessionForViolations(session, lines, forbidden, parsed) {
|
|
|
4107
4565
|
return flags;
|
|
4108
4566
|
}
|
|
4109
4567
|
function defaultStore3(cwd) {
|
|
4110
|
-
return
|
|
4568
|
+
return path13.join(os5.homedir(), ".claude", "projects", projectStoreSlug(cwd));
|
|
4111
4569
|
}
|
|
4112
4570
|
function scanStore2(repoRoot, store, limit) {
|
|
4113
4571
|
const census = extractObligations(repoRoot);
|
|
@@ -4120,14 +4578,14 @@ function scanStore2(repoRoot, store, limit) {
|
|
|
4120
4578
|
};
|
|
4121
4579
|
let files;
|
|
4122
4580
|
try {
|
|
4123
|
-
files =
|
|
4581
|
+
files = fs13.readdirSync(store).filter((f) => f.endsWith(".jsonl")).map((f) => ({ p: path13.join(store, f), m: fs13.statSync(path13.join(store, f)).mtimeMs })).sort((a, b) => b.m - a.m).slice(0, limit).map((x) => x.p);
|
|
4124
4582
|
} catch {
|
|
4125
4583
|
return report;
|
|
4126
4584
|
}
|
|
4127
4585
|
report.sessions = files.length;
|
|
4128
4586
|
for (const file of files) {
|
|
4129
|
-
const lines =
|
|
4130
|
-
const id =
|
|
4587
|
+
const lines = fs13.readFileSync(file, "utf-8").split("\n");
|
|
4588
|
+
const id = path13.basename(file).replace(/\.jsonl$/, "").slice(0, 8);
|
|
4131
4589
|
const entries = _parseSession(lines);
|
|
4132
4590
|
if (loadedSkillsFrom(entries).size > 0) report.sessionsWithASkill += 1;
|
|
4133
4591
|
report.flags.push(...scanSessionForViolations(id, lines, census.forbidden, entries));
|
|
@@ -4197,7 +4655,7 @@ function render4(r) {
|
|
|
4197
4655
|
lines.push(" ships as detection-only, and this one says so.");
|
|
4198
4656
|
return lines.join("\n");
|
|
4199
4657
|
}
|
|
4200
|
-
function
|
|
4658
|
+
function main13(argv) {
|
|
4201
4659
|
const args = argv ?? process4.argv.slice(2);
|
|
4202
4660
|
let limit = 30;
|
|
4203
4661
|
let json = false;
|
|
@@ -4250,35 +4708,35 @@ function main12(argv) {
|
|
|
4250
4708
|
}
|
|
4251
4709
|
return 0;
|
|
4252
4710
|
}
|
|
4253
|
-
function
|
|
4711
|
+
function _isCliEntry12() {
|
|
4254
4712
|
if (process4.argv[1] === void 0) return false;
|
|
4255
|
-
if (import.meta.url ===
|
|
4713
|
+
if (import.meta.url === pathToFileURL13(path13.resolve(process4.argv[1])).href) return true;
|
|
4256
4714
|
try {
|
|
4257
|
-
return
|
|
4715
|
+
return fs13.realpathSync(_HERE3) === fs13.realpathSync(path13.resolve(process4.argv[1]));
|
|
4258
4716
|
} catch {
|
|
4259
4717
|
return false;
|
|
4260
4718
|
}
|
|
4261
4719
|
}
|
|
4262
|
-
if (
|
|
4263
|
-
process4.exit(
|
|
4720
|
+
if (_isCliEntry12()) {
|
|
4721
|
+
process4.exit(main13());
|
|
4264
4722
|
}
|
|
4265
4723
|
|
|
4266
4724
|
// src/scripts/report_conformance_funnel.ts
|
|
4267
|
-
var _HERE4 =
|
|
4268
|
-
var REPO_ROOT5 =
|
|
4725
|
+
var _HERE4 = fileURLToPath14(import.meta.url);
|
|
4726
|
+
var REPO_ROOT5 = path14.resolve(path14.dirname(_HERE4), "..", "..");
|
|
4269
4727
|
function buildFunnel(opts = {}) {
|
|
4270
4728
|
const repoRoot = opts.repoRoot ?? REPO_ROOT5;
|
|
4271
|
-
const projectRulesDir = opts.projectRulesDir ??
|
|
4272
|
-
const globalRulesDir = opts.globalRulesDir ??
|
|
4273
|
-
const sourceDir = opts.sourceDir ??
|
|
4729
|
+
const projectRulesDir = opts.projectRulesDir ?? path14.join(repoRoot, PROJECT_RULES);
|
|
4730
|
+
const globalRulesDir = opts.globalRulesDir ?? path14.join(os6.homedir(), GLOBAL_RULES);
|
|
4731
|
+
const sourceDir = opts.sourceDir ?? path14.join(repoRoot, PROJECTION_SOURCE);
|
|
4274
4732
|
const store = opts.store ?? defaultStore(repoRoot);
|
|
4275
4733
|
const limit = opts.limit ?? 30;
|
|
4276
4734
|
return {
|
|
4277
4735
|
delivered: measureDelivered(projectRulesDir, globalRulesDir),
|
|
4278
4736
|
divergence: compareCarriers(projectRulesDir, globalRulesDir, sourceDir),
|
|
4279
|
-
skills: censusSkills(
|
|
4737
|
+
skills: censusSkills(path14.join(repoRoot, SKILLS_ROOT)),
|
|
4280
4738
|
usage: measureUsage(store, limit),
|
|
4281
|
-
storePresent:
|
|
4739
|
+
storePresent: fs14.existsSync(store),
|
|
4282
4740
|
sk2: scanStore2(repoRoot, store, limit)
|
|
4283
4741
|
};
|
|
4284
4742
|
}
|
|
@@ -4403,7 +4861,7 @@ function render5(r) {
|
|
|
4403
4861
|
lines.push("workflow without a measured false-positive rate first (locked policy).");
|
|
4404
4862
|
return lines.join("\n");
|
|
4405
4863
|
}
|
|
4406
|
-
function
|
|
4864
|
+
function main14(argv) {
|
|
4407
4865
|
const args = argv ?? process5.argv.slice(2);
|
|
4408
4866
|
const opts = {};
|
|
4409
4867
|
const value = (i) => {
|
|
@@ -4419,7 +4877,7 @@ function main13(argv) {
|
|
|
4419
4877
|
`);
|
|
4420
4878
|
return 1;
|
|
4421
4879
|
}
|
|
4422
|
-
const resolved =
|
|
4880
|
+
const resolved = path14.resolve(v);
|
|
4423
4881
|
if (a === "--store") opts.store = resolved;
|
|
4424
4882
|
else if (a === "--project") opts.projectRulesDir = resolved;
|
|
4425
4883
|
else if (a === "--global") opts.globalRulesDir = resolved;
|
|
@@ -4449,21 +4907,21 @@ function main13(argv) {
|
|
|
4449
4907
|
`);
|
|
4450
4908
|
return 0;
|
|
4451
4909
|
}
|
|
4452
|
-
function
|
|
4910
|
+
function _isCliEntry13() {
|
|
4453
4911
|
if (process5.argv[1] === void 0) return false;
|
|
4454
|
-
if (import.meta.url ===
|
|
4912
|
+
if (import.meta.url === pathToFileURL14(path14.resolve(process5.argv[1])).href) return true;
|
|
4455
4913
|
try {
|
|
4456
|
-
return
|
|
4914
|
+
return fs14.realpathSync(_HERE4) === fs14.realpathSync(path14.resolve(process5.argv[1]));
|
|
4457
4915
|
} catch {
|
|
4458
4916
|
return false;
|
|
4459
4917
|
}
|
|
4460
4918
|
}
|
|
4461
|
-
if (
|
|
4462
|
-
process5.exit(
|
|
4919
|
+
if (_isCliEntry13()) {
|
|
4920
|
+
process5.exit(main14());
|
|
4463
4921
|
}
|
|
4464
4922
|
|
|
4465
4923
|
// src/scripts/_cli/cmd_conformance.ts
|
|
4466
|
-
var _HERE5 =
|
|
4924
|
+
var _HERE5 = fileURLToPath15(import.meta.url);
|
|
4467
4925
|
var PACKAGE_ROOT = resolvePackageRoot(import.meta.url);
|
|
4468
4926
|
var CONFORMANCE_CHECK_IDS = [
|
|
4469
4927
|
"txlog-clean",
|
|
@@ -4486,17 +4944,17 @@ function conformanceLogPath() {
|
|
|
4486
4944
|
if (override && override.trim().length > 0) {
|
|
4487
4945
|
return override;
|
|
4488
4946
|
}
|
|
4489
|
-
return
|
|
4947
|
+
return path15.join(os7.homedir(), ".event4u", "agent-config", "conformance-log.jsonl");
|
|
4490
4948
|
}
|
|
4491
4949
|
function installLogPath() {
|
|
4492
4950
|
const override = process6.env["AGENT_CONFIG_INSTALL_LOG"];
|
|
4493
4951
|
if (override && override.trim().length > 0) {
|
|
4494
4952
|
return override;
|
|
4495
4953
|
}
|
|
4496
|
-
return
|
|
4954
|
+
return path15.join(os7.homedir(), ".event4u", "agent-config", "install-log.jsonl");
|
|
4497
4955
|
}
|
|
4498
4956
|
function _check_txlog_clean(logPath = installLogPath()) {
|
|
4499
|
-
if (!
|
|
4957
|
+
if (!fs15.existsSync(logPath)) {
|
|
4500
4958
|
return {
|
|
4501
4959
|
id: "txlog-clean",
|
|
4502
4960
|
status: "ok",
|
|
@@ -4530,11 +4988,11 @@ function _check_txlog_clean(logPath = installLogPath()) {
|
|
|
4530
4988
|
};
|
|
4531
4989
|
}
|
|
4532
4990
|
function routeTargetPaths(target) {
|
|
4533
|
-
return routeTargetPathsPosix(target).map((rel) =>
|
|
4991
|
+
return routeTargetPathsPosix(target).map((rel) => path15.join(...rel.split("/")));
|
|
4534
4992
|
}
|
|
4535
4993
|
function _check_router_pointers(packageRoot = PACKAGE_ROOT) {
|
|
4536
|
-
const routerPath =
|
|
4537
|
-
if (!
|
|
4994
|
+
const routerPath = path15.join(packageRoot, "dist", "router.json");
|
|
4995
|
+
if (!fs15.existsSync(routerPath)) {
|
|
4538
4996
|
return {
|
|
4539
4997
|
id: "router-pointers",
|
|
4540
4998
|
status: "fail",
|
|
@@ -4544,7 +5002,7 @@ function _check_router_pointers(packageRoot = PACKAGE_ROOT) {
|
|
|
4544
5002
|
}
|
|
4545
5003
|
let router;
|
|
4546
5004
|
try {
|
|
4547
|
-
router = JSON.parse(
|
|
5005
|
+
router = JSON.parse(fs15.readFileSync(routerPath, "utf8"));
|
|
4548
5006
|
} catch (exc) {
|
|
4549
5007
|
return {
|
|
4550
5008
|
id: "router-pointers",
|
|
@@ -4553,13 +5011,13 @@ function _check_router_pointers(packageRoot = PACKAGE_ROOT) {
|
|
|
4553
5011
|
remedy: "reinstall the package \u2014 dist/router.json is corrupt"
|
|
4554
5012
|
};
|
|
4555
5013
|
}
|
|
4556
|
-
const rulesDir =
|
|
5014
|
+
const rulesDir = path15.join(packageRoot, "dist", "agent-src", "rules");
|
|
4557
5015
|
const broken = [];
|
|
4558
5016
|
let ids = 0;
|
|
4559
5017
|
let targets = 0;
|
|
4560
5018
|
for (const kernelId of router["kernel"] ?? []) {
|
|
4561
5019
|
ids += 1;
|
|
4562
|
-
if (!
|
|
5020
|
+
if (!fs15.existsSync(path15.join(rulesDir, `${kernelId}.md`))) {
|
|
4563
5021
|
broken.push(`kernel:${kernelId} \u2192 rules/${kernelId}.md missing`);
|
|
4564
5022
|
}
|
|
4565
5023
|
}
|
|
@@ -4567,7 +5025,7 @@ function _check_router_pointers(packageRoot = PACKAGE_ROOT) {
|
|
|
4567
5025
|
for (const entry of router[tier] ?? []) {
|
|
4568
5026
|
const ruleId = String(entry["id"] ?? "");
|
|
4569
5027
|
ids += 1;
|
|
4570
|
-
if (!
|
|
5028
|
+
if (!fs15.existsSync(path15.join(rulesDir, `${ruleId}.md`))) {
|
|
4571
5029
|
broken.push(`${tier}:${ruleId} \u2192 rules/${ruleId}.md missing`);
|
|
4572
5030
|
}
|
|
4573
5031
|
for (const target of entry["routes_to"] ?? []) {
|
|
@@ -4577,7 +5035,7 @@ function _check_router_pointers(packageRoot = PACKAGE_ROOT) {
|
|
|
4577
5035
|
broken.push(`${ruleId} \u2192 unparseable routes_to ${JSON.stringify(target)}`);
|
|
4578
5036
|
continue;
|
|
4579
5037
|
}
|
|
4580
|
-
if (!candidates.some((rel) =>
|
|
5038
|
+
if (!candidates.some((rel) => fs15.existsSync(path15.join(packageRoot, rel)))) {
|
|
4581
5039
|
broken.push(`${ruleId} \u2192 ${target} (${candidates[0]} missing)`);
|
|
4582
5040
|
}
|
|
4583
5041
|
}
|
|
@@ -4609,9 +5067,9 @@ function detectSmokePlatform(projectRoot) {
|
|
|
4609
5067
|
return "claude";
|
|
4610
5068
|
}
|
|
4611
5069
|
function dispatcherRunner(packageRoot) {
|
|
4612
|
-
const localTsx =
|
|
4613
|
-
const script =
|
|
4614
|
-
if (
|
|
5070
|
+
const localTsx = path15.join(packageRoot, "node_modules", ".bin", "tsx");
|
|
5071
|
+
const script = path15.join(packageRoot, "src", "scripts", "hooks", "dispatch_hook.ts");
|
|
5072
|
+
if (fs15.existsSync(localTsx)) {
|
|
4615
5073
|
return [localTsx, script];
|
|
4616
5074
|
}
|
|
4617
5075
|
return ["npx", "tsx", script];
|
|
@@ -4661,12 +5119,12 @@ function _check_hook_dispatcher(projectRoot, packageRoot = PACKAGE_ROOT, opts =
|
|
|
4661
5119
|
};
|
|
4662
5120
|
}
|
|
4663
5121
|
function readSettingsMode(projectRoot) {
|
|
4664
|
-
const settingsPath =
|
|
4665
|
-
if (!
|
|
5122
|
+
const settingsPath = path15.join(projectRoot, ".agent-settings.yml");
|
|
5123
|
+
if (!fs15.existsSync(settingsPath)) {
|
|
4666
5124
|
return "eager-all";
|
|
4667
5125
|
}
|
|
4668
5126
|
try {
|
|
4669
|
-
const parsed = YAML.parse(
|
|
5127
|
+
const parsed = YAML.parse(fs15.readFileSync(settingsPath, "utf8"));
|
|
4670
5128
|
const lean = parsed?.["lean_projection"] ?? null;
|
|
4671
5129
|
const mode = lean?.["mode"];
|
|
4672
5130
|
return typeof mode === "string" && mode.length > 0 ? mode : "eager-all";
|
|
@@ -4677,7 +5135,7 @@ function readSettingsMode(projectRoot) {
|
|
|
4677
5135
|
function kernelIdsFromRouter(packageRoot) {
|
|
4678
5136
|
try {
|
|
4679
5137
|
const router = JSON.parse(
|
|
4680
|
-
|
|
5138
|
+
fs15.readFileSync(path15.join(packageRoot, "dist", "router.json"), "utf8")
|
|
4681
5139
|
);
|
|
4682
5140
|
return new Set((router["kernel"] ?? []).map(String));
|
|
4683
5141
|
} catch {
|
|
@@ -4694,8 +5152,8 @@ function _check_lean_projection(projectRoot, packageRoot = PACKAGE_ROOT, project
|
|
|
4694
5152
|
remedy: "set lean_projection.mode to 'eager-all' or 'thin' in .agent-settings.yml"
|
|
4695
5153
|
};
|
|
4696
5154
|
}
|
|
4697
|
-
const rulesDir = projectedRulesDir ??
|
|
4698
|
-
if (!
|
|
5155
|
+
const rulesDir = projectedRulesDir ?? path15.join(projectRoot, ".augment", "rules");
|
|
5156
|
+
if (!fs15.existsSync(rulesDir)) {
|
|
4699
5157
|
return {
|
|
4700
5158
|
id: "lean-projection",
|
|
4701
5159
|
status: "skipped",
|
|
@@ -4704,7 +5162,7 @@ function _check_lean_projection(projectRoot, packageRoot = PACKAGE_ROOT, project
|
|
|
4704
5162
|
};
|
|
4705
5163
|
}
|
|
4706
5164
|
const kernel = kernelIdsFromRouter(packageRoot);
|
|
4707
|
-
const files =
|
|
5165
|
+
const files = fs15.readdirSync(rulesDir).filter((f) => f.endsWith(".md") && f !== "INDEX.md").sort();
|
|
4708
5166
|
const nonKernel = files.filter((f) => !kernel.has(f.replace(/\.md$/, "")));
|
|
4709
5167
|
if (nonKernel.length === 0) {
|
|
4710
5168
|
return {
|
|
@@ -4718,7 +5176,7 @@ function _check_lean_projection(projectRoot, packageRoot = PACKAGE_ROOT, project
|
|
|
4718
5176
|
for (const f of nonKernel) {
|
|
4719
5177
|
let text = "";
|
|
4720
5178
|
try {
|
|
4721
|
-
text =
|
|
5179
|
+
text = fs15.readFileSync(path15.join(rulesDir, f), "utf8");
|
|
4722
5180
|
} catch {
|
|
4723
5181
|
continue;
|
|
4724
5182
|
}
|
|
@@ -4749,8 +5207,8 @@ function _check_lean_projection(projectRoot, packageRoot = PACKAGE_ROOT, project
|
|
|
4749
5207
|
function _check_host_manifest(projectRoot) {
|
|
4750
5208
|
const detected = Object.entries(detectToolPresence(projectRoot)).filter(([, v]) => v === true).map(([k]) => k);
|
|
4751
5209
|
const detectedNote = detected.length > 0 ? `detected surfaces: ${detected.join(", ")}` : "no surfaces detected";
|
|
4752
|
-
const settingsPath =
|
|
4753
|
-
if (!
|
|
5210
|
+
const settingsPath = path15.join(projectRoot, ".agent-settings.yml");
|
|
5211
|
+
if (!fs15.existsSync(settingsPath)) {
|
|
4754
5212
|
return {
|
|
4755
5213
|
id: "host-manifest",
|
|
4756
5214
|
status: "ok",
|
|
@@ -4760,7 +5218,7 @@ function _check_host_manifest(projectRoot) {
|
|
|
4760
5218
|
}
|
|
4761
5219
|
let parsed = null;
|
|
4762
5220
|
try {
|
|
4763
|
-
parsed = YAML.parse(
|
|
5221
|
+
parsed = YAML.parse(fs15.readFileSync(settingsPath, "utf8"));
|
|
4764
5222
|
} catch (exc) {
|
|
4765
5223
|
return {
|
|
4766
5224
|
id: "host-manifest",
|
|
@@ -4859,7 +5317,7 @@ function _parse(argv) {
|
|
|
4859
5317
|
}
|
|
4860
5318
|
return opts;
|
|
4861
5319
|
}
|
|
4862
|
-
function
|
|
5320
|
+
function main15(argv = null) {
|
|
4863
5321
|
const opts = _parse(argv !== null ? Array.from(argv) : process6.argv.slice(2));
|
|
4864
5322
|
if (opts.funnel) {
|
|
4865
5323
|
print(render5(buildFunnel()));
|
|
@@ -4930,25 +5388,25 @@ function main14(argv = null) {
|
|
|
4930
5388
|
}
|
|
4931
5389
|
return failed ? 1 : 0;
|
|
4932
5390
|
}
|
|
4933
|
-
function
|
|
5391
|
+
function _isCliEntry14() {
|
|
4934
5392
|
if (process6.argv[1] === void 0) {
|
|
4935
5393
|
return false;
|
|
4936
5394
|
}
|
|
4937
|
-
const argvUrl =
|
|
5395
|
+
const argvUrl = pathToFileURL15(path15.resolve(process6.argv[1])).href;
|
|
4938
5396
|
if (import.meta.url === argvUrl) {
|
|
4939
5397
|
return true;
|
|
4940
5398
|
}
|
|
4941
5399
|
try {
|
|
4942
|
-
const here =
|
|
4943
|
-
const argv =
|
|
5400
|
+
const here = fs15.realpathSync(fileURLToPath15(import.meta.url));
|
|
5401
|
+
const argv = fs15.realpathSync(path15.resolve(process6.argv[1]));
|
|
4944
5402
|
return here === argv;
|
|
4945
5403
|
} catch {
|
|
4946
5404
|
return false;
|
|
4947
5405
|
}
|
|
4948
5406
|
}
|
|
4949
|
-
if (
|
|
5407
|
+
if (_isCliEntry14() || process6.argv[1] === _HERE5) {
|
|
4950
5408
|
try {
|
|
4951
|
-
process6.exitCode =
|
|
5409
|
+
process6.exitCode = main15(process6.argv.slice(2));
|
|
4952
5410
|
} catch (e) {
|
|
4953
5411
|
if (e instanceof ArgparseExit) {
|
|
4954
5412
|
process6.exitCode = e.code;
|
|
@@ -4971,7 +5429,7 @@ export {
|
|
|
4971
5429
|
conformanceLogPath,
|
|
4972
5430
|
detectSmokePlatform,
|
|
4973
5431
|
installLogPath,
|
|
4974
|
-
|
|
5432
|
+
main15 as main,
|
|
4975
5433
|
routeTargetPaths,
|
|
4976
5434
|
runConformanceChecks
|
|
4977
5435
|
};
|