@event4u/agent-config 14.10.0 → 14.11.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 (399) 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 +335 -0
  5. package/README.md +1 -1
  6. package/dist/agent-src/commands/design.md +88 -0
  7. package/dist/agent-src/commands/project/analyze.md +47 -0
  8. package/dist/agent-src/commands/review/changes.md +67 -6
  9. package/dist/agent-src/commands/roadmap/create.md +49 -0
  10. package/dist/agent-src/commands/roadmap/next.md +27 -11
  11. package/dist/agent-src/commands/roadmap/process-full.md +14 -0
  12. package/dist/agent-src/commands/video/from-script.md +60 -3
  13. package/dist/agent-src/commands/video/stitch.md +14 -0
  14. package/dist/agent-src/contexts/communication/rules-auto/guidelines-mechanics.md +1 -0
  15. package/dist/agent-src/contexts/execution/roadmap-process-loop.md +154 -2
  16. package/dist/agent-src/rules/active-remediation.md +3 -3
  17. package/dist/agent-src/rules/code-provenance.md +2 -2
  18. package/dist/agent-src/rules/context-hygiene.md +13 -33
  19. package/dist/agent-src/rules/council-availability.md +2 -2
  20. package/dist/agent-src/rules/decision-revisit-gate.md +3 -1
  21. package/dist/agent-src/rules/design-fidelity.md +18 -0
  22. package/dist/agent-src/rules/design-review-after-ui-write.md +2 -2
  23. package/dist/agent-src/rules/evaluator-independence.md +56 -44
  24. package/dist/agent-src/rules/fix-what-you-see.md +9 -1
  25. package/dist/agent-src/rules/framework-neutrality-in-generic-skills.md +1 -1
  26. package/dist/agent-src/rules/minimal-safe-diff.md +14 -20
  27. package/dist/agent-src/rules/missing-skill-recovery.md +13 -1
  28. package/dist/agent-src/rules/playbook-precedence.md +105 -0
  29. package/dist/agent-src/rules/recurring-criticism.md +3 -1
  30. package/dist/agent-src/rules/roadmap-progress-sync.md +14 -13
  31. package/dist/agent-src/rules/scale-discipline.md +24 -0
  32. package/dist/agent-src/rules/security-sensitive-stop.md +2 -2
  33. package/dist/agent-src/rules/settings-ask-protocol.md +2 -2
  34. package/dist/agent-src/rules/ui-audit-gate.md +27 -15
  35. package/dist/agent-src/rules/untrusted-input-defense.md +2 -2
  36. package/dist/agent-src/skills/accessibility-auditor/SKILL.md +19 -0
  37. package/dist/agent-src/skills/adr-create/SKILL.md +7 -0
  38. package/dist/agent-src/skills/agents-md-thin-root/SKILL.md +33 -0
  39. package/dist/agent-src/skills/ai-council/references/advanced-modes.md +17 -3
  40. package/dist/agent-src/skills/ai-council/references/output-and-synthesis.md +31 -0
  41. package/dist/agent-src/skills/ai-council/references/procedure.md +19 -0
  42. package/dist/agent-src/skills/alerting-doctrine/SKILL.md +225 -0
  43. package/dist/agent-src/skills/alerting-doctrine/evals/triggers.json +17 -0
  44. package/dist/agent-src/skills/authz-review/SKILL.md +0 -1
  45. package/dist/agent-src/skills/blast-radius-analyzer/SKILL.md +32 -0
  46. package/dist/agent-src/skills/brand/SKILL.md +3 -0
  47. package/dist/agent-src/skills/brand-asset-generation/SKILL.md +3 -0
  48. package/dist/agent-src/skills/brand-audit/SKILL.md +3 -0
  49. package/dist/agent-src/skills/brand-identity/SKILL.md +3 -0
  50. package/dist/agent-src/skills/brand-strategy/SKILL.md +3 -0
  51. package/dist/agent-src/skills/brand-to-tokens/SKILL.md +3 -0
  52. package/dist/agent-src/skills/check-refs/SKILL.md +3 -0
  53. package/dist/agent-src/skills/code-review/SKILL.md +11 -0
  54. package/dist/agent-src/skills/command-routing/SKILL.md +6 -0
  55. package/dist/agent-src/skills/condense-memory/SKILL.md +3 -0
  56. package/dist/agent-src/skills/context-authoring/SKILL.md +1 -1
  57. package/dist/agent-src/skills/conventional-commits-writing/SKILL.md +3 -0
  58. package/dist/agent-src/skills/copilot-agents-optimization/SKILL.md +10 -0
  59. package/dist/agent-src/skills/corpus-grounding/SKILL.md +3 -0
  60. package/dist/agent-src/skills/design-intelligence/SKILL.md +3 -0
  61. package/dist/agent-src/skills/design-intelligence/data/landing.csv +36 -35
  62. package/dist/agent-src/skills/design-intelligence/data/stacks/threejs.csv +1 -0
  63. package/dist/agent-src/skills/design-review/SKILL.md +79 -1
  64. package/dist/agent-src/skills/design-review/references/verification-automation.md +41 -0
  65. package/dist/agent-src/skills/design-system-capture/SKILL.md +35 -40
  66. package/dist/agent-src/skills/design-system-capture/references/import-procedure.md +50 -0
  67. package/dist/agent-src/skills/design-tokens/SKILL.md +3 -0
  68. package/dist/agent-src/skills/design-variations/SKILL.md +3 -0
  69. package/dist/agent-src/skills/developer-like-execution/SKILL.md +3 -0
  70. package/dist/agent-src/skills/estimate-ticket/SKILL.md +3 -0
  71. package/dist/agent-src/skills/existing-ui-audit/SKILL.md +20 -3
  72. package/dist/agent-src/skills/fe-design/SKILL.md +74 -41
  73. package/dist/agent-src/skills/fe-design/evals/triggers.json +65 -53
  74. package/dist/agent-src/skills/fe-design/references/craft-floor.md +52 -0
  75. package/dist/agent-src/skills/fe-design/references/source-led-port.md +36 -0
  76. package/dist/agent-src/skills/file-editor/SKILL.md +5 -0
  77. package/dist/agent-src/skills/finishing-a-development-branch/SKILL.md +2 -2
  78. package/dist/agent-src/skills/git-workflow/SKILL.md +3 -0
  79. package/dist/agent-src/skills/html-deck/SKILL.md +3 -0
  80. package/dist/agent-src/skills/iconography/SKILL.md +3 -0
  81. package/dist/agent-src/skills/image-editing/SKILL.md +3 -0
  82. package/dist/agent-src/skills/image-generation/SKILL.md +3 -0
  83. package/dist/agent-src/skills/image-provider-routing/SKILL.md +3 -0
  84. package/dist/agent-src/skills/incident-commander/SKILL.md +10 -0
  85. package/dist/agent-src/skills/js-library-packaging/SKILL.md +173 -0
  86. package/dist/agent-src/skills/js-library-packaging/evals/triggers.json +17 -0
  87. package/dist/agent-src/skills/js-library-packaging/scripts/check_package_surface.ts +270 -0
  88. package/dist/agent-src/skills/laravel-migration/SKILL.md +3 -0
  89. package/dist/agent-src/skills/learning-to-rule-or-skill/SKILL.md +3 -0
  90. package/dist/agent-src/skills/lint-skills/SKILL.md +3 -0
  91. package/dist/agent-src/skills/llm-provider-knowledge/SKILL.md +3 -0
  92. package/dist/agent-src/skills/logging-monitoring/SKILL.md +234 -51
  93. package/dist/agent-src/skills/logo-generation/SKILL.md +3 -0
  94. package/dist/agent-src/skills/md-language-check/SKILL.md +3 -0
  95. package/dist/agent-src/skills/monorepo-workspace/SKILL.md +149 -0
  96. package/dist/agent-src/skills/monorepo-workspace/evals/triggers.json +17 -0
  97. package/dist/agent-src/skills/motion-choreographer/SKILL.md +6 -0
  98. package/dist/agent-src/skills/multi-tenancy/SKILL.md +4 -0
  99. package/dist/agent-src/skills/operational-readiness/SKILL.md +184 -0
  100. package/dist/agent-src/skills/operational-readiness/evals/triggers.json +17 -0
  101. package/dist/agent-src/skills/override-management/SKILL.md +3 -0
  102. package/dist/agent-src/skills/persona-improvement/SKILL.md +3 -0
  103. package/dist/agent-src/skills/pest-testing/SKILL.md +3 -0
  104. package/dist/agent-src/skills/playbook-authoring/SKILL.md +162 -0
  105. package/dist/agent-src/skills/playwright-testing/SKILL.md +3 -0
  106. package/dist/agent-src/skills/privacy-review/SKILL.md +3 -0
  107. package/dist/agent-src/skills/prompt-engineering-image/SKILL.md +3 -0
  108. package/dist/agent-src/skills/quality-tools/SKILL.md +5 -0
  109. package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +52 -21
  110. package/dist/agent-src/skills/readme-reviewer/SKILL.md +3 -0
  111. package/dist/agent-src/skills/readme-writing/SKILL.md +3 -0
  112. package/dist/agent-src/skills/readme-writing-package/SKILL.md +3 -0
  113. package/dist/agent-src/skills/receiving-code-review/SKILL.md +2 -2
  114. package/dist/agent-src/skills/refine-prompt/SKILL.md +3 -0
  115. package/dist/agent-src/skills/refine-ticket/SKILL.md +3 -0
  116. package/dist/agent-src/skills/requesting-code-review/SKILL.md +2 -2
  117. package/dist/agent-src/skills/review-routing/SKILL.md +2 -2
  118. package/dist/agent-src/skills/roadmap-writing/SKILL.md +23 -41
  119. package/dist/agent-src/skills/roadmap-writing/references/follow-up-roadmap-shape.md +47 -0
  120. package/dist/agent-src/skills/rtk-output-filtering/SKILL.md +22 -6
  121. package/dist/agent-src/skills/runway-cognition/SKILL.md +3 -0
  122. package/dist/agent-src/skills/scene-expander/scene-blueprint.schema.yaml +26 -0
  123. package/dist/agent-src/skills/secrets-management/SKILL.md +4 -0
  124. package/dist/agent-src/skills/server-hardening/SKILL.md +159 -0
  125. package/dist/agent-src/skills/server-hardening/evals/triggers.json +17 -0
  126. package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +3 -0
  127. package/dist/agent-src/skills/skill-management/SKILL.md +3 -0
  128. package/dist/agent-src/skills/skill-reviewer/SKILL.md +3 -0
  129. package/dist/agent-src/skills/skill-writing/SKILL.md +6 -0
  130. package/dist/agent-src/skills/spreadsheet-authoring/SKILL.md +3 -0
  131. package/dist/agent-src/skills/storybook-workshop/SKILL.md +194 -0
  132. package/dist/agent-src/skills/storybook-workshop/evals/triggers.json +17 -0
  133. package/dist/agent-src/skills/storybook-workshop/scripts/story_contrast_floor.ts +134 -0
  134. package/dist/agent-src/skills/subagent-orchestration/SKILL.md +1 -1
  135. package/dist/agent-src/skills/subagent-orchestration/prompts/README.md +25 -0
  136. package/dist/agent-src/skills/supply-chain-intake/SKILL.md +12 -0
  137. package/dist/agent-src/skills/systematic-debugging/SKILL.md +1 -1
  138. package/dist/agent-src/skills/terraform/SKILL.md +3 -0
  139. package/dist/agent-src/skills/test-driven-development/SKILL.md +1 -1
  140. package/dist/agent-src/skills/threat-modeling/SKILL.md +0 -3
  141. package/dist/agent-src/skills/token-optimizer/SKILL.md +3 -0
  142. package/dist/agent-src/skills/typography-system/SKILL.md +3 -0
  143. package/dist/agent-src/skills/ui-component-architect/SKILL.md +9 -1
  144. package/dist/agent-src/skills/upstream-contribute/SKILL.md +3 -0
  145. package/dist/agent-src/skills/validate-feature-fit/SKILL.md +3 -0
  146. package/dist/agent-src/skills/verify-completion-evidence/SKILL.md +2 -2
  147. package/dist/agent-src/skills/wireframe/SKILL.md +3 -0
  148. package/dist/agent-src/skills/wireframe/references/story-beat-ledger.schema.json +115 -0
  149. package/dist/agent-src/skills/workspace-link/SKILL.md +131 -0
  150. package/dist/agent-src/skills/workspace-link/evals/triggers.json +17 -0
  151. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  152. package/dist/agent-src/templates/playbook.md +75 -0
  153. package/dist/agent-src/templates/roadmaps.md +37 -0
  154. package/dist/agent-src/templates/scripts/check_playbook_invokes.ts +231 -0
  155. package/dist/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +24 -0
  156. package/dist/agent-src/templates/scripts/work_engine/directives/ui/polish.ts +2 -0
  157. package/dist/agent-src/templates/scripts/work_engine/directives/ui/review.ts +216 -0
  158. package/dist/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +159 -0
  159. package/dist/agent-src/templates/scripts/work_engine/directives/ui/stack_bundles.ts +73 -4
  160. package/dist/agent-src/templates/scripts/work_engine/stack/detect.ts +325 -40
  161. package/dist/cli/commands/uiAudit.js +221 -0
  162. package/dist/cli/commands/uiAudit.js.map +1 -0
  163. package/dist/cli/commands/uiRender.js +206 -0
  164. package/dist/cli/commands/uiRender.js.map +1 -0
  165. package/dist/cli/main.js +22 -1
  166. package/dist/cli/main.js.map +1 -1
  167. package/dist/cli/mcp/content.js +64 -1
  168. package/dist/cli/mcp/content.js.map +1 -1
  169. package/dist/cli/mcp/dispatch.js +175 -10
  170. package/dist/cli/mcp/dispatch.js.map +1 -1
  171. package/dist/cli/registry.js +3 -0
  172. package/dist/cli/registry.js.map +1 -1
  173. package/dist/cli-delegate/{chunk-H4VIVD4C.js → chunk-236PNQZK.js} +413 -391
  174. package/dist/cli-delegate/{chunk-G23AT6GD.js → chunk-DMSZHXZS.js} +57 -1
  175. package/dist/cli-delegate/{chunk-77GR3VD4.js → chunk-FF7WAFMR.js} +58 -3
  176. package/dist/cli-delegate/{chunk-PLSG6UL5.js → chunk-K4FFODTS.js} +341 -204
  177. package/dist/cli-delegate/{chunk-YM4GZDJG.js → chunk-L43NCYPB.js} +5 -0
  178. package/dist/cli-delegate/{chunk-B2ERU2VA.js → chunk-WOKWX5PL.js} +1 -1
  179. package/dist/cli-delegate/cmd_brand_status.js +8 -6
  180. package/dist/cli-delegate/cmd_conformance.js +3 -3
  181. package/dist/cli-delegate/cmd_doctor.js +3 -3
  182. package/dist/cli-delegate/cmd_export.js +4 -4
  183. package/dist/cli-delegate/cmd_handoff.js +1 -1
  184. package/dist/cli-delegate/cmd_preflight.js +2 -2
  185. package/dist/cli-delegate/cmd_prune.js +4 -4
  186. package/dist/cli-delegate/cmd_session_recycle.js +70 -9
  187. package/dist/cli-delegate/cmd_settings_migrate.js +4 -4
  188. package/dist/cli-delegate/cmd_settings_set.js +1 -1
  189. package/dist/cli-delegate/cmd_sync.js +4 -4
  190. package/dist/cli-delegate/cmd_uninstall.js +4 -4
  191. package/dist/cli-delegate/cmd_validate.js +4 -4
  192. package/dist/discovery/deprecation-report.md +1 -1
  193. package/dist/discovery/discovery-manifest.json +359 -124
  194. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  195. package/dist/discovery/discovery-manifest.summary.md +4 -4
  196. package/dist/discovery/dormancy-report.md +1 -1
  197. package/dist/discovery/orphan-report.md +1 -1
  198. package/dist/discovery/packs.json +18 -8
  199. package/dist/discovery/trust-report.md +3 -3
  200. package/dist/discovery/workspaces.json +16 -6
  201. package/dist/hooks/dispatch.js +2337 -1436
  202. package/dist/install/install.mjs +795 -708
  203. package/dist/mcp/registry-manifest.json +3 -3
  204. package/dist/mcp/server.json +2 -2
  205. package/dist/mcp/server.mjs +1685 -1250
  206. package/dist/router.json +1 -1
  207. package/dist/scripts/_lib/lean_projection_mode.js +40 -0
  208. package/dist/scripts/_lib/lean_projection_mode.js.map +1 -0
  209. package/dist/scripts/_lib/scoped_projection.js +84 -0
  210. package/dist/scripts/_lib/scoped_projection.js.map +1 -1
  211. package/dist/scripts/_lib/ui_surface.js +89 -0
  212. package/dist/scripts/_lib/ui_surface.js.map +1 -0
  213. package/dist/scripts/condense.js +6 -10
  214. package/dist/scripts/condense.js.map +1 -1
  215. package/dist/scripts/project_thin_rules.js +40 -2
  216. package/dist/scripts/project_thin_rules.js.map +1 -1
  217. package/dist/server/schemas/settings.js +3 -0
  218. package/dist/server/schemas/settings.js.map +1 -1
  219. package/dist/shared/skillRanking.js +159 -0
  220. package/dist/shared/skillRanking.js.map +1 -0
  221. package/docs/contracts/provider-lifecycle.md +47 -18
  222. package/docs/contracts/settings-classes.md +14 -4
  223. package/docs/guidelines/agent-infra/context-hygiene-mechanics.md +49 -0
  224. package/docs/guidelines/agent-infra/evaluator-independence-mechanics.md +92 -0
  225. package/docs/guidelines/agent-infra/minimal-safe-diff-mechanics.md +45 -1
  226. package/docs/guidelines/agent-infra/roadmap-deferred-resolution-provenance.md +54 -0
  227. package/docs/guidelines/design-antipatterns.md +4 -2
  228. package/docs/guidelines/design-asset-discipline.md +38 -0
  229. package/docs/guidelines/design-fidelity-mechanics.md +45 -29
  230. package/docs/guidelines/design-handover-extraction.md +35 -5
  231. package/docs/guidelines/design-modes.md +41 -1
  232. package/docs/guidelines/monorepo-antipatterns.md +141 -0
  233. package/llms.txt +50 -39
  234. package/package.json +1 -1
  235. package/src/agent-src/templates/scripts/check_playbook_invokes.ts +231 -0
  236. package/src/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +24 -0
  237. package/src/agent-src/templates/scripts/work_engine/directives/ui/polish.ts +2 -0
  238. package/src/agent-src/templates/scripts/work_engine/directives/ui/review.ts +216 -0
  239. package/src/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +159 -0
  240. package/src/agent-src/templates/scripts/work_engine/directives/ui/stack_bundles.ts +73 -4
  241. package/src/agent-src/templates/scripts/work_engine/stack/detect.ts +325 -40
  242. package/src/config/agent-settings.template.yml +28 -0
  243. package/src/config/assurance-capability-registry.json +223 -0
  244. package/src/config/assurance-threshold-budget.json +65 -0
  245. package/src/config/ci-local-parity.yml +14 -0
  246. package/src/config/discovery/unassigned-artefacts.yml +2 -0
  247. package/src/config/dispatch-economy-metrics.json +4 -2
  248. package/src/config/evaluator-budgets.json +14 -14
  249. package/src/config/gate-coverage.yml +207 -8
  250. package/src/config/gate-violation-baselines.json +76 -72
  251. package/src/config/hook-latency-budget.json +1 -0
  252. package/src/config/hook-token-budget.json +137 -125
  253. package/src/config/pack-size-budget.json +4 -2
  254. package/src/config/quorum-attendance-budget.json +12 -4
  255. package/src/config/rule-activation-census.json +7 -3
  256. package/src/config/rule-enforcement-baseline.json +0 -1
  257. package/src/config/rule-stub-ceilings.json +112 -91
  258. package/src/scripts/_cli/cmd_doctor.ts +15 -16
  259. package/src/scripts/_cli/doctor_install_mode.ts +49 -0
  260. package/src/scripts/_cli/doctor_overrides.ts +154 -0
  261. package/src/scripts/_dispatch.bash +17 -0
  262. package/src/scripts/_lib/as_of.ts +412 -0
  263. package/src/scripts/_lib/exec_evidence.ts +7 -0
  264. package/src/scripts/_lib/hook_settings.ts +33 -0
  265. package/src/scripts/_lib/host_listing_model.ts +192 -0
  266. package/src/scripts/_lib/lean_projection_mode.ts +44 -0
  267. package/src/scripts/_lib/mcp_bridge.ts +199 -0
  268. package/src/scripts/_lib/review_independence.ts +62 -10
  269. package/src/scripts/_lib/rule_injection.ts +239 -0
  270. package/src/scripts/_lib/run_checkpoint.ts +54 -1
  271. package/src/scripts/_lib/scoped_projection.ts +96 -0
  272. package/src/scripts/_lib/session_register.ts +44 -2
  273. package/src/scripts/_lib/skill_catalogue.ts +38 -2
  274. package/src/scripts/_lib/transcript_reads.ts +207 -0
  275. package/src/scripts/_lib/ui_authority.test.ts +251 -0
  276. package/src/scripts/_lib/ui_authority.ts +343 -0
  277. package/src/scripts/ai-video/adapters/fal.sh +8 -3
  278. package/src/scripts/ai-video/adapters/gemini-veo.sh +10 -0
  279. package/src/scripts/ai-video/adapters/higgsfield.sh +10 -2
  280. package/src/scripts/ai-video/adapters/kling.sh +10 -0
  281. package/src/scripts/ai-video/adapters/sora.sh +10 -0
  282. package/src/scripts/ai-video/lib/calibrate-cost.sh +145 -0
  283. package/src/scripts/ai-video/lib/model-capabilities/README.md +53 -7
  284. package/src/scripts/ai-video/lib/model-capabilities/comfyui.json +15 -3
  285. package/src/scripts/ai-video/lib/model-capabilities/fal.json +36 -6
  286. package/src/scripts/ai-video/lib/model-capabilities/gemini-veo.json +23 -0
  287. package/src/scripts/ai-video/lib/model-capabilities/higgsfield.json +23 -0
  288. package/src/scripts/ai-video/lib/model-capabilities/kling.json +23 -0
  289. package/src/scripts/ai-video/lib/model-capabilities/musetalk.json +8 -2
  290. package/src/scripts/ai-video/lib/model-capabilities/replicate.json +36 -6
  291. package/src/scripts/ai-video/lib/model-capabilities/sora.json +45 -0
  292. package/src/scripts/ai-video/lib/model-capabilities/syncso.json +8 -2
  293. package/src/scripts/ai-video/lib/parse-blueprint.sh +52 -5
  294. package/src/scripts/ai-video/lib/resume-scan.sh +92 -3
  295. package/src/scripts/ai-video/lib/seam-plan.sh +212 -0
  296. package/src/scripts/ai-video/smoke-trace.sh +450 -2
  297. package/src/scripts/ai-video/stitch.sh +191 -10
  298. package/src/scripts/ai-video/test-pipeline.sh +84 -6
  299. package/src/scripts/ai_council/cli_agency_bounds.ts +139 -0
  300. package/src/scripts/ai_council/cli_least_agency_canary.ts +347 -0
  301. package/src/scripts/ai_council/clients.ts +3 -2
  302. package/src/scripts/ai_council/consensus.ts +63 -6
  303. package/src/scripts/ai_council/events_log.ts +46 -1
  304. package/src/scripts/ai_council/orchestrator.ts +103 -108
  305. package/src/scripts/ai_council/orchestrator_results.ts +166 -0
  306. package/src/scripts/ai_council/prompts.ts +12 -5
  307. package/src/scripts/ai_council/quorum.ts +82 -1
  308. package/src/scripts/ai_council/quorum_wiring.ts +82 -5
  309. package/src/scripts/ai_council/stance_tally.ts +22 -0
  310. package/src/scripts/bench_hook_latency.ts +62 -0
  311. package/src/scripts/build_proof.ts +12 -1
  312. package/src/scripts/capture_skill_catalogue.ts +21 -0
  313. package/src/scripts/check_always_budget.ts +2 -1
  314. package/src/scripts/check_augmentignore.ts +2 -1
  315. package/src/scripts/check_beta_review_markers.ts +2 -1
  316. package/src/scripts/check_composite_arming.ts +364 -0
  317. package/src/scripts/check_corpus_staleness.ts +2 -1
  318. package/src/scripts/check_council_pin_staleness.ts +3 -1
  319. package/src/scripts/check_enforcement_coverage.ts +116 -3
  320. package/src/scripts/check_enforcement_denominator.ts +365 -0
  321. package/src/scripts/check_gate_coverage.ts +2 -1
  322. package/src/scripts/check_hook_bundle_freshness.ts +13 -1
  323. package/src/scripts/check_knowledge_cards.ts +2 -1
  324. package/src/scripts/check_knowledge_pages.ts +3 -2
  325. package/src/scripts/check_memory.ts +2 -1
  326. package/src/scripts/check_no_automerge_key.ts +287 -0
  327. package/src/scripts/check_pack_conformance_fixture.ts +565 -0
  328. package/src/scripts/check_proposal.ts +2 -1
  329. package/src/scripts/check_reach_staleness.ts +2 -1
  330. package/src/scripts/check_release_adjacent_health.ts +2 -1
  331. package/src/scripts/check_release_pr_shape.ts +5 -0
  332. package/src/scripts/check_review_schema.ts +34 -1
  333. package/src/scripts/check_roadmap_trackable.ts +48 -3
  334. package/src/scripts/check_source_size_budget.ts +2 -1
  335. package/src/scripts/check_standing_payload_delta.ts +505 -0
  336. package/src/scripts/check_trigger_evals.ts +2 -1
  337. package/src/scripts/classify_change_risk.ts +281 -0
  338. package/src/scripts/compute_skill_tiers.ts +186 -0
  339. package/src/scripts/condense.ts +8 -13
  340. package/src/scripts/council_attendance_metrics.ts +183 -0
  341. package/src/scripts/council_cli.ts +10 -8
  342. package/src/scripts/council_parse_rate.ts +116 -0
  343. package/src/scripts/derive_playbooks.ts +406 -0
  344. package/src/scripts/design_slop_rules.test.ts +7 -0
  345. package/src/scripts/design_slop_rules.ts +56 -2
  346. package/src/scripts/dispatch_r2_reviewer.ts +16 -0
  347. package/src/scripts/frontend_corpus_hash.ts +116 -0
  348. package/src/scripts/grade_target_readiness.ts +478 -0
  349. package/src/scripts/hook_manifest.json +1 -1
  350. package/src/scripts/hook_manifest.yaml +97 -16
  351. package/src/scripts/hooks/concern_registry.ts +4 -0
  352. package/src/scripts/hooks/design_pass_hook.ts +356 -0
  353. package/src/scripts/hooks/rtk_wrap_hook.ts +30 -7
  354. package/src/scripts/hooks/rule_inject_hook.ts +318 -0
  355. package/src/scripts/hot_context_hook.ts +74 -7
  356. package/src/scripts/install.ts +40 -89
  357. package/src/scripts/lint_adapter_tier.ts +663 -0
  358. package/src/scripts/lint_archived_skills.ts +93 -0
  359. package/src/scripts/lint_budget_ownership.ts +2 -1
  360. package/src/scripts/lint_deterministic_time.ts +470 -0
  361. package/src/scripts/lint_framework_leakage.ts +5 -0
  362. package/src/scripts/lint_handoffs.ts +525 -1
  363. package/src/scripts/lint_judge_prompt_expectation.ts +155 -0
  364. package/src/scripts/lint_marketplace.ts +88 -0
  365. package/src/scripts/lint_media_policy_linkage.ts +140 -1
  366. package/src/scripts/lint_one_off_age.ts +6 -1
  367. package/src/scripts/lint_override_kernel_guard.ts +87 -5
  368. package/src/scripts/lint_roadmap_complexity.ts +56 -0
  369. package/src/scripts/lint_rule_enforcement_declaration.ts +24 -7
  370. package/src/scripts/lint_rule_norm_pin.ts +321 -0
  371. package/src/scripts/lint_spawn_payload.ts +42 -5
  372. package/src/scripts/lint_symptom_intake.ts +2 -1
  373. package/src/scripts/mcp_parity_smoke.ts +30 -4
  374. package/src/scripts/mcp_render.ts +66 -1
  375. package/src/scripts/mcp_tool_fingerprint.ts +241 -0
  376. package/src/scripts/measure_risk_class_drift.ts +140 -0
  377. package/src/scripts/measure_skill_ranker_baseline.ts +212 -0
  378. package/src/scripts/media/lib/adapter-common.sh +211 -1
  379. package/src/scripts/media/lib/adapter-contract.md +74 -6
  380. package/src/scripts/model_rule_injection.ts +907 -0
  381. package/src/scripts/project_thin_rules.ts +45 -2
  382. package/src/scripts/release.ts +66 -860
  383. package/src/scripts/release_drill.ts +59 -3
  384. package/src/scripts/release_env.ts +298 -0
  385. package/src/scripts/release_publication.ts +720 -0
  386. package/src/scripts/roadmap_context.ts +778 -0
  387. package/src/scripts/schemas/fidelity-measurement-sheet.schema.json +169 -0
  388. package/src/scripts/schemas/rule.schema.json +24 -2
  389. package/src/scripts/schemas/skill.schema.json +39 -0
  390. package/src/scripts/schemas/ui-authority.schema.json +114 -0
  391. package/src/scripts/session_register_hook.ts +29 -3
  392. package/src/scripts/sessions_cli.ts +67 -3
  393. package/src/scripts/skill_tools/score_skill_relevance.ts +36 -53
  394. package/src/scripts/token_sink_report.ts +239 -0
  395. package/src/scripts/trigger_coverage.ts +122 -3
  396. package/src/scripts/update_counts.ts +7 -3
  397. package/src/scripts/validate_frontmatter.ts +66 -0
  398. package/src/server/schemas/settings.ts +5 -0
  399. package/src/shared/skillRanking.ts +183 -0
