@bonesofspring/ai-rules 0.2.20 → 0.2.22

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 (505) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +17 -2
  3. package/bin/cli.js +83 -6
  4. package/package.json +5 -2
  5. package/presets/_shared/README.md +2 -1
  6. package/presets/_shared/assets/docs-specs/INDEX.md +4 -1
  7. package/presets/_shared/core/agent-team/agent-artifact-contracts.md +15 -0
  8. package/presets/_shared/core/agent-team/agent-task-metrics.md +1 -1
  9. package/presets/_shared/core/agent-team/agent-team-orchestrator.md +1 -3
  10. package/presets/_shared/core/meta/preset-pr-checklist.md +5 -1
  11. package/presets/_shared/core/meta/preset-token-budget.md +7 -3
  12. package/presets/_shared/core/meta/preset-twin-sync.md +2 -0
  13. package/presets/_shared/core/testing/testing-principles.md +70 -0
  14. package/presets/claude/android-kotlin/agents/README.md +2 -1
  15. package/presets/claude/android-kotlin/agents/build-verifier.md +2 -0
  16. package/presets/claude/android-kotlin/agents/code-reviewer.md +2 -0
  17. package/presets/claude/android-kotlin/agents/debugger.md +1 -0
  18. package/presets/claude/android-kotlin/agents/feature-developer.md +4 -1
  19. package/presets/claude/android-kotlin/agents/openspec-author.md +163 -0
  20. package/presets/claude/android-kotlin/agents/qa-tester.md +2 -0
  21. package/presets/claude/android-kotlin/agents/task-analyst.md +1 -1
  22. package/presets/claude/android-kotlin/agents/task-router.md +9 -1
  23. package/presets/claude/android-kotlin/agents/tech-writer.md +4 -0
  24. package/presets/claude/android-kotlin/commands/README.md +0 -2
  25. package/presets/claude/android-kotlin/commands/task-continue.md +1 -1
  26. package/presets/claude/android-kotlin/commands/task.md +1 -5
  27. package/presets/claude/android-kotlin/commands/technical-retro.md +2 -2
  28. package/presets/claude/android-kotlin/hooks/chain-team-phases.sh +105 -13
  29. package/presets/claude/android-kotlin/rules/README.md +1 -0
  30. package/presets/claude/android-kotlin/rules/tooling-and-review/agent-team-orchestrator.md +7 -4
  31. package/presets/claude/android-kotlin/rules/tooling-and-review/ai-local-overlay.md +48 -0
  32. package/presets/claude/android-kotlin/rules/tooling-and-review/preset-pr-checklist.md +5 -1
  33. package/presets/claude/android-kotlin/rules/tooling-and-review/preset-token-budget.md +7 -3
  34. package/presets/claude/android-kotlin/rules/tooling-and-review/preset-twin-sync.md +2 -0
  35. package/presets/claude/go/README.md +1 -1
  36. package/presets/claude/go/agents/README.md +3 -2
  37. package/presets/claude/go/agents/build-verifier.md +4 -0
  38. package/presets/claude/go/agents/code-reviewer.md +4 -0
  39. package/presets/claude/go/agents/debugger.md +4 -0
  40. package/presets/claude/go/agents/feature-developer.md +5 -0
  41. package/presets/claude/go/agents/openspec-author.md +163 -0
  42. package/presets/claude/go/agents/qa-tester.md +4 -0
  43. package/presets/claude/go/agents/task-router.md +9 -1
  44. package/presets/claude/go/agents/tech-writer.md +4 -0
  45. package/presets/claude/go/commands/README.md +0 -2
  46. package/presets/claude/go/commands/task-continue.md +1 -1
  47. package/presets/claude/go/commands/task.md +1 -4
  48. package/presets/claude/go/hooks/chain-team-phases.sh +105 -14
  49. package/presets/claude/go/rules/README.md +1 -0
  50. package/presets/claude/go/rules/tooling-and-review/agent-team-orchestrator.md +2 -4
  51. package/presets/claude/go/rules/tooling-and-review/ai-local-overlay.md +48 -0
  52. package/presets/claude/go/rules/tooling-and-review/preset-pr-checklist.md +5 -1
  53. package/presets/claude/go/rules/tooling-and-review/preset-token-budget.md +7 -3
  54. package/presets/claude/go/rules/tooling-and-review/preset-twin-sync.md +2 -0
  55. package/presets/claude/ios-swift/agents/README.md +3 -2
  56. package/presets/claude/ios-swift/agents/build-verifier.md +2 -0
  57. package/presets/claude/ios-swift/agents/code-reviewer.md +2 -0
  58. package/presets/claude/ios-swift/agents/debugger.md +1 -0
  59. package/presets/claude/ios-swift/agents/feature-developer.md +4 -1
  60. package/presets/claude/ios-swift/agents/openspec-author.md +163 -0
  61. package/presets/claude/ios-swift/agents/qa-tester.md +2 -0
  62. package/presets/claude/ios-swift/agents/task-analyst.md +1 -1
  63. package/presets/claude/ios-swift/agents/task-router.md +9 -1
  64. package/presets/claude/ios-swift/agents/tech-writer.md +4 -0
  65. package/presets/claude/ios-swift/commands/README.md +0 -2
  66. package/presets/claude/ios-swift/commands/task-continue.md +1 -1
  67. package/presets/claude/ios-swift/commands/task.md +1 -5
  68. package/presets/claude/ios-swift/commands/technical-retro.md +2 -2
  69. package/presets/claude/ios-swift/hooks/chain-team-phases.sh +105 -13
  70. package/presets/claude/ios-swift/rules/README.md +1 -0
  71. package/presets/claude/ios-swift/rules/tooling-and-review/agent-team-orchestrator.md +7 -4
  72. package/presets/claude/ios-swift/rules/tooling-and-review/ai-local-overlay.md +48 -0
  73. package/presets/claude/ios-swift/rules/tooling-and-review/preset-pr-checklist.md +5 -1
  74. package/presets/claude/ios-swift/rules/tooling-and-review/preset-token-budget.md +7 -3
  75. package/presets/claude/ios-swift/rules/tooling-and-review/preset-twin-sync.md +2 -0
  76. package/presets/claude/java/CLAUDE.md +1 -1
  77. package/presets/claude/java/agents/README.md +3 -2
  78. package/presets/claude/java/agents/build-verifier.md +4 -0
  79. package/presets/claude/java/agents/code-reviewer.md +4 -0
  80. package/presets/claude/java/agents/debugger.md +4 -0
  81. package/presets/claude/java/agents/feature-developer.md +5 -0
  82. package/presets/claude/java/agents/openspec-author.md +163 -0
  83. package/presets/claude/java/agents/qa-tester.md +4 -0
  84. package/presets/claude/java/agents/task-router.md +9 -1
  85. package/presets/claude/java/agents/tech-writer.md +4 -0
  86. package/presets/claude/java/commands/README.md +0 -2
  87. package/presets/claude/java/commands/task-continue.md +1 -1
  88. package/presets/claude/java/commands/task.md +1 -4
  89. package/presets/claude/java/hooks/chain-team-phases.sh +105 -14
  90. package/presets/claude/java/rules/README.md +1 -0
  91. package/presets/claude/java/rules/tooling-and-review/agent-team-orchestrator.md +2 -4
  92. package/presets/claude/java/rules/tooling-and-review/ai-local-overlay.md +48 -0
  93. package/presets/claude/java/rules/tooling-and-review/preset-pr-checklist.md +5 -1
  94. package/presets/claude/java/rules/tooling-and-review/preset-token-budget.md +7 -3
  95. package/presets/claude/java/rules/tooling-and-review/preset-twin-sync.md +2 -0
  96. package/presets/claude/mcp-ts/agents/build-verifier.md +4 -0
  97. package/presets/claude/mcp-ts/agents/feature-developer.md +5 -0
  98. package/presets/claude/mcp-ts/agents/task-analyst.md +1 -1
  99. package/presets/claude/mcp-ts/agents/task-router.md +1 -1
  100. package/presets/claude/mcp-ts/commands/README.md +0 -2
  101. package/presets/claude/mcp-ts/commands/task-continue.md +1 -1
  102. package/presets/claude/mcp-ts/commands/task.md +1 -4
  103. package/presets/claude/mcp-ts/commands/technical-retro.md +2 -2
  104. package/presets/claude/mcp-ts/hooks/chain-team-phases.sh +91 -20
  105. package/presets/claude/mcp-ts/rules/README.md +1 -0
  106. package/presets/claude/mcp-ts/rules/tooling-and-review/agent-team-orchestrator.md +2 -4
  107. package/presets/claude/mcp-ts/rules/tooling-and-review/ai-local-overlay.md +48 -0
  108. package/presets/claude/mcp-ts/rules/tooling-and-review/preset-pr-checklist.md +5 -1
  109. package/presets/claude/mcp-ts/rules/tooling-and-review/preset-token-budget.md +7 -3
  110. package/presets/claude/mcp-ts/rules/tooling-and-review/preset-twin-sync.md +2 -0
  111. package/presets/claude/next/README.md +1 -0
  112. package/presets/claude/next/agents/README.md +2 -2
  113. package/presets/claude/next/agents/build-verifier.md +13 -1
  114. package/presets/claude/next/agents/code-reviewer.md +2 -0
  115. package/presets/claude/next/agents/debugger.md +4 -0
  116. package/presets/claude/next/agents/feature-developer.md +4 -1
  117. package/presets/claude/next/agents/openspec-author.md +163 -0
  118. package/presets/claude/next/agents/qa-tester.md +4 -0
  119. package/presets/claude/next/agents/task-analyst.md +1 -1
  120. package/presets/claude/next/agents/task-router.md +5 -1
  121. package/presets/claude/next/agents/tech-writer.md +4 -0
  122. package/presets/claude/next/agents/unit-test-generator.md +1 -1
  123. package/presets/claude/next/agents/unit-test-planner.md +1 -1
  124. package/presets/claude/next/commands/README.md +0 -2
  125. package/presets/claude/next/commands/task-continue.md +1 -1
  126. package/presets/claude/next/commands/task.md +1 -4
  127. package/presets/claude/next/hooks/chain-team-phases.sh +105 -13
  128. package/presets/claude/next/rules/README.md +1 -0
  129. package/presets/claude/next/rules/api-and-data/http-client.md +1 -1
  130. package/presets/claude/next/rules/architecture/reference-features.md +1 -1
  131. package/presets/claude/next/rules/testing/README.md +7 -1
  132. package/presets/claude/next/rules/testing/tests-e2e-structure.md +86 -48
  133. package/presets/claude/next/rules/testing/tests-unit.md +78 -51
  134. package/presets/claude/next/rules/tooling-and-review/agent-team-orchestrator.md +3 -4
  135. package/presets/claude/next/rules/tooling-and-review/ai-local-overlay.md +48 -0
  136. package/presets/claude/next/rules/tooling-and-review/preset-pr-checklist.md +5 -1
  137. package/presets/claude/next/rules/tooling-and-review/preset-token-budget.md +7 -3
  138. package/presets/claude/next/rules/tooling-and-review/preset-twin-sync.md +2 -0
  139. package/presets/claude/next/rules/ui-and-accessibility/react-ui.md +1 -1
  140. package/presets/claude/next/skills/playwright-e2e/SKILL.md +5 -3
  141. package/presets/claude/next/skills/unit-testing/SKILL.md +6 -4
  142. package/presets/claude/next/team/README.md +0 -3
  143. package/presets/claude/nuxt/agents/README.md +1 -1
  144. package/presets/claude/nuxt/agents/build-verifier.md +2 -0
  145. package/presets/claude/nuxt/agents/code-reviewer.md +2 -0
  146. package/presets/claude/nuxt/agents/debugger.md +4 -0
  147. package/presets/claude/nuxt/agents/feature-developer.md +4 -1
  148. package/presets/claude/nuxt/agents/openspec-author.md +163 -0
  149. package/presets/claude/nuxt/agents/qa-tester.md +4 -0
  150. package/presets/claude/nuxt/agents/task-analyst.md +1 -1
  151. package/presets/claude/nuxt/agents/task-router.md +5 -1
  152. package/presets/claude/nuxt/agents/tech-writer.md +4 -0
  153. package/presets/claude/nuxt/commands/README.md +0 -2
  154. package/presets/claude/nuxt/commands/task-continue.md +1 -1
  155. package/presets/claude/nuxt/commands/task.md +1 -5
  156. package/presets/claude/nuxt/commands/technical-retro.md +2 -2
  157. package/presets/claude/nuxt/hooks/chain-team-phases.sh +105 -13
  158. package/presets/claude/nuxt/rules/README.md +1 -0
  159. package/presets/claude/nuxt/rules/testing/README.md +6 -0
  160. package/presets/claude/nuxt/rules/testing/tests-e2e-structure.md +86 -43
  161. package/presets/claude/nuxt/rules/testing/tests-unit.md +58 -45
  162. package/presets/claude/nuxt/rules/tooling-and-review/agent-team-orchestrator.md +8 -5
  163. package/presets/claude/nuxt/rules/tooling-and-review/ai-local-overlay.md +48 -0
  164. package/presets/claude/nuxt/rules/tooling-and-review/preset-pr-checklist.md +5 -1
  165. package/presets/claude/nuxt/rules/tooling-and-review/preset-token-budget.md +7 -3
  166. package/presets/claude/nuxt/rules/tooling-and-review/preset-twin-sync.md +2 -0
  167. package/presets/claude/nuxt/team/README.md +0 -3
  168. package/presets/claude/php-hexagonal/CLAUDE.md +1 -1
  169. package/presets/claude/php-hexagonal/agents/README.md +3 -2
  170. package/presets/claude/php-hexagonal/agents/build-verifier.md +4 -0
  171. package/presets/claude/php-hexagonal/agents/code-reviewer.md +4 -0
  172. package/presets/claude/php-hexagonal/agents/debugger.md +4 -0
  173. package/presets/claude/php-hexagonal/agents/feature-developer.md +5 -0
  174. package/presets/claude/php-hexagonal/agents/openspec-author.md +163 -0
  175. package/presets/claude/php-hexagonal/agents/qa-tester.md +4 -0
  176. package/presets/claude/php-hexagonal/agents/task-router.md +9 -1
  177. package/presets/claude/php-hexagonal/agents/tech-writer.md +4 -0
  178. package/presets/claude/php-hexagonal/commands/README.md +0 -2
  179. package/presets/claude/php-hexagonal/commands/task-continue.md +1 -1
  180. package/presets/claude/php-hexagonal/commands/task.md +1 -4
  181. package/presets/claude/php-hexagonal/hooks/chain-team-phases.sh +105 -14
  182. package/presets/claude/php-hexagonal/rules/README.md +1 -0
  183. package/presets/claude/php-hexagonal/rules/tooling-and-review/agent-team-orchestrator.md +2 -4
  184. package/presets/claude/php-hexagonal/rules/tooling-and-review/ai-local-overlay.md +48 -0
  185. package/presets/claude/php-hexagonal/rules/tooling-and-review/preset-pr-checklist.md +5 -1
  186. package/presets/claude/php-hexagonal/rules/tooling-and-review/preset-token-budget.md +7 -3
  187. package/presets/claude/php-hexagonal/rules/tooling-and-review/preset-twin-sync.md +2 -0
  188. package/presets/claude/php-laravel/agents/README.md +3 -2
  189. package/presets/claude/php-laravel/agents/build-verifier.md +4 -0
  190. package/presets/claude/php-laravel/agents/code-reviewer.md +4 -0
  191. package/presets/claude/php-laravel/agents/debugger.md +4 -0
  192. package/presets/claude/php-laravel/agents/feature-developer.md +5 -0
  193. package/presets/claude/php-laravel/agents/openspec-author.md +163 -0
  194. package/presets/claude/php-laravel/agents/qa-tester.md +4 -0
  195. package/presets/claude/php-laravel/agents/task-router.md +6 -1
  196. package/presets/claude/php-laravel/agents/tech-writer.md +4 -0
  197. package/presets/claude/php-laravel/commands/README.md +0 -2
  198. package/presets/claude/php-laravel/commands/task-continue.md +1 -1
  199. package/presets/claude/php-laravel/commands/task.md +1 -4
  200. package/presets/claude/php-laravel/hooks/chain-team-phases.sh +105 -14
  201. package/presets/claude/php-laravel/rules/README.md +1 -0
  202. package/presets/claude/php-laravel/rules/tooling-and-review/agent-team-orchestrator.md +2 -4
  203. package/presets/claude/php-laravel/rules/tooling-and-review/ai-local-overlay.md +48 -0
  204. package/presets/claude/php-laravel/rules/tooling-and-review/preset-pr-checklist.md +5 -1
  205. package/presets/claude/php-laravel/rules/tooling-and-review/preset-token-budget.md +7 -3
  206. package/presets/claude/php-laravel/rules/tooling-and-review/preset-twin-sync.md +2 -0
  207. package/presets/claude/svelte/agents/README.md +1 -1
  208. package/presets/claude/svelte/agents/build-verifier.md +2 -0
  209. package/presets/claude/svelte/agents/code-reviewer.md +2 -0
  210. package/presets/claude/svelte/agents/debugger.md +4 -0
  211. package/presets/claude/svelte/agents/feature-developer.md +4 -1
  212. package/presets/claude/svelte/agents/openspec-author.md +163 -0
  213. package/presets/claude/svelte/agents/qa-tester.md +4 -0
  214. package/presets/claude/svelte/agents/task-analyst.md +1 -1
  215. package/presets/claude/svelte/agents/task-router.md +5 -1
  216. package/presets/claude/svelte/agents/tech-writer.md +4 -0
  217. package/presets/claude/svelte/commands/README.md +0 -2
  218. package/presets/claude/svelte/commands/task-continue.md +1 -1
  219. package/presets/claude/svelte/commands/task.md +1 -5
  220. package/presets/claude/svelte/commands/technical-retro.md +2 -2
  221. package/presets/claude/svelte/hooks/chain-team-phases.sh +105 -13
  222. package/presets/claude/svelte/rules/README.md +1 -0
  223. package/presets/claude/svelte/rules/testing/README.md +6 -0
  224. package/presets/claude/svelte/rules/testing/tests-e2e-structure.md +87 -45
  225. package/presets/claude/svelte/rules/testing/tests-unit.md +70 -23
  226. package/presets/claude/svelte/rules/tooling-and-review/agent-team-orchestrator.md +8 -5
  227. package/presets/claude/svelte/rules/tooling-and-review/ai-local-overlay.md +48 -0
  228. package/presets/claude/svelte/rules/tooling-and-review/preset-pr-checklist.md +5 -1
  229. package/presets/claude/svelte/rules/tooling-and-review/preset-token-budget.md +7 -3
  230. package/presets/claude/svelte/rules/tooling-and-review/preset-twin-sync.md +2 -0
  231. package/presets/claude/svelte/team/README.md +0 -3
  232. package/presets/cursor/android-kotlin/agents/README.md +2 -1
  233. package/presets/cursor/android-kotlin/agents/build-verifier.md +2 -0
  234. package/presets/cursor/android-kotlin/agents/code-reviewer.md +2 -0
  235. package/presets/cursor/android-kotlin/agents/debugger.md +1 -0
  236. package/presets/cursor/android-kotlin/agents/feature-developer.md +4 -1
  237. package/presets/cursor/android-kotlin/agents/openspec-author.md +164 -0
  238. package/presets/cursor/android-kotlin/agents/qa-tester.md +2 -0
  239. package/presets/cursor/android-kotlin/agents/task-analyst.md +1 -1
  240. package/presets/cursor/android-kotlin/agents/task-router.md +9 -1
  241. package/presets/cursor/android-kotlin/agents/tech-writer.md +4 -0
  242. package/presets/cursor/android-kotlin/commands/README.md +0 -2
  243. package/presets/cursor/android-kotlin/commands/task-continue.md +1 -1
  244. package/presets/cursor/android-kotlin/commands/task.md +1 -5
  245. package/presets/cursor/android-kotlin/commands/technical-retro.md +2 -2
  246. package/presets/cursor/android-kotlin/hooks/chain-team-phases.sh +105 -13
  247. package/presets/cursor/android-kotlin/rules/agent-team-orchestrator.mdc +7 -4
  248. package/presets/cursor/android-kotlin/rules/ai-local-overlay.mdc +43 -0
  249. package/presets/cursor/android-kotlin/rules/preset-pr-checklist.mdc +5 -1
  250. package/presets/cursor/android-kotlin/rules/preset-token-budget.mdc +7 -3
  251. package/presets/cursor/android-kotlin/rules/preset-twin-sync.mdc +2 -0
  252. package/presets/cursor/go/README.md +6 -6
  253. package/presets/cursor/go/agents/README.md +3 -2
  254. package/presets/cursor/go/agents/build-verifier.md +4 -0
  255. package/presets/cursor/go/agents/code-reviewer.md +4 -0
  256. package/presets/cursor/go/agents/debugger.md +4 -0
  257. package/presets/cursor/go/agents/feature-developer.md +5 -0
  258. package/presets/cursor/go/agents/openspec-author.md +164 -0
  259. package/presets/cursor/go/agents/qa-tester.md +4 -0
  260. package/presets/cursor/go/agents/task-router.md +9 -1
  261. package/presets/cursor/go/agents/tech-writer.md +4 -0
  262. package/presets/cursor/go/commands/README.md +0 -2
  263. package/presets/cursor/go/commands/task-continue.md +1 -1
  264. package/presets/cursor/go/commands/task.md +1 -4
  265. package/presets/cursor/go/commands/technical-retro.md +2 -2
  266. package/presets/cursor/go/hooks/chain-team-phases.sh +105 -14
  267. package/presets/cursor/go/rules/agent-team-orchestrator.mdc +2 -4
  268. package/presets/cursor/go/rules/ai-local-overlay.mdc +43 -0
  269. package/presets/cursor/go/rules/preset-pr-checklist.mdc +5 -1
  270. package/presets/cursor/go/rules/preset-token-budget.mdc +7 -3
  271. package/presets/cursor/go/rules/preset-twin-sync.mdc +2 -0
  272. package/presets/cursor/ios-swift/README.md +6 -6
  273. package/presets/cursor/ios-swift/agents/README.md +3 -2
  274. package/presets/cursor/ios-swift/agents/build-verifier.md +2 -0
  275. package/presets/cursor/ios-swift/agents/code-reviewer.md +2 -0
  276. package/presets/cursor/ios-swift/agents/debugger.md +1 -0
  277. package/presets/cursor/ios-swift/agents/feature-developer.md +4 -1
  278. package/presets/cursor/ios-swift/agents/openspec-author.md +164 -0
  279. package/presets/cursor/ios-swift/agents/qa-tester.md +2 -0
  280. package/presets/cursor/ios-swift/agents/task-analyst.md +1 -1
  281. package/presets/cursor/ios-swift/agents/task-router.md +9 -1
  282. package/presets/cursor/ios-swift/agents/tech-writer.md +4 -0
  283. package/presets/cursor/ios-swift/commands/README.md +1 -3
  284. package/presets/cursor/ios-swift/commands/task-continue.md +1 -1
  285. package/presets/cursor/ios-swift/commands/task.md +1 -5
  286. package/presets/cursor/ios-swift/commands/technical-retro.md +2 -2
  287. package/presets/cursor/ios-swift/hooks/chain-team-phases.sh +105 -13
  288. package/presets/cursor/ios-swift/rules/agent-team-orchestrator.mdc +7 -4
  289. package/presets/cursor/ios-swift/rules/ai-local-overlay.mdc +43 -0
  290. package/presets/cursor/ios-swift/rules/preset-pr-checklist.mdc +5 -1
  291. package/presets/cursor/ios-swift/rules/preset-token-budget.mdc +7 -3
  292. package/presets/cursor/ios-swift/rules/preset-twin-sync.mdc +2 -0
  293. package/presets/cursor/java/AGENTS.md +1 -1
  294. package/presets/cursor/java/agents/README.md +3 -2
  295. package/presets/cursor/java/agents/build-verifier.md +4 -0
  296. package/presets/cursor/java/agents/code-reviewer.md +4 -0
  297. package/presets/cursor/java/agents/debugger.md +4 -0
  298. package/presets/cursor/java/agents/feature-developer.md +5 -0
  299. package/presets/cursor/java/agents/openspec-author.md +164 -0
  300. package/presets/cursor/java/agents/qa-tester.md +4 -0
  301. package/presets/cursor/java/agents/task-router.md +9 -1
  302. package/presets/cursor/java/agents/tech-writer.md +4 -0
  303. package/presets/cursor/java/commands/README.md +0 -2
  304. package/presets/cursor/java/commands/task-continue.md +1 -1
  305. package/presets/cursor/java/commands/task.md +1 -4
  306. package/presets/cursor/java/commands/technical-retro.md +2 -2
  307. package/presets/cursor/java/hooks/chain-team-phases.sh +105 -14
  308. package/presets/cursor/java/rules/agent-team-orchestrator.mdc +2 -4
  309. package/presets/cursor/java/rules/ai-local-overlay.mdc +43 -0
  310. package/presets/cursor/java/rules/preset-pr-checklist.mdc +5 -1
  311. package/presets/cursor/java/rules/preset-token-budget.mdc +7 -3
  312. package/presets/cursor/java/rules/preset-twin-sync.mdc +2 -0
  313. package/presets/cursor/mcp-ts/agents/build-verifier.md +4 -0
  314. package/presets/cursor/mcp-ts/agents/feature-developer.md +5 -0
  315. package/presets/cursor/mcp-ts/agents/task-analyst.md +1 -1
  316. package/presets/cursor/mcp-ts/agents/task-router.md +1 -1
  317. package/presets/cursor/mcp-ts/commands/README.md +0 -2
  318. package/presets/cursor/mcp-ts/commands/task-continue.md +1 -1
  319. package/presets/cursor/mcp-ts/commands/task.md +1 -4
  320. package/presets/cursor/mcp-ts/commands/technical-retro.md +2 -2
  321. package/presets/cursor/mcp-ts/hooks/chain-team-phases.sh +91 -20
  322. package/presets/cursor/mcp-ts/rules/agent-team-orchestrator.mdc +2 -4
  323. package/presets/cursor/mcp-ts/rules/ai-local-overlay.mdc +43 -0
  324. package/presets/cursor/mcp-ts/rules/preset-pr-checklist.mdc +5 -1
  325. package/presets/cursor/mcp-ts/rules/preset-token-budget.mdc +7 -3
  326. package/presets/cursor/mcp-ts/rules/preset-twin-sync.mdc +2 -0
  327. package/presets/cursor/next/README.md +8 -6
  328. package/presets/cursor/next/REPO_AGENTS.md +8 -0
  329. package/presets/cursor/next/agents/README.md +2 -2
  330. package/presets/cursor/next/agents/build-verifier.md +13 -1
  331. package/presets/cursor/next/agents/code-reviewer.md +2 -0
  332. package/presets/cursor/next/agents/debugger.md +4 -0
  333. package/presets/cursor/next/agents/feature-developer.md +4 -1
  334. package/presets/cursor/next/agents/openspec-author.md +164 -0
  335. package/presets/cursor/next/agents/qa-tester.md +4 -0
  336. package/presets/cursor/next/agents/task-analyst.md +1 -1
  337. package/presets/cursor/next/agents/task-router.md +5 -1
  338. package/presets/cursor/next/agents/tech-writer.md +4 -0
  339. package/presets/cursor/next/agents/unit-test-generator.md +1 -1
  340. package/presets/cursor/next/agents/unit-test-planner.md +1 -1
  341. package/presets/cursor/next/commands/README.md +0 -2
  342. package/presets/cursor/next/commands/task-continue.md +1 -1
  343. package/presets/cursor/next/commands/task.md +1 -4
  344. package/presets/cursor/next/commands/technical-retro.md +2 -2
  345. package/presets/cursor/next/hooks/chain-team-phases.sh +105 -13
  346. package/presets/cursor/next/rules/README.md +6 -3
  347. package/presets/cursor/next/rules/agent-team-orchestrator.mdc +7 -5
  348. package/presets/cursor/next/rules/ai-local-overlay.mdc +43 -0
  349. package/presets/cursor/next/rules/http-client.mdc +1 -1
  350. package/presets/cursor/next/rules/preset-pr-checklist.mdc +5 -1
  351. package/presets/cursor/next/rules/preset-token-budget.mdc +7 -3
  352. package/presets/cursor/next/rules/preset-twin-sync.mdc +2 -0
  353. package/presets/cursor/next/rules/react-ui.mdc +1 -1
  354. package/presets/cursor/next/rules/reference-features.mdc +1 -1
  355. package/presets/cursor/next/rules/tests-e2e-structure.mdc +85 -43
  356. package/presets/cursor/next/rules/tests-unit.mdc +79 -48
  357. package/presets/cursor/next/skills/playwright-e2e/SKILL.md +5 -3
  358. package/presets/cursor/next/skills/unit-testing/SKILL.md +6 -4
  359. package/presets/cursor/next/team/README.md +0 -3
  360. package/presets/cursor/nuxt/README.md +6 -6
  361. package/presets/cursor/nuxt/agents/README.md +1 -1
  362. package/presets/cursor/nuxt/agents/build-verifier.md +2 -0
  363. package/presets/cursor/nuxt/agents/code-reviewer.md +2 -0
  364. package/presets/cursor/nuxt/agents/debugger.md +4 -0
  365. package/presets/cursor/nuxt/agents/feature-developer.md +4 -1
  366. package/presets/cursor/nuxt/agents/openspec-author.md +164 -0
  367. package/presets/cursor/nuxt/agents/qa-tester.md +4 -0
  368. package/presets/cursor/nuxt/agents/task-analyst.md +1 -1
  369. package/presets/cursor/nuxt/agents/task-router.md +5 -1
  370. package/presets/cursor/nuxt/agents/tech-writer.md +4 -0
  371. package/presets/cursor/nuxt/commands/README.md +0 -2
  372. package/presets/cursor/nuxt/commands/task-continue.md +1 -1
  373. package/presets/cursor/nuxt/commands/task.md +1 -5
  374. package/presets/cursor/nuxt/commands/technical-retro.md +2 -2
  375. package/presets/cursor/nuxt/hooks/chain-team-phases.sh +105 -13
  376. package/presets/cursor/nuxt/rules/README.md +3 -1
  377. package/presets/cursor/nuxt/rules/agent-team-orchestrator.mdc +8 -5
  378. package/presets/cursor/nuxt/rules/ai-local-overlay.mdc +43 -0
  379. package/presets/cursor/nuxt/rules/preset-pr-checklist.mdc +5 -1
  380. package/presets/cursor/nuxt/rules/preset-token-budget.mdc +7 -3
  381. package/presets/cursor/nuxt/rules/preset-twin-sync.mdc +2 -0
  382. package/presets/cursor/nuxt/rules/tests-e2e-structure.mdc +87 -43
  383. package/presets/cursor/nuxt/rules/tests-unit.mdc +62 -47
  384. package/presets/cursor/nuxt/team/README.md +0 -3
  385. package/presets/cursor/php-hexagonal/AGENTS.md +1 -1
  386. package/presets/cursor/php-hexagonal/agents/README.md +3 -2
  387. package/presets/cursor/php-hexagonal/agents/build-verifier.md +4 -0
  388. package/presets/cursor/php-hexagonal/agents/code-reviewer.md +4 -0
  389. package/presets/cursor/php-hexagonal/agents/debugger.md +4 -0
  390. package/presets/cursor/php-hexagonal/agents/feature-developer.md +5 -0
  391. package/presets/cursor/php-hexagonal/agents/openspec-author.md +164 -0
  392. package/presets/cursor/php-hexagonal/agents/qa-tester.md +4 -0
  393. package/presets/cursor/php-hexagonal/agents/task-router.md +9 -1
  394. package/presets/cursor/php-hexagonal/agents/tech-writer.md +4 -0
  395. package/presets/cursor/php-hexagonal/commands/README.md +0 -2
  396. package/presets/cursor/php-hexagonal/commands/task-continue.md +1 -1
  397. package/presets/cursor/php-hexagonal/commands/task.md +1 -4
  398. package/presets/cursor/php-hexagonal/commands/technical-retro.md +2 -2
  399. package/presets/cursor/php-hexagonal/hooks/chain-team-phases.sh +105 -14
  400. package/presets/cursor/php-hexagonal/rules/agent-team-orchestrator.mdc +2 -4
  401. package/presets/cursor/php-hexagonal/rules/ai-local-overlay.mdc +43 -0
  402. package/presets/cursor/php-hexagonal/rules/preset-pr-checklist.mdc +5 -1
  403. package/presets/cursor/php-hexagonal/rules/preset-token-budget.mdc +7 -3
  404. package/presets/cursor/php-hexagonal/rules/preset-twin-sync.mdc +2 -0
  405. package/presets/cursor/php-laravel/AGENTS.md +1 -1
  406. package/presets/cursor/php-laravel/agents/README.md +3 -2
  407. package/presets/cursor/php-laravel/agents/build-verifier.md +4 -0
  408. package/presets/cursor/php-laravel/agents/code-reviewer.md +4 -0
  409. package/presets/cursor/php-laravel/agents/debugger.md +4 -0
  410. package/presets/cursor/php-laravel/agents/feature-developer.md +5 -0
  411. package/presets/cursor/php-laravel/agents/openspec-author.md +164 -0
  412. package/presets/cursor/php-laravel/agents/qa-tester.md +4 -0
  413. package/presets/cursor/php-laravel/agents/task-router.md +6 -1
  414. package/presets/cursor/php-laravel/agents/tech-writer.md +4 -0
  415. package/presets/cursor/php-laravel/commands/README.md +0 -2
  416. package/presets/cursor/php-laravel/commands/task-continue.md +1 -1
  417. package/presets/cursor/php-laravel/commands/task.md +1 -4
  418. package/presets/cursor/php-laravel/commands/technical-retro.md +2 -2
  419. package/presets/cursor/php-laravel/hooks/chain-team-phases.sh +105 -14
  420. package/presets/cursor/php-laravel/rules/agent-team-orchestrator.mdc +2 -4
  421. package/presets/cursor/php-laravel/rules/ai-local-overlay.mdc +43 -0
  422. package/presets/cursor/php-laravel/rules/preset-pr-checklist.mdc +5 -1
  423. package/presets/cursor/php-laravel/rules/preset-token-budget.mdc +7 -3
  424. package/presets/cursor/php-laravel/rules/preset-twin-sync.mdc +2 -0
  425. package/presets/cursor/svelte/README.md +6 -6
  426. package/presets/cursor/svelte/agents/README.md +1 -1
  427. package/presets/cursor/svelte/agents/build-verifier.md +2 -0
  428. package/presets/cursor/svelte/agents/code-reviewer.md +2 -0
  429. package/presets/cursor/svelte/agents/debugger.md +4 -0
  430. package/presets/cursor/svelte/agents/feature-developer.md +4 -1
  431. package/presets/cursor/svelte/agents/openspec-author.md +164 -0
  432. package/presets/cursor/svelte/agents/qa-tester.md +4 -0
  433. package/presets/cursor/svelte/agents/task-analyst.md +1 -1
  434. package/presets/cursor/svelte/agents/task-router.md +5 -1
  435. package/presets/cursor/svelte/agents/tech-writer.md +4 -0
  436. package/presets/cursor/svelte/commands/README.md +0 -2
  437. package/presets/cursor/svelte/commands/task-continue.md +1 -1
  438. package/presets/cursor/svelte/commands/task.md +1 -5
  439. package/presets/cursor/svelte/commands/technical-retro.md +2 -2
  440. package/presets/cursor/svelte/hooks/chain-team-phases.sh +105 -13
  441. package/presets/cursor/svelte/rules/README.md +3 -1
  442. package/presets/cursor/svelte/rules/agent-team-orchestrator.mdc +8 -5
  443. package/presets/cursor/svelte/rules/ai-local-overlay.mdc +43 -0
  444. package/presets/cursor/svelte/rules/preset-pr-checklist.mdc +5 -1
  445. package/presets/cursor/svelte/rules/preset-token-budget.mdc +7 -3
  446. package/presets/cursor/svelte/rules/preset-twin-sync.mdc +2 -0
  447. package/presets/cursor/svelte/rules/tests-e2e-structure.mdc +87 -43
  448. package/presets/cursor/svelte/rules/tests-unit.mdc +72 -23
  449. package/presets/cursor/svelte/team/README.md +0 -3
  450. package/scripts/_lib/embed-stems.json +31 -0
  451. package/scripts/aggregate-agent-task-metrics.mjs +23 -0
  452. package/scripts/check-chain-hook-coverage.sh +109 -0
  453. package/scripts/check-local-overlay.sh +136 -0
  454. package/scripts/check-preset-i18n.sh +2 -2
  455. package/scripts/check-preset-leakage.sh +4 -1
  456. package/scripts/check-preset-structure.sh +31 -1
  457. package/scripts/check-preset-token-budget.sh +120 -10
  458. package/scripts/check-rule-eval.mjs +16 -0
  459. package/scripts/check-shared-core-drift.sh +10 -32
  460. package/scripts/check-task-router-intents.sh +141 -0
  461. package/scripts/close-agent-task-human-gate.mjs +22 -5
  462. package/scripts/sync-shared-core-embeds.sh +9 -20
  463. package/scripts/test-agent-task-metrics-hooks.mjs +100 -2
  464. package/scripts/test-chain-team-phases-coverage.mjs +510 -0
  465. package/scripts/test-task-router-intents-fixtures.mjs +109 -0
  466. package/presets/claude/android-kotlin/commands/feature-continue.md +0 -23
  467. package/presets/claude/android-kotlin/commands/feature-start.md +0 -41
  468. package/presets/claude/go/commands/feature-continue.md +0 -23
  469. package/presets/claude/go/commands/feature-start.md +0 -38
  470. package/presets/claude/ios-swift/commands/feature-continue.md +0 -23
  471. package/presets/claude/ios-swift/commands/feature-start.md +0 -41
  472. package/presets/claude/java/commands/feature-continue.md +0 -23
  473. package/presets/claude/java/commands/feature-start.md +0 -38
  474. package/presets/claude/mcp-ts/commands/feature-continue.md +0 -23
  475. package/presets/claude/mcp-ts/commands/feature-start.md +0 -41
  476. package/presets/claude/next/commands/feature-continue.md +0 -23
  477. package/presets/claude/next/commands/feature-start.md +0 -38
  478. package/presets/claude/nuxt/commands/feature-continue.md +0 -23
  479. package/presets/claude/nuxt/commands/feature-start.md +0 -41
  480. package/presets/claude/php-hexagonal/commands/feature-continue.md +0 -23
  481. package/presets/claude/php-hexagonal/commands/feature-start.md +0 -38
  482. package/presets/claude/php-laravel/commands/feature-continue.md +0 -23
  483. package/presets/claude/php-laravel/commands/feature-start.md +0 -38
  484. package/presets/claude/svelte/commands/feature-continue.md +0 -23
  485. package/presets/claude/svelte/commands/feature-start.md +0 -41
  486. package/presets/cursor/android-kotlin/commands/feature-continue.md +0 -23
  487. package/presets/cursor/android-kotlin/commands/feature-start.md +0 -41
  488. package/presets/cursor/go/commands/feature-continue.md +0 -23
  489. package/presets/cursor/go/commands/feature-start.md +0 -41
  490. package/presets/cursor/ios-swift/commands/feature-continue.md +0 -23
  491. package/presets/cursor/ios-swift/commands/feature-start.md +0 -41
  492. package/presets/cursor/java/commands/feature-continue.md +0 -23
  493. package/presets/cursor/java/commands/feature-start.md +0 -41
  494. package/presets/cursor/mcp-ts/commands/feature-continue.md +0 -23
  495. package/presets/cursor/mcp-ts/commands/feature-start.md +0 -41
  496. package/presets/cursor/next/commands/feature-continue.md +0 -23
  497. package/presets/cursor/next/commands/feature-start.md +0 -41
  498. package/presets/cursor/nuxt/commands/feature-continue.md +0 -23
  499. package/presets/cursor/nuxt/commands/feature-start.md +0 -41
  500. package/presets/cursor/php-hexagonal/commands/feature-continue.md +0 -23
  501. package/presets/cursor/php-hexagonal/commands/feature-start.md +0 -41
  502. package/presets/cursor/php-laravel/commands/feature-continue.md +0 -23
  503. package/presets/cursor/php-laravel/commands/feature-start.md +0 -41
  504. package/presets/cursor/svelte/commands/feature-continue.md +0 -23
  505. package/presets/cursor/svelte/commands/feature-start.md +0 -41
