@event4u/agent-config 16.1.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 (467) 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 +98 -257
  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 +5 -5
  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/commands/work.md +4 -0
  23. package/dist/agent-src/contexts/authority/decision-revisit-gate-enforcement.md +43 -0
  24. package/dist/agent-src/contexts/communication/rules-auto/design-fidelity-enforcement.md +24 -0
  25. package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +6 -6
  26. package/dist/agent-src/contexts/execution/autonomy-mechanics.md +4 -8
  27. package/dist/agent-src/contexts/execution/roadmap-process-loop.md +32 -2
  28. package/dist/agent-src/contexts/execution/session-canary-enforcement-history.md +67 -0
  29. package/dist/agent-src/contexts/execution/toolchain-resolver.md +101 -7
  30. package/dist/agent-src/rules/active-remediation.md +1 -1
  31. package/dist/agent-src/rules/autonomous-execution.md +1 -0
  32. package/dist/agent-src/rules/broken-access-control.md +1 -0
  33. package/dist/agent-src/rules/command-suggestion-policy.md +1 -0
  34. package/dist/agent-src/rules/context-hygiene.md +1 -1
  35. package/dist/agent-src/rules/decision-revisit-gate.md +16 -33
  36. package/dist/agent-src/rules/design-fidelity.md +13 -16
  37. package/dist/agent-src/rules/doc-screenshot-hygiene.md +1 -0
  38. package/dist/agent-src/rules/domain-safety-disclaimer.md +1 -0
  39. package/dist/agent-src/rules/domain-safety-pii.md +1 -0
  40. package/dist/agent-src/rules/domain-safety-retention.md +1 -0
  41. package/dist/agent-src/rules/engineering-safety-floor.md +1 -0
  42. package/dist/agent-src/rules/evaluator-independence.md +3 -2
  43. package/dist/agent-src/rules/fast-path-marker-visibility.md +1 -0
  44. package/dist/agent-src/rules/finance-safety-floor.md +1 -0
  45. package/dist/agent-src/rules/git-history-discipline.md +1 -0
  46. package/dist/agent-src/rules/image-likeness-and-rights.md +1 -0
  47. package/dist/agent-src/rules/legal-safety-floor.md +3 -2
  48. package/dist/agent-src/rules/lethal-trifecta-guard.md +1 -0
  49. package/dist/agent-src/rules/low-impact-corpus-privacy-floor.md +1 -0
  50. package/dist/agent-src/rules/media-governance-routing.md +14 -17
  51. package/dist/agent-src/rules/persona-governance.md +2 -2
  52. package/dist/agent-src/rules/provider-lifecycle-discipline.md +1 -1
  53. package/dist/agent-src/rules/question-not-instruction.md +1 -0
  54. package/dist/agent-src/rules/roadmap-progress-sync.md +1 -1
  55. package/dist/agent-src/rules/runtime-safety.md +1 -0
  56. package/dist/agent-src/rules/secret-vcs-guard.md +1 -0
  57. package/dist/agent-src/rules/security-sensitive-stop.md +3 -2
  58. package/dist/agent-src/rules/session-canary.md +8 -62
  59. package/dist/agent-src/rules/settings-ask-protocol.md +1 -0
  60. package/dist/agent-src/rules/source-confidentiality.md +1 -0
  61. package/dist/agent-src/rules/strategy-safety-floor.md +1 -0
  62. package/dist/agent-src/rules/tool-safety.md +1 -0
  63. package/dist/agent-src/rules/ui-audit-gate.md +1 -2
  64. package/dist/agent-src/rules/untrusted-input-defense.md +1 -0
  65. package/dist/agent-src/rules/user-interrupt-priority.md +1 -0
  66. package/dist/agent-src/scripts/archive_completed_roadmaps.ts +115 -20
  67. package/dist/agent-src/scripts/deferral_carry.ts +339 -0
  68. package/dist/agent-src/scripts/update_roadmap_progress.ts +4 -1
  69. package/dist/agent-src/skills/accessibility-auditor/data/aria-patterns.csv +1 -1
  70. package/dist/agent-src/skills/accessibility-auditor/data/manifest.json +2 -2
  71. package/dist/agent-src/skills/api-design/data/manifest.json +2 -2
  72. package/dist/agent-src/skills/api-testing/SKILL.md +17 -0
  73. package/dist/agent-src/skills/code-intelligence/SKILL.md +14 -2
  74. package/dist/agent-src/skills/design-review/SKILL.md +30 -4
  75. package/dist/agent-src/skills/design-review/references/verification-automation.md +32 -0
  76. package/dist/agent-src/skills/design-system-capture/references/import-procedure.md +1 -1
  77. package/dist/agent-src/skills/existing-ui-audit/SKILL.md +18 -3
  78. package/dist/agent-src/skills/existing-ui-audit/references/component-taxonomy-detection.md +56 -0
  79. package/dist/agent-src/skills/fe-design/SKILL.md +1 -1
  80. package/dist/agent-src/skills/iconography/SKILL.md +1 -1
  81. package/dist/agent-src/skills/js-library-packaging/SKILL.md +2 -2
  82. package/dist/agent-src/skills/markitdown/SKILL.md +4 -0
  83. package/dist/agent-src/skills/monorepo-workspace/SKILL.md +1 -1
  84. package/dist/agent-src/skills/playwright-testing/SKILL.md +30 -6
  85. package/dist/agent-src/skills/quality-tools/SKILL.md +11 -1
  86. package/dist/agent-src/skills/quality-tools/references/go-tools.md +76 -0
  87. package/dist/agent-src/skills/quality-tools/references/python-tools.md +104 -0
  88. package/dist/agent-src/skills/review-routing/SKILL.md +2 -2
  89. package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +1 -1
  90. package/dist/agent-src/skills/storybook-workshop/SKILL.md +3 -3
  91. package/dist/agent-src/skills/tailwind-engineer/SKILL.md +1 -1
  92. package/dist/agent-src/skills/test-case-discovery/SKILL.md +7 -0
  93. package/dist/agent-src/skills/test-driven-development/SKILL.md +17 -0
  94. package/dist/agent-src/skills/test-performance/SKILL.md +19 -1
  95. package/dist/agent-src/skills/ui-component-architect/SKILL.md +25 -2
  96. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  97. package/dist/agent-src/templates/roadmaps.md +30 -0
  98. package/dist/agent-src/templates/scripts/work_engine/directives/ui/app_spec.ts +10 -4
  99. package/dist/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +302 -21
  100. package/dist/agent-src/templates/scripts/work_engine/directives/ui/audit.ts +22 -3
  101. package/dist/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +6 -1
  102. package/dist/agent-src/templates/scripts/work_engine/stack/runner.ts +774 -109
  103. package/dist/agent-src/templates/scripts/work_engine/state.ts +57 -7
  104. package/dist/agent-src/templates/scripts/work_engine/taxonomy/detect.ts +500 -0
  105. package/dist/agent-src/templates/scripts/work_engine/taxonomy/place.ts +183 -0
  106. package/dist/cli/python/knowledge_ingest.js +1 -1
  107. package/dist/cli/python/workspace_drive.js +1 -1
  108. package/dist/cli/registry.js +1 -1
  109. package/dist/cli-delegate/archive_completed_roadmaps.js +92 -12
  110. package/dist/cli-delegate/check_update_banner.js +12 -1
  111. package/dist/cli-delegate/chunk-523HCFYO.js +90 -0
  112. package/dist/cli-delegate/{chunk-M2DPGFZ4.js → chunk-6V6TA25H.js} +22 -152
  113. package/dist/cli-delegate/chunk-7IQE3D5S.js +191 -0
  114. package/dist/cli-delegate/{chunk-6KFEC3G7.js → chunk-CQWX336L.js} +1 -1
  115. package/dist/cli-delegate/chunk-DEIV7XP7.js +108 -0
  116. package/dist/cli-delegate/chunk-EEHDXSYD.js +2040 -0
  117. package/dist/cli-delegate/{chunk-P6ZHP5W2.js → chunk-GKE7ZVFA.js} +4 -4
  118. package/dist/cli-delegate/chunk-JQOM7TTM.js +1201 -0
  119. package/dist/cli-delegate/{chunk-UNCRJBT3.js → chunk-JQVYKIZA.js} +41 -0
  120. package/dist/cli-delegate/{chunk-FC75PGJE.js → chunk-JY2I2DXV.js} +12 -1
  121. package/dist/cli-delegate/chunk-KB5FZ655.js +208 -0
  122. package/dist/cli-delegate/{chunk-YUM5KURG.js → chunk-KR6EM23A.js} +235 -1455
  123. package/dist/cli-delegate/{chunk-LTYVIY76.js → chunk-LIYTLH6O.js} +1 -1
  124. package/dist/cli-delegate/chunk-NQ7WT43P.js +2729 -0
  125. package/dist/cli-delegate/chunk-NXEILF2K.js +2160 -0
  126. package/dist/cli-delegate/{chunk-5R7HOLAF.js → chunk-NYX3L2PZ.js} +1 -1
  127. package/dist/cli-delegate/{chunk-4E2W63DA.js → chunk-OKJUIAPS.js} +62 -1
  128. package/dist/cli-delegate/{chunk-QAJS5YWY.js → chunk-PHD7OOLE.js} +2 -1
  129. package/dist/cli-delegate/{chunk-RGNIWTEA.js → chunk-QLDHIPWR.js} +1 -1
  130. package/dist/cli-delegate/{chunk-HDVVGPQW.js → chunk-RQNNW7IF.js} +1405 -567
  131. package/dist/cli-delegate/{chunk-S3VFXMTM.js → chunk-S4UMZNES.js} +1 -1
  132. package/dist/cli-delegate/{chunk-6KM6ORRY.js → chunk-S4YWNRKO.js} +24 -8
  133. package/dist/cli-delegate/{chunk-GJCBB2UG.js → chunk-TRI6DQZ6.js} +3054 -325
  134. package/dist/cli-delegate/chunk-ULQRUR23.js +208 -0
  135. package/dist/cli-delegate/{chunk-NUHLI2RX.js → chunk-YCU3TIXH.js} +2 -0
  136. package/dist/cli-delegate/chunk-ZBZV2G5R.js +210 -0
  137. package/dist/cli-delegate/{chunk-WGXTVKCQ.js → chunk-ZUZKZYCN.js} +5 -3
  138. package/dist/cli-delegate/cmd_analyze_session.js +1 -1
  139. package/dist/cli-delegate/cmd_brand_status.js +1 -1
  140. package/dist/cli-delegate/cmd_conformance.js +1862 -809
  141. package/dist/cli-delegate/cmd_doctor.js +13 -6
  142. package/dist/cli-delegate/cmd_doctor_neighbours.js +23 -0
  143. package/dist/cli-delegate/cmd_explain.js +5 -5
  144. package/dist/cli-delegate/cmd_export.js +11 -8
  145. package/dist/cli-delegate/cmd_fleet.js +3 -3
  146. package/dist/cli-delegate/cmd_handoff.js +10 -7
  147. package/dist/cli-delegate/cmd_mcp_available.js +1 -1
  148. package/dist/cli-delegate/cmd_memory_get.js +3 -1
  149. package/dist/cli-delegate/cmd_migrate.js +2 -2
  150. package/dist/cli-delegate/cmd_packs_active.js +3 -3
  151. package/dist/cli-delegate/cmd_preflight.js +6 -6
  152. package/dist/cli-delegate/cmd_prune.js +11 -8
  153. package/dist/cli-delegate/cmd_refresh.js +2 -1
  154. package/dist/cli-delegate/cmd_route_audit.js +8 -6
  155. package/dist/cli-delegate/cmd_route_explain.js +4 -4
  156. package/dist/cli-delegate/cmd_session_recycle.js +4 -3
  157. package/dist/cli-delegate/cmd_settings_get.js +1 -1
  158. package/dist/cli-delegate/cmd_settings_migrate.js +11 -8
  159. package/dist/cli-delegate/cmd_settings_set.js +4 -4
  160. package/dist/cli-delegate/cmd_sync.js +11 -8
  161. package/dist/cli-delegate/cmd_uninstall.js +11 -8
  162. package/dist/cli-delegate/cmd_update.js +1 -1
  163. package/dist/cli-delegate/cmd_upgrade.js +3 -2
  164. package/dist/cli-delegate/cmd_validate.js +11 -8
  165. package/dist/cli-delegate/cmd_versions.js +1 -1
  166. package/dist/cli-delegate/deferral_carry.js +16 -0
  167. package/dist/cli-delegate/gate_execute.js +2 -2
  168. package/dist/cli-delegate/roadmap_gates.js +5 -5
  169. package/dist/cli-delegate/update_roadmap_progress.js +1 -1
  170. package/dist/discovery/deprecation-report.md +1 -1
  171. package/dist/discovery/discovery-manifest.json +132 -80
  172. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  173. package/dist/discovery/discovery-manifest.summary.md +3 -3
  174. package/dist/discovery/dormancy-report.md +1 -1
  175. package/dist/discovery/orphan-report.md +1 -1
  176. package/dist/discovery/packs.json +7 -5
  177. package/dist/discovery/trust-report.md +2 -2
  178. package/dist/discovery/workspaces.json +6 -4
  179. package/dist/hooks/dispatch.js +7972 -5186
  180. package/dist/hooks/dispatch.sha256 +1 -0
  181. package/dist/install/claudePathsPlan.js +47 -6
  182. package/dist/install/claudeRuleRewrite.js +7 -0
  183. package/dist/install/emit_host_rules_cli.js +39 -36
  184. package/dist/install/globalRuleScope.js +87 -0
  185. package/dist/install/host_rule_ownership.js +160 -0
  186. package/dist/install/install.mjs +2226 -1055
  187. package/dist/install/installThinLayer.js +261 -0
  188. package/dist/install/installedRuleLinks.js +176 -0
  189. package/dist/install/wizard-plan.js +24 -0
  190. package/dist/mcp/registry-manifest.json +3 -3
  191. package/dist/mcp/server.json +2 -2
  192. package/dist/mcp/server.mjs +40913 -34865
  193. package/dist/scripts/_lib/agent_settings.js +11 -0
  194. package/dist/scripts/_lib/claude_settings_hooks.js +10 -8
  195. package/dist/scripts/_lib/installed_layer.js +378 -0
  196. package/dist/scripts/_lib/lean_projection_mode.js +218 -15
  197. package/dist/scripts/_lib/rule_consequence_class.js +45 -0
  198. package/dist/scripts/_lib/rule_injection.js +67 -10
  199. package/dist/scripts/_lib/rule_law_section.js +122 -0
  200. package/dist/scripts/_lib/thin_rules.js +458 -0
  201. package/dist/scripts/_lib/windsurf_render.js +60 -0
  202. package/dist/scripts/condense.js +14 -26
  203. package/dist/scripts/project_thin_rules.js +14 -294
  204. package/dist/server/schemas/settings.js +29 -0
  205. package/dist/shared/skillRanking.js +74 -13
  206. package/dist/ui/assets/index-Cwq4d0hX.js +23 -0
  207. package/dist/ui/assets/index-Cyjy8bWO.css +1 -0
  208. package/dist/ui/index.html +2 -2
  209. package/docs/contracts/settings-classes.md +10 -6
  210. package/package.json +4 -4
  211. package/src/agent-src/scripts/archive_completed_roadmaps.ts +115 -20
  212. package/src/agent-src/scripts/deferral_carry.ts +339 -0
  213. package/src/agent-src/scripts/update_roadmap_progress.ts +4 -1
  214. package/src/agent-src/templates/scripts/work_engine/directives/ui/app_spec.ts +10 -4
  215. package/src/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +302 -21
  216. package/src/agent-src/templates/scripts/work_engine/directives/ui/audit.ts +22 -3
  217. package/src/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +6 -1
  218. package/src/agent-src/templates/scripts/work_engine/stack/runner.ts +774 -109
  219. package/src/agent-src/templates/scripts/work_engine/state.ts +57 -7
  220. package/src/agent-src/templates/scripts/work_engine/taxonomy/detect.ts +500 -0
  221. package/src/agent-src/templates/scripts/work_engine/taxonomy/place.ts +183 -0
  222. package/src/config/agent-settings.template.yml +91 -22
  223. package/src/config/ci-local-parity.yml +18 -0
  224. package/src/config/continuity-surface.json +9 -2
  225. package/src/config/evaluator-budgets.json +4 -4
  226. package/src/config/gate-coverage.yml +327 -3
  227. package/src/config/gate-violation-baselines.json +21 -9
  228. package/src/config/hook-bundle-budget.json +25 -0
  229. package/src/config/hook-latency-budget.json +21 -0
  230. package/src/config/hook-token-budget.json +8 -3
  231. package/src/config/host-instruction-limits.json +33 -0
  232. package/src/config/metric-registry.yml +114 -0
  233. package/src/config/placeholder-drift-budget.json +10 -0
  234. package/src/config/routing-coverage-seed.json +38 -3
  235. package/src/config/rule-activation-census.json +7 -3
  236. package/src/config/rule-consequence-class.json +161 -0
  237. package/src/config/rule-law-ceilings.json +99 -0
  238. package/src/install/claudePathsPlan.ts +46 -4
  239. package/src/install/claudeRuleRewrite.ts +10 -1
  240. package/src/install/emit_host_rules_cli.ts +43 -34
  241. package/src/install/globalRuleScope.ts +109 -0
  242. package/src/install/host_rule_ownership.ts +170 -0
  243. package/src/install/installThinLayer.ts +312 -0
  244. package/src/install/installedRuleLinks.ts +220 -0
  245. package/src/install/wizard-plan.ts +24 -0
  246. package/src/scripts/_cli/cmd_doctor.ts +28 -90
  247. package/src/scripts/_cli/cmd_doctor_neighbours.ts +293 -0
  248. package/src/scripts/_cli/doctor_execution.ts +100 -17
  249. package/src/scripts/_cli/doctor_network_posture.ts +226 -0
  250. package/src/scripts/_dispatch.bash +16 -2
  251. package/src/scripts/_lib/agent_settings.ts +11 -0
  252. package/src/scripts/_lib/body_portable.ts +102 -0
  253. package/src/scripts/_lib/cc_transcript.ts +132 -1
  254. package/src/scripts/_lib/claude_settings_hooks.ts +10 -8
  255. package/src/scripts/_lib/concern_sla_window.ts +200 -0
  256. package/src/scripts/_lib/estate_offsets.ts +241 -0
  257. package/src/scripts/_lib/exemption_shape.ts +143 -0
  258. package/src/scripts/_lib/fnv.ts +23 -0
  259. package/src/scripts/_lib/foreign_scan.ts +106 -0
  260. package/src/scripts/_lib/forge_protection.ts +114 -0
  261. package/src/scripts/_lib/forge_reader.ts +558 -0
  262. package/src/scripts/_lib/gitignore_block.ts +314 -0
  263. package/src/scripts/_lib/global_deploy_inventory.ts +32 -0
  264. package/src/scripts/_lib/graph_feeder_record.ts +214 -0
  265. package/src/scripts/_lib/hook_settings.ts +73 -0
  266. package/src/scripts/_lib/host_capability.ts +40 -19
  267. package/src/scripts/_lib/host_env_write.ts +111 -0
  268. package/src/scripts/_lib/host_hook_merge.ts +165 -0
  269. package/src/scripts/_lib/installed_layer.ts +538 -0
  270. package/src/scripts/_lib/json_merge.ts +82 -0
  271. package/src/scripts/_lib/json_pointers.ts +93 -11
  272. package/src/scripts/_lib/lean_projection_mode.ts +275 -15
  273. package/src/scripts/_lib/llm_proposer_transport.ts +14 -4
  274. package/src/scripts/_lib/machine_wake.ts +16 -3
  275. package/src/scripts/_lib/neighbour_census.ts +760 -0
  276. package/src/scripts/_lib/neighbour_scan.ts +122 -0
  277. package/src/scripts/_lib/neighbour_tool_use.ts +189 -0
  278. package/src/scripts/_lib/obligations.ts +119 -8
  279. package/src/scripts/_lib/probe_inputs.ts +271 -0
  280. package/src/scripts/_lib/prompt_shape.ts +46 -0
  281. package/src/scripts/_lib/read_surface_scan.ts +322 -0
  282. package/src/scripts/_lib/release_highlights.ts +2 -1
  283. package/src/scripts/_lib/release_migration_gate.ts +19 -3
  284. package/src/scripts/_lib/reserved_name_sweep.ts +73 -0
  285. package/src/scripts/_lib/retrieval_sanitize.ts +77 -16
  286. package/src/scripts/_lib/review_coverage.ts +134 -0
  287. package/src/scripts/_lib/rule_consequence_class.ts +71 -0
  288. package/src/scripts/_lib/rule_injection.ts +130 -10
  289. package/src/scripts/_lib/rule_law_section.ts +147 -0
  290. package/src/scripts/_lib/rule_layer_overlap.ts +58 -0
  291. package/src/scripts/_lib/shell_write_shapes.ts +108 -0
  292. package/src/scripts/_lib/skill_origin.ts +254 -0
  293. package/src/scripts/_lib/structural_hiding.ts +622 -0
  294. package/src/scripts/_lib/structured_ask.ts +64 -21
  295. package/src/scripts/_lib/thin_rules.ts +540 -0
  296. package/src/scripts/_lib/touched_file_quality.ts +434 -0
  297. package/src/scripts/_lib/turn_end_refusals.ts +600 -4
  298. package/src/scripts/_lib/turn_end_transcript.ts +216 -0
  299. package/src/scripts/_lib/verification_command.ts +324 -0
  300. package/src/scripts/_lib/verification_evidence.ts +647 -0
  301. package/src/scripts/_lib/verify_clause.ts +280 -0
  302. package/src/scripts/_lib/windsurf_render.ts +63 -0
  303. package/src/scripts/ai_council/cli_call_budget.ts +13 -5
  304. package/src/scripts/ai_council/clients.ts +26 -57
  305. package/src/scripts/ai_council/config.ts +1 -1
  306. package/src/scripts/ai_council/vendor_defaults.ts +45 -0
  307. package/src/scripts/ai_team/team_dispatch.ts +4 -0
  308. package/src/scripts/audit_skill_overlap.ts +261 -0
  309. package/src/scripts/before_complete_hook.ts +573 -25
  310. package/src/scripts/bench_hook_latency.ts +412 -5
  311. package/src/scripts/bench_touched_file_quality.ts +238 -0
  312. package/src/scripts/cache_realization_report.ts +61 -1
  313. package/src/scripts/check_argument_hint.ts +287 -0
  314. package/src/scripts/check_claims.ts +125 -1
  315. package/src/scripts/check_enforcement_coverage.ts +38 -9
  316. package/src/scripts/check_enforcement_matrix.ts +621 -22
  317. package/src/scripts/check_estate_count.ts +130 -153
  318. package/src/scripts/check_finding_dispositions.ts +138 -7
  319. package/src/scripts/check_generator_sync.ts +71 -0
  320. package/src/scripts/check_hook_bundle_composition.ts +370 -0
  321. package/src/scripts/check_host_docs_digest.ts +786 -0
  322. package/src/scripts/check_host_format_column.ts +559 -0
  323. package/src/scripts/check_input_references.ts +228 -0
  324. package/src/scripts/check_inputs_parity.ts +235 -0
  325. package/src/scripts/check_kernel_edit_ratified.ts +89 -9
  326. package/src/scripts/check_kill_switch_table.ts +294 -0
  327. package/src/scripts/check_memory.ts +7 -1
  328. package/src/scripts/check_placeholder_drift.ts +221 -0
  329. package/src/scripts/check_read_surface_coverage.ts +515 -0
  330. package/src/scripts/check_release_highlights.ts +10 -0
  331. package/src/scripts/check_release_holds.ts +2 -1
  332. package/src/scripts/check_release_pr_shape.ts +38 -15
  333. package/src/scripts/check_routing_coverage.ts +378 -11
  334. package/src/scripts/check_standing_rule_delivery.ts +33 -13
  335. package/src/scripts/check_static_parity.ts +17 -0
  336. package/src/scripts/check_verify_expectation_delta.ts +521 -0
  337. package/src/scripts/ci_settle.ts +145 -19
  338. package/src/scripts/closure_scan.ts +115 -1
  339. package/src/scripts/code_graph/detect.ts +127 -7
  340. package/src/scripts/code_graph/foreign.ts +194 -0
  341. package/src/scripts/code_graph/query.ts +217 -4
  342. package/src/scripts/code_graph/types.ts +26 -2
  343. package/src/scripts/code_graph/validate.ts +3 -1
  344. package/src/scripts/code_graph/verbs.ts +103 -0
  345. package/src/scripts/compile_hook_manifest.ts +90 -14
  346. package/src/scripts/condense.ts +14 -27
  347. package/src/scripts/estate_exemption_shape.ts +202 -0
  348. package/src/scripts/external_sources_denylist.json +29 -4
  349. package/src/scripts/generate_host_cost_table.ts +1 -1
  350. package/src/scripts/hook_manifest.json +1 -1
  351. package/src/scripts/hook_manifest.yaml +192 -14
  352. package/src/scripts/hooks/block_config_weakening.ts +294 -4
  353. package/src/scripts/hooks/block_kernel_rule_writes.ts +9 -78
  354. package/src/scripts/hooks/block_plumbing_writes.ts +342 -0
  355. package/src/scripts/hooks/bundle_integrity.ts +291 -0
  356. package/src/scripts/hooks/chain_nudge_hook.ts +1 -2
  357. package/src/scripts/hooks/code_graph_context_hook.ts +253 -25
  358. package/src/scripts/hooks/comment_discipline_hook.ts +1 -3
  359. package/src/scripts/hooks/concern_failure_policy.ts +280 -0
  360. package/src/scripts/hooks/concern_registry.ts +2 -0
  361. package/src/scripts/hooks/concern_timings.ts +94 -0
  362. package/src/scripts/hooks/delegation_nudge_hook.ts +1 -2
  363. package/src/scripts/hooks/design_pass_hook.ts +100 -9
  364. package/src/scripts/hooks/design_slop_hook.ts +1 -2
  365. package/src/scripts/hooks/dispatch_hook.ts +77 -71
  366. package/src/scripts/hooks/edit_shape_hook.ts +1 -2
  367. package/src/scripts/hooks/end_review_nudge_hook.ts +1 -1
  368. package/src/scripts/hooks/evidence_independence.ts +1 -2
  369. package/src/scripts/hooks/exit_codes.ts +129 -0
  370. package/src/scripts/hooks/host_lowering.json +1 -0
  371. package/src/scripts/hooks/host_lowering.ts +146 -3
  372. package/src/scripts/hooks/host_lowering.yaml +262 -46
  373. package/src/scripts/hooks/host_semantics.ts +30 -2
  374. package/src/scripts/hooks/injection_budget.ts +9 -2
  375. package/src/scripts/hooks/interruption_ledger_hook.ts +1 -2
  376. package/src/scripts/hooks/journal_record_hook.ts +1 -2
  377. package/src/scripts/hooks/memory_recall_hook.ts +1 -2
  378. package/src/scripts/hooks/obligation_settle_hook.ts +151 -5
  379. package/src/scripts/hooks/one_question_per_ask_hook.ts +43 -6
  380. package/src/scripts/hooks/orchestration_record_hook.ts +1 -2
  381. package/src/scripts/hooks/payload_stub.ts +10 -1
  382. package/src/scripts/hooks/permission_gate.ts +1 -2
  383. package/src/scripts/hooks/push_settle_hook.ts +1 -3
  384. package/src/scripts/hooks/replay_hook.ts +2 -1
  385. package/src/scripts/hooks/reread_guard_hook.ts +1 -2
  386. package/src/scripts/hooks/review_baseline_hook.ts +1 -2
  387. package/src/scripts/hooks/rtk_wrap_hook.ts +1 -2
  388. package/src/scripts/hooks/rule_inject_hook.ts +765 -68
  389. package/src/scripts/hooks/run_continuation_hook.ts +13 -15
  390. package/src/scripts/hooks/skill_route_hook.ts +1 -2
  391. package/src/scripts/hooks/source_first_gate_hook.ts +1 -2
  392. package/src/scripts/hooks/spawn_guard_shadow_hook.ts +1 -2
  393. package/src/scripts/hooks/subagent_ledger_hook.ts +1 -2
  394. package/src/scripts/hooks/suggestion_capture_hook.ts +1 -1
  395. package/src/scripts/hooks/table_fingerprint.ts +70 -0
  396. package/src/scripts/hooks/telemetry_flush_hook.ts +1 -2
  397. package/src/scripts/hooks/telemetry_usage_hook.ts +65 -10
  398. package/src/scripts/hooks/tool_result_bytes_hook.ts +93 -9
  399. package/src/scripts/hooks/turn_end_gate_hook.ts +421 -324
  400. package/src/scripts/hooks/ui_route_nudge_hook.ts +1 -2
  401. package/src/scripts/hooks_status.ts +112 -0
  402. package/src/scripts/injection_scan_hook.ts +7 -0
  403. package/src/scripts/install.ts +75 -189
  404. package/src/scripts/installed_layer_report.ts +103 -0
  405. package/src/scripts/language_mirror_hook.ts +15 -6
  406. package/src/scripts/learning_sidecar.ts +119 -8
  407. package/src/scripts/lint_deny_text.ts +419 -0
  408. package/src/scripts/lint_exit_codes.ts +262 -0
  409. package/src/scripts/lint_hook_manifest.ts +108 -0
  410. package/src/scripts/lint_major_migration_sections.ts +156 -26
  411. package/src/scripts/lint_pack_boundaries.ts +63 -5
  412. package/src/scripts/lint_roadmap_blockers.ts +78 -12
  413. package/src/scripts/lint_rule_law_section.ts +517 -0
  414. package/src/scripts/lint_skill_descriptions.ts +1 -1
  415. package/src/scripts/lint_skill_scripts_readonly.ts +1 -1
  416. package/src/scripts/lint_workflow_security.ts +161 -5
  417. package/src/scripts/mcp_server/consumer_tool_catalog.json +53 -0
  418. package/src/scripts/mcp_server/graph_tools.ts +72 -3
  419. package/src/scripts/mcp_server/prompts.ts +142 -1
  420. package/src/scripts/measure_routing_signal.ts +54 -16
  421. package/src/scripts/measure_skill_ranker_baseline.ts +515 -53
  422. package/src/scripts/measure_turn_end_gate.ts +193 -0
  423. package/src/scripts/memory_learn_hook.ts +91 -6
  424. package/src/scripts/memory_lookup.ts +1 -1
  425. package/src/scripts/model_rule_injection.ts +52 -5
  426. package/src/scripts/prepack-check.mjs +53 -0
  427. package/src/scripts/project_thin_rules.ts +34 -327
  428. package/src/scripts/release_publication.ts +13 -1
  429. package/src/scripts/report_evidence_temperature.ts +657 -0
  430. package/src/scripts/report_installed_rule_links.ts +157 -0
  431. package/src/scripts/report_invocation_surface.ts +383 -0
  432. package/src/scripts/report_label_agreement.ts +233 -0
  433. package/src/scripts/report_obligation_carriers.ts +699 -0
  434. package/src/scripts/report_obligation_mechanism.ts +230 -0
  435. package/src/scripts/report_obligation_writer_split.ts +236 -0
  436. package/src/scripts/report_single_token_triggers.ts +277 -0
  437. package/src/scripts/report_skill_menu_census.ts +208 -0
  438. package/src/scripts/report_skill_ranker_confusion.ts +442 -0
  439. package/src/scripts/report_standing_payload_by_host.ts +188 -15
  440. package/src/scripts/report_verification_record_coverage.ts +306 -0
  441. package/src/scripts/roadmap_verify_share.ts +213 -0
  442. package/src/scripts/rule_activation_census.ts +5 -2
  443. package/src/scripts/rule_trigger_eval.ts +9 -9
  444. package/src/scripts/schemas/command.schema.json +44 -0
  445. package/src/scripts/schemas/review-findings.schema.json +7 -2
  446. package/src/scripts/schemas/rule.schema.json +5 -0
  447. package/src/scripts/schemas/skill.schema.json +44 -0
  448. package/src/scripts/self_review_gate.ts +421 -17
  449. package/src/scripts/semantic_parity_census.ts +314 -0
  450. package/src/scripts/session_eol_report.ts +54 -1
  451. package/src/scripts/skill_tools/score_skill_relevance.ts +290 -25
  452. package/src/scripts/sweep_dead_scan_roots.ts +1 -1
  453. package/src/scripts/sweep_skill_ranker_signals.ts +129 -0
  454. package/src/scripts/sync_gitignore.ts +29 -235
  455. package/src/scripts/trigger_eval_grandfather.json +0 -7
  456. package/src/scripts/trigger_eval_rotation.ts +122 -27
  457. package/src/scripts/ui_conformance_probe.ts +156 -4
  458. package/src/scripts/update_prices.ts +85 -3
  459. package/src/scripts/write_bundle_digest.mjs +74 -0
  460. package/src/server/schemas/settings.ts +41 -0
  461. package/src/shared/skillRanking.ts +117 -11
  462. package/src/templates/consumer-settings/ONBOARDING.md +1 -0
  463. package/dist/cli-delegate/chunk-FXYUYU4N.js +0 -4416
  464. package/dist/cli-delegate/chunk-QJWAUMJW.js +0 -1072
  465. package/dist/cli-delegate/chunk-YDPILCOL.js +0 -152
  466. package/dist/ui/assets/index-DH1xc62v.js +0 -29
  467. package/dist/ui/assets/index-jSfMW8_t.css +0 -1
