@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
@@ -39,11 +39,14 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
39
39
  // a second copy (road-to-skill-delivery-over-mcp risk 6). Everything below is
40
40
  // the disk half — globbing, frontmatter, the CLI — which stays here.
41
41
  import {
42
+ buildTermStats,
42
43
  scoreSkill,
43
44
  skillTerms as _sharedSkillTerms,
44
45
  tokenize as _sharedTokenize,
45
46
  triggerTextFromFlatLines,
47
+ widensTermSource,
46
48
  type RankOptions,
49
+ type TermStats,
47
50
  } from '../../shared/skillRanking.js';
48
51
 
49
52
  const _HERE = fileURLToPath(import.meta.url);
@@ -67,6 +70,20 @@ export const ROOT = path.resolve(path.dirname(_HERE), '..', '..', '..');
67
70
  * CLI turns that into a distinct exit code rather than an empty list.
68
71
  */
69
72
  import { DEFAULT_CATALOGUE_ROOTS, resolveSkillCatalogueRoots } from '../_lib/skill_catalogue.js';
73
+ // Authorship + scan primitives only. Deliberately NOT `neighbour_census.js`,
74
+ // whose module graph reaches the host-hook merger, the secret detector and the
75
+ // install-ownership reader — this module is inlined into the shared hook bundle,
76
+ // where every byte is paid by every concern on every dispatch.
77
+ import {
78
+ fileDigest,
79
+ makeSkillOriginResolver,
80
+ qualifiedSkillName,
81
+ readScanCache,
82
+ scanCachePath,
83
+ scanVerdict,
84
+ type ScanCache,
85
+ type SkillOrigin,
86
+ } from '../_lib/skill_origin.js';
70
87
 