@@ -16,7 +16,71 @@ from pathlib import Path
16
16
 
17
17
  presets = Path(os.environ["AI_RULES_PRESETS_ROOT"])
18
18
  STACKS = ("next", "nuxt", "svelte", "ios-swift", "android-kotlin", "go", "java", "mcp-ts", "php-hexagonal", "php-laravel")
19
- BODY_CAP = 140
19
+ BODY_CAP = 140 # applied to 3-rule trios (Claude session-start, Cursor trio when len==3)
20
+ BODY_CAP_CURSOR_4 = 170 # Cursor now allows 4 always-on (next-app-core, package-manager, code-quality, ai-local-overlay)
21
+ # Slim-companion rules (UI-edit bundle, slim app-cores, slim tooling) may be
22
+ # shorter than 15 lines **if and only if** their stem is in the allow-list and
23
+ # body is <= MIN_SLIM_BODY_LINES. A slim rule whose body grows past this cap
24
+ # without being promoted to a domain rule FAILs the check. Reference:
25
+ # presets/_shared/core/meta/preset-twin-sync.md "Twin depth" section.
26
+ # Cursor and Claude share stems by convention; the list is stem-only and
27
+ # applied per platform.
28
+ SLIM_COMPANION_ALLOWLIST = frozenset({
29
+ "agent-team-intake",
30
+ "agent-team-orchestrator",
31
+ "ai-local-overlay",
32
+ "api-grpc",
33
+ "architecture-boundaries-ui",
34
+ "css-property-order-stylelint",
35
+ "design-guidance",
36
+ "domain-layer",
37
+ "e2e",
38
+ "feature-delivery-workflow",
39
+ "http-client",
40
+ "integration",
41
+ "ios-app-core",
42
+ "mcp-usage",
43
+ "messaging-adapters",
44
+ "mockup-review",
45
+ "module-public-api",
46
+ "navigation-coordinators",
47
+ "navigation-router-stack",
48
+ "navigation",
49
+ "navigation-router-ui",
50
+ "next-app-router",
51
+ "no-props-spread",
52
+ "no-type-assertion-as-import-export",
53
+ "no-v-bind-spread",
54
+ "package-manager",
55
+ "persistence",
56
+ "persistence-data",
57
+ "playwright-agents",
58
+ "post-change-build",
59
+ "post-change-lint",
60
+ "post-change-test",
61
+ "preset-layering",
62
+ "preset-no-cross-stack-leakage",
63
+ "preset-pr-checklist",
64
+ "preset-token-budget",
65
+ "preset-twin-sync",
66
+ "react-a11y-coding",
67
+ "script-setup-conventions",
68
+ "security-android",
69
+ "security-go",
70
+ "security-ios",
71
+ "security-next",
72
+ "security-php",
73
+ "state-and-viewmodels",
74
+ "technical-retro",
75
+ "tests-e2e",
76
+ "tests-integration",
77
+ "tests-unit",
78
+ "unit",
79
+ "ux-design",
80
+ "vue-a11y-coding",
81
+ "xcode-tooling",
82
+ })
83
+ MIN_SLIM_BODY_LINES = 5
20
84
  MARKER_LINE_RE = re.compile(r"^<!--\s*shared-core:\s*[^>]+?\s*-->\s*$")