@@ -476,10 +476,81 @@ const HOOK_MANIFEST_TRIPLE: Triple = {
476
476
  },
477
477
  };
478
478
 
479
+ const HOST_LOWERING_YAML = 'src/scripts/hooks/host_lowering.yaml';
480
+ const HOST_LOWERING_JSON = 'src/scripts/hooks/host_lowering.json';
481
+
482
+ /**
483
+ * The second compiled plumbing table, and it is here for the reason the first
484
+ * one is: the fingerprint hashes the YAML TEXT, so a comment-only edit to
485
+ * `host_lowering.yaml` invalidates the committed JSON while every parsed field
486
+ * stays byte-identical. That file is mostly comments — 16.8 kB of source
487
+ * compiling to 5.9 kB of data — so the comment-only case is the LIKELY one
488
+ * here, not the corner case.
489
+ *
490
+ * A stale sibling is slow, never wrong: `loadHostLowering` falls through to the
491
+ * YAML source on a fingerprint mismatch. So what this row protects is the
492
+ * measured 9 ms per dispatch, which would otherwise be given back silently and
493
+ * would surface only as the hook-latency gate flapping again.
494
+ */
495
+ const HOST_LOWERING_TRIPLE: Triple = {
496
+ id: 'host-lowering-compiled',
497
+ output: HOST_LOWERING_JSON,
498
+ remedy: './scripts-run src/scripts/compile_hook_manifest --table host-lowering',
499
+ why:
500
+ 'the compiled lowering table carries a fingerprint hashed over the YAML TEXT, so even a ' +
501
+ 'comment-only edit to the source invalidates it — and no `task` target regenerates it',
502
+ sourcesOf() {
503
+ return { ok: true, sources: [{ kind: 'file', value: HOST_LOWERING_YAML }] };
504
+ },
505
+ regenerate(root, workDir) {
506
+ const outFile = path.join(workDir, 'host_lowering.json');
507
+ const tsx = path.join(
508
+ root,
509
+ 'node_modules',
510
+ '.bin',
511
+ process.platform === 'win32' ? 'tsx.cmd' : 'tsx',
512
+ );
513
+ if (!fs.existsSync(tsx)) {
514
+ return {
515
+ ok: false,
516
+ reason: `no tsx at ${path.relative(root, tsx)} — run \`npm ci\` before this gate`,
517
+ };
518
+ }
519
+ const res = spawnSync(
520
+ tsx,
521
+ [
522
+ path.join(root, 'src', 'scripts', 'compile_hook_manifest.ts'),
523
+ '--table',
524
+ 'host-lowering',
525
+ '--out',
526
+ outFile,
527
+ ],
528
+ { cwd: root, encoding: 'utf8', maxBuffer: 64 * 1024 * 1024 },
529
+ );
530
+ if (res.status !== 0) {
531
+ return {
532
+ ok: false,
533
+ reason:
534
+ `compile_hook_manifest --table host-lowering exited ${String(res.status)}: ` +
535
+ `${(res.stderr ?? '').trim()}`,
536
+ };
537
+ }
538
+ try {
539
+ return { ok: true, text: fs.readFileSync(outFile, 'utf8') };
540
+ } catch (e) {
541
+ return {
542
+ ok: false,
543
+ reason: `compile_hook_manifest reported success but wrote no readable file (${String(e)})`,
544
+ };
545
+ }
546
+ },
547
+ };
548
+
479
549
  export const REGISTRY: readonly Triple[] = [
480
550
  CENSUS_TRIPLE,
481
551
  INSTALL_BUNDLE_TRIPLE,
482
552
  HOOK_MANIFEST_TRIPLE,
553
+ HOST_LOWERING_TRIPLE,
483
554
  ];