@@ -0,0 +1,318 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * Rule-inject — the delivery twin of `skill-route`, with the opposite payload
4
+ * policy (`road-to-trigger-delivered-rule-bodies` Phase 1).
5
+ *
6
+ * BODIES, NEVER POINTERS — and the difference from its twin is deliberate
7
+ * rather than incidental. `skill_route_hook.ts:14` ships "POINTERS, NEVER
8
+ * BODIES" on this same slot, and it is right to: a skill is a thing the agent
9
+ * *invokes*, so naming it is enough. A rule is a thing the agent must already
10
+ * be *under*, and the only datum anyone has on pointer-shaped rule delivery is
11
+ * the 36.2 %-against-48 % run at `docs/CLAIMS.md:188-189`. Whatever that
12
+ * instrument's flaws — and ADR-202 closed it — it points one way.
13
+ *
14
+ * DEFAULT OFF, AND OFF MEANS ZERO BYTES. The concern registers on two slots but
15
+ * returns before reading the router unless `lean_projection.mode: delivery` is
16
+ * set. Under every shipped default it emits nothing, costs no injection budget,
17
+ * and leaves the standing corpus exactly as it is today. That is why its
18
+ * `hook-token-budget.json` row is registered against the per-prompt cap rather
19
+ * than a measured emission: there is no measured emission to register yet.
20
+ *
21
+ * ONE MATCHER, SHARED WITH THE OFFLINE MODEL. Everything about selection,
22
+ * ordering, capping and body loading comes from `_lib/rule_injection.ts`, which
23
+ * `model_rule_injection.ts` also imports. Step 0.5 states the reason in as many
24
+ * words: an experiment whose offline pricing and runtime delivery use different
25
+ * matchers measures nothing.
26
+ *
27
+ * ONCE PER SESSION PER RULE, RE-ARMED ON COMPACTION. A rule's body is injected
28
+ * the first time one of its triggers fires and not again, because the model
29
+ * already has it. Compaction is exactly the event that makes that false, so
30
+ * `pre_compact` clears the seen-set — the same pin-lost shape `language-mirror`
31
+ * uses. State lives under `agents/runtime/state/`, the class
32
+ * `context-hygiene.json` already occupies; no new state convention is created.
33
+ *
34
+ * NEVER BLOCKS. Every failure path returns 0: unreadable stdin, malformed JSON,
35
+ * missing router, unreadable body, unwritable state. The one non-zero exit is
36
+ * the host's advisory context channel (exit 2 + `decision: "warn"`), the same
37
+ * channel `ui-route-nudge` and `code-graph-nudge` already use on `pre_tool_use`
38
+ * with `severity: advisory` — a warn there is an injection, not a deny.
39
+ *
40
+ * HOST BOUNDARY, STATED RATHER THAN IMPLIED. `user_prompt_submit` and
41
+ * `pre_tool_use` are bound on a subset of hosts, and only `claude` honours a
42
+ * deny at all. On a host where neither slot is bound this concern cannot run,
43
+ * which is the whole reason the flip step 2.4 gates on is Claude-only. Run
44
+ * `agent-config hooks:status` for the host you are actually on.
45
+ *
46
+ * SUBAGENTS ARE OUT OF REACH, MEASURED. Neither slot fires inside a spawned
47
+ * child session and the `subagent_start` payload carries no prompt field — see
48
+ * `agents/evidence/investigations/subagent-start-payload-probe.md` (2026-08-23,
49
+ * claude 2.1.241, three verdicts). Delivery is therefore orchestrator-only, and
50
+ * no third binding is added.
51
+ */
52
+ import * as fs from 'node:fs';
53
+ import * as path from 'node:path';
54
+ import process from 'node:process';
55
+ import { fileURLToPath, pathToFileURL } from 'node:url';
56
+
57
+ import { hookSectionEnabled, leanProjectionModeRaw } from '../_lib/hook_settings.js';
58
+ import { deliversBodies, normalizeLeanProjectionMode } from '../_lib/lean_projection_mode.js';
59
+ import {
60
+ loadRuleBody,
61
+ loadRouter,
62
+ matchTierRules,
63
+ selectForInjection,
64
+ } from '../_lib/rule_injection.js';
65
+ import { readHookStdin } from './hook_stdin.js';
66
+
67
+ const EXIT_ALLOW = 0;
68
+ const EXIT_WARN = 2;
69
+
70
+ /**
71
+ * Per-prompt injection ceiling, in UTF-8 BYTES.
72
+ *
73
+ * DERIVED, NOT PICKED: `model_rule_injection --corpus tests/eval/routing-matrix`
74
+ * measured the matched-body-token distribution over the frozen labelled corpus
75
+ * at p50 1,728 / p90 4,804 / p99 8,248 / max 12,957 exact-BPE tokens, and step
76
+ * 1.1 specifies "the p90 from 0.4, rounded to 500" — 4,804 rounds up to 5,000.
77
+ *
78
+ * BYTES rather than tokens, and the unit change is the point rather than a
79
+ * detail. `_lib/token_count.ts` resolves `js-tiktoken` at module load, so a
80
+ * token-capped concern drags a tokenizer into EVERY hook dispatch on every
81
+ * slot, for a concern that is default-OFF and emits nothing. Measured: 202 ms
82
+ * -> 196 ms on the `pre_tool_use` p95 when the concern is unbound entirely, and
83
+ * the CI latency gate went red on the branch that introduced it while passing
84
+ * on main. So the runtime cap is the same bound in the unit
85
+ * `hook-token-budget.json` already enforces — 5,000 tok at the ~4 bytes/token
86
+ * this corpus measures is 20,480 B, which is exactly this concern's registered
87
+ * row. Cap and budget row are now one number instead of two units.
88
+ *
89
+ * Re-run that command if the corpus or the bodies move; a cap copied from a
90
+ * stale measurement is worse than no cap, because it looks derived.
91
+ */
92
+ export const CAP_BYTES = 20480;
93
+
94
+ /** Tools whose input names a file this concern can match path triggers against. */
95
+ export const FILE_TOOLS = new Set(['Write', 'Edit', 'NotebookEdit', 'Read', 'MultiEdit']);
96
+
97
+ type JsonObject = Record<string, unknown>;
98
+
99
+ function isObject(v: unknown): v is JsonObject {
100
+ return typeof v === 'object' && v !== null && !Array.isArray(v);
101
+ }
102
+
103
+ function str(o: JsonObject, ...keys: string[]): string | null {
104
+ for (const k of keys) {
105
+ const v = o[k];
106
+ if (typeof v === 'string' && v !== '') return v;
107
+ }
108
+ return null;
109
+ }
110
+
111
+ /** Workspace root the envelope points at, falling back to the process cwd. */
112
+ export function workspaceRoot(env: JsonObject): string {
113
+ return str(env, 'workspace', 'cwd', 'project_dir') ?? process.cwd();
114
+ }
115
+
116
+ // ── seen-set state ───────────────────────────────────────────────────────
117
+
118
+ export interface SeenState {
119
+ rules: string[];
120
+ }
121
+
122
+ export function statePath(root: string, session: string): string {
123
+ const safe = session.replace(/[^A-Za-z0-9_-]/g, '_').slice(0, 80) || 'unknown';
124
+ return path.join(root, 'agents', 'runtime', 'state', 'rule-inject', `${safe}.json`);
125
+ }
126
+
127
+ export function readSeen(root: string, session: string): Set<string> {
128
+ try {
129
+ const raw = fs.readFileSync(statePath(root, session), 'utf-8');
130
+ const parsed = JSON.parse(raw) as SeenState;
131
+ return new Set(Array.isArray(parsed.rules) ? parsed.rules.map(String) : []);
132
+ } catch {
133
+ return new Set(); // fresh session, or a file nothing can parse
134
+ }
135
+ }
136
+
137
+ export function writeSeen(root: string, session: string, seen: Set<string>): void {
138
+ const p = statePath(root, session);
139
+ try {
140
+ fs.mkdirSync(path.dirname(p), { recursive: true });
141
+ const payload: SeenState = { rules: [...seen].sort() };
142
+ fs.writeFileSync(`${p}.tmp`, `${JSON.stringify(payload)}\n`, 'utf-8');
143
+ fs.renameSync(`${p}.tmp`, p);
144
+ } catch {
145
+ /* unwritable state must never fail a turn — worst case a re-injection */
146
+ }
147
+ }
148
+
149
+ export function clearSeen(root: string, session: string): void {
150
+ try {
151
+ fs.rmSync(statePath(root, session), { force: true });
152
+ } catch {
153
+ /* ignore */
154
+ }
155
+ }
156
+
157
+ // ── payload extraction ───────────────────────────────────────────────────
158
+
159
+ /** The user's prompt, across the shapes the hosts use. */
160
+ export function extractPrompt(payload: JsonObject): string {
161
+ return str(payload, 'prompt', 'user_prompt', 'userPrompt', 'message', 'text') ?? '';
162
+ }
163
+
164
+ /** The file path a file-touching tool call names, or `null`. */
165
+ export function extractFilePath(payload: JsonObject): string | null {
166
+ const ti = payload['tool_input'] ?? payload['toolInput'] ?? payload['input'];
167
+ if (!isObject(ti)) return null;
168
+ return str(ti, 'file_path', 'path', 'filePath', 'notebook_path');
169
+ }
170
+
171
+ // ── decision ─────────────────────────────────────────────────────────────
172
+
173
+ export interface Injection {
174
+ rules: string[];
175
+ bytes: number;
176
+ body: string;
177
+ }
178
+
179
+ /**
180
+ * Build the injection for one event, or `null` for silence.
181
+ *
182
+ * `prompt` drives keyword / phrase / command triggers; `openFiles` drives
183
+ * `path_prefix` / `file_pattern`. On the tool slot the prompt is deliberately
184
+ * empty, so a file event can only ever fire a path trigger — a tool call is not
185
+ * a restatement of the user's request and must not re-fire keyword rules.
186
+ */
187
+ export function buildInjection(
188
+ root: string,
189
+ prompt: string,
190
+ openFiles: string[] | null,
191
+ command: string | null,
192
+ seen: Set<string>,
193
+ ): Injection | null {
194
+ let router;
195
+ try {
196
+ router = loadRouter(root);
197
+ } catch {
198
+ return null; // no router — nothing to deliver, and never a failure
199
+ }
200
+ const matches = matchTierRules(router, prompt, openFiles, command).filter(
201
+ (m) => !seen.has(m.id),
202
+ );
203
+ if (matches.length === 0) return null;
204
+ const sel = selectForInjection(root, matches, CAP_BYTES);
205
+ const parts: string[] = [];
206
+ const ids: string[] = [];
207
+ for (const m of sel.selected) {
208
+ const body = loadRuleBody(root, m.id);
209
+ if (body === null) continue;
210
+ ids.push(m.id);
211
+ parts.push(`<rule id="${m.id}" tier="${m.tier}">\n${body.trim()}\n</rule>`);
212
+ }
213
+ if (ids.length === 0) return null;
214
+ return { rules: ids, bytes: sel.bytes, body: parts.join('\n\n') };
215
+ }
216
+
217
+ // ── main ─────────────────────────────────────────────────────────────────
218
+
219
+ /**
220
+ * Whether the settings gate applies.
221
+ *
222
+ * Through the dispatcher the gate is absolute: no `lean_projection.mode:
223
+ * delivery`, no bytes. A DIRECT CLI invocation is a probe by definition — an
224
+ * operator piping an envelope into this file is asking to see what it would
225
+ * deliver — so there the mode defaults to on. `AGENT_CONFIG_REPLAY` re-imposes
226
+ * the gate, which is what keeps `bench_hook_injection` measuring the shipped
227
+ * default (zero bytes) rather than the probe.
228
+ */
229
+ export function gateOpen(root: string, cliEntry: boolean): boolean {
230
+ if (deliversBodies(normalizeLeanProjectionMode(leanProjectionModeRaw(root)))) return true;
231
+ if (hookSectionEnabled(root, 'rule_inject')) return true;
232
+ return cliEntry && process.env['AGENT_CONFIG_REPLAY'] !== '1';
233
+ }
234
+
235
+ export function main(argv: readonly string[] = process.argv.slice(2)): number {
236
+ let eventOverride: string | null = null;
237
+ for (let i = 0; i < argv.length; i += 1) {
238
+ if (argv[i] === '--event') {
239
+ i += 1;
240
+ eventOverride = argv[i] ?? null;
241
+ }
242
+ }
243
+
244
+ let env: JsonObject = {};
245
+ try {
246
+ const raw = readHookStdin();
247
+ const parsed = raw.trim() ? (JSON.parse(raw) as unknown) : {};
248
+ env = isObject(parsed) ? parsed : {};
249
+ } catch {
250
+ return EXIT_ALLOW; // malformed envelope — never block
251
+ }
252
+
253
+ const root = workspaceRoot(env);
254
+ const payload = isObject(env['payload']) ? (env['payload'] as JsonObject) : env;
255
+ const slot = eventOverride ?? str(env, 'event') ?? 'user_prompt_submit';
256
+ const session = str(env, 'session_id', 'sessionId') ?? str(payload, 'session_id', 'sessionId') ?? 'unknown';
257
+
258
+ if (slot === 'pre_compact') {
259
+ clearSeen(root, session);
260
+ return EXIT_ALLOW; // re-arm is silent; the next turn re-injects
261
+ }
262
+ if (slot !== 'user_prompt_submit' && slot !== 'pre_tool_use') return EXIT_ALLOW;
263
+ if (!gateOpen(root, _isCliEntry())) return EXIT_ALLOW;
264
+
265
+ let prompt = '';
266
+ let openFiles: string[] | null = null;
267
+ let command: string | null = null;
268
+ if (slot === 'user_prompt_submit') {
269
+ prompt = extractPrompt(payload);
270
+ if (prompt === '') return EXIT_ALLOW;
271
+ const m = /^\s*(\/[A-Za-z0-9:_-]+)/.exec(prompt);
272
+ command = m ? (m[1] as string) : null;
273
+ } else {
274
+ const tool = str(payload, 'tool_name', 'toolName', 'tool');
275
+ if (tool === null || !FILE_TOOLS.has(tool)) return EXIT_ALLOW;
276
+ const fp = extractFilePath(payload);
277
+ if (fp === null) return EXIT_ALLOW;
278
+ openFiles = [fp];
279
+ }
280
+
281
+ const seen = readSeen(root, session);
282
+ const injection = buildInjection(root, prompt, openFiles, command, seen);
283
+ if (injection === null) return EXIT_ALLOW; // silence is the default
284
+
285
+ for (const id of injection.rules) seen.add(id);
286
+ writeSeen(root, session, seen);
287
+
288
+ process.stdout.write(
289
+ `${JSON.stringify({
290
+ decision: 'warn',
291
+ reason: `rule-inject: ${injection.rules.length} rule body/bodies on ${slot} (${injection.bytes} B)`,
292
+ additional_context: injection.body,
293
+ })}\n`,
294
+ );
295
+ return EXIT_WARN;
296
+ }
297
+
298
+ // Bundle-safety: never auto-run when inlined into an esbuild bundle, where
299
+ // every module shares the bundle's `import.meta.url`.
300
+ declare const __AGENT_CONFIG_BUNDLE__: boolean | undefined;
301
+ function _isCliEntry(): boolean {
302
+ if (typeof __AGENT_CONFIG_BUNDLE__ !== 'undefined' && __AGENT_CONFIG_BUNDLE__) return false;
303
+ if (process.argv[1] === undefined) return false;
304
+ const argvUrl = pathToFileURL(path.resolve(process.argv[1])).href;
305
+ if (import.meta.url === argvUrl) return true;
306
+ try {
307
+ return (
308
+ fs.realpathSync(fileURLToPath(import.meta.url)) ===
309
+ fs.realpathSync(path.resolve(process.argv[1]))
310
+ );
311
+ } catch {
312
+ return false;
313
+ }
314
+ }
315
+
316
+ if (_isCliEntry()) {
317
+ process.exit(main());
318
+ }
@@ -36,6 +36,7 @@ import process from 'node:process';
36
36
  import { fileURLToPath } from 'node:url';