21
85
  ALWAYS_APPLY_RE = re.compile(r"(?m)^alwaysApply:\s*true\s*$")
22
86
  PATHS_RE = re.compile(r"(?m)^paths:\s*")
@@ -70,7 +134,7 @@ failed = 0
70
134
 
71
135
  print("Preset token / session-start budget (Option A)")
72
136
  print(f"Presets: {presets}")
73
- print(f"Body line cap (trio sum): {BODY_CAP}")
137
+ print(f"Body line cap (Claude trio): {BODY_CAP}; (Cursor 4-set): {BODY_CAP_CURSOR_4}")
74
138
  print()
75
139
 
76
140
  for stack in STACKS:
@@ -87,9 +151,15 @@ for stack in STACKS:
87
151
  print(f"FAIL: meta preset-* must not be alwaysApply: {p.name}")
88
152
  failed += 1
89
153
 
90
- if len(always) != 3:
91
- print(f"FAIL: Cursor alwaysApply count is {len(always)}, expected exactly 3")
154
+ if len(always) not in (3, 4):
155
+ print(f"FAIL: Cursor alwaysApply count is {len(always)}, expected 3 or 4 (4th slot reserved for ai-local-overlay)")
92
156
  failed += 1
157
+ elif len(always) == 4:
158
+ # 4-set: ensure the 4th rule is ai-local-overlay (or declares itself as such).
159
+ extra = [p for p in always if p.stem not in {"code-quality-and-refactoring", "package-manager", "next-app-core", "nuxt-app-core", "svelte-app-core", "ios-app-core", "android-app-core", "go-app-core", "java-app-core", "mcp-ts-app-core", "php-app-core", "laravel-app-core", "architecture-boundaries", "mcp-server-boundaries"}]
160
+ if not any(p.stem == "ai-local-overlay" for p in always) and extra:
161
+ print(f"FAIL: Cursor alwaysApply=4 but no ai-local-overlay.mdc; the 4th slot is reserved for the local overlay rule")
162
+ failed += 1
93
163
 