484
555
 
485
556
  // ---------------------------------------------------------------------------
@@ -0,0 +1,370 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * Composition gate for the self-hosted hook bundle: ONE YAML reader, and a
4
+ * byte ceiling.
5
+ *
6
+ * WHY THIS EXISTS — measured, not hypothetical.
7
+ *
8
+ * Every concern is inlined into one `dist/hooks/dispatch.js` that every hook
9
+ * event loads, so a dependency added for ONE concern is paid by all of them on
10
+ * every dispatch. On 2026-10-01 the bundle carried two YAML parsers: `yaml`,
11
+ * pulled by six modules including the dispatcher itself, and `js-yaml`, pulled
12
+ * by one call site in `block_config_weakening.ts` — 95,846 bytes, 6.13 % of a
13
+ * 1,564,211-byte bundle. Beside it, `host_lowering.ts`'s own header said the
14
+ * `yaml` reader was "the ONLY remaining YAML reader on that path".
15
+ *
16
+ * Nothing in this tree could see either fact. The freshness gate compares
17
+ * mtimes, the content gate compares digests, and neither has an opinion about
18
+ * what is INSIDE the bundle. So the second parser reached a release and was
19
+ * found by an external rescore counting bytes — a review finding where it
20
+ * should have been a red check. This gate is that red check.
21
+ *
22
+ * WHAT IT CHECKS
23
+ *
24
+ * 1. At most `max_yaml_packages` YAML packages contribute bytes to the
25
+ * bundle. The package set is {@link YAML_PACKAGES} — a closed list, so a
26
+ * third parser arriving under a name nobody listed is NOT caught here, and
27
+ * that limit is stated rather than implied.
28
+ * 2. The bundle's byte count is at or under `max_bytes`.
29
+ *
30
+ * Both bounds live in `src/config/hook-bundle-budget.json`, never in this file:
31
+ * a number a reviewer has to read a script to find is a number nobody reviews.
32
+ *
33
+ * WHY IT BUILDS RATHER THAN READS. `dist/hooks/` is untracked, so a gate that
34
+ * read the bundle on disk would be local-only like `check_hook_bundle_content`
35
+ * — and the thing being bounded is what the SOURCE produces, which is a
36
+ * property of the commit rather than of a machine. So this builds its own
37
+ * bundle with `--metafile` and measures that. It runs identically in CI and
38
+ * locally, and it never touches the live bundle.
39
+ *
40
+ * The esbuild invocation is NOT duplicated here: it is read from
41
+ * `package.json`'s `build:hooks` script with only `--outfile=` rewritten, via
42
+ * the same `rewriteOutfile` helper `rebuild_hook_bundle` and
43
+ * `check_hook_bundle_content` use, so the flag set has exactly one home. The
44
+ * trailing `&& node src/scripts/write_bundle_digest.mjs` is stripped — this
45
+ * gate must not write a sidecar for a probe bundle nobody executes.
46
+ *
47
+ * WHAT IT DOES NOT DO. It says nothing about LATENCY. A smaller bundle is not
48
+ * a measured speed-up; `src/config/hook-latency-budget.json` owns that axis and
49
+ * no number here is derived from it. It says nothing about the install or MCP
50
+ * bundles, which carry their own module graphs.
51
+ *
52
+ * Usage:
53
+ * ./scripts-run src/scripts/check_hook_bundle_composition
54
+ * ./scripts-run src/scripts/check_hook_bundle_composition --metafile <path>
55
+ * ./scripts-run src/scripts/check_hook_bundle_composition --self-test
56
+ *
57
+ * Exit codes: 0 = within budget · 1 = over the ceiling or a second reader ·
58
+ * 2 = the build or the budget file failed.
59
+ */
60
+ // ledger-exempt: single-artefact transaction — one bundle build yielding one
61
+ // aggregate verdict. The per-source accounting lives in
62
+ // check_hook_bundle_freshness, which carries the ledger.
63
+ import { spawnSync } from 'node:child_process';
64
+ import * as fs from 'node:fs';
65
+ import * as os from 'node:os';
66
+ import * as path from 'node:path';
67
+ import { fileURLToPath, pathToFileURL } from 'node:url';
68
+
69
+ import { runGateCli, runSelfTest } from './_lib/gate_self_test.js';
70
+ import { reportScanned } from './_lib/scan_scope.js';
71
+ import { buildScript } from './check_hook_bundle_content.js';
72
+ import { rewriteOutfile } from './rebuild_hook_bundle.js';
73
+
74
+ const _HERE = path.dirname(fileURLToPath(import.meta.url));
75
+ export const REPO_ROOT = path.resolve(_HERE, '..', '..');
76
+ export const SELF_REL = path.join('src', 'scripts', 'check_hook_bundle_composition.ts');
77
+ export const BUDGET_REL = path.join('src', 'config', 'hook-bundle-budget.json');
78
+ const LIVE_REL = path.join('dist', 'hooks', 'dispatch.js');
79
+
80
+ /**
81
+ * The YAML readers this tree has ever carried, by package name.
82
+ *
83
+ * A CLOSED LIST, and the consequence is worth stating: a fourth parser arriving
84
+ * under a name not listed here contributes bytes the ceiling catches and the
85
+ * parser cap does not. The alternative — treating any package whose name
86
+ * contains "yaml" as a reader — would match a YAML-adjacent utility that is not
87
+ * a parser, and a cap that fires on the wrong package is worse than one that
88
+ * misses an unlisted one, because the first teaches people to raise the cap.
89
+ */
90
+ export const YAML_PACKAGES: readonly string[] = ['yaml', 'js-yaml', 'yaml-js', 'yamljs'];
91
+
92
+ export interface Budget {
93
+ readonly maxBytes: number;
94
+ readonly maxYamlPackages: number;
95
+ }
96
+
97
+ export interface Analysis {
98
+ /** Bytes of the bundle esbuild produced. */
99
+ readonly bytes: number;
100
+ /** Modules that contributed to it — the unit `scanned:` reports. */
101
+ readonly modules: number;
102
+ /** Bytes in the output, summed per owning npm package. */
103
+ readonly packageBytes: ReadonlyMap<string, number>;
104
+ /** Listed YAML packages contributing more than zero bytes, sorted. */
105
+ readonly yamlPackages: readonly string[];
106
+ }
107
+
108
+ /**
109
+ * The npm package a bundled module path belongs to, or `null` for this tree's
110
+ * own sources.
111
+ *
112
+ * Reads the INNERMOST `node_modules/` segment: a transitively nested copy
113
+ * (`node_modules/a/node_modules/yaml/…`) is still `yaml`'s bytes, and
114
+ * attributing it to `a` would let a second parser hide one level down.
115
+ */
116
+ export function owningPackage(modulePath: string): string | null {
117
+ const marker = 'node_modules/';
118
+ const at = modulePath.lastIndexOf(marker);
119
+ if (at < 0) return null;
120
+ const parts = modulePath.slice(at + marker.length).split('/');
121
+ const head = parts[0] ?? '';
122
+ if (head === '') return null;
123
+ return head.startsWith('@') ? `${head}/${parts[1] ?? ''}` : head;
124
+ }
125
+
126
+ /** Parse an esbuild metafile and attribute its one entry-point output. */
127
+ export function analyzeMetafile(json: string): Analysis {
128
+ const meta = JSON.parse(json) as {
129
+ outputs?: Record<string, { entryPoint?: string; bytes?: number; inputs?: Record<string, { bytesInOutput?: number }> }>;
130
+ };
131
+ const outputs = Object.values(meta.outputs ?? {});
132
+ const out = outputs.find((o) => typeof o.entryPoint === 'string');
133
+ if (out === undefined) {
134
+ throw new Error(
135
+ 'metafile carries no entry-point output — refusing to report a composition for a build that produced nothing',
136
+ );
137
+ }
138
+ const packageBytes = new Map<string, number>();
139
+ const inputs = out.inputs ?? {};
140
+ for (const [p, v] of Object.entries(inputs)) {
141
+ const pkg = owningPackage(p);
142
+ if (pkg === null) continue;
143
+ packageBytes.set(pkg, (packageBytes.get(pkg) ?? 0) + (v.bytesInOutput ?? 0));
144
+ }
145
+ const yamlPackages = YAML_PACKAGES.filter((p) => (packageBytes.get(p) ?? 0) > 0).sort();
146
+ return {
147
+ bytes: out.bytes ?? 0,
148
+ modules: Object.keys(inputs).length,
149
+ packageBytes,
150
+ yamlPackages,
151
+ };
152
+ }
153
+
154
+ /** Read the committed budget. Throws rather than defaulting — a guessed ceiling bounds nothing. */
155
+ export function readBudget(root: string): Budget {
156
+ const abs = path.join(root, BUDGET_REL);
157
+ const raw = JSON.parse(fs.readFileSync(abs, 'utf-8')) as Record<string, unknown>;
158
+ const maxBytes = raw['max_bytes'];
159
+ const maxYaml = raw['max_yaml_packages'];
160
+ if (typeof maxBytes !== 'number' || !Number.isInteger(maxBytes) || maxBytes <= 0) {
161
+ throw new Error(`${BUDGET_REL}: max_bytes must be a positive integer, got ${JSON.stringify(maxBytes)}`);
162
+ }
163
+ if (typeof maxYaml !== 'number' || !Number.isInteger(maxYaml) || maxYaml < 1) {
164
+ throw new Error(
165
+ `${BUDGET_REL}: max_yaml_packages must be an integer >= 1, got ${JSON.stringify(maxYaml)}`,
166
+ );
167
+ }
168
+ return { maxBytes, maxYamlPackages: maxYaml };
169
+ }
170
+
171
+ /** Findings, one line each. Empty means within budget. */
172
+ export function verdict(a: Analysis, budget: Budget): string[] {
173
+ const findings: string[] = [];
174
+ if (a.yamlPackages.length > budget.maxYamlPackages) {
175
+ const detail = a.yamlPackages
176
+ .map((p) => `${p} (${String(a.packageBytes.get(p) ?? 0)} B)`)
177
+ .join(', ');
178
+ findings.push(
179
+ `${String(a.yamlPackages.length)} YAML readers in the bundle, cap is ` +
180
+ `${String(budget.maxYamlPackages)}: ${detail}. Every dispatch loads all of them. ` +
181
+ 'Move the odd caller onto the reader the dispatcher already uses.',
182
+ );
183
+ }
184
+ if (a.bytes > budget.maxBytes) {
185
+ findings.push(
186
+ `bundle is ${String(a.bytes)} bytes, ceiling is ${String(budget.maxBytes)} ` +
187
+ `(over by ${String(a.bytes - budget.maxBytes)}). Shrink the bundle, or raise ` +
188
+ `max_bytes in ${BUDGET_REL} WITH an entry in its raise_log naming what was added.`,
189
+ );
190
+ }
191
+ return findings;
192
+ }
193
+
194
+ /**
195
+ * Build the hook bundle to a throwaway path and return its metafile JSON.
196
+ *
197
+ * Throws on any failure rather than returning a sentinel: a composition read off
198
+ * a build that did not happen is the silent-green this gate exists to replace.
199
+ */
200
+ export function buildMetafile(root: string): string {
201
+ const script = buildScript(root);
202
+ if (script === null) {
203
+ throw new Error('package.json has no `build:hooks` script — refusing to guess the flag set');
204
+ }
205
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'hook-bundle-composition-'));
206
+ const outFile = path.join(dir, 'dispatch.js');
207
+ const metaFile = path.join(dir, 'meta.json');
208
+ try {
209
+ const rewritten = rewriteOutfile(script, outFile);
210
+ if (rewritten === null) {
211
+ throw new Error(`\`build:hooks\` no longer writes ${LIVE_REL} — refusing to build to a guessed path`);
212
+ }
213
+ // Strip the digest sidecar step: it would write `dispatch.sha256` beside
214
+ // a probe bundle nobody executes, and on failure it would mask the build
215
+ // error with a file-not-found.
216
+ const esbuildOnly = rewritten.split('&& node ')[0] ?? rewritten;
217
+ const built = spawnSync('sh', ['-c', `${esbuildOnly.trim()} --metafile=${metaFile}`], {
218
+ cwd: root,
219
+ encoding: 'utf-8',
220
+ maxBuffer: 64 * 1024 * 1024,
221
+ env: {
222
+ ...process.env,
223
+ PATH: `${path.join(root, 'node_modules', '.bin')}:${process.env['PATH'] ?? ''}`,
224
+ },
225
+ });
226
+ if (built.status !== 0 || !fs.existsSync(metaFile)) {
227
+ throw new Error(`esbuild failed (exit ${String(built.status)})\n${built.stderr ?? ''}`);
228
+ }
229
+ return fs.readFileSync(metaFile, 'utf-8');
230
+ } finally {
231
+ fs.rmSync(dir, { recursive: true, force: true });
232
+ }
233
+ }
234
+
235
+ function selfTest(): number {
236
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'hook-bundle-composition-selftest-'));
237
+ const write = (name: string, body: unknown): string => {
238
+ const p = path.join(dir, name);
239
+ fs.writeFileSync(p, JSON.stringify(body));
240
+ return p;
241
+ };
242
+ const meta = (bytes: number, inputs: Record<string, number>): unknown => ({
243
+ inputs: {},
244
+ outputs: {
245
+ 'dist/hooks/dispatch.js': {
246
+ entryPoint: 'src/scripts/hooks/dispatch_entry.ts',
247
+ bytes,
248
+ inputs: Object.fromEntries(
249
+ Object.entries(inputs).map(([k, v]) => [k, { bytesInOutput: v }]),
250
+ ),
251
+ },
252
+ },
253
+ });
254
+ const budget = readBudget(REPO_ROOT);
255
+ const clean = write('clean.json', meta(budget.maxBytes, { 'node_modules/yaml/dist/index.js': 10 }));
256
+ const twoReaders = write(
257
+ 'two-readers.json',
258
+ meta(1000, {
259
+ 'node_modules/yaml/dist/index.js': 600,
260
+ 'node_modules/js-yaml/dist/js-yaml.mjs': 400,
261
+ }),
262
+ );
263
+ const oneOver = write('one-over.json', meta(budget.maxBytes + 1, { 'src/x.ts': 1 }));
264
+ const empty = write('empty.json', { inputs: {}, outputs: {} });
265
+
266
+ const drive = (fixture: string): number =>
267
+ runGateCli(REPO_ROOT, SELF_REL, ['--metafile', fixture], REPO_ROOT);
268
+
269
+ try {
270
+ return runSelfTest({
271
+ gate: 'check_hook_bundle_composition',
272
+ minCases: 4,
273
+ minRejectCases: 3,
274
+ cases: [
275
+ {
276
+ name: 'one YAML reader, exactly at the ceiling → accepted',
277
+ expect: 'accept',
278
+ run: () => drive(clean),
279
+ },
280
+ {
281
+ name: 'a second YAML reader → rejected',
282
+ expect: 'reject',
283
+ run: () => drive(twoReaders),
284
+ },
285
+ {
286
+ name: 'one byte over the ceiling → rejected',
287
+ expect: 'reject',
288
+ run: () => drive(oneOver),
289
+ },
290
+ {
291
+ name: 'a metafile with no entry-point output → rejected, never reported as 0 bytes',
292
+ expect: 'reject',
293
+ run: () => drive(empty),
294
+ },
295
+ ],
296
+ });
297
+ } finally {
298
+ fs.rmSync(dir, { recursive: true, force: true });
299
+ }
300
+ }
301
+
302
+ export function main(argv: readonly string[] = process.argv.slice(2), root: string = REPO_ROOT): number {
303
+ if (argv.includes('--self-test')) {
304
+ return selfTest();
305
+ }
306
+ const at = argv.indexOf('--metafile');
307
+ const fixture = at >= 0 ? argv[at + 1] : undefined;
308
+
309
+ let budget: Budget;
310
+ try {
311
+ budget = readBudget(root);
312
+ } catch (e) {
313
+ process.stderr.write(`check_hook_bundle_composition: ${String(e instanceof Error ? e.message : e)}\n`);
314
+ return 2;
315
+ }
316
+
317
+ let json: string;
318
+ try {
319
+ json = fixture === undefined ? buildMetafile(root) : fs.readFileSync(fixture, 'utf-8');
320
+ } catch (e) {
321
+ process.stderr.write(`check_hook_bundle_composition: ${String(e instanceof Error ? e.message : e)}\n`);
322
+ return 2;
323
+ }
324
+
325
+ let analysis: Analysis;
326
+ try {
327
+ analysis = analyzeMetafile(json);
328
+ } catch (e) {
329
+ process.stderr.write(`check_hook_bundle_composition: ${String(e instanceof Error ? e.message : e)}\n`);
330
+ return 1;
331
+ }
332
+
333
+ const findings = verdict(analysis, budget);
334
+ // Reported on BOTH paths, red included: a census that goes quiet exactly
335
+ // when the gate fires is the shape `reportScanned` exists to prevent.
336
+ reportScanned({
337
+ gate: 'check_hook_bundle_composition',
338
+ scanned: analysis.modules,
339
+ units: 'bundled module(s)',
340
+ roots: [LIVE_REL],
341
+ });
342
+
343
+ if (findings.length === 0) {
344
+ process.stdout.write(
345
+ `✅ hook bundle: ${String(analysis.bytes)} B / ${String(budget.maxBytes)} B ceiling, ` +
346
+ `${String(analysis.yamlPackages.length)} YAML reader(s) ` +
347
+ `[${analysis.yamlPackages.join(', ')}], ${String(analysis.modules)} modules\n`,
348
+ );
349
+ return 0;
350
+ }
351
+ process.stderr.write('❌ hook bundle composition is out of budget\n');
352
+ for (const f of findings) process.stderr.write(` - ${f}\n`);
353
+ process.stderr.write(` Budget: ${BUDGET_REL}\n`);
354
+ return 1;
355
+ }
356
+
357
+ function _isCliEntry(): boolean {
358
+ const argv1 = process.argv[1];
359
+ if (argv1 === undefined) return false;
360
+ if (import.meta.url === pathToFileURL(path.resolve(argv1)).href) return true;
361
+ try {
362
+ return fs.realpathSync(fileURLToPath(import.meta.url)) === fs.realpathSync(path.resolve(argv1));
363
+ } catch {
364
+ return false;
365
+ }
366
+ }
367
+
368
+ if (_isCliEntry()) {
369
+ process.exit(main());
370
+ }