@event4u/agent-config 16.2.0 → 16.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.
Files changed (332) hide show
  1. package/.augment-plugin/marketplace.json +3 -3
  2. package/.augment-plugin/plugin.json +1 -1
  3. package/.claude-plugin/marketplace.json +1 -1
  4. package/CHANGELOG.md +89 -237
  5. package/README.md +14 -12
  6. package/dist/agent-src/commands/analyze/inbox.md +1 -1
  7. package/dist/agent-src/commands/analyze/roadmap-repos.md +1 -1
  8. package/dist/agent-src/commands/bug/fix.md +17 -2
  9. package/dist/agent-src/commands/feature/plan.md +1 -1
  10. package/dist/agent-src/commands/feature/roadmap.md +1 -1
  11. package/dist/agent-src/commands/fix/ci.md +1 -1
  12. package/dist/agent-src/commands/implement-ticket.md +1 -1
  13. package/dist/agent-src/commands/jira-ticket.md +1 -1
  14. package/dist/agent-src/commands/roadmap/create.md +1 -1
  15. package/dist/agent-src/commands/roadmap/materialize.md +1 -1
  16. package/dist/agent-src/commands/roadmap/process-full.md +4 -4
  17. package/dist/agent-src/commands/roadmap/resolve-blockers.md +361 -0
  18. package/dist/agent-src/commands/roadmap/triage-parked.md +325 -0
  19. package/dist/agent-src/commands/roadmap.md +18 -4
  20. package/dist/agent-src/commands/tests/create.md +17 -3
  21. package/dist/agent-src/commands/tests/execute.md +22 -5
  22. package/dist/agent-src/contexts/authority/decision-revisit-gate-enforcement.md +43 -0
  23. package/dist/agent-src/contexts/communication/rules-auto/design-fidelity-enforcement.md +24 -0
  24. package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +6 -6
  25. package/dist/agent-src/contexts/execution/roadmap-process-loop.md +32 -2
  26. package/dist/agent-src/contexts/execution/session-canary-enforcement-history.md +67 -0
  27. package/dist/agent-src/contexts/execution/toolchain-resolver.md +101 -7
  28. package/dist/agent-src/rules/active-remediation.md +1 -1
  29. package/dist/agent-src/rules/autonomous-execution.md +1 -0
  30. package/dist/agent-src/rules/broken-access-control.md +1 -0
  31. package/dist/agent-src/rules/command-suggestion-policy.md +1 -0
  32. package/dist/agent-src/rules/context-hygiene.md +1 -1
  33. package/dist/agent-src/rules/decision-revisit-gate.md +16 -33
  34. package/dist/agent-src/rules/design-fidelity.md +13 -16
  35. package/dist/agent-src/rules/doc-screenshot-hygiene.md +1 -0
  36. package/dist/agent-src/rules/domain-safety-disclaimer.md +1 -0
  37. package/dist/agent-src/rules/domain-safety-pii.md +1 -0
  38. package/dist/agent-src/rules/domain-safety-retention.md +1 -0
  39. package/dist/agent-src/rules/engineering-safety-floor.md +1 -0
  40. package/dist/agent-src/rules/evaluator-independence.md +3 -2
  41. package/dist/agent-src/rules/fast-path-marker-visibility.md +1 -0
  42. package/dist/agent-src/rules/finance-safety-floor.md +1 -0
  43. package/dist/agent-src/rules/git-history-discipline.md +1 -0
  44. package/dist/agent-src/rules/image-likeness-and-rights.md +1 -0
  45. package/dist/agent-src/rules/legal-safety-floor.md +3 -2
  46. package/dist/agent-src/rules/lethal-trifecta-guard.md +1 -0
  47. package/dist/agent-src/rules/low-impact-corpus-privacy-floor.md +1 -0
  48. package/dist/agent-src/rules/media-governance-routing.md +14 -17
  49. package/dist/agent-src/rules/persona-governance.md +2 -2
  50. package/dist/agent-src/rules/provider-lifecycle-discipline.md +1 -1
  51. package/dist/agent-src/rules/question-not-instruction.md +1 -0
  52. package/dist/agent-src/rules/roadmap-progress-sync.md +1 -1
  53. package/dist/agent-src/rules/runtime-safety.md +1 -0
  54. package/dist/agent-src/rules/secret-vcs-guard.md +1 -0
  55. package/dist/agent-src/rules/security-sensitive-stop.md +3 -2
  56. package/dist/agent-src/rules/session-canary.md +8 -62
  57. package/dist/agent-src/rules/settings-ask-protocol.md +1 -0
  58. package/dist/agent-src/rules/source-confidentiality.md +1 -0
  59. package/dist/agent-src/rules/strategy-safety-floor.md +1 -0
  60. package/dist/agent-src/rules/tool-safety.md +1 -0
  61. package/dist/agent-src/rules/untrusted-input-defense.md +1 -0
  62. package/dist/agent-src/rules/user-interrupt-priority.md +1 -0
  63. package/dist/agent-src/scripts/archive_completed_roadmaps.ts +115 -20
  64. package/dist/agent-src/scripts/deferral_carry.ts +339 -0
  65. package/dist/agent-src/scripts/update_roadmap_progress.ts +4 -1
  66. package/dist/agent-src/skills/api-design/data/manifest.json +2 -2
  67. package/dist/agent-src/skills/api-testing/SKILL.md +17 -0
  68. package/dist/agent-src/skills/code-intelligence/SKILL.md +14 -2
  69. package/dist/agent-src/skills/design-system-capture/references/import-procedure.md +1 -1
  70. package/dist/agent-src/skills/existing-ui-audit/SKILL.md +2 -2
  71. package/dist/agent-src/skills/fe-design/SKILL.md +1 -1
  72. package/dist/agent-src/skills/iconography/SKILL.md +1 -1
  73. package/dist/agent-src/skills/js-library-packaging/SKILL.md +2 -2
  74. package/dist/agent-src/skills/monorepo-workspace/SKILL.md +1 -1
  75. package/dist/agent-src/skills/quality-tools/SKILL.md +11 -1
  76. package/dist/agent-src/skills/quality-tools/references/go-tools.md +76 -0
  77. package/dist/agent-src/skills/quality-tools/references/python-tools.md +104 -0
  78. package/dist/agent-src/skills/review-routing/SKILL.md +2 -2
  79. package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +1 -1
  80. package/dist/agent-src/skills/storybook-workshop/SKILL.md +3 -3
  81. package/dist/agent-src/skills/tailwind-engineer/SKILL.md +1 -1
  82. package/dist/agent-src/skills/test-case-discovery/SKILL.md +7 -0
  83. package/dist/agent-src/skills/test-driven-development/SKILL.md +17 -0
  84. package/dist/agent-src/skills/test-performance/SKILL.md +19 -1
  85. package/dist/agent-src/skills/ui-component-architect/SKILL.md +2 -2
  86. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  87. package/dist/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +48 -6
  88. package/dist/agent-src/templates/scripts/work_engine/stack/runner.ts +774 -109
  89. package/dist/cli/registry.js +1 -1
  90. package/dist/cli-delegate/archive_completed_roadmaps.js +92 -12
  91. package/dist/cli-delegate/check_update_banner.js +12 -1
  92. package/dist/cli-delegate/chunk-523HCFYO.js +90 -0
  93. package/dist/cli-delegate/{chunk-M2DPGFZ4.js → chunk-6V6TA25H.js} +22 -152
  94. package/dist/cli-delegate/chunk-7IQE3D5S.js +191 -0
  95. package/dist/cli-delegate/{chunk-6KFEC3G7.js → chunk-CQWX336L.js} +1 -1
  96. package/dist/cli-delegate/chunk-DEIV7XP7.js +108 -0
  97. package/dist/cli-delegate/chunk-EEHDXSYD.js +2040 -0
  98. package/dist/cli-delegate/{chunk-P6ZHP5W2.js → chunk-GKE7ZVFA.js} +4 -4
  99. package/dist/cli-delegate/chunk-JQOM7TTM.js +1201 -0
  100. package/dist/cli-delegate/{chunk-IGD6ERX6.js → chunk-JQVYKIZA.js} +10 -0
  101. package/dist/cli-delegate/{chunk-FC75PGJE.js → chunk-JY2I2DXV.js} +12 -1
  102. package/dist/cli-delegate/chunk-KB5FZ655.js +208 -0
  103. package/dist/cli-delegate/{chunk-7RQP4UDH.js → chunk-KR6EM23A.js} +235 -1455
  104. package/dist/cli-delegate/{chunk-LTYVIY76.js → chunk-LIYTLH6O.js} +1 -1
  105. package/dist/cli-delegate/{chunk-YJ72UIAK.js → chunk-NQ7WT43P.js} +1186 -244
  106. package/dist/cli-delegate/chunk-NXEILF2K.js +2160 -0
  107. package/dist/cli-delegate/{chunk-5R7HOLAF.js → chunk-NYX3L2PZ.js} +1 -1
  108. package/dist/cli-delegate/{chunk-4E2W63DA.js → chunk-OKJUIAPS.js} +62 -1
  109. package/dist/cli-delegate/{chunk-QAJS5YWY.js → chunk-PHD7OOLE.js} +2 -1
  110. package/dist/cli-delegate/{chunk-RGNIWTEA.js → chunk-QLDHIPWR.js} +1 -1
  111. package/dist/cli-delegate/{chunk-7XGBX6ZH.js → chunk-RQNNW7IF.js} +1314 -560
  112. package/dist/cli-delegate/{chunk-4XFP2Y3E.js → chunk-S4UMZNES.js} +1 -1
  113. package/dist/cli-delegate/{chunk-6KM6ORRY.js → chunk-S4YWNRKO.js} +24 -8
  114. package/dist/cli-delegate/{chunk-FP36SWJD.js → chunk-TRI6DQZ6.js} +2781 -340
  115. package/dist/cli-delegate/chunk-ULQRUR23.js +208 -0
  116. package/dist/cli-delegate/{chunk-NUHLI2RX.js → chunk-YCU3TIXH.js} +2 -0
  117. package/dist/cli-delegate/chunk-ZBZV2G5R.js +210 -0
  118. package/dist/cli-delegate/{chunk-WGXTVKCQ.js → chunk-ZUZKZYCN.js} +5 -3
  119. package/dist/cli-delegate/cmd_analyze_session.js +1 -1
  120. package/dist/cli-delegate/cmd_brand_status.js +1 -1
  121. package/dist/cli-delegate/cmd_conformance.js +1167 -234
  122. package/dist/cli-delegate/cmd_doctor.js +13 -6
  123. package/dist/cli-delegate/cmd_doctor_neighbours.js +23 -0
  124. package/dist/cli-delegate/cmd_explain.js +5 -5
  125. package/dist/cli-delegate/cmd_export.js +11 -8
  126. package/dist/cli-delegate/cmd_fleet.js +3 -3
  127. package/dist/cli-delegate/cmd_handoff.js +10 -7
  128. package/dist/cli-delegate/cmd_mcp_available.js +1 -1
  129. package/dist/cli-delegate/cmd_memory_get.js +3 -1
  130. package/dist/cli-delegate/cmd_migrate.js +2 -2
  131. package/dist/cli-delegate/cmd_packs_active.js +3 -3
  132. package/dist/cli-delegate/cmd_preflight.js +6 -6
  133. package/dist/cli-delegate/cmd_prune.js +11 -8
  134. package/dist/cli-delegate/cmd_refresh.js +2 -1
  135. package/dist/cli-delegate/cmd_route_audit.js +8 -6
  136. package/dist/cli-delegate/cmd_route_explain.js +4 -4
  137. package/dist/cli-delegate/cmd_session_recycle.js +4 -3
  138. package/dist/cli-delegate/cmd_settings_get.js +1 -1
  139. package/dist/cli-delegate/cmd_settings_migrate.js +11 -8
  140. package/dist/cli-delegate/cmd_settings_set.js +4 -4
  141. package/dist/cli-delegate/cmd_sync.js +11 -8
  142. package/dist/cli-delegate/cmd_uninstall.js +11 -8
  143. package/dist/cli-delegate/cmd_update.js +1 -1
  144. package/dist/cli-delegate/cmd_upgrade.js +3 -2
  145. package/dist/cli-delegate/cmd_validate.js +11 -8
  146. package/dist/cli-delegate/cmd_versions.js +1 -1
  147. package/dist/cli-delegate/deferral_carry.js +16 -0
  148. package/dist/cli-delegate/gate_execute.js +2 -2
  149. package/dist/cli-delegate/roadmap_gates.js +5 -5
  150. package/dist/cli-delegate/update_roadmap_progress.js +1 -1
  151. package/dist/discovery/deprecation-report.md +1 -1
  152. package/dist/discovery/discovery-manifest.json +127 -75
  153. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  154. package/dist/discovery/discovery-manifest.summary.md +3 -3
  155. package/dist/discovery/dormancy-report.md +1 -1
  156. package/dist/discovery/orphan-report.md +1 -1
  157. package/dist/discovery/packs.json +7 -5
  158. package/dist/discovery/trust-report.md +2 -2
  159. package/dist/discovery/workspaces.json +6 -4
  160. package/dist/hooks/dispatch.js +5357 -6656
  161. package/dist/hooks/dispatch.sha256 +1 -1
  162. package/dist/install/claudePathsPlan.js +47 -6
  163. package/dist/install/claudeRuleRewrite.js +7 -0
  164. package/dist/install/emit_host_rules_cli.js +39 -36
  165. package/dist/install/globalRuleScope.js +87 -0
  166. package/dist/install/host_rule_ownership.js +160 -0
  167. package/dist/install/install.mjs +2080 -1024
  168. package/dist/install/installThinLayer.js +261 -0
  169. package/dist/install/installedRuleLinks.js +176 -0
  170. package/dist/install/wizard-plan.js +24 -0
  171. package/dist/mcp/registry-manifest.json +3 -3
  172. package/dist/mcp/server.json +2 -2
  173. package/dist/mcp/server.mjs +31965 -27154
  174. package/dist/scripts/_lib/agent_settings.js +11 -0
  175. package/dist/scripts/_lib/claude_settings_hooks.js +10 -8
  176. package/dist/scripts/_lib/installed_layer.js +378 -0
  177. package/dist/scripts/_lib/lean_projection_mode.js +218 -15
  178. package/dist/scripts/_lib/rule_consequence_class.js +45 -0
  179. package/dist/scripts/_lib/rule_injection.js +67 -10
  180. package/dist/scripts/_lib/rule_law_section.js +122 -0
  181. package/dist/scripts/_lib/thin_rules.js +458 -0
  182. package/dist/scripts/_lib/windsurf_render.js +60 -0
  183. package/dist/scripts/condense.js +14 -26
  184. package/dist/scripts/project_thin_rules.js +14 -294
  185. package/dist/server/schemas/settings.js +6 -0
  186. package/dist/shared/skillRanking.js +74 -13
  187. package/docs/contracts/settings-classes.md +7 -5
  188. package/package.json +1 -1
  189. package/src/agent-src/scripts/archive_completed_roadmaps.ts +115 -20
  190. package/src/agent-src/scripts/deferral_carry.ts +339 -0
  191. package/src/agent-src/scripts/update_roadmap_progress.ts +4 -1
  192. package/src/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +48 -6
  193. package/src/agent-src/templates/scripts/work_engine/stack/runner.ts +774 -109
  194. package/src/config/agent-settings.template.yml +62 -22
  195. package/src/config/continuity-surface.json +7 -0
  196. package/src/config/evaluator-budgets.json +4 -4
  197. package/src/config/gate-coverage.yml +96 -3
  198. package/src/config/gate-violation-baselines.json +17 -9
  199. package/src/config/hook-bundle-budget.json +25 -0
  200. package/src/config/hook-token-budget.json +6 -1
  201. package/src/config/host-instruction-limits.json +33 -0
  202. package/src/config/routing-coverage-seed.json +24 -3
  203. package/src/config/rule-activation-census.json +7 -3
  204. package/src/config/rule-consequence-class.json +161 -0
  205. package/src/config/rule-law-ceilings.json +99 -0
  206. package/src/install/claudePathsPlan.ts +46 -4
  207. package/src/install/claudeRuleRewrite.ts +10 -1
  208. package/src/install/emit_host_rules_cli.ts +43 -34
  209. package/src/install/globalRuleScope.ts +109 -0
  210. package/src/install/host_rule_ownership.ts +170 -0
  211. package/src/install/installThinLayer.ts +312 -0
  212. package/src/install/installedRuleLinks.ts +220 -0
  213. package/src/install/wizard-plan.ts +24 -0
  214. package/src/scripts/_cli/cmd_doctor.ts +23 -71
  215. package/src/scripts/_cli/cmd_doctor_neighbours.ts +293 -0
  216. package/src/scripts/_dispatch.bash +16 -2
  217. package/src/scripts/_lib/agent_settings.ts +11 -0
  218. package/src/scripts/_lib/claude_settings_hooks.ts +10 -8
  219. package/src/scripts/_lib/estate_offsets.ts +241 -0
  220. package/src/scripts/_lib/exemption_shape.ts +143 -0
  221. package/src/scripts/_lib/fnv.ts +23 -0
  222. package/src/scripts/_lib/foreign_scan.ts +106 -0
  223. package/src/scripts/_lib/gitignore_block.ts +314 -0
  224. package/src/scripts/_lib/global_deploy_inventory.ts +32 -0
  225. package/src/scripts/_lib/graph_feeder_record.ts +214 -0
  226. package/src/scripts/_lib/hook_settings.ts +73 -0
  227. package/src/scripts/_lib/host_capability.ts +40 -19
  228. package/src/scripts/_lib/host_hook_merge.ts +165 -0
  229. package/src/scripts/_lib/installed_layer.ts +538 -0
  230. package/src/scripts/_lib/json_merge.ts +82 -0
  231. package/src/scripts/_lib/json_pointers.ts +93 -11
  232. package/src/scripts/_lib/lean_projection_mode.ts +275 -15
  233. package/src/scripts/_lib/machine_wake.ts +16 -3
  234. package/src/scripts/_lib/neighbour_census.ts +760 -0
  235. package/src/scripts/_lib/neighbour_scan.ts +122 -0
  236. package/src/scripts/_lib/neighbour_tool_use.ts +189 -0
  237. package/src/scripts/_lib/prompt_shape.ts +46 -0
  238. package/src/scripts/_lib/release_migration_gate.ts +19 -3
  239. package/src/scripts/_lib/reserved_name_sweep.ts +73 -0
  240. package/src/scripts/_lib/review_coverage.ts +134 -0
  241. package/src/scripts/_lib/rule_consequence_class.ts +71 -0
  242. package/src/scripts/_lib/rule_injection.ts +130 -10
  243. package/src/scripts/_lib/rule_law_section.ts +147 -0
  244. package/src/scripts/_lib/rule_layer_overlap.ts +58 -0
  245. package/src/scripts/_lib/skill_origin.ts +254 -0
  246. package/src/scripts/_lib/structured_ask.ts +64 -21
  247. package/src/scripts/_lib/thin_rules.ts +540 -0
  248. package/src/scripts/_lib/touched_file_quality.ts +434 -0
  249. package/src/scripts/_lib/turn_end_refusals.ts +77 -2
  250. package/src/scripts/_lib/windsurf_render.ts +63 -0
  251. package/src/scripts/ai_council/cli_call_budget.ts +13 -5
  252. package/src/scripts/ai_council/clients.ts +26 -57
  253. package/src/scripts/ai_council/config.ts +1 -1
  254. package/src/scripts/ai_council/vendor_defaults.ts +45 -0
  255. package/src/scripts/audit_skill_overlap.ts +261 -0
  256. package/src/scripts/before_complete_hook.ts +243 -12
  257. package/src/scripts/bench_touched_file_quality.ts +238 -0
  258. package/src/scripts/check_enforcement_matrix.ts +377 -20
  259. package/src/scripts/check_estate_count.ts +130 -153
  260. package/src/scripts/check_finding_dispositions.ts +116 -4
  261. package/src/scripts/check_hook_bundle_composition.ts +370 -0
  262. package/src/scripts/check_kernel_edit_ratified.ts +49 -11
  263. package/src/scripts/check_memory.ts +7 -1
  264. package/src/scripts/check_release_highlights.ts +10 -0
  265. package/src/scripts/check_release_pr_shape.ts +38 -15
  266. package/src/scripts/check_standing_rule_delivery.ts +33 -13
  267. package/src/scripts/check_verify_expectation_delta.ts +521 -0
  268. package/src/scripts/code_graph/detect.ts +127 -7
  269. package/src/scripts/code_graph/foreign.ts +194 -0
  270. package/src/scripts/code_graph/query.ts +217 -4
  271. package/src/scripts/code_graph/types.ts +26 -2
  272. package/src/scripts/code_graph/validate.ts +3 -1
  273. package/src/scripts/code_graph/verbs.ts +103 -0
  274. package/src/scripts/compile_hook_manifest.ts +33 -1
  275. package/src/scripts/condense.ts +14 -27
  276. package/src/scripts/estate_exemption_shape.ts +202 -0
  277. package/src/scripts/generate_host_cost_table.ts +1 -1
  278. package/src/scripts/hook_manifest.json +1 -1
  279. package/src/scripts/hook_manifest.yaml +150 -9
  280. package/src/scripts/hooks/block_config_weakening.ts +67 -2
  281. package/src/scripts/hooks/block_plumbing_writes.ts +29 -1
  282. package/src/scripts/hooks/code_graph_context_hook.ts +252 -23
  283. package/src/scripts/hooks/concern_failure_policy.ts +280 -0
  284. package/src/scripts/hooks/dispatch_hook.ts +52 -52
  285. package/src/scripts/hooks/exit_codes.ts +2 -1
  286. package/src/scripts/hooks/host_lowering.json +1 -1
  287. package/src/scripts/hooks/host_lowering.ts +19 -1
  288. package/src/scripts/hooks/one_question_per_ask_hook.ts +41 -25
  289. package/src/scripts/hooks/payload_stub.ts +10 -1
  290. package/src/scripts/hooks/rule_inject_hook.ts +757 -63
  291. package/src/scripts/hooks/table_fingerprint.ts +21 -0
  292. package/src/scripts/hooks/telemetry_usage_hook.ts +64 -8
  293. package/src/scripts/hooks/turn_end_gate_hook.ts +84 -0
  294. package/src/scripts/hooks_status.ts +112 -0
  295. package/src/scripts/injection_scan_hook.ts +7 -0
  296. package/src/scripts/install.ts +72 -185
  297. package/src/scripts/installed_layer_report.ts +103 -0
  298. package/src/scripts/language_mirror_hook.ts +15 -6
  299. package/src/scripts/learning_sidecar.ts +119 -8
  300. package/src/scripts/lint_hook_manifest.ts +53 -0
  301. package/src/scripts/lint_major_migration_sections.ts +156 -26
  302. package/src/scripts/lint_pack_boundaries.ts +63 -5
  303. package/src/scripts/lint_rule_law_section.ts +517 -0
  304. package/src/scripts/lint_workflow_security.ts +161 -5
  305. package/src/scripts/mcp_server/consumer_tool_catalog.json +53 -0
  306. package/src/scripts/mcp_server/graph_tools.ts +72 -3
  307. package/src/scripts/measure_routing_signal.ts +54 -16
  308. package/src/scripts/measure_skill_ranker_baseline.ts +216 -8
  309. package/src/scripts/memory_learn_hook.ts +91 -6
  310. package/src/scripts/model_rule_injection.ts +52 -5
  311. package/src/scripts/project_thin_rules.ts +34 -327
  312. package/src/scripts/report_evidence_temperature.ts +657 -0
  313. package/src/scripts/report_installed_rule_links.ts +157 -0
  314. package/src/scripts/report_label_agreement.ts +233 -0
  315. package/src/scripts/report_obligation_mechanism.ts +230 -0
  316. package/src/scripts/report_single_token_triggers.ts +277 -0
  317. package/src/scripts/report_skill_ranker_confusion.ts +442 -0
  318. package/src/scripts/report_standing_payload_by_host.ts +188 -15
  319. package/src/scripts/report_verification_record_coverage.ts +306 -0
  320. package/src/scripts/rule_activation_census.ts +5 -2
  321. package/src/scripts/rule_trigger_eval.ts +9 -9
  322. package/src/scripts/schemas/review-findings.schema.json +3 -2
  323. package/src/scripts/schemas/rule.schema.json +5 -0
  324. package/src/scripts/self_review_gate.ts +62 -7
  325. package/src/scripts/skill_tools/score_skill_relevance.ts +290 -25
  326. package/src/scripts/sweep_skill_ranker_signals.ts +129 -0
  327. package/src/scripts/sync_gitignore.ts +29 -235
  328. package/src/scripts/trigger_eval_grandfather.json +0 -5
  329. package/src/server/schemas/settings.ts +10 -0
  330. package/src/shared/skillRanking.ts +117 -11
  331. package/dist/cli-delegate/chunk-JNMVLWLR.js +0 -4457
  332. package/dist/cli-delegate/chunk-YDPILCOL.js +0 -152