94
164
  # --- Claude no-paths (excl README) ---
95
165
  session = claude_session_start(claude_rules)
@@ -108,10 +178,12 @@ for stack in STACKS:
108
178
  )
109
179
  failed += 1
110
180
 
111
- # --- Body sum of intended trio (Cursor alwaysApply + Claude session) ---
112
- # Prefer Cursor trio for budget; also check Claude trio independently.
181
+ # --- Body sum of intended session-start set (Cursor alwaysApply + Claude session) ---
182
+ # Cursor allows 3 or 4 rules (4th slot reserved for ai-local-overlay); Claude is exactly 3.
113
183
  for label, files in (("Cursor", always), ("Claude", session)):
114
- if len(files) != 3:
184
+ if label == "Cursor" and len(files) not in (3, 4):
185
+ continue
186
+ if label == "Claude" and len(files) != 3:
115
187
  continue
116
188
  total = 0
117
189
  for path in files:
@@ -121,13 +193,51 @@ for stack in STACKS:
121
193
  total += n
122
194
  name = path.name if label == "Cursor" else path.relative_to(claude_rules).as_posix()
123
195
  print(f" {label} body lines {name}: {n}")
124
- print(f" {label} trio body sum: {total}")
125
- if total > BODY_CAP:
196
+ cap = BODY_CAP_CURSOR_4 if label == "Cursor" and len(always) == 4 else BODY_CAP
197
+ print(f" {label} session-start body sum: {total} (cap {cap}, files={len(files)})")
198
+ if total > cap:
126
199
  print(
127
- f"FAIL: {label} session-start body sum {total} > {BODY_CAP} ({stack})"
200
+ f"FAIL: {label} session-start body sum {total} > {cap} ({stack})"
128
201
  )
