@event4u/agent-config 10.1.0 → 10.3.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 +110 -167
- package/README.md +1 -1
- package/dist/agent-src/commands/analyze/reference-repo.md +62 -0
- package/dist/agent-src/commands/roadmap/create.md +4 -1
- package/dist/agent-src/commands/roadmap/next.md +38 -0
- package/dist/agent-src/contexts/communication/rules-auto/token-efficiency-mechanics.md +22 -1
- package/dist/agent-src/contexts/contracts/frugality-charter.md +1 -1
- package/dist/agent-src/personas/advisors/first-principles.md +6 -0
- package/dist/agent-src/rules/active-remediation.md +53 -2
- package/dist/agent-src/rules/code-provenance.md +66 -4
- package/dist/agent-src/rules/content-quoting-floor.md +6 -0
- package/dist/agent-src/rules/context-hygiene.md +39 -0
- package/dist/agent-src/rules/design-fidelity.md +49 -3
- package/dist/agent-src/rules/token-budget-discipline.md +3 -2
- package/dist/agent-src/rules/token-efficiency.md +22 -0
- package/dist/agent-src/skills/ai-council/SKILL.md +28 -6
- package/dist/agent-src/skills/condense-memory/SKILL.md +1 -1
- package/dist/agent-src/skills/design-review/references/verification-automation.md +23 -1
- package/dist/agent-src/skills/fe-design/SKILL.md +27 -3
- package/dist/agent-src/skills/judge-synthesis/SKILL.md +30 -0
- package/dist/agent-src/skills/learning-to-rule-or-skill/SKILL.md +11 -0
- package/dist/agent-src/skills/roadmap-writing/SKILL.md +9 -9
- package/dist/agent-src/skills/skill-writing/SKILL.md +4 -0
- package/dist/agent-src/skills/token-optimizer/SKILL.md +5 -1
- package/dist/agent-src/templates/agent-settings.md +12 -28
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +2 -2
- package/dist/agent-src/templates/persona.md +26 -0
- package/dist/agent-src/templates/roadmaps.md +27 -7
- package/dist/agent-src/templates/scripts/work_engine/_lib/agent_settings.ts +0 -1
- package/dist/agent-src/templates/skill.md +35 -1
- package/dist/cli/commands/commands.candidates.test.js +257 -0
- package/dist/cli/commands/commands.candidates.test.js.map +1 -0
- package/dist/cli/commands/commands.js +199 -0
- package/dist/cli/commands/commands.js.map +1 -1
- package/dist/cli/main.js +1 -0
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/registry.js +2 -2
- package/dist/cli/registry.js.map +1 -1
- package/dist/cli-delegate/{chunk-3JUTT26I.js → chunk-6ENSXSBW.js} +1 -1
- package/dist/cli-delegate/{chunk-TVGXH7VA.js → chunk-6LOPHJLD.js} +1 -1
- package/dist/cli-delegate/{chunk-XT2YTJCZ.js → chunk-AYKQGIBG.js} +4 -0
- package/dist/cli-delegate/{chunk-HJSKTMIF.js → chunk-BV3WR67D.js} +3 -19
- package/dist/cli-delegate/{chunk-HTIU3W56.js → chunk-BWMXLD4B.js} +6 -2
- package/dist/cli-delegate/{chunk-2H5SE7DU.js → chunk-FV34EGEX.js} +166 -39
- package/dist/cli-delegate/{chunk-XTC5ARB6.js → chunk-IR3IVRVC.js} +7 -2
- package/dist/cli-delegate/{chunk-LRXJK6GN.js → chunk-JMQZ7MM5.js} +1 -1
- package/dist/cli-delegate/{chunk-NX5AXSLD.js → chunk-X3VOARZD.js} +3 -3
- 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 +881 -204
- package/dist/cli-delegate/cmd_doctor.js +3 -3
- 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 +6 -5
- 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 +44 -9
- package/dist/cli-delegate/cmd_settings_get.js +2 -2
- package/dist/cli-delegate/cmd_settings_migrate.js +4 -4
- package/dist/cli-delegate/cmd_settings_set.js +2 -2
- 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 +21 -21
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +1 -1
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +2 -2
- package/dist/discovery/trust-report.md +1 -1
- package/dist/discovery/workspaces.json +2 -2
- package/dist/hooks/dispatch.js +204 -44
- package/dist/install/install.mjs +9 -21
- package/dist/mcp/registry-manifest.json +2 -2
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +1337 -490
- package/dist/router.json +1 -1
- package/dist/scripts/_lib/agent_settings.js +25 -2
- package/dist/scripts/_lib/agent_settings.js.map +1 -1
- package/dist/scripts/_lib/compile_time_toggles.js +4 -3
- package/dist/scripts/_lib/compile_time_toggles.js.map +1 -1
- package/dist/server/io/yamlIO.js +0 -2
- package/dist/server/io/yamlIO.js.map +1 -1
- package/dist/server/schemas/settings.js +3 -9
- package/dist/server/schemas/settings.js.map +1 -1
- package/dist/shared/settingsClasses.js +64 -2
- package/dist/shared/settingsClasses.js.map +1 -1
- package/dist/ui/assets/{index-B5qGYOJo.js → index-5fXOHoVh.js} +2 -2
- package/dist/ui/assets/index-5fXOHoVh.js.map +1 -0
- package/dist/ui/index.html +1 -1
- package/docs/contracts/settings-classes.md +307 -145
- package/docs/guidelines/agent-infra/active-remediation-mechanics.md +54 -0
- package/docs/guidelines/agent-infra/layered-settings.md +1 -2
- package/docs/guidelines/agent-infra/symptom-driven-harvest-loop.md +104 -0
- package/docs/guidelines/design-antipatterns.md +79 -10
- package/docs/guidelines/design-fidelity-mechanics.md +120 -2
- package/package.json +1 -1
- package/src/agent-src/templates/scripts/work_engine/_lib/agent_settings.ts +0 -1
- package/src/config/agent-settings.template.yml +12 -30
- package/src/config/gate-coverage.yml +42 -8
- package/src/config/gate-violation-baselines.json +15 -3
- package/src/config/profiles/balanced.ini +0 -2
- package/src/config/profiles/full.ini +1 -3
- package/src/config/profiles/minimal.ini +0 -2
- package/src/config/review-prompt-binding-baseline.json +19 -0
- package/src/config/rule-enforcement-baseline.json +0 -1
- package/src/scripts/_cli/cmd_session_recycle.ts +66 -9
- package/src/scripts/_cli/handoff_sessions.ts +3 -2
- package/src/scripts/_dispatch.bash +1 -0
- package/src/scripts/_lib/agent_settings.ts +25 -2
- package/src/scripts/_lib/bench_telegraph.ts +1 -1
- package/src/scripts/_lib/cc_transcript.ts +25 -0
- package/src/scripts/_lib/compile_time_toggles.ts +4 -3
- package/src/scripts/ai_council/clients.ts +243 -34
- package/src/scripts/cache_realization_report.ts +3 -2
- package/src/scripts/check_ci_local_parity.ts +60 -6
- package/src/scripts/check_review_prompt_binding.ts +553 -0
- package/src/scripts/check_rule_projection_integrity.ts +3 -1
- package/src/scripts/check_suppression_hygiene.ts +19 -3
- package/src/scripts/conformance_scan.ts +282 -9
- package/src/scripts/cost/track.mjs +10 -4
- package/src/scripts/council_cli.ts +33 -3
- package/src/scripts/design_slop_rules.test.ts +37 -6
- package/src/scripts/design_slop_rules.ts +150 -22
- package/src/scripts/dispatch_r2_reviewer.ts +15 -1
- package/src/scripts/external_sources_denylist.json +3 -1
- package/src/scripts/hook_manifest.yaml +17 -6
- package/src/scripts/hooks/block_unauthorized_git.ts +54 -8
- package/src/scripts/hooks/delegation_nudge_hook.ts +33 -8
- package/src/scripts/hooks/evidence_independence.ts +61 -9
- package/src/scripts/hooks/session_eol_hook.ts +123 -3
- package/src/scripts/hooks/turn_end_gate_hook.ts +31 -0
- package/src/scripts/hooks/ui_route_nudge_hook.ts +55 -2
- package/src/scripts/lint_design_antipattern_parity.ts +201 -0
- package/src/scripts/lint_harvest_provenance.ts +483 -0
- package/src/scripts/lint_settings_classes.ts +273 -11
- package/src/scripts/lint_skill_router_head.ts +254 -0
- package/src/scripts/lint_symptom_intake.ts +241 -0
- package/src/scripts/report_consultation_rate.ts +128 -2
- package/src/scripts/report_skill_activation.ts +6 -4
- package/src/scripts/report_skill_obligation_violations.ts +2 -1
- package/src/scripts/run_skill_evals.ts +10 -5
- package/src/scripts/schemas/persona.schema.json +8 -0
- package/src/scripts/schemas/provenance-harvest.schema.json +39 -0
- package/src/scripts/sweep_dead_scan_roots.ts +51 -0
- package/src/server/io/yamlIO.ts +0 -2
- package/src/server/schemas/settings.ts +3 -19
- package/src/shared/settingsClasses.ts +93 -2
- package/dist/ui/assets/index-B5qGYOJo.js.map +0 -1
|
@@ -18,8 +18,9 @@ import {
|
|
|
18
18
|
comparePair,
|
|
19
19
|
frontmatterPaths,
|
|
20
20
|
proseEqual,
|
|
21
|
+
resolveSessionRole,
|
|
21
22
|
splitFrontmatter
|
|
22
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-FV34EGEX.js";
|
|
23
24
|
import "./chunk-FTAISGDQ.js";
|
|
24
25
|
import {
|
|
25
26
|
atomic_write_json,
|
|
@@ -27,7 +28,9 @@ import {
|
|
|
27
28
|
is_replay_mode
|
|
28
29
|
} from "./chunk-EJITJBJX.js";
|
|
29
30
|
import "./chunk-Q26HT4QT.js";
|
|
30
|
-
import
|
|
31
|
+
import {
|
|
32
|
+
projectStoreSlug
|
|
33
|
+
} from "./chunk-AYKQGIBG.js";
|
|
31
34
|
import "./chunk-PZWRPRWP.js";
|
|
32
35
|
import "./chunk-M2DPGFZ4.js";
|
|
33
36
|
import {
|
|
@@ -37,7 +40,9 @@ import {
|
|
|
37
40
|
} from "./chunk-63WSP6YZ.js";
|
|
38
41
|
import "./chunk-GRRPEPRN.js";
|
|
39
42
|
import "./chunk-NXFWFAYV.js";
|
|
40
|
-
import
|
|
43
|
+
import {
|
|
44
|
+
load_agent_settings
|
|
45
|
+
} from "./chunk-IR3IVRVC.js";
|
|
41
46
|
import "./chunk-NDJLNC6Q.js";
|
|
42
47
|
import {
|
|
43
48
|
detectToolPresence
|
|
@@ -54,12 +59,12 @@ import {
|
|
|
54
59
|
|
|
55
60
|
// src/scripts/_cli/cmd_conformance.ts
|
|
56
61
|
var YAML = __toESM(require_dist(), 1);
|
|
57
|
-
import * as
|
|
62
|
+
import * as fs14 from "node:fs";
|
|
58
63
|
import * as os7 from "node:os";
|
|
59
|
-
import * as
|
|
60
|
-
import
|
|
64
|
+
import * as path14 from "node:path";
|
|
65
|
+
import process6 from "node:process";
|
|
61
66
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
62
|
-
import { fileURLToPath as
|
|
67
|
+
import { fileURLToPath as fileURLToPath14, pathToFileURL as pathToFileURL14 } from "node:url";
|
|
63
68
|
|
|
64
69
|
// src/install/txlog.ts
|
|
65
70
|
import { createReadStream, createWriteStream, existsSync, readFileSync, renameSync, statSync, unlinkSync } from "node:fs";
|
|
@@ -120,18 +125,18 @@ function routeTargetPathsPosix(target) {
|
|
|
120
125
|
}
|
|
121
126
|
|
|
122
127
|
// src/scripts/report_conformance_funnel.ts
|
|
123
|
-
import * as
|
|
128
|
+
import * as fs13 from "node:fs";
|
|
124
129
|
import * as os6 from "node:os";
|
|
125
|
-
import * as
|
|
126
|
-
import
|
|
127
|
-
import { fileURLToPath as
|
|
130
|
+
import * as path13 from "node:path";
|
|
131
|
+
import process5 from "node:process";
|
|
132
|
+
import { fileURLToPath as fileURLToPath13, pathToFileURL as pathToFileURL13 } from "node:url";
|
|
128
133
|
|
|
129
134
|
// src/scripts/conformance_scan.ts
|
|
130
135
|
import { createHash as createHash3 } from "node:crypto";
|
|
131
|
-
import
|
|
136
|
+
import fs9 from "node:fs";
|
|
132
137
|
import os2 from "node:os";
|
|
133
|
-
import
|
|
134
|
-
import { fileURLToPath as
|
|
138
|
+
import path9 from "node:path";
|
|
139
|
+
import { fileURLToPath as fileURLToPath9, pathToFileURL as pathToFileURL9 } from "node:url";
|
|
135
140
|
|
|
136
141
|
// src/scripts/_lib/transcript_entry.ts
|
|
137
142
|
function _isObject(v) {
|
|
@@ -683,21 +688,37 @@ var WARN_OPS = /* @__PURE__ */ new Set([
|
|
|
683
688
|
"branch"
|
|
684
689
|
]);
|
|
685
690
|
var G = "(?:-[A-Za-z-]+(?:=\\S+)?(?:\\s+\\S+)?\\s+)*";
|
|
691
|
+
var P = "^(?:\\S*\\/)?";
|
|
692
|
+
function ghApiWrite(pathRe) {
|
|
693
|
+
return new RegExp(
|
|
694
|
+
`${P}gh\\s+api\\b(?=[^\\n]*${pathRe})(?=[^\\n]*(?:-X|--method)\\s+(?:POST|PATCH|PUT|DELETE)\\b)`,
|
|
695
|
+
"i"
|
|
696
|
+
);
|
|
697
|
+
}
|
|
686
698
|
var COMMAND_OPS = [
|
|
687
|
-
{ op: "publish", re: new RegExp(
|
|
688
|
-
{
|
|
699
|
+
{ op: "publish", re: new RegExp(`${P}(npm|pnpm|yarn)\\s+${G}publish\\b`, "i") },
|
|
700
|
+
{
|
|
701
|
+
op: "release",
|
|
702
|
+
re: new RegExp(`${P}gh\\s+release\\s+create\\b|${ghApiWrite("\\/releases\\b").source}`, "i")
|
|
703
|
+
},
|
|
689
704
|
{
|
|
690
705
|
op: "tag",
|
|
706
|
+
re: new RegExp(`${P}git\\s+${G}push\\b[^\\n;|&]*(--tags|--follow-tags|refs\\/tags\\/)`, "i")
|
|
707
|
+
},
|
|
708
|
+
{
|
|
709
|
+
op: "pr-merge",
|
|
691
710
|
re: new RegExp(
|
|
692
|
-
|
|
711
|
+
`${P}gh\\s+pr\\s+merge\\b|${ghApiWrite("\\/pulls\\/\\d+\\/merge\\b").source}`,
|
|
693
712
|
"i"
|
|
694
713
|
)
|
|
695
714
|
},
|
|
696
|
-
{
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
{ op: "
|
|
715
|
+
{
|
|
716
|
+
op: "pr-create",
|
|
717
|
+
re: new RegExp(`${P}gh\\s+pr\\s+create\\b|${ghApiWrite("\\/pulls\\b").source}`, "i")
|
|
718
|
+
},
|
|
719
|
+
{ op: "push", re: new RegExp(`${P}git\\s+${G}push\\b`, "i") },
|
|
720
|
+
{ op: "commit", re: new RegExp(`${P}git\\s+${G}commit\\b`, "i") },
|
|
721
|
+
{ op: "branch", re: new RegExp(`${P}git\\s+${G}(checkout\\s+-b|switch\\s+-c)\\b`, "i") }
|
|
701
722
|
];
|
|
702
723
|
var COMMAND_TOOLS = /* @__PURE__ */ new Set([
|
|
703
724
|
"launch-process",
|
|
@@ -1808,12 +1829,19 @@ function readCiSettled(workspaceRoot) {
|
|
|
1808
1829
|
return { seen: false, settled: false };
|
|
1809
1830
|
}
|
|
1810
1831
|
var _COMPLETION_RE = /(^|\n)\s*(?:\*\*)?(?:fertig\b|damit ist alles erledigt|aufgabe erledigt|alles erledigt\b|komplett(?:er)? (?:auftrag|abgearbeitet)|der komplette auftrag ist durch|done[.!]|all done\b|task complete)/i;
|
|
1832
|
+
var _NEGATED_CLAIM_RE = /\b(noch nicht|nicht fertig|nicht durch|wäre verfrüht|ist verfrüht|not yet|not done|isn'?t done|nein)\b/i;
|
|
1833
|
+
function _lineAround(prose, at) {
|
|
1834
|
+
const start = prose.lastIndexOf("\n", at) + 1;
|
|
1835
|
+
const end = prose.indexOf("\n", at);
|
|
1836
|
+
return prose.slice(start, end === -1 ? prose.length : end);
|
|
1837
|
+
}
|
|
1811
1838
|
function detectCompletionClaim(reply, ci) {
|
|
1812
1839
|
if (!ci.seen || ci.settled) return null;
|
|
1813
1840
|
const prose = visibleProse(reply);
|
|
1814
1841
|
const m = _COMPLETION_RE.exec(prose);
|
|
1815
1842
|
if (!m) return null;
|
|
1816
1843
|
const at = m.index;
|
|
1844
|
+
if (_NEGATED_CLAIM_RE.test(_lineAround(prose, at))) return null;
|
|
1817
1845
|
return {
|
|
1818
1846
|
detector: "completion",
|
|
1819
1847
|
evidence: prose.slice(at, at + 120).trim(),
|
|
@@ -2107,7 +2135,7 @@ function isDispatchTool(tool) {
|
|
|
2107
2135
|
function isEvaluationPrompt(prompt) {
|
|
2108
2136
|
return EVALUATION_RE.test(prompt);
|
|
2109
2137
|
}
|
|
2110
|
-
var SELF_SCOPE_RE = /\b(my (work|change|diff|implementation|code|fix|patch|branch|pr)|this (diff|change|
|
|
2138
|
+
var SELF_SCOPE_RE = /\b(my (work|change|diff|implementation|code|fix|patch|branch|pr)|this (diff|change|pr|delta|implementation|patch)|the delta|the change i|what i (wrote|built|changed|implemented)|i just (wrote|built|changed|implemented))\b/i;
|
|
2111
2139
|
function isSelfScoped(prompt) {
|
|
2112
2140
|
return SELF_SCOPE_RE.test(prompt);
|
|
2113
2141
|
}
|
|
@@ -2175,11 +2203,14 @@ function decide2(tool, prompt, priorEvaluations) {
|
|
|
2175
2203
|
}
|
|
2176
2204
|
if (priorEvaluations >= 1) {
|
|
2177
2205
|
return {
|
|
2178
|
-
exit:
|
|
2179
|
-
stdout:
|
|
2180
|
-
|
|
2206
|
+
exit: EXIT_ALLOW5,
|
|
2207
|
+
stdout: `${JSON.stringify({
|
|
2208
|
+
decision: "warn",
|
|
2209
|
+
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.`
|
|
2210
|
+
})}
|
|
2181
2211
|
`,
|
|
2182
|
-
|
|
2212
|
+
stderr: "",
|
|
2213
|
+
evaluations: priorEvaluations + 1
|
|
2183
2214
|
};
|
|
2184
2215
|
}
|
|
2185
2216
|
return {
|
|
@@ -2269,8 +2300,561 @@ if (_isCliEntry7()) {
|
|
|
2269
2300
|
process.exit(main7());
|
|
2270
2301
|
}
|
|
2271
2302
|
|
|
2303
|
+
// src/scripts/hooks/delegation_nudge_hook.ts
|
|
2304
|
+
import fs8 from "node:fs";
|
|
2305
|
+
import path8 from "node:path";
|
|
2306
|
+
import { fileURLToPath as fileURLToPath8, pathToFileURL as pathToFileURL8 } from "node:url";
|
|
2307
|
+
|
|
2308
|
+
// src/scripts/_lib/host_capability.ts
|
|
2309
|
+
import process2 from "node:process";
|
|
2310
|
+
var SAFE_DEFAULT = {
|
|
2311
|
+
schema_version: 1,
|
|
2312
|
+
subagent_spawn: false,
|
|
2313
|
+
parallel_spawn: false,
|
|
2314
|
+
status_polling: false,
|
|
2315
|
+
separate_quota_pool: false,
|
|
2316
|
+
agent_teams: false,
|
|
2317
|
+
worker_respawn: false
|
|
2318
|
+
};
|
|
2319
|
+
function asBool(value) {
|
|
2320
|
+
return value === true;
|
|
2321
|
+
}
|
|
2322
|
+
function normalizeHostManifest(input) {
|
|
2323
|
+
if (input === null || typeof input !== "object") {
|
|
2324
|
+
return { ...SAFE_DEFAULT };
|
|
2325
|
+
}
|
|
2326
|
+
const src = input;
|
|
2327
|
+
return {
|
|
2328
|
+
schema_version: 1,
|
|
2329
|
+
subagent_spawn: asBool(src.subagent_spawn),
|
|
2330
|
+
parallel_spawn: asBool(src.parallel_spawn),
|
|
2331
|
+
status_polling: asBool(src.status_polling),
|
|
2332
|
+
separate_quota_pool: asBool(src.separate_quota_pool),
|
|
2333
|
+
agent_teams: asBool(src.agent_teams),
|
|
2334
|
+
worker_respawn: asBool(src.worker_respawn)
|
|
2335
|
+
};
|
|
2336
|
+
}
|
|
2337
|
+
var HOST_CAPABILITY_REGISTRY = {
|
|
2338
|
+
claude: { subagent_spawn: true, parallel_spawn: true }
|
|
2339
|
+
};
|
|
2340
|
+
function resolveHostCapabilities(hostId, override) {
|
|
2341
|
+
if (override !== void 0 && override !== null && typeof override === "object" && !Array.isArray(override)) {
|
|
2342
|
+
return normalizeHostManifest(override);
|
|
2343
|
+
}
|
|
2344
|
+
const row = hostId !== null && hostId !== void 0 ? HOST_CAPABILITY_REGISTRY[hostId] : void 0;
|
|
2345
|
+
if (row === void 0) {
|
|
2346
|
+
return { ...SAFE_DEFAULT };
|
|
2347
|
+
}
|
|
2348
|
+
return { ...SAFE_DEFAULT, ...row, schema_version: 1 };
|
|
2349
|
+
}
|
|
2350
|
+
function probeHostCapabilities(hostId) {
|
|
2351
|
+
const base = resolveHostCapabilities(hostId);
|
|
2352
|
+
const flag = process2.env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS;
|
|
2353
|
+
const probedAgentTeams = typeof flag === "string" && flag !== "";
|
|
2354
|
+
return { ...base, agent_teams: base.agent_teams || probedAgentTeams };
|
|
2355
|
+
}
|
|
2356
|
+
|
|
2357
|
+
// src/scripts/_lib/auto_dispatch.ts
|
|
2358
|
+
var SIZE_FLOOR = 1;
|
|
2359
|
+
function inSession(reason) {
|
|
2360
|
+
return { delegable: false, action: "in-session", mode: null, reason };
|
|
2361
|
+
}
|
|
2362
|
+
function classifyTask(signals, activation) {
|
|
2363
|
+
if (activation.halted) return inSession("emergency.orchestration_halt is set");
|
|
2364
|
+
if (!activation.subagent_spawn) return inSession("host has no subagent_spawn primitive");
|
|
2365
|
+
if (!(signals.size_estimate > SIZE_FLOOR)) {
|
|
2366
|
+
return inSession(`task below size floor (${signals.size_estimate} <= ${SIZE_FLOOR})`);
|
|
2367
|
+
}
|
|
2368
|
+
const slices = signals.independent_slices ?? 0;
|
|
2369
|
+
let mode = null;
|
|
2370
|
+
let reason = "";
|
|
2371
|
+
if (signals.parallelizable === "steps" || signals.ordered_plan === true) {
|
|
2372
|
+
mode = "do-in-steps";
|
|
2373
|
+
reason = signals.parallelizable === "steps" ? "declared parallelizable: steps" : "ordered-plan structure";
|
|
2374
|
+
} else if (signals.parallelizable === "files" || signals.parallelizable === "independent" || slices >= 2) {
|
|
2375
|
+
mode = "do-in-parallel";
|
|
2376
|
+
reason = signals.parallelizable ? `declared parallelizable: ${signals.parallelizable}` : `independent slices (${slices})`;
|
|
2377
|
+
}
|
|
2378
|
+
if (mode === null) {
|
|
2379
|
+
return { delegable: false, action: "ask", mode: null, reason: "no delegable signal \u2014 borderline, ask" };
|
|
2380
|
+
}
|
|
2381
|
+
return { delegable: true, action: "dispatch", mode, reason };
|
|
2382
|
+
}
|
|
2383
|
+
var LOOKUP_PATTERNS = [
|
|
2384
|
+
{
|
|
2385
|
+
cls: "definition",
|
|
2386
|
+
primitive: "code-graph-query",
|
|
2387
|
+
re: /\b(where\s+is\s+\S+\s+defined|definition\s+(location|of|site)|find\s+the\s+definition|locate\s+the\s+(class|enum|function|type|interface|symbol)|confirm\w*\s+\S+\s+definition)\b/i
|
|
2388
|
+
},
|
|
2389
|
+
{
|
|
2390
|
+
cls: "references",
|
|
2391
|
+
primitive: "code-graph-query",
|
|
2392
|
+
re: /\b(who\s+(calls|imports|uses|references)|call\s*sites?|import\s+(call\s*)?sites?|reverse\s+references|where\s+is\s+\S+\s+(used|imported|referenced|called)|all\s+(callers|usages|references)\s+of)\b/i
|
|
2393
|
+
},
|
|
2394
|
+
{
|
|
2395
|
+
cls: "string-existence",
|
|
2396
|
+
primitive: "fts-or-capped-grep",
|
|
2397
|
+
re: /\b(does\s+(the\s+)?string\s+.*\bexist|is\s+(the\s+)?string\s+.*\b(present|used)\b|prob\w+\s+(candidate\s+)?strings?|search\s+for\s+the\s+(exact\s+)?string|(grep|check)\s+(for\s+)?(the\s+)?(literal|string)\b|does\s+\S+\s+appear\s+anywhere)/i
|
|
2398
|
+
},
|
|
2399
|
+
{
|
|
2400
|
+
cls: "report-run",
|
|
2401
|
+
primitive: "script-run-rtk",
|
|
2402
|
+
re: /\b(run(ning)?\s+(the\s+)?\S*(report|check|lint\w*|coverage)\b|run(ning)?\s+(check|lint|report)_\w+|regenerate\s+the\s+\S+\s+report)/i
|
|
2403
|
+
}
|
|
2404
|
+
];
|
|
2405
|
+
function classifyLookup(taskText) {
|
|
2406
|
+
for (const p of LOOKUP_PATTERNS) {
|
|
2407
|
+
if (p.re.test(taskText)) {
|
|
2408
|
+
return {
|
|
2409
|
+
lookup_class: p.cls,
|
|
2410
|
+
route: "primitive",
|
|
2411
|
+
primitive: p.primitive,
|
|
2412
|
+
reason: `lookup-class ${p.cls} \u2014 deterministic primitive, no spawn`
|
|
2413
|
+
};
|
|
2414
|
+
}
|
|
2415
|
+
}
|
|
2416
|
+
return {
|
|
2417
|
+
lookup_class: null,
|
|
2418
|
+
route: "escalate",
|
|
2419
|
+
primitive: null,
|
|
2420
|
+
reason: "not lookup-shaped \u2014 regular classification path (never down-guessed)"
|
|
2421
|
+
};
|
|
2422
|
+
}
|
|
2423
|
+
|
|
2424
|
+
// src/scripts/_lib/judgment_ladder.ts
|
|
2425
|
+
var RENAME_RE = /\brename\s+\S+\s+to\s+\S+\b/i;
|
|
2426
|
+
var CODEMOD_RE = /\bcodemod\b/i;
|
|
2427
|
+
var FORMATTER_RUN_RE = /\bauto-?format(?:ting)?\b|\breformat(?:ting)?\b|\brun(?:ning)?\s+prettier\b|\brun(?:ning)?\s+eslint\s*--fix\b|\bapply\s+eslint\s*--fix\b/i;
|
|
2428
|
+
var SEARCH_REPLACE_RE = /\bsearch-and-replace\b|\bfind-and-replace\b|\bbulk\s+rename\b/i;
|
|
2429
|
+
function detectMechanicalTransform(text) {
|
|
2430
|
+
const rename = RENAME_RE.exec(text);
|
|
2431
|
+
if (rename) {
|
|
2432
|
+
return { matched: true, reason: `rename signal ("${rename[0]}") \u2014 deterministic script, no spawn` };
|
|
2433
|
+
}
|
|
2434
|
+
const codemod = CODEMOD_RE.exec(text);
|
|
2435
|
+
if (codemod) {
|
|
2436
|
+
return { matched: true, reason: `codemod signal ("${codemod[0]}") \u2014 deterministic script, no spawn` };
|
|
2437
|
+
}
|
|
2438
|
+
const formatter = FORMATTER_RUN_RE.exec(text);
|
|
2439
|
+
if (formatter) {
|
|
2440
|
+
return { matched: true, reason: `formatter-run signal ("${formatter[0]}") \u2014 deterministic script, no spawn` };
|
|
2441
|
+
}
|
|
2442
|
+
const searchReplace = SEARCH_REPLACE_RE.exec(text);
|
|
2443
|
+
if (searchReplace) {
|
|
2444
|
+
return {
|
|
2445
|
+
matched: true,
|
|
2446
|
+
reason: `search-and-replace/bulk-rename signal ("${searchReplace[0]}") \u2014 deterministic script, no spawn`
|
|
2447
|
+
};
|
|
2448
|
+
}
|
|
2449
|
+
return { matched: false, reason: "no mechanical-transform signal" };
|
|
2450
|
+
}
|
|
2451
|
+
var SINGLE_SLICE_READHEAVY_RE = /\b(?:read|review|summarize|summarise|inventory|audit|investigate|research|inspect|dig into|look into)\b[^.!?\n]{0,80}\b(?:this file|the file|this codebase|the codebase|this transcript|the transcript|this log|the log|this document|the document|this diff|the diff)\b/i;
|
|
2452
|
+
function detectBoundedReadHeavySlice(text) {
|
|
2453
|
+
const m = SINGLE_SLICE_READHEAVY_RE.exec(text);
|
|
2454
|
+
return m ? {
|
|
2455
|
+
matched: true,
|
|
2456
|
+
reason: `single bounded read-heavy slice ("${m[0]}") \u2014 one lite-tier subagent instead of session-context burn`
|
|
2457
|
+
} : { matched: false, reason: "no single-slice read-heavy signal" };
|
|
2458
|
+
}
|
|
2459
|
+
var CROSS_LAYER_RE = /\bcross[- ]layer\b|\bcross[- ]cutting\b|\bback[- ]?end\s+and\s+front[- ]?end\b|\bfront[- ]?end\s+and\s+back[- ]?end\b/i;
|
|
2460
|
+
var REVIEW_WITH_CHALLENGE_RE = /\breview[- ]with[- ]challenge\b|\bchallenge[- ]and[- ]implement\b|\bimplementer\s+and\s+(?:a\s+)?(?:judge|reviewer)\s+(?:working\s+)?together\b|\bsecond\s+opinion\s+while\s+(?:building|implementing)\b/i;
|
|
2461
|
+
var SHARED_TASK_LIST_RE = /\bshared\s+(?:task\s+list|todo\s+list|backlog)\b|\bcoordinat(?:e|ed|ing)\s+(?:with|between|across)\s+(?:multiple\s+|several\s+)?(?:agents|workers|subagents|teammates)\b/i;
|
|
2462
|
+
function detectCommunicationNeed(text) {
|
|
2463
|
+
const crossLayer = CROSS_LAYER_RE.exec(text);
|
|
2464
|
+
if (crossLayer) {
|
|
2465
|
+
return { matched: true, reason: `cross-layer communication signal ("${crossLayer[0]}")` };
|
|
2466
|
+
}
|
|
2467
|
+
const reviewChallenge = REVIEW_WITH_CHALLENGE_RE.exec(text);
|
|
2468
|
+
if (reviewChallenge) {
|
|
2469
|
+
return { matched: true, reason: `review-with-challenge signal ("${reviewChallenge[0]}")` };
|
|
2470
|
+
}
|
|
2471
|
+
const sharedList = SHARED_TASK_LIST_RE.exec(text);
|
|
2472
|
+
if (sharedList) {
|
|
2473
|
+
return { matched: true, reason: `shared-task-list signal ("${sharedList[0]}")` };
|
|
2474
|
+
}
|
|
2475
|
+
return { matched: false, reason: "no communication-need signal" };
|
|
2476
|
+
}
|
|
2477
|
+
var DESIGN_DECISION_RE = /\bdesign\s+decision\b|\barchitectur(?:e|al)\s+decision\b|\b(?:record(?:ing)?|decide|deciding|decision|accept(?:ed|ing)?|approv(?:e|ed|ing|al)|challeng(?:e|ed|ing)|choos(?:e|ing)|reject(?:ed|ing)?)\b[^.!?\n]{0,40}\bADR\b|\bADR\b[^.!?\n]{0,40}\b(?:record(?:ing)?|decide|deciding|decision|accept(?:ed|ing)?|approv(?:e|ed|ing|al)|challeng(?:e|ed|ing)|choos(?:e|ing)|reject(?:ed|ing)?)\b/i;
|
|
2478
|
+
var SECURITY_DOWNGRADE_RE = /\bsecurity\s+downgrade\b|\bdowngrade\s+(?:the\s+)?security\b|\bsecurity\s+exception\b/i;
|
|
2479
|
+
var RELEASE_GATE_ESCALATION_RE = /\bgate\s+escalation\b|\bescalat(?:e|ion)\s+to\s+(?:the\s+)?council\b|\b(?:escalat(?:e|ing|ion)|contest(?:ed|ing)?|dispute|disputing|override|overriding|waiv(?:e|ing)|bypass(?:ed|ing)?|challeng(?:e|ed|ing))\b[^.!?\n]{0,40}\brelease[- ]gate\b|\brelease[- ]gate\b[^.!?\n]{0,40}\b(?:escalat(?:e|ing|ion)|contest(?:ed|ing)?|dispute|disputing|override|overriding|waiv(?:e|ing)|bypass(?:ed|ing)?|challeng(?:e|ed|ing))\b/i;
|
|
2480
|
+
function detectContestedJudgment(text) {
|
|
2481
|
+
const design = DESIGN_DECISION_RE.exec(text);
|
|
2482
|
+
if (design) {
|
|
2483
|
+
return { matched: true, reason: `design-decision signal ("${design[0]}")` };
|
|
2484
|
+
}
|
|
2485
|
+
const security = SECURITY_DOWNGRADE_RE.exec(text);
|
|
2486
|
+
if (security) {
|
|
2487
|
+
return { matched: true, reason: `security-downgrade signal ("${security[0]}")` };
|
|
2488
|
+
}
|
|
2489
|
+
const releaseGate = RELEASE_GATE_ESCALATION_RE.exec(text);
|
|
2490
|
+
if (releaseGate) {
|
|
2491
|
+
return { matched: true, reason: `release-gate-escalation signal ("${releaseGate[0]}")` };
|
|
2492
|
+
}
|
|
2493
|
+
return { matched: false, reason: "no contested-judgment signal" };
|
|
2494
|
+
}
|
|
2495
|
+
var _QUESTION_IMPERATIVE_RE = /\b(fix|implement|refactor|build|create|write|add|update|delete|remove|rename|migrate|install|deploy|commit|push|merge|run|execute|generate|erstelle|baue|implementiere|schreibe|behebe)\b/i;
|
|
2496
|
+
var _QUESTION_LEAD_RE = /^(is|are|does|do|did|can|could|should|would|will|which|what|why|how|when|where|who|whose|ist|sind|hat|haben|kann|welche[rs]?|was|warum|wie|wann|wo|wer)\b/i;
|
|
2497
|
+
var _CLASSIFY_LEAD_RE = /^(classify|categori[sz]e|klassifiziere)\b/i;
|
|
2498
|
+
var _QUESTION_MAX_LEN = 240;
|
|
2499
|
+
var _NEEDS_TOOLS_RE = /\b(this|the|that|my|our)\s+(?:[\w-]+\s+){0,2}?(file|files|codebase|repo|repository|transcript|log|logs|diff|document|branch|pr|route|routes|schema|module|class|function|endpoint|test|tests)\b|[\w.-]+\/[\w.-]+|\b[\w-]+\.(ts|js|py|php|md|json|yaml|yml|sh|go|rs)\b/i;
|
|
2500
|
+
function detectBoundedQuestion(taskText) {
|
|
2501
|
+
const text = taskText.trim();
|
|
2502
|
+
if (!text || text.length > _QUESTION_MAX_LEN || text.includes("\n")) {
|
|
2503
|
+
return { matched: false, reason: "not-bounded" };
|
|
2504
|
+
}
|
|
2505
|
+
if (_NEEDS_TOOLS_RE.test(text)) {
|
|
2506
|
+
return { matched: false, reason: "references-tool-requiring-objects" };
|
|
2507
|
+
}
|
|
2508
|
+
if (_CLASSIFY_LEAD_RE.test(text)) {
|
|
2509
|
+
return {
|
|
2510
|
+
matched: true,
|
|
2511
|
+
reason: "bounded-question (classification) \u2014 rung-0.5 single completion via ask_transport, no session"
|
|
2512
|
+
};
|
|
2513
|
+
}
|
|
2514
|
+
if (_QUESTION_IMPERATIVE_RE.test(text)) {
|
|
2515
|
+
return { matched: false, reason: "imperative-work-verb" };
|
|
2516
|
+
}
|
|
2517
|
+
if (_QUESTION_LEAD_RE.test(text) && text.endsWith("?")) {
|
|
2518
|
+
return {
|
|
2519
|
+
matched: true,
|
|
2520
|
+
reason: "bounded-question \u2014 rung-0.5 single completion via ask_transport, no session"
|
|
2521
|
+
};
|
|
2522
|
+
}
|
|
2523
|
+
return { matched: false, reason: "no-interrogative-shape" };
|
|
2524
|
+
}
|
|
2525
|
+
function classifyLadder(inp) {
|
|
2526
|
+
if (inp.interactiveApprovalRequired === true) {
|
|
2527
|
+
return {
|
|
2528
|
+
rung: null,
|
|
2529
|
+
verdict: "in-session",
|
|
2530
|
+
reason: "interactive-approval-required \u2014 caller-stated, needs a human decision before anything may run"
|
|
2531
|
+
};
|
|
2532
|
+
}
|
|
2533
|
+
const lookup = classifyLookup(inp.taskText);
|
|
2534
|
+
if (lookup.route === "primitive") {
|
|
2535
|
+
return { rung: 0, verdict: "script", reason: `lookup-class ${lookup.lookup_class} \u2014 ${lookup.reason}` };
|
|
2536
|
+
}
|
|
2537
|
+
const mechanical = detectMechanicalTransform(inp.taskText);
|
|
2538
|
+
if (mechanical.matched) {
|
|
2539
|
+
return { rung: 0, verdict: "script", reason: mechanical.reason };
|
|
2540
|
+
}
|
|
2541
|
+
if (inp.insideSubagentSession === true) {
|
|
2542
|
+
return {
|
|
2543
|
+
rung: null,
|
|
2544
|
+
verdict: "in-session",
|
|
2545
|
+
reason: "recursive-dispatch guard: this classification runs inside a subagent/teammate session \u2014 rungs 1-4 resolve in-session"
|
|
2546
|
+
};
|
|
2547
|
+
}
|
|
2548
|
+
if (inp.activation.halted) {
|
|
2549
|
+
return { rung: null, verdict: "in-session", reason: "emergency.orchestration_halt is set" };
|
|
2550
|
+
}
|
|
2551
|
+
if (!inp.activation.subagent_spawn) {
|
|
2552
|
+
return { rung: null, verdict: "in-session", reason: "host has no subagent_spawn primitive" };
|
|
2553
|
+
}
|
|
2554
|
+
const contested = detectContestedJudgment(inp.taskText);
|
|
2555
|
+
if (contested.matched) {
|
|
2556
|
+
return { rung: 4, verdict: "council", reason: contested.reason };
|
|
2557
|
+
}
|
|
2558
|
+
const communication = detectCommunicationNeed(inp.taskText);
|
|
2559
|
+
if (communication.matched) {
|
|
2560
|
+
if (inp.agentTeams) {
|
|
2561
|
+
return { rung: 3, verdict: "team", reason: communication.reason };
|
|
2562
|
+
}
|
|
2563
|
+
const fallback = classifyTask(inp.signals, inp.activation);
|
|
2564
|
+
if (fallback.action === "dispatch" && fallback.mode !== null) {
|
|
2565
|
+
return {
|
|
2566
|
+
rung: 2,
|
|
2567
|
+
verdict: "subagent",
|
|
2568
|
+
mode: fallback.mode,
|
|
2569
|
+
degraded_from: 3,
|
|
2570
|
+
reason: `${communication.reason} \u2014 no agent_teams host capability, degraded to rung 2 (${fallback.reason})`
|
|
2571
|
+
};
|
|
2572
|
+
}
|
|
2573
|
+
return {
|
|
2574
|
+
rung: null,
|
|
2575
|
+
verdict: fallback.action === "ask" ? "ask" : "in-session",
|
|
2576
|
+
degraded_from: 3,
|
|
2577
|
+
reason: `${communication.reason} \u2014 no agent_teams host capability, degraded below rung 2 (${fallback.reason})`
|
|
2578
|
+
};
|
|
2579
|
+
}
|
|
2580
|
+
const classification = classifyTask(inp.signals, inp.activation);
|
|
2581
|
+
if (classification.action === "dispatch" && classification.mode !== null) {
|
|
2582
|
+
return { rung: 2, verdict: "subagent", mode: classification.mode, reason: classification.reason };
|
|
2583
|
+
}
|
|
2584
|
+
if (inp.signals.size_estimate <= SIZE_FLOOR) {
|
|
2585
|
+
const question = detectBoundedQuestion(inp.taskText);
|
|
2586
|
+
if (question.matched) {
|
|
2587
|
+
return { rung: 0.5, verdict: "ask", reason: question.reason };
|
|
2588
|
+
}
|
|
2589
|
+
return {
|
|
2590
|
+
rung: null,
|
|
2591
|
+
verdict: classification.action === "ask" ? "ask" : "in-session",
|
|
2592
|
+
reason: classification.reason
|
|
2593
|
+
};
|
|
2594
|
+
}
|
|
2595
|
+
const single = detectBoundedReadHeavySlice(inp.taskText);
|
|
2596
|
+
if (single.matched) {
|
|
2597
|
+
return { rung: 1, verdict: "subagent", mode: null, reason: single.reason };
|
|
2598
|
+
}
|
|
2599
|
+
return {
|
|
2600
|
+
rung: null,
|
|
2601
|
+
verdict: classification.action === "ask" ? "ask" : "in-session",
|
|
2602
|
+
reason: classification.reason
|
|
2603
|
+
};
|
|
2604
|
+
}
|
|
2605
|
+
|
|
2606
|
+
// src/scripts/_lib/subagent_routing.ts
|
|
2607
|
+
function modelForTier(tier, map) {
|
|
2608
|
+
if (tier === "lite") return map.lite ?? "";
|
|
2609
|
+
if (tier === "medium") return map.medium ?? "";
|
|
2610
|
+
if (tier === "high") return map.high ?? "";
|
|
2611
|
+
return "";
|
|
2612
|
+
}
|
|
2613
|
+
function resolveSubagentRouting(inp) {
|
|
2614
|
+
const tier = !inp.downshift || inp.task_tier === "inherit" ? inp.session_tier : inp.task_tier;
|
|
2615
|
+
const downshifted = inp.downshift && inp.task_tier !== "inherit" && tier !== inp.session_tier;
|
|
2616
|
+
const applied = inp.downshift && inp.task_tier !== "inherit";
|
|
2617
|
+
const tier_source = applied ? inp.task_tier_origin ?? "static" : "inherit";
|
|
2618
|
+
const useSeparate = inp.quota_arbitrage && inp.separate_quota_pool;
|
|
2619
|
+
const quota_pool = useSeparate ? "separate" : "shared";
|
|
2620
|
+
const reasonParts = [];
|
|
2621
|
+
reasonParts.push(downshifted ? `downshift to ${tier}` : `session tier ${tier}`);
|
|
2622
|
+
reasonParts.push(useSeparate ? "separate quota pool (bonus)" : "shared quota pool");
|
|
2623
|
+
return {
|
|
2624
|
+
tier,
|
|
2625
|
+
model: modelForTier(tier, inp.model_map),
|
|
2626
|
+
quota_pool,
|
|
2627
|
+
tier_source,
|
|
2628
|
+
reason: reasonParts.join(" \xB7 ")
|
|
2629
|
+
};
|
|
2630
|
+
}
|
|
2631
|
+
|
|
2632
|
+
// src/scripts/hooks/delegation_nudge_hook.ts
|
|
2633
|
+
var EXIT_ALLOW6 = 0;
|
|
2634
|
+
var EXIT_WARN3 = 2;
|
|
2635
|
+
function _isObject7(v) {
|
|
2636
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
2637
|
+
}
|
|
2638
|
+
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;
|
|
2639
|
+
var FILE_SIGNAL_FLOOR = 3;
|
|
2640
|
+
function enumeratedFileTokens(text) {
|
|
2641
|
+
const matches = text.match(FILE_TOKEN_RE) ?? [];
|
|
2642
|
+
return [...new Set(matches.map((m) => m.replace(/`/g, "").toLowerCase()))];
|
|
2643
|
+
}
|
|
2644
|
+
function detectEnumeratedFiles(text) {
|
|
2645
|
+
return enumeratedFileTokens(text).length;
|
|
2646
|
+
}
|
|
2647
|
+
var EXPLICIT_COUNT_RE = /\b(\d+)\s+(files?|modules?|components?|endpoints?|scripts?|skills?|rules?|tickets?|tests?|screens?|pages?|repos?|services?|classes?|functions?|methods?|slices?|tasks?|items?|targets?|routes?|controllers?|Dateien|Module|Tests|Komponenten|Skripte|Regeln|Tickets|Aufgaben|Klassen|Funktionen|Endpunkte)\b/i;
|
|
2648
|
+
function detectExplicitSliceCount(text) {
|
|
2649
|
+
const m = EXPLICIT_COUNT_RE.exec(text);
|
|
2650
|
+
if (!m) return null;
|
|
2651
|
+
const n = Number.parseInt(m[1] ?? "", 10);
|
|
2652
|
+
return Number.isFinite(n) && n > 0 ? n : null;
|
|
2653
|
+
}
|
|
2654
|
+
var FOR_EACH_RE = /\bfor\s+each\b|\bfor\s+every\b|\beach\s+of\s+the\b|\bevery\s+one\s+of\b|\ball(?:e|en)\b|\bjed(?:e|er|es|en)\b|\bjeweils\b/i;
|
|
2655
|
+
function detectForEachShape(text) {
|
|
2656
|
+
return FOR_EACH_RE.test(text);
|
|
2657
|
+
}
|
|
2658
|
+
function detectMultiDeliverableConjunction(text) {
|
|
2659
|
+
for (const sentence of text.split(/[.!?\n]+/)) {
|
|
2660
|
+
const commaCount = (sentence.match(/,/g) ?? []).length;
|
|
2661
|
+
if (commaCount < 2) continue;
|
|
2662
|
+
const tail = sentence.slice(sentence.lastIndexOf(",") + 1);
|
|
2663
|
+
if (/^\s*(and|und)\b/i.test(tail)) {
|
|
2664
|
+
return commaCount + 1;
|
|
2665
|
+
}
|
|
2666
|
+
}
|
|
2667
|
+
return 0;
|
|
2668
|
+
}
|
|
2669
|
+
var STEP_WORD_RE = /\b(?:step|schritt)\s*\d+\b/gi;
|
|
2670
|
+
var STEP_LINE_RE = /^\s*\d+[.)]\s+\S/gm;
|
|
2671
|
+
var ORDERED_LINE_FLOOR = 3;
|
|
2672
|
+
var ORDERED_WORD_FLOOR = 2;
|
|
2673
|
+
function detectOrderedPlan(text) {
|
|
2674
|
+
const wordMatches = text.match(STEP_WORD_RE) ?? [];
|
|
2675
|
+
const lineMatches = text.match(STEP_LINE_RE) ?? [];
|
|
2676
|
+
const ordered = wordMatches.length >= ORDERED_WORD_FLOOR || lineMatches.length >= ORDERED_LINE_FLOOR;
|
|
2677
|
+
const count = Math.max(wordMatches.length, lineMatches.length);
|
|
2678
|
+
return { ordered, stepCount: count };
|
|
2679
|
+
}
|
|
2680
|
+
function extractTaskSignals(text) {
|
|
2681
|
+
const ordered = detectOrderedPlan(text);
|
|
2682
|
+
if (ordered.ordered) {
|
|
2683
|
+
return {
|
|
2684
|
+
signals: {
|
|
2685
|
+
parallelizable: null,
|
|
2686
|
+
ordered_plan: true,
|
|
2687
|
+
independent_slices: 0,
|
|
2688
|
+
size_estimate: Math.max(ordered.stepCount, 2)
|
|
2689
|
+
},
|
|
2690
|
+
sliceCountForLine: ordered.stepCount
|
|
2691
|
+
};
|
|
2692
|
+
}
|
|
2693
|
+
const fileCount = detectEnumeratedFiles(text);
|
|
2694
|
+
const explicit = detectExplicitSliceCount(text) ?? 0;
|
|
2695
|
+
const conjunction = detectMultiDeliverableConjunction(text);
|
|
2696
|
+
const forEach = detectForEachShape(text);
|
|
2697
|
+
const fileSignal = fileCount >= FILE_SIGNAL_FLOOR ? fileCount : 0;
|
|
2698
|
+
let slices = Math.max(fileSignal, explicit, conjunction);
|
|
2699
|
+
if (slices === 0 && forEach) {
|
|
2700
|
+
slices = 2;
|
|
2701
|
+
}
|
|
2702
|
+
const parallelizable = fileSignal >= 3 ? "files" : forEach ? "independent" : null;
|
|
2703
|
+
return {
|
|
2704
|
+
signals: {
|
|
2705
|
+
parallelizable,
|
|
2706
|
+
ordered_plan: false,
|
|
2707
|
+
independent_slices: slices,
|
|
2708
|
+
size_estimate: slices > 0 ? Math.max(slices, 2) : 0
|
|
2709
|
+
},
|
|
2710
|
+
sliceCountForLine: slices
|
|
2711
|
+
};
|
|
2712
|
+
}
|
|
2713
|
+
function resolveActivation(workspace_root, hostId) {
|
|
2714
|
+
const settings = load_agent_settings({ cwd: workspace_root });
|
|
2715
|
+
const emergency = settings["emergency"] ?? {};
|
|
2716
|
+
const halted = emergency["orchestration_halt"] === true;
|
|
2717
|
+
const host_manifest = probeHostCapabilities(hostId);
|
|
2718
|
+
const sub = settings["subagents"] ?? {};
|
|
2719
|
+
const downshift = sub["downshift"] !== false;
|
|
2720
|
+
return {
|
|
2721
|
+
activation: { halted, subagent_spawn: host_manifest.subagent_spawn },
|
|
2722
|
+
downshift,
|
|
2723
|
+
separate_quota_pool: host_manifest.separate_quota_pool,
|
|
2724
|
+
agentTeams: host_manifest.agent_teams
|
|
2725
|
+
};
|
|
2726
|
+
}
|
|
2727
|
+
function recommendSliceTier(downshift, separate_quota_pool) {
|
|
2728
|
+
const decision = resolveSubagentRouting({
|
|
2729
|
+
task_tier: "lite",
|
|
2730
|
+
session_tier: "high",
|
|
2731
|
+
downshift,
|
|
2732
|
+
quota_arbitrage: false,
|
|
2733
|
+
model_map: {},
|
|
2734
|
+
separate_quota_pool
|
|
2735
|
+
});
|
|
2736
|
+
return decision.tier;
|
|
2737
|
+
}
|
|
2738
|
+
function buildNudgeLine(rung, classification, sliceCount, tier) {
|
|
2739
|
+
const unit = sliceCount === 1 ? "slice" : "slices";
|
|
2740
|
+
const rungLabel = rung === null ? "rung-?" : `rung-${rung}`;
|
|
2741
|
+
if (rung === 0.5) {
|
|
2742
|
+
return `<delegation-nudge>rung-0.5: ask, est. <1k tokens. This is a single bounded question \u2014 answer it via ONE completion (\`./scripts-run src/scripts/ask_transport "<question>"\`) instead of a subagent spawn (measured spawn floor: ~251k tokens) \u2014 ${classification.reason}.</delegation-nudge>`;
|
|
2743
|
+
}
|
|
2744
|
+
const modeLabel = classification.mode ?? "single-slice";
|
|
2745
|
+
return `<delegation-nudge>${rungLabel}: dispatch ${modeLabel} (${sliceCount} ${unit}, ${tier} tier recommended). Consider dispatching via subagent-orchestration instead of doing every slice in-session \u2014 ${classification.reason}.</delegation-nudge>`;
|
|
2746
|
+
}
|
|
2747
|
+
function classifyPrompt(prompt, workspace_root, hostId) {
|
|
2748
|
+
try {
|
|
2749
|
+
const { signals, sliceCountForLine } = extractTaskSignals(prompt);
|
|
2750
|
+
const { activation, downshift, separate_quota_pool, agentTeams } = resolveActivation(
|
|
2751
|
+
workspace_root,
|
|
2752
|
+
hostId
|
|
2753
|
+
);
|
|
2754
|
+
const sessionRole = resolveSessionRole(process.env);
|
|
2755
|
+
const ladder = classifyLadder({
|
|
2756
|
+
taskText: prompt,
|
|
2757
|
+
signals,
|
|
2758
|
+
activation,
|
|
2759
|
+
agentTeams,
|
|
2760
|
+
insideSubagentSession: sessionRole !== "orchestrator"
|
|
2761
|
+
});
|
|
2762
|
+
if (ladder.verdict !== "subagent") {
|
|
2763
|
+
return null;
|
|
2764
|
+
}
|
|
2765
|
+
const tier = recommendSliceTier(downshift, separate_quota_pool);
|
|
2766
|
+
const sliceCount = ladder.rung === 1 ? 1 : sliceCountForLine;
|
|
2767
|
+
const classification = {
|
|
2768
|
+
delegable: true,
|
|
2769
|
+
action: "dispatch",
|
|
2770
|
+
mode: ladder.mode ?? null,
|
|
2771
|
+
reason: ladder.reason
|
|
2772
|
+
};
|
|
2773
|
+
return { classification, sliceCount, tier, rung: ladder.rung };
|
|
2774
|
+
} catch {
|
|
2775
|
+
return null;
|
|
2776
|
+
}
|
|
2777
|
+
}
|
|
2778
|
+
function _extractPrompt2(payload) {
|
|
2779
|
+
for (const key of ["prompt", "userPrompt", "user_prompt", "message", "text"]) {
|
|
2780
|
+
const v = payload[key];
|
|
2781
|
+
if (typeof v === "string" && v.trim()) {
|
|
2782
|
+
return v;
|
|
2783
|
+
}
|
|
2784
|
+
}
|
|
2785
|
+
return "";
|
|
2786
|
+
}
|
|
2787
|
+
function _workspaceRoot(envelope) {
|
|
2788
|
+
const v = envelope["workspace_root"];
|
|
2789
|
+
if (typeof v === "string" && v) {
|
|
2790
|
+
return v;
|
|
2791
|
+
}
|
|
2792
|
+
return process.cwd();
|
|
2793
|
+
}
|
|
2794
|
+
function main8() {
|
|
2795
|
+
let envelope = {};
|
|
2796
|
+
try {
|
|
2797
|
+
const raw = readHookStdin();
|
|
2798
|
+
envelope = raw.trim() ? JSON.parse(raw) : {};
|
|
2799
|
+
} catch {
|
|
2800
|
+
return EXIT_ALLOW6;
|
|
2801
|
+
}
|
|
2802
|
+
const env = _isObject7(envelope) ? envelope : {};
|
|
2803
|
+
const event = env["event"];
|
|
2804
|
+
const slot = typeof event === "string" && event !== "" ? event : "user_prompt_submit";
|
|
2805
|
+
if (slot !== "user_prompt_submit") {
|
|
2806
|
+
return EXIT_ALLOW6;
|
|
2807
|
+
}
|
|
2808
|
+
const payload = _isObject7(env["payload"]) ? env["payload"] : env;
|
|
2809
|
+
const prompt = _extractPrompt2(payload);
|
|
2810
|
+
if (!prompt) {
|
|
2811
|
+
return EXIT_ALLOW6;
|
|
2812
|
+
}
|
|
2813
|
+
if (isSyntheticPrompt(prompt)) {
|
|
2814
|
+
return EXIT_ALLOW6;
|
|
2815
|
+
}
|
|
2816
|
+
const root = _workspaceRoot(env);
|
|
2817
|
+
const platform = env["platform"];
|
|
2818
|
+
const hostId = typeof platform === "string" && platform ? platform : null;
|
|
2819
|
+
const result = classifyPrompt(prompt, root, hostId);
|
|
2820
|
+
if (!result) {
|
|
2821
|
+
return EXIT_ALLOW6;
|
|
2822
|
+
}
|
|
2823
|
+
process.stdout.write(
|
|
2824
|
+
`${JSON.stringify({
|
|
2825
|
+
decision: "warn",
|
|
2826
|
+
reason: `delegation-nudge: rung-${result.rung} verdict (${result.sliceCount} slices, ${result.tier} tier)`,
|
|
2827
|
+
additional_context: buildNudgeLine(result.rung, result.classification, result.sliceCount, result.tier)
|
|
2828
|
+
})}
|
|
2829
|
+
`
|
|
2830
|
+
);
|
|
2831
|
+
return EXIT_WARN3;
|
|
2832
|
+
}
|
|
2833
|
+
function _isCliEntry8() {
|
|
2834
|
+
if (true) {
|
|
2835
|
+
return false;
|
|
2836
|
+
}
|
|
2837
|
+
if (process.argv[1] === void 0) {
|
|
2838
|
+
return false;
|
|
2839
|
+
}
|
|
2840
|
+
const argvUrl = pathToFileURL8(path8.resolve(process.argv[1])).href;
|
|
2841
|
+
if (import.meta.url === argvUrl) {
|
|
2842
|
+
return true;
|
|
2843
|
+
}
|
|
2844
|
+
try {
|
|
2845
|
+
const here = fs8.realpathSync(fileURLToPath8(import.meta.url));
|
|
2846
|
+
const argv = fs8.realpathSync(path8.resolve(process.argv[1]));
|
|
2847
|
+
return here === argv;
|
|
2848
|
+
} catch {
|
|
2849
|
+
return false;
|
|
2850
|
+
}
|
|
2851
|
+
}
|
|
2852
|
+
if (_isCliEntry8()) {
|
|
2853
|
+
process.exit(main8());
|
|
2854
|
+
}
|
|
2855
|
+
|
|
2272
2856
|
// src/scripts/conformance_scan.ts
|
|
2273
|
-
var REPO_ROOT =
|
|
2857
|
+
var REPO_ROOT = path9.resolve(path9.dirname(fileURLToPath9(import.meta.url)), "..", "..");
|
|
2274
2858
|
var OBSERVED_BAND = { low: 9.1, high: 39.2 };
|
|
2275
2859
|
var BAND_MIN_TURNS = 1978;
|
|
2276
2860
|
var CARRIER_CHANGES = [
|
|
@@ -2304,14 +2888,19 @@ var CHECK_IDS = [
|
|
|
2304
2888
|
"git-authorization",
|
|
2305
2889
|
"vacuous-evidence",
|
|
2306
2890
|
"evidence-steering",
|
|
2307
|
-
"completion-claim"
|
|
2891
|
+
"completion-claim",
|
|
2892
|
+
"task-completeness"
|
|
2308
2893
|
];
|
|
2309
2894
|
var CHECK_MEANINGS = {
|
|
2310
2895
|
"language-pin": "An assistant turn whose user-visible prose is not in the language that turn's own pin named. Carries provenance (turns_since_prompt, compaction_since_prompt) so a pin that was ABSENT because compaction removed it stays distinguishable from one that was present and ignored.",
|
|
2311
2896
|
"git-authorization": "A gated git operation performed in a session where no authorization for that operation was observed. Authorization is per-operation and never carries from one to the next.",
|
|
2312
2897
|
"vacuous-evidence": "A CI poll read as settled without ever observing an in-flight run \u2014 the poll gap that reports a green settle over a window in which nothing was pending yet.",
|
|
2313
2898
|
"evidence-steering": "A self-commissioned evaluation whose prompt pre-loaded its own verdict, or a second self-scoped evaluation of the same subject within one turn.",
|
|
2314
|
-
"completion-claim": "An assistant turn claiming the work is complete while the last CI read in that session was NOT settled. Round 7 measured 14 instances by reading, each followed by the user handing the work back; this is the same predicate `turn-end-gate`'s completion detector refuses on, so the rate and the gate cannot disagree. A session that never polled CI can never hit."
|
|
2899
|
+
"completion-claim": "An assistant turn claiming the work is complete while the last CI read in that session was NOT settled. Round 7 measured 14 instances by reading, each followed by the user handing the work back; this is the same predicate `turn-end-gate`'s completion detector refuses on, so the rate and the gate cannot disagree. A session that never polled CI can never hit.",
|
|
2900
|
+
"task-completeness": `A reply window that left at least one file the prompt ENUMERATED untouched \u2014 the token appears in neither any tool-call input nor any assistant prose before the next user prompt. Scope is deliberately narrow: only prompts naming >= ${FILE_SIGNAL_FLOOR} distinct file tokens are measured, the same floor \`delegation_nudge_hook\` uses for its FILE shape, and the token list comes from that module rather than a second regex.
|
|
2901
|
+
What distinguishes a hit from a false read: a hit is EVIDENCE OF AN OMISSION, not proof of one. Four legitimate shapes produce the same signature and are NOT excluded here \u2014 a blocking question, a hand-back, a user-fenced scope, and an explicitly deferred item all address fewer files than the prompt named, correctly. That is why every hit is hand-validated and a precision is published beside the rate; an unvalidated count from this check means nothing.
|
|
2902
|
+
What it cannot see, stated so a zero is not misread as health: the ordered-plan, explicit-count, for-each and conjunction shapes name a COUNT of deliverables but not their identities, so this check is blind to them by construction \u2014 it does not score them complete, it does not score them at all. A prose deliverable that is not a filename is invisible to it.
|
|
2903
|
+
MEASURED PRECISION: 0 of 3 hits, over 4 eligible windows in 28 sessions (2026-08-12). All three were false positives from ONE extraction defect: the token list is taken from the whole prompt, so files quoted inside material the user PASTED \u2014 a review, a log, an example \u2014 read as deliverables. In all three, the user's own ask contributed zero tokens. \`isInjectedBody\` did not filter them because it only excludes long ENGLISH text, and this corpus is mostly German (12 295 and 7 656 chars, both classified \`de\`, both passed); the one English case missed the 2 500-char cut by 12. So a hit here is not evidence of anything until the ask is separated from the pasted material. Detector D was NOT built on this result \u2014 see \`agents/evidence/analysis/task-completeness-measurement.md\`.`
|
|
2315
2904
|
};
|
|
2316
2905
|
function renderWhy(report, id) {
|
|
2317
2906
|
const hits = report.per_session.flatMap((s) => s.violations.filter((v) => v.check === id));
|
|
@@ -2338,10 +2927,18 @@ function renderWhy(report, id) {
|
|
|
2338
2927
|
` provenance: turns_since_prompt=${since ?? "\u2014"} \xB7 compaction_since_prompt=${compacted ?? "\u2014"}`
|
|
2339
2928
|
);
|
|
2340
2929
|
}
|
|
2930
|
+
const missed = v.missed;
|
|
2931
|
+
if (missed !== void 0) {
|
|
2932
|
+
const enumerated = v.enumerated;
|
|
2933
|
+
const addressed = v.addressed;
|
|
2934
|
+
lines.push(
|
|
2935
|
+
` provenance: enumerated=${enumerated ?? "\u2014"} \xB7 addressed=${addressed ?? "\u2014"} \xB7 missed=[${missed.join(", ")}]`
|
|
2936
|
+
);
|
|
2937
|
+
}
|
|
2341
2938
|
}
|
|
2342
2939
|
return lines.join("\n");
|
|
2343
2940
|
}
|
|
2344
|
-
function
|
|
2941
|
+
function _isObject8(v) {
|
|
2345
2942
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
2346
2943
|
}
|
|
2347
2944
|
function userText(entry) {
|
|
@@ -2365,15 +2962,15 @@ function assistantText(entry) {
|
|
|
2365
2962
|
}
|
|
2366
2963
|
function toolUses2(entry) {
|
|
2367
2964
|
const msg = entry["message"];
|
|
2368
|
-
const content =
|
|
2965
|
+
const content = _isObject8(msg) ? msg["content"] : void 0;
|
|
2369
2966
|
if (!Array.isArray(content)) {
|
|
2370
2967
|
return [];
|
|
2371
2968
|
}
|
|
2372
|
-
return content.filter((b) =>
|
|
2969
|
+
return content.filter((b) => _isObject8(b) && b["type"] === "tool_use").map((b) => {
|
|
2373
2970
|
const o = b;
|
|
2374
2971
|
return {
|
|
2375
2972
|
name: String(o["name"] ?? ""),
|
|
2376
|
-
input:
|
|
2973
|
+
input: _isObject8(o["input"]) ? o["input"] : {}
|
|
2377
2974
|
};
|
|
2378
2975
|
});
|
|
2379
2976
|
}
|
|
@@ -2385,6 +2982,24 @@ function isInjectedBody(text) {
|
|
|
2385
2982
|
}
|
|
2386
2983
|
var HARNESS_TEXT = /^(API Error:|Request (timed out|was aborted)|\[Request interrupted|Error: |Credit balance is too low|You've hit your|Prompt is too long)/i;
|
|
2387
2984
|
var EN_OPENER = /^(let me|i'?ll |i'?m |found it|ok[,. ]|okay|alright|here'?s|now[,. ]|looking|checking|reading|running|the |this |that |there |we |you |good |right[,. ]|perfect|done[.,]|all |confirmed|correct)/i;
|
|
2985
|
+
function markAddressed(text, w) {
|
|
2986
|
+
if (w.tokens.length === 0) {
|
|
2987
|
+
return;
|
|
2988
|
+
}
|
|
2989
|
+
const hay = text.toLowerCase();
|
|
2990
|
+
for (const t of w.tokens) {
|
|
2991
|
+
if (!w.addressed.has(t) && hay.includes(t)) {
|
|
2992
|
+
w.addressed.add(t);
|
|
2993
|
+
}
|
|
2994
|
+
}
|
|
2995
|
+
}
|
|
2996
|
+
function evaluateWindow(w) {
|
|
2997
|
+
if (!w.worked || w.tokens.length === 0) {
|
|
2998
|
+
return null;
|
|
2999
|
+
}
|
|
3000
|
+
const missed = w.tokens.filter((t) => !w.addressed.has(t));
|
|
3001
|
+
return missed.length > 0 ? { missed } : null;
|
|
3002
|
+
}
|
|
2388
3003
|
function scanSession(sessionId, lines) {
|
|
2389
3004
|
const report = {
|
|
2390
3005
|
session: sessionId,
|
|
@@ -2392,7 +3007,8 @@ function scanSession(sessionId, lines) {
|
|
|
2392
3007
|
assistant_turns: 0,
|
|
2393
3008
|
violations: [],
|
|
2394
3009
|
de_pin_turns: 0,
|
|
2395
|
-
first_at: ""
|
|
3010
|
+
first_at: "",
|
|
3011
|
+
completeness_windows: 0
|
|
2396
3012
|
};
|
|
2397
3013
|
let pinned = null;
|
|
2398
3014
|
let pendingPoll = null;
|
|
@@ -2403,6 +3019,29 @@ function scanSession(sessionId, lines) {
|
|
|
2403
3019
|
let compactionSincePrompt = false;
|
|
2404
3020
|
let ciSeen = false;
|
|
2405
3021
|
let ciSettled = false;
|
|
3022
|
+
let openWindow = null;
|
|
3023
|
+
const closeWindow = () => {
|
|
3024
|
+
if (openWindow === null) {
|
|
3025
|
+
return;
|
|
3026
|
+
}
|
|
3027
|
+
if (openWindow.worked) {
|
|
3028
|
+
report.completeness_windows += 1;
|
|
3029
|
+
}
|
|
3030
|
+
const verdict = evaluateWindow(openWindow);
|
|
3031
|
+
if (verdict !== null) {
|
|
3032
|
+
const addressed = openWindow.tokens.length - verdict.missed.length;
|
|
3033
|
+
report.violations.push({
|
|
3034
|
+
check: "task-completeness",
|
|
3035
|
+
session: sessionId,
|
|
3036
|
+
at: openWindow.at,
|
|
3037
|
+
detail: `prompt enumerated ${openWindow.tokens.length} file(s), reply window touched ${addressed}; untouched: ${verdict.missed.join(", ").slice(0, 160)}`,
|
|
3038
|
+
enumerated: openWindow.tokens.length,
|
|
3039
|
+
addressed,
|
|
3040
|
+
missed: verdict.missed
|
|
3041
|
+
});
|
|
3042
|
+
}
|
|
3043
|
+
openWindow = null;
|
|
3044
|
+
};
|
|
2406
3045
|
for (const line of lines) {
|
|
2407
3046
|
if (!line.trim()) {
|
|
2408
3047
|
continue;
|
|
@@ -2451,6 +3090,16 @@ function scanSession(sessionId, lines) {
|
|
|
2451
3090
|
continue;
|
|
2452
3091
|
}
|
|
2453
3092
|
report.user_turns += 1;
|
|
3093
|
+
closeWindow();
|
|
3094
|
+
const deliverables = enumeratedFileTokens(ut);
|
|
3095
|
+
if (deliverables.length >= FILE_SIGNAL_FLOOR) {
|
|
3096
|
+
openWindow = {
|
|
3097
|
+
at: String(entry["timestamp"] ?? ""),
|
|
3098
|
+
tokens: deliverables,
|
|
3099
|
+
addressed: /* @__PURE__ */ new Set(),
|
|
3100
|
+
worked: false
|
|
3101
|
+
};
|
|
3102
|
+
}
|
|
2454
3103
|
turnsSincePrompt = 0;
|
|
2455
3104
|
compactionSincePrompt = false;
|
|
2456
3105
|
const c = classify(ut);
|
|
@@ -2471,6 +3120,11 @@ function scanSession(sessionId, lines) {
|
|
|
2471
3120
|
if (prose !== null) {
|
|
2472
3121
|
report.assistant_turns += 1;
|
|
2473
3122
|
turnsSincePrompt += 1;
|
|
3123
|
+
const firstLine = (prose.split("\n").find((l) => l.trim()) ?? "").trim();
|
|
3124
|
+
if (openWindow !== null && !HARNESS_TEXT.test(firstLine)) {
|
|
3125
|
+
openWindow.worked = true;
|
|
3126
|
+
markAddressed(prose, openWindow);
|
|
3127
|
+
}
|
|
2474
3128
|
if (pinned === "de") {
|
|
2475
3129
|
report.de_pin_turns += 1;
|
|
2476
3130
|
}
|
|
@@ -2504,6 +3158,10 @@ function scanSession(sessionId, lines) {
|
|
|
2504
3158
|
}
|
|
2505
3159
|
}
|
|
2506
3160
|
for (const tu of toolUses2(entry)) {
|
|
3161
|
+
if (openWindow !== null) {
|
|
3162
|
+
openWindow.worked = true;
|
|
3163
|
+
markAddressed(`${tu.name} ${JSON.stringify(tu.input)}`, openWindow);
|
|
3164
|
+
}
|
|
2507
3165
|
const cmd = typeof tu.input["command"] === "string" ? tu.input["command"] : null;
|
|
2508
3166
|
if (cmd !== null) {
|
|
2509
3167
|
const op = commandOp(cmd);
|
|
@@ -2543,9 +3201,10 @@ function scanSession(sessionId, lines) {
|
|
|
2543
3201
|
}
|
|
2544
3202
|
}
|
|
2545
3203
|
}
|
|
3204
|
+
closeWindow();
|
|
2546
3205
|
return report;
|
|
2547
3206
|
}
|
|
2548
|
-
var DEFAULT_RATE_SERIES =
|
|
3207
|
+
var DEFAULT_RATE_SERIES = path9.join(
|
|
2549
3208
|
REPO_ROOT,
|
|
2550
3209
|
"agents",
|
|
2551
3210
|
"runtime",
|
|
@@ -2553,8 +3212,8 @@ var DEFAULT_RATE_SERIES = path8.join(
|
|
|
2553
3212
|
"conformance-rates.jsonl"
|
|
2554
3213
|
);
|
|
2555
3214
|
function defaultStore(projectDir) {
|
|
2556
|
-
const slug = projectDir
|
|
2557
|
-
return
|
|
3215
|
+
const slug = projectStoreSlug(projectDir);
|
|
3216
|
+
return path9.join(process.env["HOME"] ?? "", ".claude", "projects", slug);
|
|
2558
3217
|
}
|
|
2559
3218
|
function _tokens(chars) {
|
|
2560
3219
|
return Math.round(chars / 4);
|
|
@@ -2565,13 +3224,13 @@ function measureDelivered(projectRulesDir, globalRulesDir) {
|
|
|
2565
3224
|
return {
|
|
2566
3225
|
project: {
|
|
2567
3226
|
dir: projectRulesDir,
|
|
2568
|
-
present:
|
|
3227
|
+
present: fs9.existsSync(projectRulesDir),
|
|
2569
3228
|
files: p.files,
|
|
2570
3229
|
tokens: _tokens(p.chars)
|
|
2571
3230
|
},
|
|
2572
3231
|
global: {
|
|
2573
3232
|
dir: globalRulesDir,
|
|
2574
|
-
present:
|
|
3233
|
+
present: fs9.existsSync(globalRulesDir),
|
|
2575
3234
|
files: g.files,
|
|
2576
3235
|
tokens: _tokens(g.chars)
|
|
2577
3236
|
},
|
|
@@ -2579,13 +3238,13 @@ function measureDelivered(projectRulesDir, globalRulesDir) {
|
|
|
2579
3238
|
};
|
|
2580
3239
|
}
|
|
2581
3240
|
function storeKey(store) {
|
|
2582
|
-
return createHash3("sha256").update(
|
|
3241
|
+
return createHash3("sha256").update(path9.resolve(store)).digest("hex").slice(0, 12);
|
|
2583
3242
|
}
|
|
2584
3243
|
function scanStore(store, limit) {
|
|
2585
|
-
const files =
|
|
3244
|
+
const files = fs9.readdirSync(store).filter((f) => f.endsWith(".jsonl")).map((f) => ({ f, m: fs9.statSync(path9.join(store, f)).mtimeMs })).sort((a, b) => b.m - a.m).slice(0, limit).map((x) => x.f);
|
|
2586
3245
|
const per_session = [];
|
|
2587
3246
|
for (const f of files) {
|
|
2588
|
-
const lines =
|
|
3247
|
+
const lines = fs9.readFileSync(path9.join(store, f), "utf8").split("\n");
|
|
2589
3248
|
const r = scanSession(f.replace(/\.jsonl$/, "").slice(0, 8), lines);
|
|
2590
3249
|
if (r.assistant_turns > 0) {
|
|
2591
3250
|
per_session.push(r);
|
|
@@ -2608,12 +3267,15 @@ function scanStore(store, limit) {
|
|
|
2608
3267
|
const rate_pct = assistant_turns === 0 ? 0 : Number((100 * language_pin / assistant_turns).toFixed(1));
|
|
2609
3268
|
const de_pin_turns = per_session.reduce((n, s) => n + s.de_pin_turns, 0);
|
|
2610
3269
|
const rate_pct_de_pin = de_pin_turns === 0 ? 0 : Number((100 * language_pin / de_pin_turns).toFixed(1));
|
|
3270
|
+
const completeness_windows = per_session.reduce((n, s) => n + s.completeness_windows, 0);
|
|
3271
|
+
const task_completeness = totals["task-completeness"] ?? 0;
|
|
3272
|
+
const task_completeness_rate_pct = completeness_windows === 0 ? 0 : Number((100 * task_completeness / completeness_windows).toFixed(1));
|
|
2611
3273
|
const era = spansCarrierChange(per_session.map((s) => s.first_at));
|
|
2612
3274
|
const delivered = measureDelivered(
|
|
2613
|
-
|
|
2614
|
-
|
|
3275
|
+
path9.join(REPO_ROOT, ".claude", "rules"),
|
|
3276
|
+
path9.join(process.env["HOME"] ?? os2.homedir(), ".claude", "rules")
|
|
2615
3277
|
);
|
|
2616
|
-
const ownStore =
|
|
3278
|
+
const ownStore = path9.resolve(store) === path9.resolve(defaultStore(REPO_ROOT));
|
|
2617
3279
|
return {
|
|
2618
3280
|
scanned_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2619
3281
|
store,
|
|
@@ -2629,6 +3291,9 @@ function scanStore(store, limit) {
|
|
|
2629
3291
|
rate_pct,
|
|
2630
3292
|
de_pin_turns,
|
|
2631
3293
|
rate_pct_de_pin,
|
|
3294
|
+
completeness_windows,
|
|
3295
|
+
task_completeness,
|
|
3296
|
+
task_completeness_rate_pct,
|
|
2632
3297
|
era_spanning: era.spans,
|
|
2633
3298
|
era_reason: era.what,
|
|
2634
3299
|
band: bandVerdict(rate_pct, assistant_turns, { spansCarrier: era.spans }),
|
|
@@ -2640,8 +3305,8 @@ function scanStore(store, limit) {
|
|
|
2640
3305
|
};
|
|
2641
3306
|
}
|
|
2642
3307
|
function recordRate(file, scanned_at, rate) {
|
|
2643
|
-
|
|
2644
|
-
|
|
3308
|
+
fs9.mkdirSync(path9.dirname(file), { recursive: true });
|
|
3309
|
+
fs9.appendFileSync(file, `${JSON.stringify({ measured_at: scanned_at, ...rate })}
|
|
2645
3310
|
`, "utf8");
|
|
2646
3311
|
}
|
|
2647
3312
|
function render(report) {
|
|
@@ -2683,6 +3348,18 @@ function render(report) {
|
|
|
2683
3348
|
);
|
|
2684
3349
|
lines.push(" is the comparable one and the second is the honest one. Both are printed.");
|
|
2685
3350
|
}
|
|
3351
|
+
const cWindows = report.rate.completeness_windows;
|
|
3352
|
+
const cRate = report.rate.task_completeness_rate_pct;
|
|
3353
|
+
if (typeof cWindows === "number" && typeof cRate === "number") {
|
|
3354
|
+
lines.push("");
|
|
3355
|
+
lines.push(
|
|
3356
|
+
` task-completeness ${cRate.toFixed(1)}% (${report.rate.task_completeness ?? 0} of ${cWindows} eligible reply windows)`
|
|
3357
|
+
);
|
|
3358
|
+
lines.push(" A hit is EVIDENCE of an omission, never proof: a blocking question, a");
|
|
3359
|
+
lines.push(" hand-back, a fenced scope and a deferred item all produce this signature");
|
|
3360
|
+
lines.push(" correctly. Read the hand-validated precision beside this figure or not");
|
|
3361
|
+
lines.push(" at all \u2014 `--why task-completeness` lists every hit with its missed tokens.");
|
|
3362
|
+
}
|
|
2686
3363
|
if (report.rate.band === "era-spanning") {
|
|
2687
3364
|
lines.push(
|
|
2688
3365
|
` Not compared: the corpus SPANS a carrier landing \u2014 ${report.rate.era_reason || "see CARRIER_CHANGES"}.`
|
|
@@ -2728,7 +3405,7 @@ function render(report) {
|
|
|
2728
3405
|
lines.push(" checkbox batching \u2014 measured NOWHERE. ~5 low-severity findings.");
|
|
2729
3406
|
return lines.join("\n");
|
|
2730
3407
|
}
|
|
2731
|
-
function
|
|
3408
|
+
function main9(argv) {
|
|
2732
3409
|
const args = argv ?? process.argv.slice(2);
|
|
2733
3410
|
let store = null;
|
|
2734
3411
|
let limit = 30;
|
|
@@ -2760,14 +3437,14 @@ function main8(argv) {
|
|
|
2760
3437
|
return 2;
|
|
2761
3438
|
}
|
|
2762
3439
|
const resolved = store ?? defaultStore(process.cwd());
|
|
2763
|
-
if (!
|
|
3440
|
+
if (!fs9.existsSync(resolved)) {
|
|
2764
3441
|
process.stderr.write(`conformance:behavior: no transcript store at ${resolved}
|
|
2765
3442
|
`);
|
|
2766
3443
|
return 1;
|
|
2767
3444
|
}
|
|
2768
3445
|
const report = scanStore(resolved, Number.isFinite(limit) && limit > 0 ? limit : 30);
|
|
2769
3446
|
if (out) {
|
|
2770
|
-
|
|
3447
|
+
fs9.writeFileSync(out, `${JSON.stringify(report, null, 2)}
|
|
2771
3448
|
`, "utf8");
|
|
2772
3449
|
}
|
|
2773
3450
|
if (record) {
|
|
@@ -2775,7 +3452,7 @@ function main8(argv) {
|
|
|
2775
3452
|
}
|
|
2776
3453
|
if (why !== null) {
|
|
2777
3454
|
const id = why;
|
|
2778
|
-
|
|
3455
|
+
fs9.writeSync(
|
|
2779
3456
|
1,
|
|
2780
3457
|
json ? `${JSON.stringify(
|
|
2781
3458
|
{
|
|
@@ -2795,48 +3472,48 @@ function main8(argv) {
|
|
|
2795
3472
|
);
|
|
2796
3473
|
return 0;
|
|
2797
3474
|
}
|
|
2798
|
-
|
|
3475
|
+
fs9.writeSync(1, json ? `${JSON.stringify(report, null, 2)}
|
|
2799
3476
|
` : `${render(report)}
|
|
2800
3477
|
`);
|
|
2801
3478
|
return 0;
|
|
2802
3479
|
}
|
|
2803
|
-
function
|
|
3480
|
+
function _isCliEntry9() {
|
|
2804
3481
|
if (true) {
|
|
2805
3482
|
return false;
|
|
2806
3483
|
}
|
|
2807
3484
|
if (process.argv[1] === void 0) {
|
|
2808
3485
|
return false;
|
|
2809
3486
|
}
|
|
2810
|
-
const argvUrl =
|
|
3487
|
+
const argvUrl = pathToFileURL9(path9.resolve(process.argv[1])).href;
|
|
2811
3488
|
if (import.meta.url === argvUrl) {
|
|
2812
3489
|
return true;
|
|
2813
3490
|
}
|
|
2814
3491
|
try {
|
|
2815
|
-
const here =
|
|
2816
|
-
const argv =
|
|
3492
|
+
const here = fs9.realpathSync(fileURLToPath9(import.meta.url));
|
|
3493
|
+
const argv = fs9.realpathSync(path9.resolve(process.argv[1]));
|
|
2817
3494
|
return here === argv;
|
|
2818
3495
|
} catch {
|
|
2819
3496
|
return false;
|
|
2820
3497
|
}
|
|
2821
3498
|
}
|
|
2822
|
-
if (
|
|
2823
|
-
process.exit(
|
|
3499
|
+
if (_isCliEntry9()) {
|
|
3500
|
+
process.exit(main9());
|
|
2824
3501
|
}
|
|
2825
3502
|
|
|
2826
3503
|
// src/scripts/report_carrier_divergence.ts
|
|
2827
|
-
import * as
|
|
3504
|
+
import * as fs10 from "node:fs";
|
|
2828
3505
|
import * as os3 from "node:os";
|
|
2829
|
-
import * as
|
|
2830
|
-
import
|
|
2831
|
-
import { fileURLToPath as
|
|
2832
|
-
var _HERE =
|
|
2833
|
-
var REPO_ROOT2 =
|
|
2834
|
-
var PROJECT_RULES =
|
|
2835
|
-
var PROJECTION_SOURCE =
|
|
2836
|
-
var GLOBAL_RULES =
|
|
3506
|
+
import * as path10 from "node:path";
|
|
3507
|
+
import process3 from "node:process";
|
|
3508
|
+
import { fileURLToPath as fileURLToPath10, pathToFileURL as pathToFileURL10 } from "node:url";
|
|
3509
|
+
var _HERE = fileURLToPath10(import.meta.url);
|
|
3510
|
+
var REPO_ROOT2 = path10.resolve(path10.dirname(_HERE), "..", "..");
|
|
3511
|
+
var PROJECT_RULES = path10.join(".claude", "rules");
|
|
3512
|
+
var PROJECTION_SOURCE = path10.join("dist", "agent-src", "rules");
|
|
3513
|
+
var GLOBAL_RULES = path10.join(".claude", "rules");
|
|
2837
3514
|
function _listRules(dir) {
|
|
2838
3515
|
try {
|
|
2839
|
-
return
|
|
3516
|
+
return fs10.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
|
|
2840
3517
|
} catch {
|
|
2841
3518
|
return [];
|
|
2842
3519
|
}
|
|
@@ -2844,7 +3521,7 @@ function _listRules(dir) {
|
|
|
2844
3521
|
function _ruleType(file) {
|
|
2845
3522
|
let text;
|
|
2846
3523
|
try {
|
|
2847
|
-
text =
|
|
3524
|
+
text = fs10.readFileSync(file, "utf-8");
|
|
2848
3525
|
} catch {
|
|
2849
3526
|
return "";
|
|
2850
3527
|
}
|
|
@@ -2855,8 +3532,8 @@ function compareCarriers(projectDir, globalDir, sourceDir) {
|
|
|
2855
3532
|
const out = {
|
|
2856
3533
|
projectDir,
|
|
2857
3534
|
globalDir,
|
|
2858
|
-
globalPresent:
|
|
2859
|
-
projectPresent:
|
|
3535
|
+
globalPresent: fs10.existsSync(globalDir),
|
|
3536
|
+
projectPresent: fs10.existsSync(projectDir),
|
|
2860
3537
|
shared: 0,
|
|
2861
3538
|
identical: [],
|
|
2862
3539
|
provenanceOnly: [],
|
|
@@ -2879,7 +3556,7 @@ function compareCarriers(projectDir, globalDir, sourceDir) {
|
|
|
2879
3556
|
}
|
|
2880
3557
|
if (!inP && inG) {
|
|
2881
3558
|
out.globalOnly.push(rule);
|
|
2882
|
-
if (sourceDir !== void 0 && _ruleType(
|
|
3559
|
+
if (sourceDir !== void 0 && _ruleType(path10.join(sourceDir, rule)) === "manual") {
|
|
2883
3560
|
out.manualOnlyGlobal.push(rule);
|
|
2884
3561
|
}
|
|
2885
3562
|
continue;
|
|
@@ -2889,8 +3566,8 @@ function compareCarriers(projectDir, globalDir, sourceDir) {
|
|
|
2889
3566
|
let projectCopy;
|
|
2890
3567
|
let globalCopy;
|
|
2891
3568
|
try {
|
|
2892
|
-
projectCopy =
|
|
2893
|
-
globalCopy =
|
|
3569
|
+
projectCopy = fs10.readFileSync(path10.join(projectDir, rule));
|
|
3570
|
+
globalCopy = fs10.readFileSync(path10.join(globalDir, rule));
|
|
2894
3571
|
verdict = comparePair(projectCopy, globalCopy);
|
|
2895
3572
|
} catch {
|
|
2896
3573
|
out.shared -= 1;
|
|
@@ -3035,11 +3712,11 @@ function render2(d) {
|
|
|
3035
3712
|
}
|
|
3036
3713
|
return lines.join("\n");
|
|
3037
3714
|
}
|
|
3038
|
-
function
|
|
3039
|
-
const args = argv ??
|
|
3040
|
-
let projectDir =
|
|
3041
|
-
let globalDir =
|
|
3042
|
-
let sourceDir =
|
|
3715
|
+
function main10(argv) {
|
|
3716
|
+
const args = argv ?? process3.argv.slice(2);
|
|
3717
|
+
let projectDir = path10.join(REPO_ROOT2, PROJECT_RULES);
|
|
3718
|
+
let globalDir = path10.join(os3.homedir(), GLOBAL_RULES);
|
|
3719
|
+
let sourceDir = path10.join(REPO_ROOT2, PROJECTION_SOURCE);
|
|
3043
3720
|
const value = (i) => {
|
|
3044
3721
|
const v = args[i + 1];
|
|
3045
3722
|
return v === void 0 || v.startsWith("-") ? null : v;
|
|
@@ -3049,68 +3726,68 @@ function main9(argv) {
|
|
|
3049
3726
|
if (a === "--project" || a === "--global" || a === "--source") {
|
|
3050
3727
|
const v = value(i);
|
|
3051
3728
|
if (v === null) {
|
|
3052
|
-
|
|
3729
|
+
process3.stderr.write(`report_carrier_divergence: ${a} needs a directory
|
|
3053
3730
|
`);
|
|
3054
3731
|
return 1;
|
|
3055
3732
|
}
|
|
3056
|
-
const resolved =
|
|
3733
|
+
const resolved = path10.resolve(v);
|
|
3057
3734
|
if (a === "--project") projectDir = resolved;
|
|
3058
3735
|
else if (a === "--global") globalDir = resolved;
|
|
3059
3736
|
else sourceDir = resolved;
|
|
3060
3737
|
i += 1;
|
|
3061
3738
|
} else if (a === "--help" || a === "-h") {
|
|
3062
|
-
|
|
3739
|
+
process3.stdout.write(
|
|
3063
3740
|
"usage: report_carrier_divergence [--project DIR] [--global DIR] [--source DIR]\n"
|
|
3064
3741
|
);
|
|
3065
3742
|
return 0;
|
|
3066
3743
|
} else if (a !== void 0 && a.startsWith("--") && a !== "--quiet") {
|
|
3067
|
-
|
|
3744
|
+
process3.stderr.write(`report_carrier_divergence: unknown flag ${a}
|
|
3068
3745
|
`);
|
|
3069
3746
|
return 1;
|
|
3070
3747
|
}
|
|
3071
3748
|
}
|
|
3072
|
-
|
|
3749
|
+
process3.stdout.write(`${render2(compareCarriers(projectDir, globalDir, sourceDir))}
|
|
3073
3750
|
`);
|
|
3074
3751
|
return 0;
|
|
3075
3752
|
}
|
|
3076
|
-
function
|
|
3077
|
-
if (
|
|
3078
|
-
if (import.meta.url ===
|
|
3753
|
+
function _isCliEntry10() {
|
|
3754
|
+
if (process3.argv[1] === void 0) return false;
|
|
3755
|
+
if (import.meta.url === pathToFileURL10(path10.resolve(process3.argv[1])).href) return true;
|
|
3079
3756
|
try {
|
|
3080
|
-
return
|
|
3757
|
+
return fs10.realpathSync(_HERE) === fs10.realpathSync(path10.resolve(process3.argv[1]));
|
|
3081
3758
|
} catch {
|
|
3082
3759
|
return false;
|
|
3083
3760
|
}
|
|
3084
3761
|
}
|
|
3085
|
-
if (
|
|
3086
|
-
|
|
3762
|
+
if (_isCliEntry10()) {
|
|
3763
|
+
process3.exit(main10());
|
|
3087
3764
|
}
|
|
3088
3765
|
|
|
3089
3766
|
// src/scripts/report_skill_activation.ts
|
|
3090
|
-
import * as
|
|
3767
|
+
import * as fs11 from "node:fs";
|
|
3091
3768
|
import * as os4 from "node:os";
|
|
3092
|
-
import * as
|
|
3093
|
-
import { fileURLToPath as
|
|
3094
|
-
var _HERE2 =
|
|
3095
|
-
var REPO_ROOT3 =
|
|
3769
|
+
import * as path11 from "node:path";
|
|
3770
|
+
import { fileURLToPath as fileURLToPath11, pathToFileURL as pathToFileURL11 } from "node:url";
|
|
3771
|
+
var _HERE2 = fileURLToPath11(import.meta.url);
|
|
3772
|
+
var REPO_ROOT3 = path11.resolve(path11.dirname(_HERE2), "..", "..");
|
|
3096
3773
|
var SKILLS_ROOT = "src/skills";
|
|
3097
3774
|
var TRIGGER_KEYS = ["triggers:", "trigger_description:", "file_pattern:", "path_prefix:"];
|
|
3098
3775
|
var DETERMINISTIC_RE = /^\s*(?:[-*]\s*)?(?:\*\*)?(MUST|NEVER|ALWAYS)\b/m;
|
|
3099
3776
|
function censusSkills(root) {
|
|
3100
3777
|
const out = { total: 0, withTriggerKey: [], withDeterministicObligation: [] };
|
|
3101
|
-
if (!
|
|
3778
|
+
if (!fs11.existsSync(root)) {
|
|
3102
3779
|
return out;
|
|
3103
3780
|
}
|
|
3104
|
-
for (const entry of
|
|
3781
|
+
for (const entry of fs11.readdirSync(root, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
3105
3782
|
if (!entry.isDirectory()) {
|
|
3106
3783
|
continue;
|
|
3107
3784
|
}
|
|
3108
|
-
const file =
|
|
3109
|
-
if (!
|
|
3785
|
+
const file = path11.join(root, entry.name, "SKILL.md");
|
|
3786
|
+
if (!fs11.existsSync(file)) {
|
|
3110
3787
|
continue;
|
|
3111
3788
|
}
|
|
3112
3789
|
out.total += 1;
|
|
3113
|
-
const text =
|
|
3790
|
+
const text = fs11.readFileSync(file, "utf8");
|
|
3114
3791
|
const fmEnd = text.startsWith("---") ? text.indexOf("\n---", 3) : -1;
|
|
3115
3792
|
const fm = fmEnd === -1 ? "" : text.slice(0, fmEnd);
|
|
3116
3793
|
if (TRIGGER_KEYS.some((k) => new RegExp(`^${k}`, "m").test(fm))) {
|
|
@@ -3124,17 +3801,17 @@ function censusSkills(root) {
|
|
|
3124
3801
|
return out;
|
|
3125
3802
|
}
|
|
3126
3803
|
function defaultStore2(cwd) {
|
|
3127
|
-
return
|
|
3804
|
+
return path11.join(os4.homedir(), ".claude", "projects", projectStoreSlug(cwd));
|
|
3128
3805
|
}
|
|
3129
3806
|
function measureUsage(store, limit) {
|
|
3130
3807
|
const rep = { store, sessions: 0, assistantTurns: 0, invocations: 0, bySkill: {} };
|
|
3131
|
-
if (!
|
|
3808
|
+
if (!fs11.existsSync(store)) {
|
|
3132
3809
|
return rep;
|
|
3133
3810
|
}
|
|
3134
|
-
const files =
|
|
3811
|
+
const files = fs11.readdirSync(store).filter((f) => f.endsWith(".jsonl")).map((f) => path11.join(store, f)).sort((a, b) => fs11.statSync(b).mtimeMs - fs11.statSync(a).mtimeMs).slice(0, limit);
|
|
3135
3812
|
rep.sessions = files.length;
|
|
3136
3813
|
for (const file of files) {
|
|
3137
|
-
for (const line of
|
|
3814
|
+
for (const line of fs11.readFileSync(file, "utf8").split("\n")) {
|
|
3138
3815
|
if (!line.trim()) {
|
|
3139
3816
|
continue;
|
|
3140
3817
|
}
|
|
@@ -3197,7 +3874,7 @@ function render3(census, usage) {
|
|
|
3197
3874
|
}
|
|
3198
3875
|
totalInv += u.invocations;
|
|
3199
3876
|
lines.push(
|
|
3200
|
-
` ${
|
|
3877
|
+
` ${path11.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)}`
|
|
3201
3878
|
);
|
|
3202
3879
|
}
|
|
3203
3880
|
lines.push("");
|
|
@@ -3222,7 +3899,7 @@ function render3(census, usage) {
|
|
|
3222
3899
|
lines.push(" catalogue once per session, then count descriptions against bare names.");
|
|
3223
3900
|
return lines.join("\n");
|
|
3224
3901
|
}
|
|
3225
|
-
function
|
|
3902
|
+
function main11(argv) {
|
|
3226
3903
|
let limit = 30;
|
|
3227
3904
|
const stores = [];
|
|
3228
3905
|
for (let i = 0; i < argv.length; i += 1) {
|
|
@@ -3245,24 +3922,24 @@ function main10(argv) {
|
|
|
3245
3922
|
if (stores.length === 0) {
|
|
3246
3923
|
stores.push(defaultStore2(REPO_ROOT3));
|
|
3247
3924
|
}
|
|
3248
|
-
const census = censusSkills(
|
|
3925
|
+
const census = censusSkills(path11.join(REPO_ROOT3, SKILLS_ROOT));
|
|
3249
3926
|
const usage = stores.map((s) => measureUsage(s, limit));
|
|
3250
3927
|
process.stdout.write(`${render3(census, usage)}
|
|
3251
3928
|
`);
|
|
3252
3929
|
return 0;
|
|
3253
3930
|
}
|
|
3254
|
-
if (process.argv[1] !== void 0 && import.meta.url ===
|
|
3255
|
-
process.exit(
|
|
3931
|
+
if (process.argv[1] !== void 0 && import.meta.url === pathToFileURL11(path11.resolve(process.argv[1])).href) {
|
|
3932
|
+
process.exit(main11(process.argv.slice(2)));
|
|
3256
3933
|
}
|
|
3257
3934
|
|
|
3258
3935
|
// src/scripts/report_skill_obligation_violations.ts
|
|
3259
|
-
import * as
|
|
3936
|
+
import * as fs12 from "node:fs";
|
|
3260
3937
|
import * as os5 from "node:os";
|
|
3261
|
-
import * as
|
|
3262
|
-
import
|
|
3263
|
-
import { fileURLToPath as
|
|
3264
|
-
var _HERE3 =
|
|
3265
|
-
var REPO_ROOT4 =
|
|
3938
|
+
import * as path12 from "node:path";
|
|
3939
|
+
import process4 from "node:process";
|
|
3940
|
+
import { fileURLToPath as fileURLToPath12, pathToFileURL as pathToFileURL12 } from "node:url";
|
|
3941
|
+
var _HERE3 = fileURLToPath12(import.meta.url);
|
|
3942
|
+
var REPO_ROOT4 = path12.resolve(path12.dirname(_HERE3), "..", "..");
|
|
3266
3943
|
var OBLIGATION_LINE_RE = new RegExp(`${DETERMINISTIC_RE.source}.*`, "gm");
|
|
3267
3944
|
var PATH_RE = /`([A-Za-z0-9_./-]*\/[A-Za-z0-9_.-]+\.[a-z]{2,6})`/g;
|
|
3268
3945
|
var CMD_RE = /`([a-z][a-z0-9-]*(?: [a-z][a-z0-9:._-]*){1,3})`/g;
|
|
@@ -3300,7 +3977,7 @@ function _artefacts(line) {
|
|
|
3300
3977
|
return out;
|
|
3301
3978
|
}
|
|
3302
3979
|
function extractObligations(repoRoot) {
|
|
3303
|
-
const skillsRoot =
|
|
3980
|
+
const skillsRoot = path12.join(repoRoot, SKILLS_ROOT);
|
|
3304
3981
|
const census = censusSkills(skillsRoot);
|
|
3305
3982
|
const out = {
|
|
3306
3983
|
skills: census.withDeterministicObligation,
|
|
@@ -3314,7 +3991,7 @@ function extractObligations(repoRoot) {
|
|
|
3314
3991
|
for (const skill of census.withDeterministicObligation) {
|
|
3315
3992
|
let text;
|
|
3316
3993
|
try {
|
|
3317
|
-
text =
|
|
3994
|
+
text = fs12.readFileSync(path12.join(skillsRoot, skill, "SKILL.md"), "utf-8");
|
|
3318
3995
|
} catch {
|
|
3319
3996
|
continue;
|
|
3320
3997
|
}
|
|
@@ -3430,7 +4107,7 @@ function scanSessionForViolations(session, lines, forbidden, parsed) {
|
|
|
3430
4107
|
return flags;
|
|
3431
4108
|
}
|
|
3432
4109
|
function defaultStore3(cwd) {
|
|
3433
|
-
return
|
|
4110
|
+
return path12.join(os5.homedir(), ".claude", "projects", projectStoreSlug(cwd));
|
|
3434
4111
|
}
|
|
3435
4112
|
function scanStore2(repoRoot, store, limit) {
|
|
3436
4113
|
const census = extractObligations(repoRoot);
|
|
@@ -3443,14 +4120,14 @@ function scanStore2(repoRoot, store, limit) {
|
|
|
3443
4120
|
};
|
|
3444
4121
|
let files;
|
|
3445
4122
|
try {
|
|
3446
|
-
files =
|
|
4123
|
+
files = fs12.readdirSync(store).filter((f) => f.endsWith(".jsonl")).map((f) => ({ p: path12.join(store, f), m: fs12.statSync(path12.join(store, f)).mtimeMs })).sort((a, b) => b.m - a.m).slice(0, limit).map((x) => x.p);
|
|
3447
4124
|
} catch {
|
|
3448
4125
|
return report;
|
|
3449
4126
|
}
|
|
3450
4127
|
report.sessions = files.length;
|
|
3451
4128
|
for (const file of files) {
|
|
3452
|
-
const lines =
|
|
3453
|
-
const id =
|
|
4129
|
+
const lines = fs12.readFileSync(file, "utf-8").split("\n");
|
|
4130
|
+
const id = path12.basename(file).replace(/\.jsonl$/, "").slice(0, 8);
|
|
3454
4131
|
const entries = _parseSession(lines);
|
|
3455
4132
|
if (loadedSkillsFrom(entries).size > 0) report.sessionsWithASkill += 1;
|
|
3456
4133
|
report.flags.push(...scanSessionForViolations(id, lines, census.forbidden, entries));
|
|
@@ -3520,8 +4197,8 @@ function render4(r) {
|
|
|
3520
4197
|
lines.push(" ships as detection-only, and this one says so.");
|
|
3521
4198
|
return lines.join("\n");
|
|
3522
4199
|
}
|
|
3523
|
-
function
|
|
3524
|
-
const args = argv ??
|
|
4200
|
+
function main12(argv) {
|
|
4201
|
+
const args = argv ?? process4.argv.slice(2);
|
|
3525
4202
|
let limit = 30;
|
|
3526
4203
|
let json = false;
|
|
3527
4204
|
const stores = [];
|
|
@@ -3534,7 +4211,7 @@ function main11(argv) {
|
|
|
3534
4211
|
if (a === "--limit") {
|
|
3535
4212
|
const v = value(i);
|
|
3536
4213
|
if (v === null) {
|
|
3537
|
-
|
|
4214
|
+
process4.stderr.write("report_skill_obligation_violations: --limit needs a number\n");
|
|
3538
4215
|
return 1;
|
|
3539
4216
|
}
|
|
3540
4217
|
limit = Number.parseInt(v, 10);
|
|
@@ -3542,7 +4219,7 @@ function main11(argv) {
|
|
|
3542
4219
|
} else if (a === "--store") {
|
|
3543
4220
|
const v = value(i);
|
|
3544
4221
|
if (v === null) {
|
|
3545
|
-
|
|
4222
|
+
process4.stderr.write("report_skill_obligation_violations: --store needs a path\n");
|
|
3546
4223
|
return 1;
|
|
3547
4224
|
}
|
|
3548
4225
|
stores.push(v);
|
|
@@ -3550,58 +4227,58 @@ function main11(argv) {
|
|
|
3550
4227
|
} else if (a === "--json") {
|
|
3551
4228
|
json = true;
|
|
3552
4229
|
} else if (a === "--help" || a === "-h") {
|
|
3553
|
-
|
|
4230
|
+
process4.stdout.write(
|
|
3554
4231
|
"usage: report_skill_obligation_violations [--limit N] [--store PATH]... [--json]\n"
|
|
3555
4232
|
);
|
|
3556
4233
|
return 0;
|
|
3557
4234
|
} else if (a !== void 0 && a.startsWith("--") && a !== "--quiet") {
|
|
3558
|
-
|
|
4235
|
+
process4.stderr.write(`report_skill_obligation_violations: unknown flag ${a}
|
|
3559
4236
|
`);
|
|
3560
4237
|
return 1;
|
|
3561
4238
|
}
|
|
3562
4239
|
}
|
|
3563
4240
|
if (!Number.isFinite(limit) || limit <= 0) {
|
|
3564
|
-
|
|
4241
|
+
process4.stderr.write("report_skill_obligation_violations: --limit must be a positive integer\n");
|
|
3565
4242
|
return 1;
|
|
3566
4243
|
}
|
|
3567
4244
|
if (stores.length === 0) stores.push(defaultStore3(REPO_ROOT4));
|
|
3568
4245
|
for (const store of stores) {
|
|
3569
4246
|
const r = scanStore2(REPO_ROOT4, store, limit);
|
|
3570
|
-
|
|
4247
|
+
process4.stdout.write(json ? `${JSON.stringify(r, null, 2)}
|
|
3571
4248
|
` : `${render4(r)}
|
|
3572
4249
|
`);
|
|
3573
4250
|
}
|
|
3574
4251
|
return 0;
|
|
3575
4252
|
}
|
|
3576
|
-
function
|
|
3577
|
-
if (
|
|
3578
|
-
if (import.meta.url ===
|
|
4253
|
+
function _isCliEntry11() {
|
|
4254
|
+
if (process4.argv[1] === void 0) return false;
|
|
4255
|
+
if (import.meta.url === pathToFileURL12(path12.resolve(process4.argv[1])).href) return true;
|
|
3579
4256
|
try {
|
|
3580
|
-
return
|
|
4257
|
+
return fs12.realpathSync(_HERE3) === fs12.realpathSync(path12.resolve(process4.argv[1]));
|
|
3581
4258
|
} catch {
|
|
3582
4259
|
return false;
|
|
3583
4260
|
}
|
|
3584
4261
|
}
|
|
3585
|
-
if (
|
|
3586
|
-
|
|
4262
|
+
if (_isCliEntry11()) {
|
|
4263
|
+
process4.exit(main12());
|
|
3587
4264
|
}
|
|
3588
4265
|
|
|
3589
4266
|
// src/scripts/report_conformance_funnel.ts
|
|
3590
|
-
var _HERE4 =
|
|
3591
|
-
var REPO_ROOT5 =
|
|
4267
|
+
var _HERE4 = fileURLToPath13(import.meta.url);
|
|
4268
|
+
var REPO_ROOT5 = path13.resolve(path13.dirname(_HERE4), "..", "..");
|
|
3592
4269
|
function buildFunnel(opts = {}) {
|
|
3593
4270
|
const repoRoot = opts.repoRoot ?? REPO_ROOT5;
|
|
3594
|
-
const projectRulesDir = opts.projectRulesDir ??
|
|
3595
|
-
const globalRulesDir = opts.globalRulesDir ??
|
|
3596
|
-
const sourceDir = opts.sourceDir ??
|
|
4271
|
+
const projectRulesDir = opts.projectRulesDir ?? path13.join(repoRoot, PROJECT_RULES);
|
|
4272
|
+
const globalRulesDir = opts.globalRulesDir ?? path13.join(os6.homedir(), GLOBAL_RULES);
|
|
4273
|
+
const sourceDir = opts.sourceDir ?? path13.join(repoRoot, PROJECTION_SOURCE);
|
|
3597
4274
|
const store = opts.store ?? defaultStore(repoRoot);
|
|
3598
4275
|
const limit = opts.limit ?? 30;
|
|
3599
4276
|
return {
|
|
3600
4277
|
delivered: measureDelivered(projectRulesDir, globalRulesDir),
|
|
3601
4278
|
divergence: compareCarriers(projectRulesDir, globalRulesDir, sourceDir),
|
|
3602
|
-
skills: censusSkills(
|
|
4279
|
+
skills: censusSkills(path13.join(repoRoot, SKILLS_ROOT)),
|
|
3603
4280
|
usage: measureUsage(store, limit),
|
|
3604
|
-
storePresent:
|
|
4281
|
+
storePresent: fs13.existsSync(store),
|
|
3605
4282
|
sk2: scanStore2(repoRoot, store, limit)
|
|
3606
4283
|
};
|
|
3607
4284
|
}
|
|
@@ -3726,8 +4403,8 @@ function render5(r) {
|
|
|
3726
4403
|
lines.push("workflow without a measured false-positive rate first (locked policy).");
|
|
3727
4404
|
return lines.join("\n");
|
|
3728
4405
|
}
|
|
3729
|
-
function
|
|
3730
|
-
const args = argv ??
|
|
4406
|
+
function main13(argv) {
|
|
4407
|
+
const args = argv ?? process5.argv.slice(2);
|
|
3731
4408
|
const opts = {};
|
|
3732
4409
|
const value = (i) => {
|
|
3733
4410
|
const v = args[i + 1];
|
|
@@ -3738,11 +4415,11 @@ function main12(argv) {
|
|
|
3738
4415
|
if (a === "--store" || a === "--project" || a === "--global" || a === "--source") {
|
|
3739
4416
|
const v = value(i);
|
|
3740
4417
|
if (v === null) {
|
|
3741
|
-
|
|
4418
|
+
process5.stderr.write(`report_conformance_funnel: ${a} needs a value
|
|
3742
4419
|
`);
|
|
3743
4420
|
return 1;
|
|
3744
4421
|
}
|
|
3745
|
-
const resolved =
|
|
4422
|
+
const resolved = path13.resolve(v);
|
|
3746
4423
|
if (a === "--store") opts.store = resolved;
|
|
3747
4424
|
else if (a === "--project") opts.projectRulesDir = resolved;
|
|
3748
4425
|
else if (a === "--global") opts.globalRulesDir = resolved;
|
|
@@ -3752,41 +4429,41 @@ function main12(argv) {
|
|
|
3752
4429
|
const v = value(i);
|
|
3753
4430
|
const n = v === null ? Number.NaN : Number.parseInt(v, 10);
|
|
3754
4431
|
if (!Number.isFinite(n) || n <= 0) {
|
|
3755
|
-
|
|
4432
|
+
process5.stderr.write("report_conformance_funnel: --limit must be a positive integer\n");
|
|
3756
4433
|
return 1;
|
|
3757
4434
|
}
|
|
3758
4435
|
opts.limit = n;
|
|
3759
4436
|
i += 1;
|
|
3760
4437
|
} else if (a === "--help" || a === "-h") {
|
|
3761
|
-
|
|
4438
|
+
process5.stdout.write(
|
|
3762
4439
|
"usage: report_conformance_funnel [--store PATH] [--limit N]\n [--project DIR] [--global DIR] [--source DIR]\n"
|
|
3763
4440
|
);
|
|
3764
4441
|
return 0;
|
|
3765
4442
|
} else if (a !== void 0 && a.startsWith("--") && a !== "--quiet") {
|
|
3766
|
-
|
|
4443
|
+
process5.stderr.write(`report_conformance_funnel: unknown flag ${a}
|
|
3767
4444
|
`);
|
|
3768
4445
|
return 1;
|
|
3769
4446
|
}
|
|
3770
4447
|
}
|
|
3771
|
-
|
|
4448
|
+
process5.stdout.write(`${render5(buildFunnel(opts))}
|
|
3772
4449
|
`);
|
|
3773
4450
|
return 0;
|
|
3774
4451
|
}
|
|
3775
|
-
function
|
|
3776
|
-
if (
|
|
3777
|
-
if (import.meta.url ===
|
|
4452
|
+
function _isCliEntry12() {
|
|
4453
|
+
if (process5.argv[1] === void 0) return false;
|
|
4454
|
+
if (import.meta.url === pathToFileURL13(path13.resolve(process5.argv[1])).href) return true;
|
|
3778
4455
|
try {
|
|
3779
|
-
return
|
|
4456
|
+
return fs13.realpathSync(_HERE4) === fs13.realpathSync(path13.resolve(process5.argv[1]));
|
|
3780
4457
|
} catch {
|
|
3781
4458
|
return false;
|
|
3782
4459
|
}
|
|
3783
4460
|
}
|
|
3784
|
-
if (
|
|
3785
|
-
|
|
4461
|
+
if (_isCliEntry12()) {
|
|
4462
|
+
process5.exit(main13());
|
|
3786
4463
|
}
|
|
3787
4464
|
|
|
3788
4465
|
// src/scripts/_cli/cmd_conformance.ts
|
|
3789
|
-
var _HERE5 =
|
|
4466
|
+
var _HERE5 = fileURLToPath14(import.meta.url);
|
|
3790
4467
|
var PACKAGE_ROOT = resolvePackageRoot(import.meta.url);
|
|
3791
4468
|
var CONFORMANCE_CHECK_IDS = [
|
|
3792
4469
|
"txlog-clean",
|
|
@@ -3797,29 +4474,29 @@ var CONFORMANCE_CHECK_IDS = [
|
|
|
3797
4474
|
];
|
|
3798
4475
|
var THIN_STUB_MARKER = "Routed rule \u2014 load the body on trigger-match";
|
|
3799
4476
|
function print(s = "") {
|
|
3800
|
-
|
|
4477
|
+
process6.stdout.write(`${s}
|
|
3801
4478
|
`);
|
|
3802
4479
|
}
|
|
3803
4480
|
function eprint(s = "") {
|
|
3804
|
-
|
|
4481
|
+
process6.stderr.write(`${s}
|
|
3805
4482
|
`);
|
|
3806
4483
|
}
|
|
3807
4484
|
function conformanceLogPath() {
|
|
3808
|
-
const override =
|
|
4485
|
+
const override = process6.env["AGENT_CONFIG_CONFORMANCE_LOG"];
|
|
3809
4486
|
if (override && override.trim().length > 0) {
|
|
3810
4487
|
return override;
|
|
3811
4488
|
}
|
|
3812
|
-
return
|
|
4489
|
+
return path14.join(os7.homedir(), ".event4u", "agent-config", "conformance-log.jsonl");
|
|
3813
4490
|
}
|
|
3814
4491
|
function installLogPath() {
|
|
3815
|
-
const override =
|
|
4492
|
+
const override = process6.env["AGENT_CONFIG_INSTALL_LOG"];
|
|
3816
4493
|
if (override && override.trim().length > 0) {
|
|
3817
4494
|
return override;
|
|
3818
4495
|
}
|
|
3819
|
-
return
|
|
4496
|
+
return path14.join(os7.homedir(), ".event4u", "agent-config", "install-log.jsonl");
|
|
3820
4497
|
}
|
|
3821
4498
|
function _check_txlog_clean(logPath = installLogPath()) {
|
|
3822
|
-
if (!
|
|
4499
|
+
if (!fs14.existsSync(logPath)) {
|
|
3823
4500
|
return {
|
|
3824
4501
|
id: "txlog-clean",
|
|
3825
4502
|
status: "ok",
|
|
@@ -3853,11 +4530,11 @@ function _check_txlog_clean(logPath = installLogPath()) {
|
|
|
3853
4530
|
};
|
|
3854
4531
|
}
|
|
3855
4532
|
function routeTargetPaths(target) {
|
|
3856
|
-
return routeTargetPathsPosix(target).map((rel) =>
|
|
4533
|
+
return routeTargetPathsPosix(target).map((rel) => path14.join(...rel.split("/")));
|
|
3857
4534
|
}
|
|
3858
4535
|
function _check_router_pointers(packageRoot = PACKAGE_ROOT) {
|
|
3859
|
-
const routerPath =
|
|
3860
|
-
if (!
|
|
4536
|
+
const routerPath = path14.join(packageRoot, "dist", "router.json");
|
|
4537
|
+
if (!fs14.existsSync(routerPath)) {
|
|
3861
4538
|
return {
|
|
3862
4539
|
id: "router-pointers",
|
|
3863
4540
|
status: "fail",
|
|
@@ -3867,7 +4544,7 @@ function _check_router_pointers(packageRoot = PACKAGE_ROOT) {
|
|
|
3867
4544
|
}
|
|
3868
4545
|
let router;
|
|
3869
4546
|
try {
|
|
3870
|
-
router = JSON.parse(
|
|
4547
|
+
router = JSON.parse(fs14.readFileSync(routerPath, "utf8"));
|
|
3871
4548
|
} catch (exc) {
|
|
3872
4549
|
return {
|
|
3873
4550
|
id: "router-pointers",
|
|
@@ -3876,13 +4553,13 @@ function _check_router_pointers(packageRoot = PACKAGE_ROOT) {
|
|
|
3876
4553
|
remedy: "reinstall the package \u2014 dist/router.json is corrupt"
|
|
3877
4554
|
};
|
|
3878
4555
|
}
|
|
3879
|
-
const rulesDir =
|
|
4556
|
+
const rulesDir = path14.join(packageRoot, "dist", "agent-src", "rules");
|
|
3880
4557
|
const broken = [];
|
|
3881
4558
|
let ids = 0;
|
|
3882
4559
|
let targets = 0;
|
|
3883
4560
|
for (const kernelId of router["kernel"] ?? []) {
|
|
3884
4561
|
ids += 1;
|
|
3885
|
-
if (!
|
|
4562
|
+
if (!fs14.existsSync(path14.join(rulesDir, `${kernelId}.md`))) {
|
|
3886
4563
|
broken.push(`kernel:${kernelId} \u2192 rules/${kernelId}.md missing`);
|
|
3887
4564
|
}
|
|
3888
4565
|
}
|
|
@@ -3890,7 +4567,7 @@ function _check_router_pointers(packageRoot = PACKAGE_ROOT) {
|
|
|
3890
4567
|
for (const entry of router[tier] ?? []) {
|
|
3891
4568
|
const ruleId = String(entry["id"] ?? "");
|
|
3892
4569
|
ids += 1;
|
|
3893
|
-
if (!
|
|
4570
|
+
if (!fs14.existsSync(path14.join(rulesDir, `${ruleId}.md`))) {
|
|
3894
4571
|
broken.push(`${tier}:${ruleId} \u2192 rules/${ruleId}.md missing`);
|
|
3895
4572
|
}
|
|
3896
4573
|
for (const target of entry["routes_to"] ?? []) {
|
|
@@ -3900,7 +4577,7 @@ function _check_router_pointers(packageRoot = PACKAGE_ROOT) {
|
|
|
3900
4577
|
broken.push(`${ruleId} \u2192 unparseable routes_to ${JSON.stringify(target)}`);
|
|
3901
4578
|
continue;
|
|
3902
4579
|
}
|
|
3903
|
-
if (!candidates.some((rel) =>
|
|
4580
|
+
if (!candidates.some((rel) => fs14.existsSync(path14.join(packageRoot, rel)))) {
|
|
3904
4581
|
broken.push(`${ruleId} \u2192 ${target} (${candidates[0]} missing)`);
|
|
3905
4582
|
}
|
|
3906
4583
|
}
|
|
@@ -3932,9 +4609,9 @@ function detectSmokePlatform(projectRoot) {
|
|
|
3932
4609
|
return "claude";
|
|
3933
4610
|
}
|
|
3934
4611
|
function dispatcherRunner(packageRoot) {
|
|
3935
|
-
const localTsx =
|
|
3936
|
-
const script =
|
|
3937
|
-
if (
|
|
4612
|
+
const localTsx = path14.join(packageRoot, "node_modules", ".bin", "tsx");
|
|
4613
|
+
const script = path14.join(packageRoot, "src", "scripts", "hooks", "dispatch_hook.ts");
|
|
4614
|
+
if (fs14.existsSync(localTsx)) {
|
|
3938
4615
|
return [localTsx, script];
|
|
3939
4616
|
}
|
|
3940
4617
|
return ["npx", "tsx", script];
|
|
@@ -3984,12 +4661,12 @@ function _check_hook_dispatcher(projectRoot, packageRoot = PACKAGE_ROOT, opts =
|
|
|
3984
4661
|
};
|
|
3985
4662
|
}
|
|
3986
4663
|
function readSettingsMode(projectRoot) {
|
|
3987
|
-
const settingsPath =
|
|
3988
|
-
if (!
|
|
4664
|
+
const settingsPath = path14.join(projectRoot, ".agent-settings.yml");
|
|
4665
|
+
if (!fs14.existsSync(settingsPath)) {
|
|
3989
4666
|
return "eager-all";
|
|
3990
4667
|
}
|
|
3991
4668
|
try {
|
|
3992
|
-
const parsed = YAML.parse(
|
|
4669
|
+
const parsed = YAML.parse(fs14.readFileSync(settingsPath, "utf8"));
|
|
3993
4670
|
const lean = parsed?.["lean_projection"] ?? null;
|
|
3994
4671
|
const mode = lean?.["mode"];
|
|
3995
4672
|
return typeof mode === "string" && mode.length > 0 ? mode : "eager-all";
|
|
@@ -4000,7 +4677,7 @@ function readSettingsMode(projectRoot) {
|
|
|
4000
4677
|
function kernelIdsFromRouter(packageRoot) {
|
|
4001
4678
|
try {
|
|
4002
4679
|
const router = JSON.parse(
|
|
4003
|
-
|
|
4680
|
+
fs14.readFileSync(path14.join(packageRoot, "dist", "router.json"), "utf8")
|
|
4004
4681
|
);
|
|
4005
4682
|
return new Set((router["kernel"] ?? []).map(String));
|
|
4006
4683
|
} catch {
|
|
@@ -4017,8 +4694,8 @@ function _check_lean_projection(projectRoot, packageRoot = PACKAGE_ROOT, project
|
|
|
4017
4694
|
remedy: "set lean_projection.mode to 'eager-all' or 'thin' in .agent-settings.yml"
|
|
4018
4695
|
};
|
|
4019
4696
|
}
|
|
4020
|
-
const rulesDir = projectedRulesDir ??
|
|
4021
|
-
if (!
|
|
4697
|
+
const rulesDir = projectedRulesDir ?? path14.join(projectRoot, ".augment", "rules");
|
|
4698
|
+
if (!fs14.existsSync(rulesDir)) {
|
|
4022
4699
|
return {
|
|
4023
4700
|
id: "lean-projection",
|
|
4024
4701
|
status: "skipped",
|
|
@@ -4027,7 +4704,7 @@ function _check_lean_projection(projectRoot, packageRoot = PACKAGE_ROOT, project
|
|
|
4027
4704
|
};
|
|
4028
4705
|
}
|
|
4029
4706
|
const kernel = kernelIdsFromRouter(packageRoot);
|
|
4030
|
-
const files =
|
|
4707
|
+
const files = fs14.readdirSync(rulesDir).filter((f) => f.endsWith(".md") && f !== "INDEX.md").sort();
|
|
4031
4708
|
const nonKernel = files.filter((f) => !kernel.has(f.replace(/\.md$/, "")));
|
|
4032
4709
|
if (nonKernel.length === 0) {
|
|
4033
4710
|
return {
|
|
@@ -4041,7 +4718,7 @@ function _check_lean_projection(projectRoot, packageRoot = PACKAGE_ROOT, project
|
|
|
4041
4718
|
for (const f of nonKernel) {
|
|
4042
4719
|
let text = "";
|
|
4043
4720
|
try {
|
|
4044
|
-
text =
|
|
4721
|
+
text = fs14.readFileSync(path14.join(rulesDir, f), "utf8");
|
|
4045
4722
|
} catch {
|
|
4046
4723
|
continue;
|
|
4047
4724
|
}
|
|
@@ -4072,8 +4749,8 @@ function _check_lean_projection(projectRoot, packageRoot = PACKAGE_ROOT, project
|
|
|
4072
4749
|
function _check_host_manifest(projectRoot) {
|
|
4073
4750
|
const detected = Object.entries(detectToolPresence(projectRoot)).filter(([, v]) => v === true).map(([k]) => k);
|
|
4074
4751
|
const detectedNote = detected.length > 0 ? `detected surfaces: ${detected.join(", ")}` : "no surfaces detected";
|
|
4075
|
-
const settingsPath =
|
|
4076
|
-
if (!
|
|
4752
|
+
const settingsPath = path14.join(projectRoot, ".agent-settings.yml");
|
|
4753
|
+
if (!fs14.existsSync(settingsPath)) {
|
|
4077
4754
|
return {
|
|
4078
4755
|
id: "host-manifest",
|
|
4079
4756
|
status: "ok",
|
|
@@ -4083,7 +4760,7 @@ function _check_host_manifest(projectRoot) {
|
|
|
4083
4760
|
}
|
|
4084
4761
|
let parsed = null;
|
|
4085
4762
|
try {
|
|
4086
|
-
parsed = YAML.parse(
|
|
4763
|
+
parsed = YAML.parse(fs14.readFileSync(settingsPath, "utf8"));
|
|
4087
4764
|
} catch (exc) {
|
|
4088
4765
|
return {
|
|
4089
4766
|
id: "host-manifest",
|
|
@@ -4110,7 +4787,7 @@ function _check_host_manifest(projectRoot) {
|
|
|
4110
4787
|
};
|
|
4111
4788
|
}
|
|
4112
4789
|
function runConformanceChecks(opts = {}) {
|
|
4113
|
-
const projectRoot = opts.projectRoot ??
|
|
4790
|
+
const projectRoot = opts.projectRoot ?? process6.cwd();
|
|
4114
4791
|
const packageRoot = opts.packageRoot ?? PACKAGE_ROOT;
|
|
4115
4792
|
const checks = [];
|
|
4116
4793
|
checks.push(_check_txlog_clean());
|
|
@@ -4151,7 +4828,7 @@ function _parse(argv) {
|
|
|
4151
4828
|
while (i < argv.length) {
|
|
4152
4829
|
const a = argv[i];
|
|
4153
4830
|
if (a === "-h" || a === "--help") {
|
|
4154
|
-
|
|
4831
|
+
process6.stdout.write(USAGE);
|
|
4155
4832
|
throw new ArgparseExit(0);
|
|
4156
4833
|
}
|
|
4157
4834
|
if (a === "--json") {
|
|
@@ -4165,16 +4842,16 @@ function _parse(argv) {
|
|
|
4165
4842
|
opts.project = a.slice(a.indexOf("=") + 1);
|
|
4166
4843
|
} else {
|
|
4167
4844
|
if (i + 1 >= argv.length) {
|
|
4168
|
-
|
|
4169
|
-
|
|
4845
|
+
process6.stderr.write(USAGE);
|
|
4846
|
+
process6.stderr.write("agent-config conformance: error: --project expects a value\n");
|
|
4170
4847
|
throw new ArgparseExit(2);
|
|
4171
4848
|
}
|
|
4172
4849
|
opts.project = argv[i + 1];
|
|
4173
4850
|
i += 1;
|
|
4174
4851
|
}
|
|
4175
4852
|
} else {
|
|
4176
|
-
|
|
4177
|
-
|
|
4853
|
+
process6.stderr.write(USAGE);
|
|
4854
|
+
process6.stderr.write(`agent-config conformance: error: unrecognized argument ${a}
|
|
4178
4855
|
`);
|
|
4179
4856
|
throw new ArgparseExit(2);
|
|
4180
4857
|
}
|
|
@@ -4182,8 +4859,8 @@ function _parse(argv) {
|
|
|
4182
4859
|
}
|
|
4183
4860
|
return opts;
|
|
4184
4861
|
}
|
|
4185
|
-
function
|
|
4186
|
-
const opts = _parse(argv !== null ? Array.from(argv) :
|
|
4862
|
+
function main14(argv = null) {
|
|
4863
|
+
const opts = _parse(argv !== null ? Array.from(argv) : process6.argv.slice(2));
|
|
4187
4864
|
if (opts.funnel) {
|
|
4188
4865
|
print(render5(buildFunnel()));
|
|
4189
4866
|
return 0;
|
|
@@ -4253,28 +4930,28 @@ function main13(argv = null) {
|
|
|
4253
4930
|
}
|
|
4254
4931
|
return failed ? 1 : 0;
|
|
4255
4932
|
}
|
|
4256
|
-
function
|
|
4257
|
-
if (
|
|
4933
|
+
function _isCliEntry13() {
|
|
4934
|
+
if (process6.argv[1] === void 0) {
|
|
4258
4935
|
return false;
|
|
4259
4936
|
}
|
|
4260
|
-
const argvUrl =
|
|
4937
|
+
const argvUrl = pathToFileURL14(path14.resolve(process6.argv[1])).href;
|
|
4261
4938
|
if (import.meta.url === argvUrl) {
|
|
4262
4939
|
return true;
|
|
4263
4940
|
}
|
|
4264
4941
|
try {
|
|
4265
|
-
const here =
|
|
4266
|
-
const argv =
|
|
4942
|
+
const here = fs14.realpathSync(fileURLToPath14(import.meta.url));
|
|
4943
|
+
const argv = fs14.realpathSync(path14.resolve(process6.argv[1]));
|
|
4267
4944
|
return here === argv;
|
|
4268
4945
|
} catch {
|
|
4269
4946
|
return false;
|
|
4270
4947
|
}
|
|
4271
4948
|
}
|
|
4272
|
-
if (
|
|
4949
|
+
if (_isCliEntry13() || process6.argv[1] === _HERE5) {
|
|
4273
4950
|
try {
|
|
4274
|
-
|
|
4951
|
+
process6.exitCode = main14(process6.argv.slice(2));
|
|
4275
4952
|
} catch (e) {
|
|
4276
4953
|
if (e instanceof ArgparseExit) {
|
|
4277
|
-
|
|
4954
|
+
process6.exitCode = e.code;
|
|
4278
4955
|
} else {
|
|
4279
4956
|
throw e;
|
|
4280
4957
|
}
|
|
@@ -4294,7 +4971,7 @@ export {
|
|
|
4294
4971
|
conformanceLogPath,
|
|
4295
4972
|
detectSmokePlatform,
|
|
4296
4973
|
installLogPath,
|
|
4297
|
-
|
|
4974
|
+
main14 as main,
|
|
4298
4975
|
routeTargetPaths,
|
|
4299
4976
|
runConformanceChecks
|
|
4300
4977
|
};
|