@@ -52,6 +52,38 @@ export function isAcceptedEdge(e: CodeEdge): boolean {
52
52
  return isStatedResolution(e.resolved_via);
53
53
  }
54
54
 
55
+ /** Why a gate verb refused. A closed set so a caller can branch on it. */
56
+ export type RefusalReason = 'foreign-edges-not-accepted' | 'entry-points-unavailable';
57
+
58
+ /**
59
+ * A graph whose every edge came from a file this package did not build.
60
+ *
61
+ * Those edges are tagged `foreign` and sit in the guess set, so a gate verb
62
+ * walking one would accept nothing and report an empty answer — and an empty
63
+ * answer from a gate reads as "nothing to worry about", which is the wrong
64
+ * reading and the dangerous one. The verbs refuse instead, by name, so the
65
+ * consumer learns that their graph is readable but not gate-grade rather than
66
+ * being told their diff impacts nothing.
67
+ *
68
+ * A MIXED graph is not refused: it carries edges this package did resolve, and
69
+ * the guess filter already excludes the foreign ones from the walk.
70
+ */
71
+ export function foreignRefusal(g: LoadedGraph): string | null {
72
+ // `graph` is null on the index-backed read path, which answers per-node
73
+ // from the twin and never materialises the edge list. Nothing to classify
74
+ // there, and an index-backed graph is one this package built.
75
+ const edges: readonly CodeEdge[] = g.graph?.edges ?? [];
76
+ if (edges.length === 0) return null;
77
+ if (!edges.every((e) => e.resolved_via === 'foreign')) return null;
78
+ return (
79
+ 'every edge in this graph was read from a file this package did not build, so all of them ' +
80
+ 'are guesses and none is gate-grade. A gate verb would accept no edge and report an empty ' +
81
+ 'answer, which reads as "nothing found" rather than "nothing trusted". Build a native graph ' +
82
+ '(`agent-config graph build`) to use this verb, or use `query` and `explain`, which answer ' +
83
+ 'from foreign edges and say so.'
84
+ );
85
+ }
86
+
55
87
  /**
56
88
  * Relations that constitute a REFERENCE to the target, as opposed to
57
89
  * containment of it.
@@ -132,6 +164,10 @@ export interface ReachedNode {
132
164
  }
133
165
 
134
166
  export interface ImpactResult extends VerbReport {
167
+ /** Non-null when the verb REFUSED to answer. Every list is then empty. */
168
+ refusal: string | null;
169
+ /** Machine-readable reason, when `refusal` is set. */
170
+ refusal_reason: RefusalReason | null;
135
171
  /** Node ids the diff touched that the graph knows. */