129
202
  failed += 1
130
203
 
204
+ # --- Slim-companion enforcement (per stack, both platforms) ---
205
+ # All .mdc (Cursor) / .md (Claude) rules under the stack's rules/ directory
206
+ # are scanned. A rule whose body is > MIN_SLIM_BODY_LINES AND whose stem
207
+ # is NOT in SLIM_COMPANION_ALLOWLIST must be promoted to a domain rule
208
+ # (>=15 body lines per preset-twin-sync.md "Twin depth"). FAIL otherwise.
209
+ slim_violations: list[str] = []
210
+ for rules_dir in (cursor_rules, claude_rules):
211
+ if not rules_dir.exists():
212
+ continue
213
+ pattern = "*.mdc" if rules_dir is cursor_rules else "*.md"
214
+ for rule_path in sorted(rules_dir.rglob(pattern)):
215
+ if rule_path.name == "README.md":
216
+ continue
217
+ text = rule_path.read_text(encoding="utf-8")
218
+ _, body = strip_frontmatter(text)
219
+ n = body_nonempty_lines(body)
220
+ if n <= MIN_SLIM_BODY_LINES:
221
+ continue
222
+ # Skip rules explicitly in the slim-companion allow-list (they are
223
+ # allowed to be short pointers regardless of body length).
224
+ if rule_path.stem in SLIM_COMPANION_ALLOWLIST:
225
+ continue
226
+ # Domain rules (>=15 lines) are fine; we only flag the 6..14 line
227
+ # "slim-but-not-allowed" bucket.
228
+ if n >= 15:
229
+ continue
230
+ slim_violations.append(
231
+ f"{rule_path.relative_to(presets).as_posix()} ({n} lines, slim but not in allow-list)"
232
+ )
233
+ if slim_violations:
234
+ print(f" Slim-companion allow-list violations ({len(slim_violations)}):")
235
+ for v in slim_violations[:10]:
236
+ print(f" FAIL: {v}")
237
+ if len(slim_violations) > 10:
238
+ print(f" ... and {len(slim_violations) - 10} more")
239
+ failed += len(slim_violations)
240
+
131
241
  print()