37
37
 
38
38
  import { hardenedSpawnEnv } from './_lib/spawn_env.js';
39
+ import { computeRereads } from './_lib/transcript_reads.js';
39
40
  import { redact_low_impact_entry } from './ai_council/redact_low_impact_entry.js';
40
41
  import { readHookStdin } from './hooks/hook_stdin.js';
41
42
 
@@ -57,6 +58,7 @@ const MAX_OPEN_VERIFICATIONS = 3;
57
58
  const THREAD_SNIPPET_CHARS = 200;
58
59
  const CHANGE_SNIPPET_CHARS = 120;
59
60
  const KEY_FACTS_CHARS = 600;
61
+ const MAX_REREAD_LINES = 3; // advisory, not an inventory — see _reread_lines
60
62
 
61
63
  const VERIFICATION_RE = /\b(fail(ing|ed|ure)?|error|exit[= ][1-9]|red\b|broken)\b/i;
62
64
 
@@ -161,11 +163,55 @@ function _word_count(text: string): number {
161
163
  return text.split(/\s+/).filter((w) => w.length > 0).length;
162
164
  }
163
165
 
166
+ // ---------------------------------------------------------------------
167
+ // re-read advisory (road-to-role-scoped-spawn-profiles Phase 3 Steps 4-5)
168
+ // ---------------------------------------------------------------------
169
+
170
+ /**
171
+ * Files this leg read more than once, as advisory lines for the cache.
172
+ *
173
+ * Phase 3 Step 4 of `road-to-role-scoped-spawn-profiles` requires the
174
+ * suppression to ride THIS surface rather than arrive as a second artefact,
175
+ * and Step 5 requires it to stay advice: there is no refuse branch anywhere
176
+ * below, and there is no code path that returns a deny on a re-read condition.
177
+ * The output is three lines in a markdown cache; the next leg may ignore it.
178
+ *
179
+ * **Why the path is relativised, and why an outside path is dropped rather
180
+ * than shortened.** The privacy floor
181
+ * ({@link _redact_lines} → `redact_low_impact_entry`) drops any line carrying
182
+ * a project-rooted absolute path, so emitting `/Users/...` would produce a
183
+ * silently empty section — the feature would look implemented and do nothing.
184
+ * Relativising to the workspace root keeps the line inside the floor. A path
185
+ * OUTSIDE the root cannot be relativised without `../` escapes that re-reveal
186
+ * the layout, and it is another project's business in any case, so it is
187
+ * dropped entirely.
188
+ *
189
+ * Fail-silent: no transcript path, an unreadable one, or a malformed leg all
190
+ * yield `[]`. This is a cache, and a cache that throws is worse than a cache
191
+ * that is short.
192
+ */
193
+ export function _reread_lines(transcriptPath: string | null, root: string): string[] {
194
+ if (!transcriptPath) return [];
195
+ const result = computeRereads([transcriptPath]);
196
+ const lines: string[] = [];
197
+ for (const f of result.files) {
198
+ if (lines.length >= MAX_REREAD_LINES) break;
199
+ const rel = path.relative(root, f.file_path);
200
+ if (rel === '' || rel.startsWith('..') || path.isAbsolute(rel)) continue;
201
+ lines.push(`${rel} — read ${f.total_reads}x this leg (${f.duplicate_reads} re-read)`);
202
+ }
203
+ return lines;
204
+ }
205
+
164
206
  // ---------------------------------------------------------------------