136
172
  seeds: string[];
137
173
  /**
@@ -219,6 +255,26 @@ export function impact(
219
255
  depth = 2,
220
256
  isTest: (relPath: string) => boolean = () => false,
221
257
  ): ImpactResult {
258
+ const foreign = foreignRefusal(g);
259
+ if (foreign !== null) {
260
+ return {
261
+ source: g.source,
262
+ state,
263
+ accepted_via: '(none)',
264
+ rejected_via: '(none)',
265
+ refusal: foreign,
266
+ refusal_reason: 'foreign-edges-not-accepted',
267
+ seeds: [],
268
+ unresolved_files: [],
269
+ not_indexed_files: [],
270
+ dependents: [],
271
+ reached: [],
272
+ test_files: [],
273
+ producing_edges: [],
274
+ lines: [],
275
+ recommended_reads: [],
276
+ };
277
+ }
222
278
  const { seeds, unresolved, not_indexed } = seedsForFiles(g, files);
223
279
  const accepted: CodeEdge[] = [];
224
280
  const rejected: CodeEdge[] = [];
@@ -258,6 +314,8 @@ export function impact(
258
314
  state,
259
315
  accepted_via: viaHistogram(accepted),
260
316
  rejected_via: viaHistogram(rejected),
317
+ refusal: null,
318
+ refusal_reason: null,
261
319
  seeds,
262
320
  unresolved_files: unresolved,
263
321
  not_indexed_files: not_indexed,
@@ -334,6 +392,10 @@ export function testsFor(g: LoadedGraph, symbol: string, state: GraphState): Tes
334
392
  }
335
393
 
336
394
  export interface UntestedResult extends VerbReport {
395
+ /** Non-null when the verb REFUSED to answer. Every list is then empty. */
396
+ refusal: string | null;
397
+ /** Machine-readable reason, when `refusal` is set. */
398
+ refusal_reason: RefusalReason | null;
337
399
  seeds: string[];