132
242
 
133
243
  if failed:
@@ -99,6 +99,22 @@ function checkFile(relPath, minPairs, requireImpact) {
99
99
  ) && ok;
100
100
  }
101
101
 
102
+ // Order check: each Incorrect heading must precede its matching Correct heading.
103
+ // Without this, an agent reading the rule may learn a "correct" pattern before
104
+ // seeing the "incorrect" example it contrasts with.
105
+ if (incorrectCount > 0 && correctCount > 0) {
106
+ const incRe = /^#{2,3}\s+Incorrect\s*$/gim;
107
+ const corRe = /^#{2,3}\s+Correct\s*$/gim;
108
+ const firstInc = text.search(incRe);
109
+ const firstCor = text.search(corRe);
110
+ if (firstInc >= 0 && firstCor >= 0 && firstInc >= firstCor) {
111
+ ok =
112
+ fail(
113
+ `${relPath}: first "Incorrect" heading (offset ${firstInc}) must precede first "Correct" heading (offset ${firstCor})`,
114
+ ) && ok;
115
+ }
116
+ }
117
+
102
118
  const incorrectBodies = sectionBodies(text, 'Incorrect');
103
119
  const correctBodies = sectionBodies(text, 'Correct');
104
120
  for (let i = 0; i < Math.min(incorrectBodies.length, correctBodies.length); i++) {
@@ -7,48 +7,26 @@ set -euo pipefail
7
7
  ROOT="$(cd "$(dirname "$0")/../../.." && pwd)"
8
8
  export AI_RULES_PRESETS_ROOT="$ROOT/packages/ai-rules/presets"
9
9
 
10
- python3 <<'PY'
10
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
11
+ EMBED_LIST_FILE="$SCRIPT_DIR/_lib/embed-stems.json"
12
+
13
+ python3 - "$EMBED_LIST_FILE" <<'PY'
11
14
  from __future__ import annotations
12
15
 
16
+ import json
13
17
  import os
14
18
  import re
15
19
  import sys
16
20
  from pathlib import Path
17
21
 
22
+ embed_list_file = Path(sys.argv[1])
23
+ _stems = json.loads(embed_list_file.read_text(encoding="utf-8"))
24
+ EMBED = _stems["embed"]
25
+ LINEAGE = _stems["lineage"]
26
+
18
27
  presets = Path(os.environ["AI_RULES_PRESETS_ROOT"])
19
28
  core_root = presets / "_shared" / "core"
20
29
 
21
- EMBED = [
22
- "quality/code-quality-and-refactoring.md",
23
- "quality/anti-sycophancy-discipline.md",
24
- "quality/design-guidance.md",
25
- "quality/mcp-usage.md",
26
- "meta/preset-layering.md",
27
- "meta/preset-twin-sync.md",
28
- "meta/preset-token-budget.md",
29
- "meta/preset-pr-checklist.md",
30
- "meta/preset-no-cross-stack-leakage.md",
31
- "review/code-review-mr.md",
32
- "review/technical-retro.md",
33
- "review/mockup-review.md",
34
- "review/ux-design.md",
35
- "agent-team/agent-team-intake.md",
36
- "architecture/product-specs.md",
37
- "architecture/product-specs-authoring.md",
38
- # Whole-file embed: skill debug-investigation = core + ## Stack notes only.
39
- "quality/debug-investigation.md",
40
- ]
41
-
42
- LINEAGE = [
43
- "architecture/feature-delivery-workflow.md",
44
- "architecture/reference-features.template.md",
45
- "agent-team/agent-team-orchestrator.md",
46
- # Section snippets in fat agents/skills — body is not the whole file.
47
- "quality/verification-before-completion.md",
48
- "review/receiving-code-review.md",
49
- "agent-team/task-classification.md",
50
- ]
51
-
52
30
  # Full-line sync marker only (do not strip prose that *mentions* the marker).
53
31
  MARKER_LINE_RE = re.compile(r"^<!--\s*shared-core:\s*[^>]+?\s*-->\s*$")
54
32
 
@@ -0,0 +1,141 @@
1
+ #!/usr/bin/env bash
2
+ # Cross-check `task-router.md` intent rows against `agents/*.md` `name:` frontmatter.
3
+ #
4
+ # Two-sided verification:
5
+ # 1. Every agent file (frontmatter `name:` other than `task-router` itself) must
6
+ # be referenced somewhere in the stack's `task-router.md` so the router knows
7
+ # how to invoke it. Missing mention ⇒ FAIL (the agent will silently never
8
+ # receive a handoff).
9
+ # 2. Every agent stem referenced in `task-router.md` (in the `Default steps`
10
+ # column, the `Model tiers` table, or other inline mentions) must have a
11
+ # corresponding `agents/<stem>.md` file. Missing agent ⇒ FAIL (the router
12
+ # emits an intent that no agent can satisfy).
13
+ #
14
+ # The check is per `(platform, stack)` pair and runs all 20 ships (cursor + claude
15
+ # × 10 stacks). Exits non-zero on any FAIL.
16
+ #
17
+ # Stack-specific exemptions:
18
+ # - mcp-ts does not ship `playwright-test-*`, `xcuitest-test-*`, `unit-test-*`
19
+ # in the standard mix; intent rows that reference those agents are flagged
20
+ # only on stacks that ship the corresponding `agents/<stem>.md` file.
21
+ # - Stack leakage (positive agent stems on the wrong stack) is enforced in
22
+ # `check-preset-leakage.sh`; this check covers task-router sync only.
23
+ set -euo pipefail
24
+
25
+ ROOT="$(cd "$(dirname "$0")/../../.." && pwd)"
26
+ # Allow callers (notably the fixture test) to redirect the presets root via
27
+ # the env var. Default to the real repo path.
28
+ export AI_RULES_PRESETS_ROOT="${AI_RULES_PRESETS_ROOT:-$ROOT/packages/ai-rules/presets}"
29
+
30
+ python3 <<'PY'
31
+ from __future__ import annotations
32
+
33
+ import os
34
+ import re
35
+ import sys
36
+ from pathlib import Path
37
+
38
+ presets = Path(os.environ["AI_RULES_PRESETS_ROOT"])
39
+ PLATFORMS = ("cursor", "claude")
40
+ STACKS = ("next", "nuxt", "svelte", "ios-swift", "android-kotlin", "go", "java", "mcp-ts", "php-hexagonal", "php-laravel")
41
+
42
+ # Agents that are shipped for orchestration purposes but do not need to appear
43
+ # in task-router.md intent rows (router-only / analyzer-only / orchestrator-only).
44
+ ROUTER_EXEMPT_FROM_INTENT = frozenset({
45
+ "task-router", # this file
46
+ "codebase-analyzer", # ad-hoc explain-as-is agent
47
+ "agent-team-intake", # one-off intake, not a pipeline target
48
+ })
49
+
50
+ # Agent-stem regex: kebab-case, lowercase, may include digits and dots (x.y).
51
+ # Two patterns: (a) hyphen/dot-bounded names like `feature-developer`, `unit.test`,
52
+ # (b) single-word agents that are present in `shipped_names`. Both feed the
53
+ # `agent_like` filter.
54
+ AGENT_NAME_RE = re.compile(r"\b([a-z][a-z0-9]*(?:[-.][a-z0-9]+)+)\b")
55
+ SINGLE_WORD_AGENT_RE = re.compile(r"\b([a-z][a-z0-9]+)\b")
56
+ FRONTMATTER_NAME_RE = re.compile(r"^name:\s*([a-z][a-z0-9]*(?:[-.][a-z0-9]+)+)\s*$", re.MULTILINE)
57
+
58
+ failures: list[str] = []
59
+ checks = 0
60
+
61
+ for platform in PLATFORMS:
62
+ for stack in STACKS:
63
+ agents_dir = presets / platform / stack / "agents"
64
+ if not agents_dir.is_dir():
65
+ continue
66
+ task_router = agents_dir / "task-router.md"
67
+ if not task_router.is_file():
68
+ failures.append(f"{platform}/{stack}: missing task-router.md")
69
+ continue
70
+
71
+ # 1) All agent `name:` frontmatter in this stack's agents dir.
72
+ shipped_names: set[str] = set()
73
+ for path in sorted(agents_dir.glob("*.md")):
74
+ text = path.read_text(encoding="utf-8")
75
+ m = FRONTMATTER_NAME_RE.search(text)
76
+ if m:
77
+ shipped_names.add(m.group(1))
78
+ # Also pick up the file stem as a fallback (in case frontmatter is missing).
79
+ if path.stem not in shipped_names and path.stem != "README":
80
+ shipped_names.add(path.stem)
81
+
82
+ # 2) All agent stems referenced in task-router.md (anywhere in body).
83
+ router_text = task_router.read_text(encoding="utf-8")
84
+ # Restrict to body (drop YAML frontmatter).
85
+ body = router_text
86
+ if router_text.startswith("---\n"):
87
+ end = router_text.find("\n---\n", 4)
88
+ if end >= 0:
89
+ body = router_text[end + 5 :]
90
+ referenced_in_router: set[str] = set(AGENT_NAME_RE.findall(body))
91
+ # Single-word tokens that match a shipped agent (e.g. `debugger`,
92
+ # `codebase-analyzer`, `ci-investigator`) are valid router mentions even
93
+ # without a hyphen/dot boundary.
94
+ for token in SINGLE_WORD_AGENT_RE.findall(body):
95
+ if token in shipped_names:
96
+ referenced_in_router.add(token)
97
+ agent_like: set[str] = referenced_in_router - ROUTER_EXEMPT_FROM_INTENT
98
+
99
+ # Subset of shipped agents that are not router-exempt AND not referenced.
100
+ shipped_pipeline_agents = shipped_names - ROUTER_EXEMPT_FROM_INTENT
101
+ # 1-sided check (FAIL when shipped but not mentioned).
102
+ not_referenced = sorted(shipped_pipeline_agents - agent_like)
103
+ for name in not_referenced:
104
+ checks += 1
105
+ # The README is not an agent.
106
+ if name == "README":
107
+ continue
108
+ # Skip agents only used as commands or skills (e.g. technical-retro,
109
+ # agent-team-intake when still present). These are explicitly
110
+ # exempt — but we already filter ROUTER_EXEMPT_FROM_INTENT, so any
111
+ # remaining mismatch is a real gap.
112
+ failures.append(
113
+ f"{platform}/{stack}: ships agent '{name}.md' but task-router.md does not mention '{name}'"
114
+ )
115
+
116
+ # 2-sided check (FAIL when mentioned in router but not shipped).
117
+ not_shipped = sorted(agent_like - shipped_names)
118
+ for name in not_shipped:
119
+ checks += 1
120
+ # Allow mentions of common stacks/tools that aren't agents (filter).
121
+ # Common false positives: branch names, mixed-case strings, etc.
122
+ # The regex already constrains to lowercase kebab/dot; further filter
123
+ # by requiring the suffix to look like an agent suffix.
124
+ if name in {"feature-developer", "build-verifier", "code-reviewer"}:
125
+ # These should be shipped; surface as FAIL.
126
+ failures.append(
127
+ f"{platform}/{stack}: task-router.md references '{name}' but agents/{name}.md is missing"
128
+ )
129
+ # Otherwise ignore (likely prose token or matcher noise).
130
+
131
+ if failures:
132
+ print(f"FAIL: task-router vs agents drift ({len(failures)} issue(s) / {checks} checks):")
133
+ for f in failures[:30]:
134
+ print(f" - {f}")
135
+ if len(failures) > 30:
136
+ print(f" ... and {len(failures) - 30} more")
137
+ sys.exit(1)
138
+
139
+ print(f"OK: task-router.md intent rows match agents/*.md ({checks} checks across {len(PLATFORMS) * len(STACKS)} (platform, stack) pairs)")
140
+ sys.exit(0)
141
+ PY
@@ -13,18 +13,35 @@ import path from 'node:path';
13
13
 
14
14
  function parseArgs(argv) {
15
15
  const options = { cwd: process.cwd(), platform: 'cursor', slug: null };
16
+ // Read the next token from argv for value-taking flags. Returns the value or null
17
+ // when the flag is missing its value; the caller exits with a friendly error.
18
+ function nextValue(flag, i) {
19
+ const next = argv[i + 1];
20
+ if (next === undefined || next.startsWith('-')) {
21
+ console.error(`Missing value for ${flag} (use ${flag} <value>)`);
22
+ process.exit(2);
23
+ }
24
+ return next;
25
+ }
16
26
  for (let i = 2; i < argv.length; i += 1) {
17
27
  const arg = argv[i];
18
- if (arg === '--cwd') options.cwd = path.resolve(argv[++i]);
19
- else if (arg === '--platform') options.platform = argv[++i];
20
- else if (arg === '--slug') options.slug = argv[++i];
21
- else if (arg === '--activate-next') {
28
+ if (arg === '--cwd') {
29
+ options.cwd = path.resolve(nextValue(arg, i));
30
+ i += 1;
31
+ } else if (arg === '--platform') {
32
+ options.platform = nextValue(arg, i);
33
+ i += 1;
34
+ } else if (arg === '--slug') {
35
+ options.slug = nextValue(arg, i);
36
+ i += 1;
37
+ } else if (arg === '--activate-next') {
22
38
  /* always activate via hook payload */
23
39
  } else if (arg === '--team-root') {
24
40
  // Compatibility with earlier docs: derive platform + cwd from team root.
25
- const teamRoot = path.resolve(argv[++i]);
41
+ const teamRoot = path.resolve(nextValue(arg, i));
26
42
  options.cwd = path.resolve(teamRoot, '..', '..');
27
43
  options.platform = path.basename(path.dirname(teamRoot)) === '.claude' ? 'claude' : 'cursor';
44
+ i += 1;
28
45
  } else {
29
46
  console.error(`Unknown argument: ${arg}`);
30
47
  process.exit(2);
@@ -8,35 +8,24 @@ set -euo pipefail
8
8
  ROOT="$(cd "$(dirname "$0")/../../.." && pwd)"
9
9
  export AI_RULES_PRESETS_ROOT="$ROOT/packages/ai-rules/presets"
10
10
 
11
- python3 <<'PY'
11
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
12
+ EMBED_LIST_FILE="$SCRIPT_DIR/_lib/embed-stems.json"
13
+
14
+ python3 - "$EMBED_LIST_FILE" <<'PY'
12
15
  from __future__ import annotations
13
16
 
17
+ import json
14
18
  import os
15
19
  import re
20
+ import sys
16
21
  from pathlib import Path
17
22
 
23
+ embed_list_file = Path(sys.argv[1])
24
+ EMBED = json.loads(embed_list_file.read_text(encoding="utf-8"))["embed"]
25
+
18
26
  presets = Path(os.environ["AI_RULES_PRESETS_ROOT"])
19
27
  core_root = presets / "_shared" / "core"
20
28
 
21
- EMBED = [
22
- "quality/code-quality-and-refactoring.md",
23
- "quality/anti-sycophancy-discipline.md",
24
- "quality/design-guidance.md",
25
- "quality/mcp-usage.md",
26
- "meta/preset-layering.md",
27
- "meta/preset-twin-sync.md",
28
- "meta/preset-token-budget.md",
29
- "meta/preset-pr-checklist.md",
30
- "meta/preset-no-cross-stack-leakage.md",
31
- "review/code-review-mr.md",
32
- "review/technical-retro.md",
33
- "review/mockup-review.md",
34
- "review/ux-design.md",
35
- "agent-team/agent-team-intake.md",
36
- "architecture/product-specs.md",
37
- "architecture/product-specs-authoring.md",
38
- ]
39
-
40
29
  MARKER_LINE_RE = re.compile(r"^<!--\s*shared-core:\s*([^>]+?)\s*-->\s*$")
41
30
 
42
31
 
@@ -14,7 +14,7 @@ const hooks = [
14
14
  ...fs.readdirSync(path.join(presetsDirectory, 'claude')).map((stack) => path.join(presetsDirectory, 'claude', stack, 'hooks', 'chain-team-phases.sh')),
15
15
  ];
16
16
 
17
- assert.equal(hooks.length, 14, 'expected every packaged Cursor and Claude hook');
17
+ assert.equal(hooks.length, 20, 'expected every packaged Cursor and Claude hook (10 stacks × 2 platforms)');
18
18
 
19
19
  function readJson(filePath) {
20
20
  return JSON.parse(fs.readFileSync(filePath, 'utf8'));
@@ -892,4 +892,102 @@ for (const hook of hooks) {
892
892
  }
893
893
  }
894
894
 
895
- console.log(`Verified retry, parallel, skip, gate, manifest-reconcile, and aggregation lifecycle in ${hooks.length} hooks.`);
895
+ // ---------------------------------------------------------------------------
896
+ // Test — OD-1: parallel-stop lock race. The hook's waitForMetricsLock must
897
+ // actually block a second writer when the lock file is held. We pre-acquire
898
+ // `metrics.json.lock` (fs.openSync(_, 'wx') — same primitive the hook uses)
899
+ // in the test, then invoke the hook concurrently; the hook must NOT acquire
900
+ // the lock until the test releases it. Without the real lock primitive the
901
+ // hook would race through, run the metrics write, and leave a corrupt ledger.
902
+ // ---------------------------------------------------------------------------
903
+ for (const hook of hooks) {
904
+ const root = fs.mkdtempSync(path.join(packageDirectory, '.agent-task-metrics-lock-race-'));
905
+ try {
906
+ const platform = hook.includes(`${path.sep}cursor${path.sep}`) ? 'cursor' : 'claude';
907
+ const runId = 'lock-race-run';
908
+ const attemptId = `${runId}:step-0:feature-developer:attempt-1`;
909
+ const taskDirectory = writeTask(
910
+ root,
911
+ hook,
912
+ 'lock-race',
913
+ { autoChain: true, steps: [{ agent: 'feature-developer' }] },
914
+ {
915
+ slug: 'lock-race',
916
+ intent: 'feature',
917
+ pipelineIndex: 0,
918
+ currentAgent: 'feature-developer',
919
+ phase: 'executing',
920
+ state: 'completed',
921
+ activeAttempts: {
922
+ [attemptId]: {
923
+ agent: 'feature-developer',
924
+ stepIndex: 0,
925
+ attempt: 1,
926
+ startedAt: '2026-01-01T00:00:00.000Z',
927
+ parallelGroupId: null,
928
+ },
929
+ },
930
+ metricsRunId: runId,
931
+ },
932
+ {
933
+ schemaVersion: 1,
934
+ task: { runId, slug: 'lock-race', preset: 'ai-rules', stack: 'test', platform, intent: 'feature', profile: 'test' },
935
+ events: [
936
+ { eventId: `${runId}:task_started`, type: 'task_started', at: '2026-01-01T00:00:00.000Z' },
937
+ { eventId: `${runId}:start`, type: 'attempt_started', attemptId, agent: 'feature-developer', stepIndex: 0, attempt: 1, at: '2026-01-01T00:00:00.000Z' },
938
+ ],
939
+ },
940
+ );
941
+ const metricsPath = path.join(taskDirectory, 'metrics.json');
942
+ const lockPath = `${metricsPath}.lock`;
943
+
944
+ // Pre-acquire the lock the same way the hook does (fs.openSync 'wx').
945
+ const holderFd = fs.openSync(lockPath, 'wx');
946
+
947
+ // Spawn the hook while the lock is held. The hook must wait.
948
+ const child = spawn('bash', [hook], { cwd: root, stdio: ['pipe', 'pipe', 'pipe'] });
949
+ let stderr = '';
950
+ let stdout = '';
951
+ child.stderr.setEncoding('utf8');
952
+ child.stdout.setEncoding('utf8');
953
+ child.stderr.on('data', (chunk) => { stderr += chunk; });
954
+ child.stdout.on('data', (chunk) => { stdout += chunk; });
955
+ child.stdin.end(JSON.stringify({ status: 'completed', attemptId }));
956
+
957
+ // Give the child time to enter waitForMetricsLock and hit the EEXIST retry path.
958
+ const holdMs = 60;
959
+ await new Promise((resolve) => setTimeout(resolve, holdMs));
960
+ assert.ok(
961
+ child.exitCode === null,
962
+ `${hook}: hook exited prematurely while lock was held (stdout=${stdout.slice(0, 200)} stderr=${stderr.slice(0, 200)})`,
963
+ );
964
+
965
+ // Release the lock — child should now proceed.
966
+ const releaseAt = Date.now();
967
+ fs.closeSync(holderFd);
968
+ fs.unlinkSync(lockPath);
969
+
970
+ const exitCode = await new Promise((resolve, reject) => {
971
+ child.on('error', reject);
972
+ child.on('close', resolve);
973
+ });
974
+ const elapsed = Date.now() - releaseAt;
975
+ assert.equal(exitCode, 0, `${hook}: hook did not exit 0 after lock release (stderr=${stderr.slice(0, 400)})`);
976
+
977
+ // The hook's waitForMetricsLock busy-waits on EEXIST in 10 ms slices; with a
978
+ // 60 ms hold the child should have been blocked for >= holdMs and run to
979
+ // completion in well under the 2 s ceiling. Both assertions guard against
980
+ // regressions to the fake Atomics.wait impl (which never blocked).
981
+ assert.ok(elapsed >= 1, `${hook}: hook finished suspiciously fast after lock release (${elapsed} ms)`);
982
+ assert.ok(elapsed < 1500, `${hook}: hook took ${elapsed} ms after lock release — lock impl may be stuck`);
983
+ const ledger = readJson(metricsPath);
984
+ const finished = ledger.events.find(
985
+ (event) => event.type === 'attempt_finished' && event.attemptId === attemptId,
986
+ );
987
+ assert.ok(finished, `${hook}: lock-race did not emit attempt_finished; ledger=${JSON.stringify(ledger.events.map((e) => e.type))}`);
988
+ } finally {
989
+ fs.rmSync(root, { recursive: true, force: true });
990
+ }
991
+ }
992
+
993
+ console.log(`Verified retry, parallel, skip, gate, manifest-reconcile, lock-race, and aggregation lifecycle in ${hooks.length} hooks.`);