165
207
  // stop — deterministic write
166
208
  // ---------------------------------------------------------------------
167
209
 
168
- export function build_hot_context(root: string, now: Date = new Date()): string {
210
+ export function build_hot_context(
211
+ root: string,
212
+ now: Date = new Date(),
213
+ transcriptPath: string | null = null,
214
+ ): string {
169
215
  const session = _latest_session_entries(_read_history(root));
170
216
 
171
217
  const userPrompts = session.filter((e) => e.t === 'user_prompt' && e.text);
@@ -188,20 +234,36 @@ export function build_hot_context(root: string, now: Date = new Date()): string
188
234
  );
189
235
  const lastStop = String(stops[stops.length - 1]?.text ?? '');
190
236
  const keyFacts = _redact_lines(lastStop ? [_snippet(lastStop, KEY_FACTS_CHARS)] : []);
237
+ const rereads = _redact_lines(_reread_lines(transcriptPath, root));
191
238
 
192
239
  const droppedTotal =
193
- activeThreads.dropped + recentChanges.dropped + openVerifications.dropped + keyFacts.dropped;
240
+ activeThreads.dropped +
241
+ recentChanges.dropped +
242
+ openVerifications.dropped +
243
+ keyFacts.dropped +
244
+ rereads.dropped;
194
245
 
195
246
  // Assemble; trim lowest-priority sections first until under the word cap.
196
247
  // Priority (highest kept longest): Key Facts > Active Threads >
197
- // Open Verifications > Recent Changes.
248
+ // Open Verifications > Recent Changes > Re-Read Advisory.
249
+ //
250
+ // The advisory sits LAST on purpose. It is the only section that is a
251
+ // suggestion rather than a record of what happened, so when the 400-word
252
+ // cap bites it is the one whose loss costs nothing.
198
253
  const sections: Array<{ title: string; items: string[] }> = [
199
254
  { title: 'Key Facts', items: keyFacts.kept },
200
255
  { title: 'Active Threads', items: activeThreads.kept },
201
256
  { title: 'Open Verifications', items: openVerifications.kept },
202
257
  { title: 'Recent Changes', items: recentChanges.kept },
258
+ { title: 'Re-Read Advisory', items: rereads.kept },
259
+ ];
260
+ const trimOrder = [
261
+ 'Re-Read Advisory',
262
+ 'Recent Changes',
263
+ 'Open Verifications',
264
+ 'Active Threads',
265
+ 'Key Facts',
203
266
  ];
204
- const trimOrder = ['Recent Changes', 'Open Verifications', 'Active Threads', 'Key Facts'];
205
267
 
206
268
  const render = (): string => {
207
269
  const lines: string[] = [
@@ -240,9 +302,9 @@ export function build_hot_context(root: string, now: Date = new Date()): string
240
302
  return text;
241
303
  }
242
304
 
243
- function _write_hot_context(root: string): void {
305
+ function _write_hot_context(root: string, transcriptPath: string | null = null): void {
244
306
  const target = _hot_context_path(root);
245
- const text = build_hot_context(root);
307
+ const text = build_hot_context(root, new Date(), transcriptPath);
246
308
  fs.mkdirSync(path.dirname(target), { recursive: true });
247
309
  const tmp = `${target}.tmp-${process.pid}`;
248
310
  fs.writeFileSync(tmp, text, { encoding: 'utf-8' });
@@ -392,7 +454,12 @@ export function main(): number {
392
454
  // one rebuild and can never produce a worse cache than the older one it
393
455
  // replaces. It emits nothing — the restore side is unchanged.
394
456
  if (event === 'stop' || event === 'session_end' || event === 'pre_compact') {
395
- _write_hot_context(root);
457
+ // Claude Code puts the leg's own transcript on the stop payload;
458
+ // the camelCase alias is defensive, matching how the subagent
459
+ // ledger reads `last_assistant_message`. Absent on other hosts,
460
+ // where the advisory is simply empty.
461
+ const tp = payload.transcript_path ?? payload.transcriptPath;
462
+ _write_hot_context(root, typeof tp === 'string' && tp.length > 0 ? tp : null);
396
463
  } else if (event === 'session_start') {
397
464
  const source = String(payload.source ?? '');
398
465
  const decision = restore_hot_context(root, source);
@@ -74,6 +74,7 @@ import type * as YamlModule from 'yaml';
74
74
  import { build_merge_entries } from './_lib/json_pointers.js';
75
75
  import { is_claude_builtin_name } from './_lib/claude_builtin_names.js';
76
76
  import * as installed_lock from './_lib/installed_lock.js';
77
+ import * as mcp_bridge from './_lib/mcp_bridge.js';
77
78
  import * as scoped_projection from './_lib/scoped_projection.js';
78
79
  import * as surface_tiers from './_lib/surface_tiers.js';
79
80
  import * as global_deploy_inventory from './_lib/global_deploy_inventory.js';
@@ -1115,6 +1116,18 @@ function ensure_claude_bridge(project_root: string, force: boolean): Record<stri
1115
1116
  return merge_json_file(target, bridge, force || healed.length > 0, '.claude/settings.json');
1116
1117
  }
1117
1118
 
1119
+ // `.mcp.json` registration + the skill-tier projection lever live in
1120
+ // `_lib/mcp_bridge.ts`; only the call sites are here (see that module's header
1121
+ // for why). Names are forwarded so the export surface is unchanged.
1122
+ const ensure_mcp_bridge = mcp_bridge.makeEnsureMcpBridge(merge_json_file);
1123
+ const _resolve_tier_b = mcp_bridge.resolveTierB;
1124
+ const _tier_b_advisory = mcp_bridge.tierBAdvisory;
1125
+ const _prune_tier_b_modules = (
1126
+ dr: Record<string, DeployResult>,
1127
+ tier_b: ReadonlySet<string>,
1128
+ ): [number, Record<string, DeployResult>] =>
1129
+ _prune_modules_by(dr, mcp_bridge.tierBPrunePredicate(tier_b));
1130
+
1118
1131
  const CURSOR_DISPATCHER_BINDINGS: ReadonlyArray<readonly [string, string]> = [
1119
1132
  ['session_start', 'sessionStart'],
1120
1133
  ['session_end', 'sessionEnd'],
@@ -2472,7 +2485,7 @@ function _file_entry(p: string, kind: string, hash_content: boolean): Record<str
2472
2485
  };
2473
2486
  }
2474
2487
 
2475
- type DeployResult = [number, number, string, string[]];
2488
+ type DeployResult = scoped_projection.DeployTuple;
2476
2489
 
2477
2490
  function _files_by_tool_from_deploy(
2478
2491
  deploy_results: Record<string, DeployResult>,
@@ -3397,91 +3410,10 @@ function _verify_deploy_targets(anchor: string, plan: ReadonlyArray<readonly [st
3397
3410
  return missing;
3398
3411
  }
3399
3412
 
3400
- /**
3401
- * Remove skills/commands matching `is_pruned` from a completed deploy.
3402
- *
3403
- * road-to-install-contract-stability Phase 2 Step 2 (generalized in
3404
- * road-to-credible-install Phase 2 to back both the core-only lab prune and
3405
- * the scoped-projection pack prune off the same mechanics). Skills are
3406
- * pruned by whole directory (tier decided by the skill's `SKILL.md`
3407
- * frontmatter); commands by file (own frontmatter). Rules / personas /
3408
- * contexts / templates are core/shared and left intact. Returns
3409
- * `[pruned_count, adjusted_results]` with the pruned paths removed from each
3410
- * tool's `written_paths` so the manifest never records them.
3411
- */
3412
- function _prune_modules_by(
3413
- deploy_results: Record<string, DeployResult>,
3414
- is_pruned: (md_path: string) => boolean,
3415
- ): [number, Record<string, DeployResult>] {
3416
- let pruned = 0;
3417
- const adjusted: Record<string, DeployResult> = {};
3418
- for (const tool_id of Object.keys(deploy_results)) {
3419
- const [written, skipped, status, paths] = deploy_results[tool_id] as DeployResult;
3420
- const pruned_skill_dirs = new Set<string>();
3421
- for (const p of paths) {
3422
- const parts = p.split(path.sep);
3423
- if (parts.includes('skills')) {
3424
- const i = parts.indexOf('skills');
3425
- if (i + 1 < parts.length) {
3426
- const skill_root = parts.slice(0, i + 2).join(path.sep);
3427
- if (!pruned_skill_dirs.has(skill_root)) {
3428
- const skillmd = path.join(skill_root, 'SKILL.md');
3429
- if (pathExists(skillmd) && is_pruned(skillmd)) {
3430
- pruned_skill_dirs.add(skill_root);
3431
- }
3432
- }
3433
- }
3434
- }
3435
- }
3436
- const keep: string[] = [];
3437
- const delete_files: string[] = [];
3438
- for (const p of paths) {
3439
- const parts = p.split(path.sep);
3440
- let is_target = false;
3441
- if (parts.includes('skills')) {
3442
- const i = parts.indexOf('skills');
3443
- if (i + 1 < parts.length && pruned_skill_dirs.has(parts.slice(0, i + 2).join(path.sep))) {
3444
- is_target = true;
3445
- }
3446
- } else if (
3447
- parts.includes('commands') &&
3448
- path.extname(p) === '.md' &&
3449
- is_pruned(p)
3450
- ) {
3451
- is_target = true;
3452
- }
3453
- (is_target ? delete_files : keep).push(p);
3454
- }
3455
- for (const d of pruned_skill_dirs) {
3456
- fs.rmSync(d, { recursive: true, force: true });
3457
- }
3458
- for (const p of delete_files) {
3459
- if (p.split(path.sep).includes('commands') && pathExists(p)) {
3460
- try {
3461
- fs.unlinkSync(p);
3462
- } catch {
3463
- // OSError → swallow, mirroring the .py.
3464
- }
3465
- }
3466
- }
3467
- pruned += delete_files.length;
3468
- adjusted[tool_id] = [Math.max(0, written - delete_files.length), skipped, status, keep];
3469
- }
3470
- return [pruned, adjusted];
3471
- }
3472
-
3473
- /**
3474
- * Remove lab-tier skills/commands from a completed deploy (core-only).
3475
- *
3476
- * road-to-install-contract-stability Phase 2 Step 2. Thin wrapper over
3477
- * `_prune_modules_by` — see that function for the mechanics.
3478
- */
3479
- function _prune_lab_modules(
3480
- deploy_results: Record<string, DeployResult>,
3481
- lab_ids: Set<string>,
3482
- ): [number, Record<string, DeployResult>] {
3483
- return _prune_modules_by(deploy_results, (p) => surface_tiers.is_lab_artefact(p, lab_ids));
3484
- }
3413
+ // The prune mechanics moved WHOLE into `_lib/scoped_projection.ts` beside the
3414
+ // predicate they consume — a pure move, names forwarded, no behaviour change.
3415
+ const _prune_modules_by = scoped_projection.prune_modules_by;
3416
+ const _prune_lab_modules = scoped_projection.prune_lab_modules;
3485
3417
 
3486
3418
  // --- Scoped-projection prune (road-to-credible-install Phase 2) ----------
3487
3419
  //
@@ -3549,10 +3481,10 @@ function _resolve_global_settings_path(): string | null {
3549
3481
  */
3550
3482
  function _resolve_scoped_projection(
3551
3483
  package_root: string,
3552
- ): { mode: 'scoped' | 'legacy-all'; active_packs: string[] } {
3484
+ ): { mode: mcp_bridge.ProjectionMode; active_packs: string[] } {
3553
3485
  const doc = _resolve_global_settings_doc() ?? _load_default_settings(package_root);
3554
3486
  const projection = _isPlainObject(doc['projection']) ? (doc['projection'] as Record<string, unknown>) : {};
3555
- const mode: 'scoped' | 'legacy-all' = projection['mode'] === 'scoped' ? 'scoped' : 'legacy-all';
3487
+ const mode = mcp_bridge.projectionModeOf(projection['mode']);
3556
3488
  const runtime = _isPlainObject(doc['runtime']) ? (doc['runtime'] as Record<string, unknown>) : {};
3557
3489
  const active_packs_raw = runtime['active_packs'];
3558
3490
  const active_packs = Array.isArray(active_packs_raw)
@@ -3782,6 +3714,13 @@ function install_global(
3782
3714
  // here and restores the full tree — never a partial or crashed prune.
3783
3715
  try {
3784
3716
  const { mode, active_packs } = _resolve_scoped_projection(package_root);
3717
+ if (mode === 'tiered') {
3718
+ const outcome = mcp_bridge.applyTieredPrune(deploy_results, package_root, _prune_modules_by);
3719
+ deploy_results = outcome.deployResults;
3720
+ if (!state.QUIET && outcome.message !== null) {
3721
+ (outcome.level === 'warn' ? warn : info)(outcome.message);
3722
+ }
3723
+ }
3785
3724
  if (mode === 'scoped') {
3786
3725
  const packs_registry = _load_packs_registry(package_root);
3787
3726
  const active_ids = _compute_active_pack_ids(packs_registry, active_packs);
@@ -5225,7 +5164,10 @@ function _main_project_install(
5225
5164
  ...ensure_augment_bridge(project_root, opts.force),
5226
5165
  ];
5227
5166
  if (_is_tool_enabled(tools, 'claude-code')) {
5228
- merged_keys_by_tool['claude-code'] = ensure_claude_bridge(project_root, opts.force);
5167
+ merged_keys_by_tool['claude-code'] = [
5168
+ ...ensure_claude_bridge(project_root, opts.force),
5169
+ ...ensure_mcp_bridge(project_root, opts.force),
5170
+ ];
5229
5171
  }
5230
5172
  if (_is_tool_enabled(tools, 'cursor')) {
5231
5173
  merged_keys_by_tool['cursor'] = ensure_cursor_bridge(project_root, opts.force);
@@ -5249,6 +5191,11 @@ function _main_project_install(
5249
5191
  if (_is_tool_enabled(tools, 'kiro')) ensure_kiro_bridge(project_root, opts.force);
5250
5192
  }
5251
5193
 
5194
+ const tier_advisory = _tier_b_advisory(package_root);
5195
+ if (tier_advisory !== null && !state.QUIET) {
5196
+ info(tier_advisory);
5197
+ }
5198
+
5252
5199
  if (opts.augment_user_hooks) {
5253
5200
  (merged_keys_by_tool['augment'] ??= []).push(...ensure_augment_user_hooks(package_root, opts.force));
5254
5201
  }
@@ -5441,6 +5388,10 @@ export {
5441
5388
  GEMINI_DISPATCHER_BINDINGS,
5442
5389
  ensure_cursor_bridge,
5443
5390
  ensure_cline_bridge,
5391
+ ensure_mcp_bridge,
5392
+ _prune_tier_b_modules,
5393
+ _resolve_tier_b,
5394
+ _tier_b_advisory,
5444
5395
  ensure_windsurf_bridge,
5445
5396
  ensure_gemini_bridge,
5446
5397
  // road-to-credible-install Phase 2: exported for the scoped-projection