338
400
  unresolved_files: string[];
339
401
  not_indexed_files: string[];
@@ -351,6 +413,24 @@ export interface UntestedResult extends VerbReport {
351
413
  * count and make the ratio meaningless.
352
414
  */
353
415
  export function untested(g: LoadedGraph, files: readonly string[], state: GraphState): UntestedResult {
416
+ const foreign = foreignRefusal(g);
417
+ if (foreign !== null) {
418
+ return {
419
+ source: g.source,
420
+ state,
421
+ accepted_via: '(none)',
422
+ rejected_via: '(none)',
423
+ refusal: foreign,
424
+ refusal_reason: 'foreign-edges-not-accepted',
425
+ seeds: [],
426
+ unresolved_files: [],
427
+ not_indexed_files: [],
428
+ untested: [],
429
+ tested: [],
430
+ lines: [],
431
+ recommended_reads: [],
432
+ };
433
+ }
354
434
  const { seeds, unresolved, not_indexed } = seedsForFiles(g, files);
355
435
  const accepted: CodeEdge[] = [];
356
436
  const rejected: CodeEdge[] = [];
@@ -375,6 +455,8 @@ export function untested(g: LoadedGraph, files: readonly string[], state: GraphS
375
455
  state,
376
456
  accepted_via: viaHistogram(accepted),
377
457
  rejected_via: viaHistogram(rejected),
458
+ refusal: null,
459
+ refusal_reason: null,
378
460
  seeds,
379
461
  unresolved_files: unresolved,
380
462
  not_indexed_files: not_indexed,
@@ -403,6 +485,8 @@ export interface DeadResult extends VerbReport {
403
485
  sources: EntryPointSource[];
404
486
  /** Non-null when the verb REFUSED to answer. The list is then empty. */
405
487
  refusal: string | null;
488
+ /** Machine-readable reason, when `refusal` is set. */
489
+ refusal_reason: RefusalReason | null;
406
490
  dead: string[];
407
491
  /** Entry points excluded from `dead` — the audit trail for the exclusion. */
408
492
  excluded: string[];
@@ -448,6 +532,23 @@ export function dead(
448
532
  state,
449
533
  sources: [...sources],
450
534
  };
535
+ // Checked BEFORE the entry-point sources: on an all-foreign graph every
536
+ // in-edge is a guess, so every symbol would report dead — the confident
537
+ // false "dead" this verb's own header calls worse than no verb at all.
538
+ const foreign = foreignRefusal(g);
539
+ if (foreign !== null) {
540
+ return {
541
+ ...base,
542
+ accepted_via: '(none)',
543
+ rejected_via: '(none)',
544
+ refusal: foreign,
545
+ refusal_reason: 'foreign-edges-not-accepted',
546
+ dead: [],
547
+ excluded: [],
548
+ lines: [],
549
+ recommended_reads: [],
550
+ };
551
+ }
451
552
  if (unavailable.length > 0 && opts.acceptMissingExports !== true) {
452
553
  return {
453
554
  ...base,
@@ -460,6 +561,7 @@ export function dead(
460
561
  'A symbol they would have declared an entry point is indistinguishable from a dead one, ' +
461
562
  'so no list is produced. Supply the missing source with --entry-points <file>, or state ' +
462
563
  'that you accept the gap with --accept-missing-exports.',
564
+ refusal_reason: 'entry-points-unavailable',
463
565
  dead: [],
464
566
  excluded: [],
465
567
  lines: [],
@@ -496,6 +598,7 @@ export function dead(
496
598
  accepted_via: viaHistogram(accepted),
497
599
  rejected_via: viaHistogram(rejected),
498
600
  refusal: null,
601
+ refusal_reason: null,
499
602
  dead: list,
500
603
  excluded: excluded.sort(),
501
604
  lines: list,
@@ -79,12 +79,44 @@ const TABLES = {
79
79
 
80
80
  export type TableName = keyof typeof TABLES;
81
81
 
82
+ /**
83
+ * The TWO labels a compiled table carries, and why one was not enough.
84
+ *
85
+ * `fingerprint` binds the file to its YAML SOURCE — it answers "is this
86
+ * compiled from the YAML as it stands". `body_fingerprint` binds the file to
87
+ * ITSELF: it is the fingerprint of the exact body bytes this writer emitted,
88
+ * and it answers "is the body a reader is about to serve the body that was
89
+ * compiled".
90
+ *
91
+ * road-to-blocking-severities 2.3. The source label alone left a real hole,
92
+ * and it is the one the roadmap measured: edit a cell of the compiled `table`
93
+ * and leave `fingerprint` alone, and it still equals the YAML's fingerprint,
94
+ * so the reader serves the edited body — and since both readers prefer the
95
+ * compiled form, the edited cell is what every host is told while the reviewed
96
+ * YAML beside it says something else.
97
+ *
98
+ * WHAT THIS DOES NOT CLAIM. Someone who edits the body can recompute this
99
+ * label as easily as the writer does; it is an integrity check against a
100
+ * PARTIAL edit — a hand edit, a bad merge, a truncated write — not a signature.
101
+ * That is the same honesty the source label already owed: neither resists an
102
+ * author, and resisting an author is what the tool-call deny (2.2) and the
103
+ * ratification record (2.1) are for. Three cheap mechanisms over one expensive
104
+ * one, each named for what it actually covers.
105
+ *
106
+ * The body text is `JSON.stringify` of the parsed document, which is exactly
107
+ * what lands in the file, so a reader recovers it by re-stringifying what it
108
+ * parsed. A test pins that round trip rather than assuming it.
109
+ */
82
110
  export function compile(yamlText: string, table: TableName = 'manifest'): string {
83
111
  const spec = TABLES[table];
84
112
  const doc = (spec.yamlVersion === undefined
85
113
  ? parseYaml(yamlText)
86
114
  : parseYaml(yamlText, { version: spec.yamlVersion })) as unknown;
87
- return JSON.stringify({ fingerprint: tableFingerprint(yamlText), [spec.key]: doc });
115
+ return JSON.stringify({
116
+ fingerprint: tableFingerprint(yamlText),
117
+ body_fingerprint: tableFingerprint(JSON.stringify(doc)),
118
+ [spec.key]: doc,
119
+ });
88
120
  }
89
121
 
90
122
  export function main(argv: readonly string[] = process.argv.slice(2)): number {
@@ -42,6 +42,7 @@ import {
42
42
  strip_source_prefix,
43
43
  } from './_lib/agent_src.js';
44
44
  import { rewriteProjectedBodyLinks } from './_lib/guidelines_lane.js';
45
+ import { render_windsurfrules, strip_frontmatter } from './_lib/windsurf_render.js';
45
46
  // Import-safety note: `project_thin_rules` guards its CLI entry
46
47
  // (`_isCliEntry()` before `process.exit(main())`), so importing it here is
47
48
  // side-effect-free. condense.ts is bundled into the installer, where a bare
@@ -49,7 +50,7 @@ import { rewriteProjectedBodyLinks } from './_lib/guidelines_lane.js';
49
50
  // bundled-CLI-entry-guard landmine. Verified before wiring, not assumed.
50
51
  import { build_thin } from './project_thin_rules.js';
51
52
  import { build_claude_hook_matrix } from './_lib/claude_settings_hooks.js';
52
- import { describeDroppedHosts, normalizeLeanProjectionMode, resolveLeanProjectionHosts, thinsHost,
53
+ import { describeDroppedHosts, resolveLeanProjection, thinsHost,
53
54
  writesThinFiles, type LeanProjectionHosts, type LeanProjectionMode } from './_lib/lean_projection_mode.js';
54
55
  import { is_claude_builtin_name } from './_lib/claude_builtin_names.js';
55
56
  import { project_settings_path, load_agent_settings } from './_lib/agent_settings.js';
@@ -461,16 +462,14 @@ function _read_projection_scope_dedup(): boolean {
461
462
 
462
463
 
463
464
  function _lean_projection_settings(): { mode: LeanProjectionMode; hosts: LeanProjectionHosts } {
464
- const data = load_agent_settings({ project_path: MODULE_STATE.SETTINGS_FILE });
465
- const lean = data['lean_projection'];
466
- const obj =
467
- typeof lean === 'object' && lean !== null && !Array.isArray(lean)
468
- ? (lean as Record<string, unknown>)
469
- : {};
470
- return {
471
- mode: normalizeLeanProjectionMode(obj['mode'] ?? ''),
472
- hosts: resolveLeanProjectionHosts(obj['hosts']),
473
- };
465
+ // Step 1.2 of `road-to-a-rule-carrier-that-works-outside-the-repo`: this is
466
+ // now the shared resolver rather than one of three private readers. The
467
+ // INPUT is unchanged — `MODULE_STATE.SETTINGS_FILE` is still the file, so
468
+ // the projector's answer is the answer it always gave — and only the code
469
+ // that interprets it is shared. That is risk 2 of the roadmap's register
470
+ // ("making the hook agree with the projector could also move the
471
+ // projector") discharged by construction instead of by a test alone.
472
+ return resolveLeanProjection({ settingsPath: MODULE_STATE.SETTINGS_FILE });
474
473
  }
475
474
 
476
475
  // --- hashing -----------------------------------------------------------------
@@ -778,15 +777,9 @@ function _filter_tool_dirs(mapping: Record<string, string>): Record<string, stri
778
777
  return out;
779
778
  }
780
779
 
781
- export function strip_frontmatter(content: string): string {
782
- if (content.startsWith('---')) {
783
- const end = content.indexOf('---', 3);
784
- if (end !== -1) {
785
- content = _lstripNewlines(content.slice(end + 3));
786
- }
787
- }
788
- return content;
789
- }
780
+ // Moved to `_lib/windsurf_render.ts` beside its one remaining caller here and
781
+ // the census that renders through it; re-exported so every importer's path holds.
782
+ export { strip_frontmatter };
790
783
 
791
784
  // ── Path rewriter (P1 of road-to-path-fixes.md) ───────────────────────────
792
785
  // Kept byte-identical to check_condensation.ts::_rewritePaths (the two MUST
@@ -1229,14 +1222,8 @@ export function generate_windsurfrules(): number {
1229
1222
  // on `.windsurf/rules`. Without this line removing the per-run filter regressed
1230
1223
  // it 13 → 113: the per-run filter had been covering it by accident.
1231
1224
  const rules = partition_rules_for_dir('.windsurf/rules', _scoped_rule_basenames());
1232
- const parts = ['# Auto-generated from dist/agent-src/rules/ — do not edit directly\n'];
1233
- for (const rule of rules) {
1234
- const p = path.join(MODULE_STATE.RULES_SOURCE, rule);
1235
- const content = strip_frontmatter(_readText(p));
1236
- parts.push(`---\n\n${_strip(content)}\n`);
1237
- }
1238
1225
  const output = path.join(MODULE_STATE.PROJECT_ROOT, '.windsurfrules');
1239
- _writeText(output, parts.join('\n') + '\n');
1226
+ _writeText(output, render_windsurfrules(MODULE_STATE.RULES_SOURCE, rules));
1240
1227
  info(` ✅ Generated .windsurfrules (${rules.length} rules)`);
1241
1228
  return rules.length;
1242
1229
  }
@@ -0,0 +1,202 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * What the `estate_offset_exempt` population actually says — the producing command.
4
+ *
5
+ * THIS IS A READER, NOT A GATE. It exits 0 on every corpus, including one where
6
+ * no reason names anything. The refusal lives in `check_estate_count`, applies
7
+ * to ADDED files only, and is grandfathered precisely because of what this
8
+ * script measures: 43 of the 221 reasons in the tree on 2026-10-01 name no
9
+ * alternative disposition, so a check that re-read them would land red on a
10
+ * fifth of its corpus.
11
+ *
12
+ * WHAT IT BUYS. Two numbers nobody could produce before: how many exemptions
13
+ * name a rejected alternative, and how many repeat another file's reason
14
+ * verbatim. Both are the inputs to whether the refusal vocabulary is the right
15
+ * one, and both move as the estate moves — so the NEXT reading is a delta
16
+ * rather than a re-derivation, which is the same bargain `roadmap_verify_share`
17
+ * makes for the verify grammar.
18
+ *
19
+ * THE VOCABULARY IS NOT THIS SCRIPT'S. It imports the lemma list the gate
20
+ * refuses on, so the report and the refusal cannot drift. A drifted pair fails
21
+ * silently and in the worst direction: the report says the tree conforms while
22
+ * the gate rejects it.
23
+ *
24
+ * CLI:
25
+ * ./scripts-run src/scripts/estate_exemption_shape
26
+ * ./scripts-run src/scripts/estate_exemption_shape --json
27
+ * ./scripts-run src/scripts/estate_exemption_shape --root <dir>
28
+ *
29
+ * Exit codes: 0 always, except 2 for bad argv or a scan root that holds nothing.
30
+ */
31
+ import * as fs from 'node:fs';
32
+ import * as path from 'node:path';
33
+ import process from 'node:process';
34
+ import { fileURLToPath } from 'node:url';
35
+
36
+ import { exemptionReason } from './_lib/estate_offsets.js';
37
+ import { DISPOSITION_LEMMAS, lemmasNamed, namesDisposition, reasonKey } from './_lib/exemption_shape.js';
38
+ import { DeadScopeError, assertScanned } from './_lib/scan_scope.js';
39
+
40
+ const _HERE = fileURLToPath(import.meta.url);
41
+ const _PROG = 'estate_exemption_shape';
42
+ const REPO_ROOT = path.resolve(path.dirname(_HERE), '..', '..');
43
+
44
+ /** The three trees an exemption can sit in. `stubs/` and `skipped/` carry none. */
45
+ const TREES: readonly { readonly label: string; readonly dir: string }[] = [
46
+ { label: 'active', dir: 'agents/roadmaps' },
47
+ { label: 'later', dir: 'agents/roadmaps/later' },
48
+ { label: 'archive', dir: 'agents/roadmaps/archive' },
49
+ ];
50
+
51
+ export interface ExemptionRow {
52
+ readonly tree: string;
53
+ readonly file: string;
54
+ readonly reason: string;
55
+ /** The disposition lemmas this reason names; empty means it names none. */
56
+ readonly lemmas: readonly string[];
57
+ }
58
+
59
+ export interface ShapeReport {
60
+ readonly rows: readonly ExemptionRow[];
61
+ readonly shaped: number;
62
+ readonly shapeless: number;
63
+ /** Per-lemma hit counts, in the gate's own lemma order. */
64
+ readonly byLemma: Readonly<Record<string, number>>;
65
+ /** Groups of two or more files sharing one reason, largest first. */
66
+ readonly duplicates: readonly (readonly string[])[];
67
+ }
68
+
69
+ /** Read every exemption under `root`, in a stable order. */
70
+ export function collectExemptions(root: string): ExemptionRow[] {
71
+ const rows: ExemptionRow[] = [];
72
+ for (const tree of TREES) {
73
+ const abs = path.join(root, tree.dir);
74
+ let names: string[];
75
+ try {
76
+ names = fs.readdirSync(abs);
77
+ } catch {
78
+ continue;
79
+ }
80
+ for (const name of [...names].sort()) {
81
+ if (!name.endsWith('.md')) continue;
82
+ const file = path.join(abs, name);
83
+ let text: string;
84
+ try {
85
+ if (!fs.statSync(file).isFile()) continue;
86
+ text = fs.readFileSync(file, 'utf-8');
87
+ } catch {
88
+ continue;
89
+ }
90
+ const reason = exemptionReason(text);
91
+ if (reason === null) continue;
92
+ rows.push({ tree: tree.label, file: `${tree.dir}/${name}`, reason, lemmas: lemmasNamed(reason) });
93
+ }
94
+ }
95
+ return rows;
96
+ }
97
+
98
+ /** Summarise the population against the gate's vocabulary. */
99
+ export function report(rows: readonly ExemptionRow[]): ShapeReport {
100
+ const byLemma: Record<string, number> = {};
101
+ for (const l of DISPOSITION_LEMMAS) {
102
+ byLemma[l.name] = rows.filter((r) => r.lemmas.includes(l.name)).length;
103
+ }
104
+ const groups = new Map<string, string[]>();
105
+ for (const r of rows) {
106
+ const key = reasonKey(r.reason);
107
+ const list = groups.get(key) ?? [];
108
+ list.push(r.file);
109
+ groups.set(key, list);
110
+ }
111
+ const duplicates = [...groups.values()].filter((g) => g.length > 1).sort((a, b) => b.length - a.length);
112
+ return {
113
+ rows,
114
+ shaped: rows.filter((r) => namesDisposition(r.reason)).length,
115
+ shapeless: rows.filter((r) => !namesDisposition(r.reason)).length,
116
+ byLemma,
117
+ duplicates,
118
+ };
119
+ }
120
+
121
+ function render(rep: ShapeReport): string {
122
+ const out: string[] = [];
123
+ const total = rep.rows.length;
124
+ out.push(`${_PROG}: ${String(total)} exemption(s)`);
125
+ for (const tree of TREES) {
126
+ out.push(` ${tree.label.padEnd(10)} ${String(rep.rows.filter((r) => r.tree === tree.label).length).padStart(4)}`);
127
+ }
128
+ out.push(` names a rejected alternative ${String(rep.shaped).padStart(4)}`);
129
+ out.push(` names none ${String(rep.shapeless).padStart(4)}`);
130
+ out.push(' per lemma:');
131
+ for (const l of DISPOSITION_LEMMAS) {
132
+ out.push(` ${l.name.padEnd(12)} ${String(rep.byLemma[l.name] ?? 0).padStart(4)}`);
133
+ }
134
+ const dupFiles = rep.duplicates.reduce((n, g) => n + g.length, 0);
135
+ out.push(` verbatim duplicate groups ${String(rep.duplicates.length).padStart(4)} covering ${String(dupFiles)} file(s)`);
136
+ for (const g of rep.duplicates) {
137
+ out.push(` (${String(g.length)}x) ${g.join(', ')}`);
138
+ }
139
+ if (rep.shapeless > 0) {
140
+ out.push(' naming no rejected alternative:');
141
+ for (const r of rep.rows.filter((x) => !namesDisposition(x.reason))) {
142
+ out.push(` ${r.file}: ${r.reason.slice(0, 120)}`);
143
+ }
144
+ }
145
+ return out.join('\n') + '\n';
146
+ }
147
+
148
+ export function main(argv: string[] = process.argv.slice(2)): number {
149
+ const json = argv.includes('--json');
150
+ const rootIdx = argv.indexOf('--root');
151
+ let root = REPO_ROOT;
152
+ if (rootIdx !== -1) {
153
+ const next = argv[rootIdx + 1];
154
+ if (next === undefined || next.startsWith('-')) {
155
+ process.stderr.write(`usage: ${_PROG} [--root <dir>] [--json]\n`);
156
+ return 2;
157
+ }
158
+ root = path.resolve(next);
159
+ }
160
+ const unknown = argv.filter((a) => a.startsWith('-') && a !== '--json' && a !== '--root');
161
+ if (unknown.length > 0) {
162
+ process.stderr.write(`${_PROG}: unknown argument(s) ${unknown.join(', ')}\n`);
163
+ return 2;
164
+ }
165
+
166
+ const rows = collectExemptions(root);
167
+ try {
168
+ // A root holding no roadmap at all is a dead scope, never an estate with
169
+ // nothing to report: this reader would otherwise print a confident zero
170
+ // over a path that does not exist.
171
+ assertScanned({
172
+ gate: _PROG,
173
+ scanned: TREES.reduce((n, t) => {
174
+ try {
175
+ return n + fs.readdirSync(path.join(root, t.dir)).filter((f) => f.endsWith('.md')).length;
176
+ } catch {
177
+ return n;
178
+ }
179
+ }, 0),
180
+ units: 'roadmap file(s)',
181
+ roots: TREES.map((t) => t.dir),
182
+ });
183
+ } catch (err) {
184
+ if (err instanceof DeadScopeError) {
185
+ process.stderr.write(`❌ ${_PROG}: ${err.message}\n`);
186
+ return 2;
187
+ }
188
+ throw err;
189
+ }
190
+
191
+ const rep = report(rows);
192
+ if (json) {
193
+ process.stdout.write(JSON.stringify(rep, null, 2) + '\n');
194
+ return 0;
195
+ }
196
+ process.stdout.write(render(rep));
197
+ return 0;
198
+ }
199
+
200
+ if (path.resolve(process.argv[1] ?? '') === _HERE) {
201
+ process.exit(main());
202
+ }
@@ -63,7 +63,7 @@ import {
63
63
  const _HERE = fileURLToPath(import.meta.url);
64
64
  export const REPO_ROOT = path.resolve(path.dirname(_HERE), '..', '..');
65
65
 
66
- /** The contract the README points at for projection modes (README.md:288). */
66
+ /** The contract the README points at for projection modes. */
67
67
  export const CONTRACT_REL = path.join('docs', 'contracts', 'rule-router.md');
68
68
 
69
69
  export const BEGIN = '<!-- BEGIN generated: host-standing-cost -->';