71
88
  /**
72
89
  * Every readable catalogue root, in precedence order — possibly empty.
@@ -100,7 +117,17 @@ export interface Frontmatter {
100
117
  export function _parse_frontmatter(filePath: string): Frontmatter {
101
118
  // text.read_text(errors="replace") — Node `utf-8` decode replaces the same
102
119
  // way for the inputs these tools see (well-formed SKILL.md files).
103
- const text = fs.readFileSync(filePath, 'utf-8');
120
+ return _parse_frontmatter_text(fs.readFileSync(filePath, 'utf-8'));
121
+ }
122
+
123
+ /**
124
+ * The same reader over text already in hand.
125
+ *
126
+ * The loader needs the body as well as the frontmatter, and reading each
127
+ * SKILL.md twice to get them would double the per-call I/O of a ranker that
128
+ * runs on a hook path.
129
+ */
130
+ export function _parse_frontmatter_text(text: string): Frontmatter {
104
131
  if (!text.startsWith('---')) {
105
132
  return {};
106
133
  }
@@ -164,38 +191,204 @@ function _rstrip(s: string): string {
164
191
 
165
192
  export interface Skill {
166
193
  name: string;
194
+ /**
195
+ * Where the skill came from — `package` for ours, `project` / `home` for a
196
+ * neighbour another installer put in a root this ranker unions in.
197
+ */
198
+ origin: SkillOrigin;
199
+ /** What a route line prints: `name` for ours, `origin:name` otherwise. */
200
+ qualified: string;
201
+ /**
202
+ * Finding kind when a neighbour body did not pass the shape scan, else
203
+ * `null`. Such a skill is still ranked — by its NAME only; see
204
+ * {@link _load_skills}.
205
+ */
206
+ unscanned: string | null;
167
207
  description: string;
168
208
  personas: string[];
169
209
  terms: Set<string>;
170
210
  /** `triggers[].keyword` / `.phrase` prose. Indexed only under keyword-v2. */
171
211
  triggerText: string[];
212
+ /** The body's `## When to use` section. Indexed only behind its own flag. */
213
+ whenToUseText: string;
214
+ /** The body's `##` / `###` heading lines. Indexed only behind its own flag. */
215
+ headingText: string[];
216
+ }
217
+
218
+ /** Everything after the frontmatter block, or the whole text when there is none. */
219
+ export function _body_of(text: string): string {
220
+ if (!text.startsWith('---')) return text;
221
+ const end = text.indexOf('\n---', 3);
222
+ if (end === -1) return text;
223
+ return text.slice(end + 4);
172
224
  }
173
225
 
174
226
  /**
175
- * Load one root, or several with the FIRST occurrence of a name winning.
227
+ * The `## When to use` section, and every `##` / `###` heading, out of a body.
228
+ *
229
+ * Line-oriented, and bounded in two ways that a first version got wrong in the
230
+ * same direction — it indexed something other than what this block describes,
231
+ * which makes a measurement of the FLAG a measurement of the PARSER:
176
232
  *
177
- * Precedence by name, never by root: every root is read, and a collision
178
- * resolves to the earliest root that carries it — `resolveSkillCatalogueRoots`
179
- * owns what that order means. Reading only the first root is the defect this
180
- * replaced; silently ranking one name twice would be the next one.
233
+ * - the section ends at the next heading of the SAME OR A HIGHER level, so a
234
+ * `###` subsection of `## When to use` stays inside it. Ending at any
235
+ * heading truncated the capture at the first subsection;
236
+ * - a line inside a fenced code block is never a heading. These skills are
237
+ * documentation and routinely fence markdown samples, so a `## …` line in a
238
+ * fence was both harvested as a topic and used to terminate the section.
239
+ *
240
+ * Without the first bound a skill whose whole file is one section could still
241
+ * not put its procedure into an index whose flag says "when to use", because a
242
+ * sibling `##` ends it.
243
+ */
244
+ export function _body_signals(body: string): { whenToUse: string; headings: string[] } {
245
+ const headings: string[] = [];
246
+ const when: string[] = [];
247
+ let whenLevel = 0;
248
+ let fenceMark: string | null = null;
249
+ let fenceLen = 0;
250
+ for (const raw of body.split('\n')) {
251
+ const line = raw.trimEnd();
252
+ const f = /^\s*(`{3,}|~{3,})(.*)$/.exec(line);
253
+ if (f) {
254
+ const run = f[1] as string;
255
+ const mark = run[0] as string;
256
+ if (fenceMark === null) {
257
+ fenceMark = mark;
258
+ fenceLen = run.length;
259
+ // The DELIMITER and its info string are not prose. Pushing them
260
+ // put the language tag of every fenced sample (`bash`, `yaml`)
261
+ // into the index, which is the parser leaking into the signal in
262
+ // the opposite direction from the truncation this block fixed.
263
+ continue;
264
+ }
265
+ // A closing fence has to be at least as long as the opening one and
266
+ // use the same marker; otherwise a ``` inside a ```` block would
267
+ // close it early.
268
+ if (mark === fenceMark && run.length >= fenceLen && (f[2] as string).trim() === '') {
269
+ fenceMark = null;
270
+ fenceLen = 0;
271
+ }
272
+ continue;
273
+ }
274
+ if (fenceMark !== null) {
275
+ if (whenLevel > 0) when.push(raw);
276
+ continue;
277
+ }
278
+ // `#{1,6}`, not `#{2,6}`: a level-1 heading is strictly HIGHER than the
279
+ // section and must close it. Matching only `##`+ let a `# New Section`
280
+ // and everything after it leak into an open capture.
281
+ const h = /^(#{1,6})\s+(.*)$/.exec(line);
282
+ if (h) {
283
+ const level = (h[1] as string).length;
284
+ const title = (h[2] as string).trim();
285
+ if (level >= 2 && level <= 3) headings.push(title);
286
+ if (whenLevel > 0 && level <= whenLevel) {
287
+ whenLevel = 0;
288
+ } else if (whenLevel > 0) {
289
+ // A SUBSECTION TITLE inside `## When to use` is part of that
290
+ // section's text. Skipping it indexed the prose under a `### Do
291
+ // NOT use when` while dropping the words that say what it is.
292
+ when.push(title);
293
+ }
294
+ // Only OPEN a section when none is open. Assigning unconditionally
295
+ // let a `### When to use it on a monorepo` overwrite the outer
296
+ // level 2 with 3, after which the next sibling `###` satisfied
297
+ // `level <= whenLevel` and closed the section early — silently
298
+ // dropping everything from that sibling to the real end.
299
+ if (whenLevel === 0 && /^when to use\b/i.test(title)) whenLevel = level;
300
+ continue;
301
+ }
302
+ if (whenLevel > 0) when.push(raw);
303
+ }
304
+ return { whenToUse: when.join(' ').trim(), headings };
305
+ }
306
+
307
+ /**
308
+ * Everything a load needs to know about who owns a file and whether its body was
309
+ * scanned. Built once per `rank` call, never per file.
181
310
  */
182
- function _load_skills_across(roots: readonly string[]): Skill[] {
311
+ export interface NeighbourContext {
312
+ origin: (skillMdPath: string) => SkillOrigin;
313
+ scans: ScanCache | null;
314
+ }
315
+
316
+ /**
317
+ * The context for a workspace: manifest-backed origins plus the scan cache.
318
+ *
319
+ * Built once per `rank` call rather than per file — one manifest read and one
320
+ * cache read for a catalogue of several hundred entries.
321
+ */
322
+ export function defaultNeighbourContext(workspaceRoot: string = ROOT): NeighbourContext {
323
+ return {
324
+ origin: makeSkillOriginResolver(workspaceRoot, { packageRoot: ROOT }),
325
+ scans: readScanCache(scanCachePath(workspaceRoot)),
326
+ };
327
+ }
328
+
329
+ /**
330
+ * Load one root, or several, with the FIRST occurrence of a QUALIFIED name winning.
331
+ *
332
+ * **It used to dedupe on the bare name, and that was the defect.** Every root is
333
+ * read, so a second package's `design-system` in `~/.claude/skills` and ours both
334
+ * reached this loop — and whichever root came second was dropped, silently, with
335
+ * the surviving row printing one bare name. The reader could not tell which skill
336
+ * the route line meant, and in the direction where the neighbour came first, ours
337
+ * was simply gone.
338
+ *
339
+ * Deduping on the qualified name keeps the only collision that is genuinely a
340
+ * duplicate — the same PACKAGE skill reached through two roots, which is the
341
+ * authored tree beside its own projection — and lets a collision between two
342
+ * different owners rank twice, which is the thing a reader needs to see. A
343
+ * no-manifest tree labels everything `package` (`makeOriginResolver`), so there
344
+ * the behavior is byte-identical to the bare-name dedupe it replaced.
345
+ */
346
+ function _load_skills_across(
347
+ roots: readonly string[],
348
+ opts: RankOptions = {},
349
+ ctx?: NeighbourContext,
350
+ ): Skill[] {
351
+ const context = ctx ?? defaultNeighbourContext();
183
352
  const out: Skill[] = [];
184
353
  const seen = new Set<string>();
185
354
  for (const root of roots) {
186
- for (const s of _load_skills(root)) {
187
- if (seen.has(s.name)) continue;
188
- seen.add(s.name);
355
+ for (const s of _load_skills(root, opts, context)) {
356
+ if (seen.has(s.qualified)) continue;
357
+ seen.add(s.qualified);
189
358
  out.push(s);
190
359
  }
191
360
  }
192
361
  return out;
193
362
  }
194
363
 
195
- function _load_skills(skillsDir: string): Skill[] {
364
+ /**
365
+ * One root's skills.
366
+ *
367
+ * A NEIGHBOUR whose body did not pass the shape scan is loaded with every term
368
+ * source but its name emptied — description, triggers, `## When to use`,
369
+ * headings and personas — so it ranks by name and nothing from the file can
370
+ * reach the index or, through it, the injected route line. It is NOT dropped:
371
+ * a skill hidden for a finding is a skill the reader cannot weigh, and the
372
+ * finding kind rides along on `unscanned` instead.
373
+ *
374
+ * "Did not pass" includes "was never scanned". `scanVerdict` refuses a missing
375
+ * census record and a stale digest as firmly as a real finding, which is what
376
+ * makes this a floor rather than a preference — a gate that passes on missing
377
+ * evidence is satisfied by deleting the evidence.
378
+ */
379
+ function _load_skills(
380
+ skillsDir: string,
381
+ opts: RankOptions = {},
382
+ ctx: NeighbourContext = defaultNeighbourContext(),
383
+ ): Skill[] {
384
+ // The body is parsed only when a flag indexes it. Under keyword-v1 the
385
+ // loader's work is exactly what it always was, which is what keeps the
386
+ // default path's per-prompt cost comparable to the pre-flag reading.
387
+ const wantsBody = Boolean(opts.includeWhenToUse || opts.includeHeadings);
196
388
  const skills: Skill[] = [];
197
389
  for (const skillMd of _globSkillMd(skillsDir)) {
198
- const fm = _parse_frontmatter(skillMd);
390
+ const text = fs.readFileSync(skillMd, 'utf-8');
391
+ const fm = _parse_frontmatter_text(text);
199
392
  const rawName = fm['name'];
200
393
  const name = _truthyStr(rawName) ? String(rawName) : path.basename(path.dirname(skillMd));
201
394
  const rawDesc = fm['description'];
@@ -209,12 +402,41 @@ function _load_skills(skillsDir: string): Skill[] {
209
402
  const triggerText = Array.isArray(rawTriggers)
210
403
  ? triggerTextFromFlatLines(rawTriggers as string[])
211
404
  : [];
405
+ const { whenToUse, headings } = wantsBody
406
+ ? _body_signals(_body_of(text))
407
+ : { whenToUse: '', headings: [] as string[] };
408
+ const origin = ctx.origin(skillMd);
409
+ const qualified = qualifiedSkillName(name, origin);
410
+ const verdict =
411
+ origin === 'package'
412
+ ? ({ ok: true } as const)
413
+ : scanVerdict(ctx.scans, qualified, fileDigest(skillMd));
414
+ if (!verdict.ok) {
415
+ skills.push({
416
+ name,
417
+ origin,
418
+ qualified,
419
+ unscanned: verdict.kind,
420
+ description: '',
421
+ personas: [],
422
+ terms: _tokenize(name),
423
+ triggerText: [],
424
+ whenToUseText: '',
425
+ headingText: [],
426
+ });
427
+ continue;
428
+ }
212
429
  skills.push({
213
430
  name,
431
+ origin,
432
+ qualified,
433
+ unscanned: null,
214
434
  description: desc,
215
435
  personas: personaList,
216
436
  terms: _tokenize(name + ' ' + desc),
217
437
  triggerText,
438
+ whenToUseText: whenToUse,
439
+ headingText: headings,
218
440
  });
219
441
  }
220
442
  return skills;
@@ -234,7 +456,7 @@ function _truthyStr(v: string | string[] | undefined): boolean {
234
456
  * Python sorts `Path` objects component-wise. Since every match is
235
457
  * `<dir>/SKILL.md`, sorting by the directory component reproduces that order.
236
458
  */
237
- function _globSkillMd(root: string): string[] {
459
+ export function _globSkillMd(root: string): string[] {
238
460
  let names: string[];
239
461
  try {
240
462
  names = fs.readdirSync(root);
@@ -257,38 +479,81 @@ function _globSkillMd(root: string): string[] {
257
479
  return dirs.map((name) => path.join(root, name, 'SKILL.md'));
258
480
  }
259
481
 
260
- function _score(taskTerms: Set<string>, skill: Skill, opts: RankOptions = {}): number {
261
- // Single-sourced in `src/shared/skillRanking.ts`. Under keyword-v1 (the
262
- // default) `skill.terms` is already `tokenize(name + ' ' + description)`, so
263
- // the precomputed set is reused unchanged; keyword-v2 re-derives the term
264
- // set with the skill's trigger prose folded in.
265
- const rankable = {
482
+ function _rankable(skill: Skill): {
483
+ name: string;
484
+ description: string;
485
+ personas: string[];
486
+ triggerText: string[];
487
+ whenToUseText: string;
488
+ headingText: string[];
489
+ } {
490
+ return {
266
491
  name: skill.name,
267
492
  description: skill.description,
268
493
  personas: skill.personas,
269
494
  triggerText: skill.triggerText,
495
+ whenToUseText: skill.whenToUseText,
496
+ headingText: skill.headingText,
270
497
  };
271
- const terms = opts.includeTriggers ? _sharedSkillTerms(rankable, opts) : skill.terms;
272
- return scoreSkill(taskTerms, rankable, terms);
498
+ }
499
+
500
+ /**
501
+ * The indexed term set for one skill.
502
+ *
503
+ * With no term-source flag set, `skill.terms` is already
504
+ * `tokenize(name + ' ' + description)` and the precomputed set is reused
505
+ * unchanged; a flag that widens the source re-derives it with that source
506
+ * folded in. Separated from `_score` so the caller can build each set ONCE and
507
+ * share it between the document-frequency pass and the scoring loop.
508
+ */
509
+ function _terms(skill: Skill, opts: RankOptions): ReadonlySet<string> {
510
+ return widensTermSource(opts) ? _sharedSkillTerms(_rankable(skill), opts) : skill.terms;
511
+ }
512
+
513
+ function _score(
514
+ taskTerms: Set<string>,
515
+ skill: Skill,
516
+ terms: ReadonlySet<string>,
517
+ opts: RankOptions = {},
518
+ stats?: TermStats,
519
+ ): number {
520
+ // Single-sourced in `src/shared/skillRanking.ts`.
521
+ return scoreSkill(taskTerms, _rankable(skill), terms, opts, stats);
273
522
  }
274
523
 
275
524
  export type RankRow = [string, number, string[]];
276
525
 
277
526
  /**
278
527
  * @param skillsDir one root, or several to rank across (see `_load_skills_across`).
528
+ * @param ctx origin + scan context; omitted, it is built from {@link ROOT}.
529
+ *
530
+ * Row names are QUALIFIED (`project:design-system`) for a neighbour and bare for
531
+ * ours, so two same-named skills are two distinguishable rows rather than one
532
+ * ambiguous one. On a tree with no installed-tools manifest every skill resolves
533
+ * to `package` and every row is bare, which is what it was before.
279
534
  */
280
535
  export function rank(
281
536
  task: string,
282
537
  skillsDir: string | readonly string[],
283
538
  opts: RankOptions = {},
539
+ ctx?: NeighbourContext,
284
540
  ): RankRow[] {
285
541
  const taskTerms = _tokenize(task);
286
- const skills = _load_skills_across(typeof skillsDir === 'string' ? [skillsDir] : skillsDir);
542
+ const skills = _load_skills_across(
543
+ typeof skillsDir === 'string' ? [skillsDir] : skillsDir,
544
+ opts,
545
+ ctx,
546
+ );
547
+ // ONE term set per skill, shared between the document-frequency pass and the
548
+ // scoring loop — the two used to tokenize the whole catalogue separately.
549
+ const termSets = skills.map((s) => _terms(s, opts));
550
+ const stats = opts.idfWeighting ? buildTermStats(skills.map(_rankable), termSets) : undefined;
287
551
  const rows: RankRow[] = [];
288
- for (const s of skills) {
289
- const score = _score(taskTerms, s, opts);
552
+ for (let i = 0; i < skills.length; i += 1) {
553
+ const s = skills[i] as Skill;
554
+ const score = _score(taskTerms, s, termSets[i] as ReadonlySet<string>, opts, stats);
290
555
  if (score > 0) {
291
- rows.push([s.name, score, [...s.personas]]);
556
+ rows.push([s.qualified, score, [...s.personas]]);
292
557
  }
293
558
  }
294
559
  // rows.sort(key=lambda r: (-r[1], r[0])) — Python stable tuple sort.
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env -S node --import tsx
1
+ #!/usr/bin/env tsx
2
2
  /**
3
3
  * sweep_dead_scan_roots — which gate scripts walk a root that does not exist?
4
4
  *
@@ -0,0 +1,129 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * sweep_skill_ranker_signals — every candidate signal, alone, on both slices.
4
+ *
5
+ * `road-to-a-ranker-that-routes` 2.2 asks for top-1, top-3 and MRR with
6
+ * intervals for each candidate flag measured ALONE, and the flags are a table in
7
+ * `measure_skill_ranker_baseline.RANKER_LABELS`. This script is the thing that
8
+ * produces that table, and it exists as a committed script rather than a
9
+ * one-off because a number nobody can regenerate is a claim rather than a
10
+ * measurement.
11
+ *
12
+ * IT PRINTS BOTH SLICES, and the two are read for different purposes. The
13
+ * TUNING reading is what a signal may be CHOSEN on. The SEALED reading is the
14
+ * only one a lift may be CLAIMED on. Printing only the sealed column would
15
+ * invite choosing on it, which is the one thing the partition exists to stop;
16
+ * printing only the tuning column would leave the claim unsupported.
17
+ *
18
+ * Usage:
19
+ * ./scripts-run src/scripts/sweep_skill_ranker_signals
20
+ * ./scripts-run src/scripts/sweep_skill_ranker_signals keyword-v1 idf
21
+ * ./scripts-run src/scripts/sweep_skill_ranker_signals --json
22
+ */
23
+
24
+ import * as path from 'node:path';
25
+ import { fileURLToPath } from 'node:url';
26
+
27
+ import { wilsonInterval } from './_lib/capture_rate.js';
28
+ import {
29
+ RANKER_LABELS,
30
+ REPO,
31
+ SKILLS_DIR,
32
+ type SliceName,
33
+ isKnownRanker,
34
+ partitionBySlice,
35
+ readMatrixLabelledPrompts,
36
+ } from './measure_skill_ranker_baseline.js';
37
+ import { meanReciprocalRank, readRows } from './report_skill_ranker_confusion.js';
38
+
39
+ export interface SweepRow {
40
+ label: string;
41
+ slice: SliceName;
42
+ n: number;
43
+ top1: number;
44
+ top1_ci95: { lower: number; upper: number };
45
+ top3: number;
46
+ top3_ci95: { lower: number; upper: number };
47
+ mrr: number;
48
+ }
49
+
50
+ function round3(n: number): number {
51
+ return Math.round(n * 1000) / 1000;
52
+ }
53
+
54
+ function ci(successes: number, trials: number): { lower: number; upper: number } {
55
+ const raw = wilsonInterval(successes, trials);
56
+ return { lower: round3(raw.lower), upper: round3(raw.upper) };
57
+ }
58
+
59
+ /**
60
+ * Every configuration on both slices, ONE ranking pass per prompt.
61
+ *
62
+ * `rank()` re-globs and re-reads the whole SKILL.md catalogue on every call, so
63
+ * it is the dominant cost by a wide margin and ranking each prompt twice doubles
64
+ * the whole sweep. The earlier shape took top-1/top-3 from `measureAccuracy` and
65
+ * MRR from a second pass in `readRows`, which also derived the row set from two
66
+ * independent corpus reads — so a future divergence between them would have been
67
+ * silent rather than loud. All three rates now come off the same readings of the
68
+ * same rows.
69
+ */
70
+ export function sweep(labels: readonly string[], repo = REPO, skillsDir = SKILLS_DIR): SweepRow[] {
71
+ const whole = readMatrixLabelledPrompts(repo);
72
+ const out: SweepRow[] = [];
73
+ for (const label of labels) {
74
+ for (const slice of ['tuning', 'sealed'] as const) {
75
+ const rows = partitionBySlice(whole, slice);
76
+ const readings = readRows(rows, skillsDir, label);
77
+ const n = readings.length;
78
+ const t1 = readings.filter((r) => r.rankOfExpected === 1).length;
79
+ const t3 = readings.filter((r) => r.rankOfExpected >= 1 && r.rankOfExpected <= 3).length;
80
+ out.push({
81
+ label,
82
+ slice,
83
+ n,
84
+ top1: n ? round3(t1 / n) : 0,
85
+ top1_ci95: ci(t1, n),
86
+ top3: n ? round3(t3 / n) : 0,
87
+ top3_ci95: ci(t3, n),
88
+ mrr: round3(meanReciprocalRank(readings)),
89
+ });
90
+ }
91
+ }
92
+ return out;
93
+ }
94
+
95
+ export function renderTable(rows: readonly SweepRow[]): string {
96
+ const L = ['| configuration | slice | n | top-1 | 95 % CI | top-3 | 95 % CI | MRR |', '|---|---|---:|---:|---|---:|---|---:|'];
97
+ for (const r of rows) {
98
+ L.push(
99
+ `| \`${r.label}\` | ${r.slice} | ${String(r.n)} | ${r.top1.toFixed(3)} | ` +
100
+ `${r.top1_ci95.lower.toFixed(3)} – ${r.top1_ci95.upper.toFixed(3)} | ${r.top3.toFixed(3)} | ` +
101
+ `${r.top3_ci95.lower.toFixed(3)} – ${r.top3_ci95.upper.toFixed(3)} | ${r.mrr.toFixed(3)} |`,
102
+ );
103
+ }
104
+ return `${L.join('\n')}\n`;
105
+ }
106
+
107
+ export function main(argv: readonly string[]): number {
108
+ const json = argv.includes('--json');
109
+ const named = argv.filter((a) => !a.startsWith('--'));
110
+ const labels = named.length > 0 ? named : Object.keys(RANKER_LABELS);
111
+ // `isKnownRanker` (Object.hasOwn), not `in`: `in` walks the prototype chain,
112
+ // so `constructor` and `toString` would pass here while `Object.keys` below
113
+ // prints a set that does not contain them — two answers to one question.
114
+ const unknown = labels.filter((l) => !isKnownRanker(l));
115
+ if (unknown.length > 0) {
116
+ process.stderr.write(
117
+ `sweep_skill_ranker_signals: unknown configuration(s) ${unknown.join(', ')}; ` +
118
+ `known: ${Object.keys(RANKER_LABELS).join(', ')}\n`,
119
+ );
120
+ return 2;
121
+ }
122
+ const rows = sweep(labels);
123
+ process.stdout.write(json ? `${JSON.stringify(rows, null, 2)}\n` : renderTable(rows));
124
+ return 0;
125
+ }
126
+
127
+ if (process.argv[1] && fileURLToPath(import.meta.url) === path.resolve(process.argv[1])) {
128
+ process.exit(main(process.argv.slice(2)));
129
+ }