@bonesofspring/ai-rules 0.2.23 → 0.2.25

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 (287) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +20 -5
  3. package/bin/cli.js +121 -15
  4. package/bin/mavis-install.js +5 -1
  5. package/bin/opencode-install.js +535 -0
  6. package/package.json +10 -3
  7. package/presets/_shared/core/agent-team/agent-team-orchestrator.md +2 -2
  8. package/presets/_shared/core/meta/preset-layering.md +3 -3
  9. package/presets/_shared/core/meta/preset-no-cross-stack-leakage.md +1 -1
  10. package/presets/_shared/core/meta/preset-pr-checklist.md +4 -3
  11. package/presets/_shared/core/meta/preset-token-budget.md +3 -0
  12. package/presets/_shared/core/meta/preset-twin-sync.md +16 -0
  13. package/presets/claude/android-kotlin/rules/tooling-and-review/preset-layering.md +3 -3
  14. package/presets/claude/android-kotlin/rules/tooling-and-review/preset-no-cross-stack-leakage.md +1 -1
  15. package/presets/claude/android-kotlin/rules/tooling-and-review/preset-pr-checklist.md +4 -3
  16. package/presets/claude/android-kotlin/rules/tooling-and-review/preset-token-budget.md +3 -0
  17. package/presets/claude/android-kotlin/rules/tooling-and-review/preset-twin-sync.md +16 -0
  18. package/presets/claude/go/rules/tooling-and-review/preset-layering.md +3 -3
  19. package/presets/claude/go/rules/tooling-and-review/preset-no-cross-stack-leakage.md +1 -1
  20. package/presets/claude/go/rules/tooling-and-review/preset-pr-checklist.md +4 -3
  21. package/presets/claude/go/rules/tooling-and-review/preset-token-budget.md +3 -0
  22. package/presets/claude/go/rules/tooling-and-review/preset-twin-sync.md +16 -0
  23. package/presets/claude/ios-swift/rules/tooling-and-review/preset-layering.md +3 -3
  24. package/presets/claude/ios-swift/rules/tooling-and-review/preset-no-cross-stack-leakage.md +1 -1
  25. package/presets/claude/ios-swift/rules/tooling-and-review/preset-pr-checklist.md +4 -3
  26. package/presets/claude/ios-swift/rules/tooling-and-review/preset-token-budget.md +3 -0
  27. package/presets/claude/ios-swift/rules/tooling-and-review/preset-twin-sync.md +16 -0
  28. package/presets/claude/java/rules/tooling-and-review/preset-layering.md +3 -3
  29. package/presets/claude/java/rules/tooling-and-review/preset-no-cross-stack-leakage.md +1 -1
  30. package/presets/claude/java/rules/tooling-and-review/preset-pr-checklist.md +4 -3
  31. package/presets/claude/java/rules/tooling-and-review/preset-token-budget.md +3 -0
  32. package/presets/claude/java/rules/tooling-and-review/preset-twin-sync.md +16 -0
  33. package/presets/claude/mcp-ts/rules/tooling-and-review/preset-layering.md +3 -3
  34. package/presets/claude/mcp-ts/rules/tooling-and-review/preset-no-cross-stack-leakage.md +1 -1
  35. package/presets/claude/mcp-ts/rules/tooling-and-review/preset-pr-checklist.md +4 -3
  36. package/presets/claude/mcp-ts/rules/tooling-and-review/preset-token-budget.md +3 -0
  37. package/presets/claude/mcp-ts/rules/tooling-and-review/preset-twin-sync.md +16 -0
  38. package/presets/claude/next/REPO_AGENTS.md +34 -8
  39. package/presets/claude/next/agents/build-verifier.md +3 -1
  40. package/presets/claude/next/rules/tooling-and-review/ai-local-overlay.md +1 -1
  41. package/presets/claude/next/rules/tooling-and-review/preset-layering.md +3 -3
  42. package/presets/claude/next/rules/tooling-and-review/preset-no-cross-stack-leakage.md +1 -1
  43. package/presets/claude/next/rules/tooling-and-review/preset-pr-checklist.md +4 -3
  44. package/presets/claude/next/rules/tooling-and-review/preset-token-budget.md +3 -0
  45. package/presets/claude/next/rules/tooling-and-review/preset-twin-sync.md +16 -0
  46. package/presets/claude/nuxt/rules/tooling-and-review/preset-layering.md +3 -3
  47. package/presets/claude/nuxt/rules/tooling-and-review/preset-no-cross-stack-leakage.md +1 -1
  48. package/presets/claude/nuxt/rules/tooling-and-review/preset-pr-checklist.md +4 -3
  49. package/presets/claude/nuxt/rules/tooling-and-review/preset-token-budget.md +3 -0
  50. package/presets/claude/nuxt/rules/tooling-and-review/preset-twin-sync.md +16 -0
  51. package/presets/claude/php-hexagonal/rules/tooling-and-review/preset-layering.md +3 -3
  52. package/presets/claude/php-hexagonal/rules/tooling-and-review/preset-no-cross-stack-leakage.md +1 -1
  53. package/presets/claude/php-hexagonal/rules/tooling-and-review/preset-pr-checklist.md +4 -3
  54. package/presets/claude/php-hexagonal/rules/tooling-and-review/preset-token-budget.md +3 -0
  55. package/presets/claude/php-hexagonal/rules/tooling-and-review/preset-twin-sync.md +16 -0
  56. package/presets/claude/php-laravel/rules/tooling-and-review/preset-layering.md +3 -3
  57. package/presets/claude/php-laravel/rules/tooling-and-review/preset-no-cross-stack-leakage.md +1 -1
  58. package/presets/claude/php-laravel/rules/tooling-and-review/preset-pr-checklist.md +4 -3
  59. package/presets/claude/php-laravel/rules/tooling-and-review/preset-token-budget.md +3 -0
  60. package/presets/claude/php-laravel/rules/tooling-and-review/preset-twin-sync.md +16 -0
  61. package/presets/claude/svelte/rules/tooling-and-review/preset-layering.md +3 -3
  62. package/presets/claude/svelte/rules/tooling-and-review/preset-no-cross-stack-leakage.md +1 -1
  63. package/presets/claude/svelte/rules/tooling-and-review/preset-pr-checklist.md +4 -3
  64. package/presets/claude/svelte/rules/tooling-and-review/preset-token-budget.md +3 -0
  65. package/presets/claude/svelte/rules/tooling-and-review/preset-twin-sync.md +16 -0
  66. package/presets/cursor/android-kotlin/rules/preset-layering.mdc +3 -3
  67. package/presets/cursor/android-kotlin/rules/preset-no-cross-stack-leakage.mdc +1 -1
  68. package/presets/cursor/android-kotlin/rules/preset-pr-checklist.mdc +4 -3
  69. package/presets/cursor/android-kotlin/rules/preset-token-budget.mdc +3 -0
  70. package/presets/cursor/android-kotlin/rules/preset-twin-sync.mdc +16 -0
  71. package/presets/cursor/go/rules/preset-layering.mdc +3 -3
  72. package/presets/cursor/go/rules/preset-no-cross-stack-leakage.mdc +1 -1
  73. package/presets/cursor/go/rules/preset-pr-checklist.mdc +4 -3
  74. package/presets/cursor/go/rules/preset-token-budget.mdc +3 -0
  75. package/presets/cursor/go/rules/preset-twin-sync.mdc +16 -0
  76. package/presets/cursor/ios-swift/rules/preset-layering.mdc +3 -3
  77. package/presets/cursor/ios-swift/rules/preset-no-cross-stack-leakage.mdc +1 -1
  78. package/presets/cursor/ios-swift/rules/preset-pr-checklist.mdc +4 -3
  79. package/presets/cursor/ios-swift/rules/preset-token-budget.mdc +3 -0
  80. package/presets/cursor/ios-swift/rules/preset-twin-sync.mdc +16 -0
  81. package/presets/cursor/java/rules/preset-layering.mdc +3 -3
  82. package/presets/cursor/java/rules/preset-no-cross-stack-leakage.mdc +1 -1
  83. package/presets/cursor/java/rules/preset-pr-checklist.mdc +4 -3
  84. package/presets/cursor/java/rules/preset-token-budget.mdc +3 -0
  85. package/presets/cursor/java/rules/preset-twin-sync.mdc +16 -0
  86. package/presets/cursor/mcp-ts/rules/preset-layering.mdc +3 -3
  87. package/presets/cursor/mcp-ts/rules/preset-no-cross-stack-leakage.mdc +1 -1
  88. package/presets/cursor/mcp-ts/rules/preset-pr-checklist.mdc +4 -3
  89. package/presets/cursor/mcp-ts/rules/preset-token-budget.mdc +3 -0
  90. package/presets/cursor/mcp-ts/rules/preset-twin-sync.mdc +16 -0
  91. package/presets/cursor/next/REPO_AGENTS.md +26 -8
  92. package/presets/cursor/next/agents/build-verifier.md +3 -1
  93. package/presets/cursor/next/rules/ai-local-overlay.mdc +1 -1
  94. package/presets/cursor/next/rules/preset-layering.mdc +3 -3
  95. package/presets/cursor/next/rules/preset-no-cross-stack-leakage.mdc +1 -1
  96. package/presets/cursor/next/rules/preset-pr-checklist.mdc +4 -3
  97. package/presets/cursor/next/rules/preset-token-budget.mdc +3 -0
  98. package/presets/cursor/next/rules/preset-twin-sync.mdc +16 -0
  99. package/presets/cursor/nuxt/rules/preset-layering.mdc +3 -3
  100. package/presets/cursor/nuxt/rules/preset-no-cross-stack-leakage.mdc +1 -1
  101. package/presets/cursor/nuxt/rules/preset-pr-checklist.mdc +4 -3
  102. package/presets/cursor/nuxt/rules/preset-token-budget.mdc +3 -0
  103. package/presets/cursor/nuxt/rules/preset-twin-sync.mdc +16 -0
  104. package/presets/cursor/php-hexagonal/rules/preset-layering.mdc +3 -3
  105. package/presets/cursor/php-hexagonal/rules/preset-no-cross-stack-leakage.mdc +1 -1
  106. package/presets/cursor/php-hexagonal/rules/preset-pr-checklist.mdc +4 -3
  107. package/presets/cursor/php-hexagonal/rules/preset-token-budget.mdc +3 -0
  108. package/presets/cursor/php-hexagonal/rules/preset-twin-sync.mdc +16 -0
  109. package/presets/cursor/php-laravel/rules/preset-layering.mdc +3 -3
  110. package/presets/cursor/php-laravel/rules/preset-no-cross-stack-leakage.mdc +1 -1
  111. package/presets/cursor/php-laravel/rules/preset-pr-checklist.mdc +4 -3
  112. package/presets/cursor/php-laravel/rules/preset-token-budget.mdc +3 -0
  113. package/presets/cursor/php-laravel/rules/preset-twin-sync.mdc +16 -0
  114. package/presets/cursor/svelte/rules/preset-layering.mdc +3 -3
  115. package/presets/cursor/svelte/rules/preset-no-cross-stack-leakage.mdc +1 -1
  116. package/presets/cursor/svelte/rules/preset-pr-checklist.mdc +4 -3
  117. package/presets/cursor/svelte/rules/preset-token-budget.mdc +3 -0
  118. package/presets/cursor/svelte/rules/preset-twin-sync.mdc +16 -0
  119. package/presets/mavis/next/MAVIS.md +1 -0
  120. package/presets/mavis/next/REPO_AGENTS.md +28 -48
  121. package/presets/mavis/next/adapter-map.json +3 -3
  122. package/presets/mavis/next/agents/build-verifier.md +3 -1
  123. package/presets/mavis/next/rules/agent-team-orchestrator.md +2 -2
  124. package/presets/mavis/next/rules/ai-local-overlay.md +1 -1
  125. package/presets/mavis/next/rules/preset-layering.md +3 -3
  126. package/presets/mavis/next/rules/preset-no-cross-stack-leakage.md +1 -1
  127. package/presets/mavis/next/rules/preset-pr-checklist.md +4 -3
  128. package/presets/mavis/next/rules/preset-token-budget.md +3 -0
  129. package/presets/mavis/next/rules/preset-twin-sync.md +16 -0
  130. package/presets/opencode/README.md +61 -0
  131. package/presets/opencode/next/MCP.md +36 -0
  132. package/presets/opencode/next/OPENCODE.md +65 -0
  133. package/presets/opencode/next/README.md +16 -0
  134. package/presets/opencode/next/REPO_AGENTS.md +74 -0
  135. package/presets/opencode/next/adapter-map.json +959 -0
  136. package/presets/opencode/next/agents/README.md +201 -0
  137. package/presets/opencode/next/agents/accessibility-reviewer.md +73 -0
  138. package/presets/opencode/next/agents/api-contract-reviewer.md +69 -0
  139. package/presets/opencode/next/agents/build-verifier.md +124 -0
  140. package/presets/opencode/next/agents/ci-investigator.md +71 -0
  141. package/presets/opencode/next/agents/code-reviewer.md +73 -0
  142. package/presets/opencode/next/agents/codebase-analyzer.md +33 -0
  143. package/presets/opencode/next/agents/debugger.md +88 -0
  144. package/presets/opencode/next/agents/feature-developer.md +109 -0
  145. package/presets/opencode/next/agents/migration-specialist.md +79 -0
  146. package/presets/opencode/next/agents/mockup-reviewer.md +65 -0
  147. package/presets/opencode/next/agents/openspec-author.md +169 -0
  148. package/presets/opencode/next/agents/performance-auditor.md +80 -0
  149. package/presets/opencode/next/agents/playwright-test-generator.md +36 -0
  150. package/presets/opencode/next/agents/playwright-test-healer.md +36 -0
  151. package/presets/opencode/next/agents/playwright-test-planner.md +33 -0
  152. package/presets/opencode/next/agents/qa-tester.md +60 -0
  153. package/presets/opencode/next/agents/security-reviewer.md +66 -0
  154. package/presets/opencode/next/agents/solution-architect.md +80 -0
  155. package/presets/opencode/next/agents/task-analyst.md +178 -0
  156. package/presets/opencode/next/agents/task-router.md +190 -0
  157. package/presets/opencode/next/agents/tech-writer.md +69 -0
  158. package/presets/opencode/next/agents/unit-test-generator.md +39 -0
  159. package/presets/opencode/next/agents/unit-test-healer.md +40 -0
  160. package/presets/opencode/next/agents/unit-test-planner.md +66 -0
  161. package/presets/opencode/next/commands/README.md +49 -0
  162. package/presets/opencode/next/commands/spec-start.md +32 -0
  163. package/presets/opencode/next/commands/task-continue.md +58 -0
  164. package/presets/opencode/next/commands/task.md +58 -0
  165. package/presets/opencode/next/commands/technical-retro.md +88 -0
  166. package/presets/opencode/next/hooks/README.md +22 -0
  167. package/presets/opencode/next/hooks/chain-team-phases.sh +845 -0
  168. package/presets/opencode/next/opencode.json +33 -0
  169. package/presets/opencode/next/rules/README.md +20 -0
  170. package/presets/opencode/next/rules/agent-team-intake.md +11 -0
  171. package/presets/opencode/next/rules/agent-team-orchestrator.md +214 -0
  172. package/presets/opencode/next/rules/ai-local-overlay.md +37 -0
  173. package/presets/opencode/next/rules/anti-sycophancy-discipline.md +23 -0
  174. package/presets/opencode/next/rules/api-services.md +72 -0
  175. package/presets/opencode/next/rules/architecture-boundaries-ui.md +9 -0
  176. package/presets/opencode/next/rules/architecture-boundaries.md +86 -0
  177. package/presets/opencode/next/rules/arrow-functions.md +25 -0
  178. package/presets/opencode/next/rules/code-quality-and-refactoring.md +40 -0
  179. package/presets/opencode/next/rules/code-review-mr.md +40 -0
  180. package/presets/opencode/next/rules/css-property-order-stylelint.md +5 -0
  181. package/presets/opencode/next/rules/design-guidance.md +99 -0
  182. package/presets/opencode/next/rules/feature-delivery-workflow.md +49 -0
  183. package/presets/opencode/next/rules/http-client.md +55 -0
  184. package/presets/opencode/next/rules/layer-barrel-exports.md +68 -0
  185. package/presets/opencode/next/rules/mcp-usage.md +86 -0
  186. package/presets/opencode/next/rules/mockup-review.md +107 -0
  187. package/presets/opencode/next/rules/navigation-router-stack.md +56 -0
  188. package/presets/opencode/next/rules/navigation-router-ui.md +10 -0
  189. package/presets/opencode/next/rules/next-app-core.md +29 -0
  190. package/presets/opencode/next/rules/next-app-router.md +44 -0
  191. package/presets/opencode/next/rules/no-props-spread.md +56 -0
  192. package/presets/opencode/next/rules/no-type-assertion-as-import-export.md +51 -0
  193. package/presets/opencode/next/rules/package-manager.md +11 -0
  194. package/presets/opencode/next/rules/playwright-agents.md +67 -0
  195. package/presets/opencode/next/rules/post-change-lint.md +35 -0
  196. package/presets/opencode/next/rules/preset-layering.md +27 -0
  197. package/presets/opencode/next/rules/preset-no-cross-stack-leakage.md +90 -0
  198. package/presets/opencode/next/rules/preset-pr-checklist.md +36 -0
  199. package/presets/opencode/next/rules/preset-token-budget.md +39 -0
  200. package/presets/opencode/next/rules/preset-twin-sync.md +81 -0
  201. package/presets/opencode/next/rules/product-specs-authoring.md +112 -0
  202. package/presets/opencode/next/rules/product-specs.md +56 -0
  203. package/presets/opencode/next/rules/public-imports.md +50 -0
  204. package/presets/opencode/next/rules/react-a11y-coding.md +31 -0
  205. package/presets/opencode/next/rules/react-next-anti-hallucination.md +60 -0
  206. package/presets/opencode/next/rules/react-ui.md +105 -0
  207. package/presets/opencode/next/rules/reference-features.md +45 -0
  208. package/presets/opencode/next/rules/security-next.md +45 -0
  209. package/presets/opencode/next/rules/store-rtk.md +78 -0
  210. package/presets/opencode/next/rules/technical-retro.md +11 -0
  211. package/presets/opencode/next/rules/tests-e2e-structure.md +72 -0
  212. package/presets/opencode/next/rules/tests-unit.md +72 -0
  213. package/presets/opencode/next/rules/types-jsdoc.md +43 -0
  214. package/presets/opencode/next/rules/ux-design.md +99 -0
  215. package/presets/opencode/next/skills/README.md +21 -0
  216. package/presets/opencode/next/skills/ci-investigation/SKILL.md +44 -0
  217. package/presets/opencode/next/skills/code-review/SKILL.md +44 -0
  218. package/presets/opencode/next/skills/debug-investigation/SKILL.md +59 -0
  219. package/presets/opencode/next/skills/feature-delivery/SKILL.md +39 -0
  220. package/presets/opencode/next/skills/mockup-review/SKILL.md +29 -0
  221. package/presets/opencode/next/skills/playwright-e2e/SKILL.md +33 -0
  222. package/presets/opencode/next/skills/react-performance/SKILL.md +44 -0
  223. package/presets/opencode/next/skills/spec-authoring/SKILL.md +26 -0
  224. package/presets/opencode/next/skills/spec-discovery/SKILL.md +58 -0
  225. package/presets/opencode/next/skills/technical-retro/SKILL.md +54 -0
  226. package/presets/opencode/next/skills/unit-testing/SKILL.md +34 -0
  227. package/presets/opencode/next/skills/ux-design/SKILL.md +36 -0
  228. package/presets/opencode/next/skills/write-adr/SKILL.md +41 -0
  229. package/presets/opencode/next/team/README.md +148 -0
  230. package/presets/opencode/next/team/conventions.md +21 -0
  231. package/presets/opencode/next/team/fixtures/artifact-manifest.example.json +79 -0
  232. package/presets/opencode/next/team/fixtures/bugfix-standard.json +25 -0
  233. package/presets/opencode/next/team/fixtures/feature-full.json +29 -0
  234. package/presets/opencode/next/team/fixtures/feature-light.json +27 -0
  235. package/presets/opencode/next/team/fixtures/feature-with-figma-url.json +17 -0
  236. package/presets/opencode/next/team/fixtures/feature-with-ux-no-figma.json +17 -0
  237. package/presets/opencode/next/team/fixtures/memlog.example.md +9 -0
  238. package/presets/opencode/next/team/fixtures/metrics-scenarios/tasks/human-gate/metrics.json +69 -0
  239. package/presets/opencode/next/team/fixtures/metrics-scenarios/tasks/missing-ledger/status.json +5 -0
  240. package/presets/opencode/next/team/fixtures/metrics-scenarios/tasks/parallel-receipts/metrics.json +79 -0
  241. package/presets/opencode/next/team/fixtures/metrics-scenarios/tasks/serial-retry/metrics.json +124 -0
  242. package/presets/opencode/next/team/fixtures/metrics-scenarios/tasks/validation-failed/metrics.json +124 -0
  243. package/presets/opencode/next/team/fixtures/metrics.example.json +54 -0
  244. package/presets/opencode/next/team/fixtures/mockup-review-fail-embedded-status.json +8 -0
  245. package/presets/opencode/next/team/fixtures/mockup-review-standalone.json +14 -0
  246. package/presets/opencode/next/team/fixtures/ux-design-standalone.json +15 -0
  247. package/presets/opencode/next/team/tasks/.gitkeep +0 -0
  248. package/presets/opencode/platform-contract.json +131 -0
  249. package/scripts/capture-cli-golden.mjs +5 -1
  250. package/scripts/check-chain-hook-coverage.sh +1 -0
  251. package/scripts/check-opencode-adapter-map.mjs +294 -0
  252. package/scripts/check-opencode-local-overlay.mjs +56 -0
  253. package/scripts/check-opencode-platform-contract.mjs +388 -0
  254. package/scripts/check-opencode-token-budget.mjs +48 -0
  255. package/scripts/check-preset-leakage.sh +30 -1
  256. package/scripts/check-preset-structure.sh +45 -0
  257. package/scripts/check-task-router-intents.sh +4 -4
  258. package/scripts/fixtures/cli-golden/claude/next.json +8 -8
  259. package/scripts/fixtures/cli-golden/cursor/next.json +8 -8
  260. package/scripts/fixtures/cli-golden/mavis/next.json +10 -10
  261. package/scripts/fixtures/cli-golden/opencode/next.json +125 -0
  262. package/scripts/fixtures/opencode-adapter-map/invalid-unmapped/cursor/AGENTS.md +1 -0
  263. package/scripts/fixtures/opencode-adapter-map/invalid-unmapped/cursor/rules/extra.mdc +1 -0
  264. package/scripts/fixtures/opencode-adapter-map/invalid-unmapped/cursor/rules/sample.mdc +2 -0
  265. package/scripts/fixtures/opencode-adapter-map/invalid-unmapped/opencode/OPENCODE.md +1 -0
  266. package/scripts/fixtures/opencode-adapter-map/invalid-unmapped/opencode/adapter-map.json +26 -0
  267. package/scripts/fixtures/opencode-adapter-map/invalid-unmapped/opencode/rules/sample.md +2 -0
  268. package/scripts/fixtures/opencode-adapter-map/valid/cursor/AGENTS.md +1 -0
  269. package/scripts/fixtures/opencode-adapter-map/valid/cursor/rules/sample.mdc +2 -0
  270. package/scripts/fixtures/opencode-adapter-map/valid/opencode/OPENCODE.md +1 -0
  271. package/scripts/fixtures/opencode-adapter-map/valid/opencode/adapter-map.json +26 -0
  272. package/scripts/fixtures/opencode-adapter-map/valid/opencode/rules/sample.md +2 -0
  273. package/scripts/fixtures/opencode-platform-contract/invalid-home-destination.json +131 -0
  274. package/scripts/fixtures/opencode-platform-contract/invalid-missing-capability.json +126 -0
  275. package/scripts/fixtures/opencode-platform-contract/invalid-released-unknown-stack.json +133 -0
  276. package/scripts/fixtures/opencode-platform-contract/invalid-unknown-native-path.json +131 -0
  277. package/scripts/fixtures/opencode-platform-contract/invalid-version-pin.json +132 -0
  278. package/scripts/fixtures/opencode-platform-contract/valid.json +131 -0
  279. package/scripts/generate-mavis-next.mjs +4 -101
  280. package/scripts/generate-opencode-next.mjs +730 -0
  281. package/scripts/lib/discover-hooks.mjs +23 -1
  282. package/scripts/sync-dogfood-mavis.sh +90 -0
  283. package/scripts/sync-dogfood-opencode.sh +85 -0
  284. package/scripts/test-agent-task-metrics-hooks.mjs +4 -1
  285. package/scripts/test-chain-team-phases-coverage.mjs +6 -1
  286. package/scripts/test-cli-init-clean.mjs +180 -2
  287. package/scripts/test-opencode-context-budget.mjs +53 -0
package/CHANGELOG.md CHANGED
@@ -2,6 +2,22 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ### Quad-install Next: shared root `AGENTS.md`
6
+
7
+ - Cursor, Claude, Mavis, and OpenCode **next** presets now ship the **same** `REPO_AGENTS.md` (presence-based load + per-tool pipeline caveat + local overlay). Last `init` still overwrites the file; content no longer depends on which tool ran last.
8
+ - `clean <tool>` leaves root `AGENTS.md` when another tool install is still present.
9
+ - `init multi --preset next` installs all four platforms in one command (Mavis/OpenCode skipped on stacks they have not released).
10
+ - Consumers: `npx @bonesofspring/ai-rules init multi --preset next` on Next repos.
11
+
12
+ ### OpenCode platform (experimental Next-only)
13
+
14
+ - New platform **`opencode`**: `npx @bonesofspring/ai-rules init opencode --preset next` installs **`.opencode/**`** plus root `AGENTS.md` and merges MCP into **`opencode.json`**. `clean opencode` is manifest/hash-safe. The CLI never writes `~/.config/opencode/**`.
15
+ - Source: `presets/opencode/next/` derived from `presets/cursor/next` (`adapter-map.json`, `generate-opencode-next.mjs`). `platform-contract.json` `releasedStacks: ["next"]`; nine other stacks deferred.
16
+ - Native OpenCode discovery for agents, skills, and slash commands. Rules under `.opencode/rules/` are lazy-loaded from `AGENTS.md` (no `alwaysApply`/`globs` engine). Pipeline hook is manual `chain-team-phases.sh` (no `hooks.json` plugin in v1).
17
+ - Docs: [`docs/OPENCODE.md`](docs/OPENCODE.md) (consumer), [`docs/OPENCODE-COMPATIBILITY.md`](docs/OPENCODE-COMPATIBILITY.md) (docs-floor evidence). Gates: `check-opencode-*`, `test-opencode-context-budget` wired into `check:preset-structure`.
18
+ - Review follow-up: team-agent write-scope lead-in is role-specific; consumer `OPENCODE.md` no longer uses broken relative doc links; orchestrator uses OpenCode `mode`/`permission` wording; `build-verifier` preset-structure lists OpenCode/Mavis derive gates; Cursor/Claude `REPO_AGENTS.md` keep OpenCode/Mavis pointers so mixed-tool `init` does not drop them.
19
+ - Consumers: re-run `npx @bonesofspring/ai-rules init opencode --preset next` after publish. Cursor/Claude/Mavis installs unchanged.
20
+
5
21
  ### Mavis platform (MiniMax Code, experimental Next-only)
6
22
 
7
23
  - New platform **`mavis`** (`mcode` runtime): `npx @bonesofspring/ai-rules init mavis --preset next` installs **`.mavis/**`** plus root `AGENTS.md`. `clean mavis` is manifest/hash-safe. MCP merges to **`.mavis/mcp.json`** only — the CLI never writes `~/.minimax/**`.
package/README.md CHANGED
@@ -1,16 +1,15 @@
1
1
  # @bonesofspring/ai-rules
2
2
 
3
- Presets for Cursor, Claude Code, and **Mavis / MiniMax Code (experimental Next-only)**:
3
+ Presets for Cursor, Claude Code, **Mavis / MiniMax Code (experimental Next-only)**, and **OpenCode (experimental Next-only)**:
4
4
 
5
5
  Node 18+.
6
6
 
7
7
  ```bash
8
8
  # from the project root
9
- npx @bonesofspring/ai-rules init cursor --preset next
10
- npx @bonesofspring/ai-rules init claude --preset next
11
- npx @bonesofspring/ai-rules init mavis --preset next
9
+ npx @bonesofspring/ai-rules init multi --preset next
12
10
  npx @bonesofspring/ai-rules clean cursor
13
11
  npx @bonesofspring/ai-rules clean mavis
12
+ npx @bonesofspring/ai-rules clean opencode
14
13
  ```
15
14
 
16
15
  Global: `npm i -g @bonesofspring/ai-rules`, then `ai-rules ...`.
@@ -36,7 +35,7 @@ If `.cursor` does not appear, check the command output for errors and confirm yo
36
35
  - optional dirs when present: `agents/`, `hooks/`, `skills/`, `team/`
37
36
  - Cursor root files: `hooks.json`, `BUGBOT.md`, `AGENTS.md`, `MCP.md`, `mcp.json`
38
37
  - Claude: `CLAUDE.md`, `MCP.md` under `.claude/`; project `.mcp.json` at repo root
39
- - **Both tools:** repo-root `AGENTS.md` (from preset `REPO_AGENTS.md`)
38
+ - **Shared root `AGENTS.md`:** removed only when no other tool install remains (Cursor, Claude, Mavis, or OpenCode markers still on disk)
40
39
 
41
40
  Any other files you added under `.cursor/` or `.claude/` (notes, local overrides, IDE state) are **left intact**. Older releases that deleted the whole tool directory are no longer the behavior.
42
41
 
@@ -58,6 +57,22 @@ Where things go on `init`:
58
57
 
59
58
  **Mavis (MiniMax Code, experimental Next-only):** `ai-rules init mavis --preset next` writes ai-rules-owned **`.mavis/**`** plus root `AGENTS.md`. MCP merges into **`.mavis/mcp.json`** only — the CLI never writes `~/.minimax/**`. `clean mavis` is manifest-owned: unchanged hashes are removed; modified files stay. See [`docs/MAVIS.md`](docs/MAVIS.md), [`presets/mavis/README.md`](presets/mavis/README.md), and [`docs/MAVIS-COMPATIBILITY.md`](docs/MAVIS-COMPATIBILITY.md).
60
59
 
60
+ **OpenCode (experimental Next-only):** `ai-rules init opencode --preset next` writes native **`.opencode/**`** plus root `AGENTS.md` and merges MCP into **`opencode.json`**. `clean opencode` is manifest-owned. The CLI never writes `~/.config/opencode/**`. All four next platforms ship the **same** root `AGENTS.md` (last `init` still overwrites, content does not change). See [`docs/OPENCODE.md`](docs/OPENCODE.md), [`presets/opencode/README.md`](presets/opencode/README.md), and [`docs/OPENCODE-COMPATIBILITY.md`](docs/OPENCODE-COMPATIBILITY.md).
61
+
62
+ ### Multi-tool on one branch (Next)
63
+
64
+ Install all four from the app root (`init multi` is the one-shot), then commit the four trees plus root `AGENTS.md`. Living exceptions belong in **`.ai.local/`** (init never touches it).
65
+
66
+ ```bash
67
+ npx @bonesofspring/ai-rules init multi --preset next
68
+ ```
69
+
70
+ Per-tool: `init cursor|claude|mavis|opencode --preset next`. On stacks other than `next`, `init multi` still installs Cursor and Claude and **skips** Mavis/OpenCode until those platforms list the stack in `releasedStacks`.
71
+
72
+ **Shared:** stack rules (packaged per tool), root `AGENTS.md`, `.ai.local/` overlay.
73
+
74
+ **Not shared:** `/task` pipelines. Each tool writes `.tool/team/tasks/<slug>/` (`status.json` is not cross-tool). Cursor auto-chains via `hooks.json` / `subagentStop`. Claude ships `chain-team-phases.sh` without `hooks.json`. Mavis and OpenCode are semi-auto: `printf '{"status":"completed"}' | bash .tool/hooks/chain-team-phases.sh`. Mavis/OpenCode remain Next-only.
75
+
61
76
  Skills of note: `write-adr` (all stacks); `spec-authoring` (Generate/Bootstrap `docs/specs`); `mockup-review` (**next** / **nuxt** / **svelte** / **ios-swift** / **android-kotlin** — Figma mockup reviewer via agent `mockup-reviewer`); `ux-design` (**next** / **nuxt** / **svelte** / **ios-swift** / **android-kotlin** — behavioral UX via `task-analyst`, no agent); `react-performance` (**next only**); `vue-performance` (**nuxt only**); `svelte-performance` (**svelte only**). Optional command `/spec-start`. Living gotchas: `team/conventions.md`. Opt-in rule samples eval: `yarn check:rule-eval` (workflow `rule-eval.yml`; not part of `check:preset-structure`). Optional consumer specs check: `yarn check:product-specs` (WARN default; `--strict` FAIL).
62
77
 
63
78
  ## Product specs (`docs/specs/`)
package/bin/cli.js CHANGED
@@ -5,11 +5,15 @@
5
5
  const fs = require('fs');
6
6
  const path = require('path');
7
7
  const { cmdInitMavis, cmdCleanMavis } = require('./mavis-install');
8
+ const { cmdInitOpencode, cmdCleanOpencode } = require('./opencode-install');
8
9
 
9
10
  /** Single path segment: letters, digits, dot, underscore, hyphen; no separators or "..". */
10
11
  const PRESET_NAME_RE = /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/;
11
12
  const DEFAULT_PRESET = 'next';
12
- const TOOLS = new Set(['cursor', 'claude', 'mavis']);
13
+ const TOOLS = new Set(['cursor', 'claude', 'mavis', 'opencode']);
14
+ /** Meta-target: `init multi` runs every platform that has released the preset. */
15
+ const INIT_TARGETS = new Set([...TOOLS, 'multi']);
16
+ const MULTI_INSTALL_ORDER = ['cursor', 'claude', 'mavis', 'opencode'];
13
17
 
14
18
  const PRESETS = {
15
19
  cursor: {
@@ -52,9 +56,9 @@ function printHelp() {
52
56
  console.log(`@bonesofspring/ai-rules
53
57
 
54
58
  Usage:
55
- ai-rules init <cursor|claude|mavis> [--preset <name>]
56
- ai-rules init <cursor|claude|mavis> <preset-name>
57
- ai-rules clean <cursor|claude|mavis> [--cwd <dir>]
59
+ ai-rules init <cursor|claude|mavis|opencode|multi> [--preset <name>]
60
+ ai-rules init <cursor|claude|mavis|opencode|multi> <preset-name>
61
+ ai-rules clean <cursor|claude|mavis|opencode> [--cwd <dir>]
58
62
 
59
63
  Options:
60
64
  --preset <name> Preset name (default: ${DEFAULT_PRESET})
@@ -68,9 +72,11 @@ Notes:
68
72
  Cursor init copies rules, commands, agents, hooks, skills, team, hooks.json, BUGBOT.md, AGENTS.md → .cursor/AGENTS.md, MCP.md, mcp.json → .cursor/mcp.json.
69
73
  Claude init copies rules, commands, skills, agents, hooks, team, CLAUDE.md, MCP.md, and mcp.json → .mcp.json (project root).
70
74
  Mavis init copies into .mavis/ (ai-rules-owned) plus REPO_AGENTS.md → <cwd>/AGENTS.md; MCP merges into .mavis/mcp.json only (never ~/.minimax/**).
71
- Both tools also copy REPO_AGENTS.md → <cwd>/AGENTS.md (repo-root cross-tool agents file; overwrite).
75
+ OpenCode init copies into .opencode/ plus REPO_AGENTS.md → <cwd>/AGENTS.md; MCP merges into <cwd>/opencode.json (never ~/.config/opencode/**).
76
+ All init targets also copy REPO_AGENTS.md → <cwd>/AGENTS.md (repo-root cross-tool agents file; overwrite; all next platforms ship the same file).
77
+ init multi installs every platform that has released the preset (cursor, claude, plus mavis/opencode when listed in releasedStacks). Not a clean target.
72
78
  When <cwd>/docs/specs/ is absent, init also seeds INDEX.md stub + _templates/* from package assets (never overwrites an existing INDEX).
73
- clean removes tool dirs/files and <cwd>/AGENTS.md (shared across tools — re-init the other tool to restore).
79
+ clean removes tool dirs/files. Shared <cwd>/AGENTS.md is removed only when no other tool install remains.
74
80
  Command forms: "init cursor --preset next", "init cursor next", "--preset next init cursor", "cursor init --preset next".
75
81
 
76
82
  Examples:
@@ -96,7 +102,10 @@ Examples:
96
102
  npx @bonesofspring/ai-rules init claude --preset php-hexagonal
97
103
  npx @bonesofspring/ai-rules init claude --preset php-laravel
98
104
  npx @bonesofspring/ai-rules init mavis --preset next
105
+ npx @bonesofspring/ai-rules init opencode --preset next
106
+ npx @bonesofspring/ai-rules init multi --preset next
99
107
  npx @bonesofspring/ai-rules clean mavis
108
+ npx @bonesofspring/ai-rules clean opencode
100
109
  npx @bonesofspring/ai-rules clean cursor
101
110
  `);
102
111
  }
@@ -154,7 +163,7 @@ function parseArgs(argv) {
154
163
  }
155
164
 
156
165
  /**
157
- * Supports: init cursor, cursor init, init cursor next (positional preset).
166
+ * Supports: init cursor, cursor init, init cursor next (positional preset), init multi.
158
167
  */
159
168
  function normalizeInitClean(parsed) {
160
169
  const positional = [...parsed._];
@@ -162,11 +171,11 @@ function normalizeInitClean(parsed) {
162
171
  let tool;
163
172
  let presetFromPositional;
164
173
 
165
- if (positional.length >= 2 && TOOLS.has(positional[0]) && positional[1] === 'init') {
174
+ if (positional.length >= 2 && INIT_TARGETS.has(positional[0]) && positional[1] === 'init') {
166
175
  command = 'init';
167
176
  tool = positional[0];
168
177
  presetFromPositional = positional[2];
169
- } else if (positional.length >= 2 && positional[0] === 'init' && TOOLS.has(positional[1])) {
178
+ } else if (positional.length >= 2 && positional[0] === 'init' && INIT_TARGETS.has(positional[1])) {
170
179
  command = 'init';
171
180
  tool = positional[1];
172
181
  presetFromPositional = positional[2];
@@ -387,6 +396,23 @@ function removeFileIfExists(filePath) {
387
396
  }
388
397
  }
389
398
 
399
+ /** Markers that mean a tool install is still present (directory leftovers do not count). */
400
+ const TOOL_INSTALL_MARKERS = {
401
+ '.cursor': ['.cursor/AGENTS.md', '.cursor/hooks.json', '.cursor/rules'],
402
+ '.claude': ['.claude/CLAUDE.md', '.claude/rules'],
403
+ '.mavis': ['.mavis/.ai-rules-install.json', '.mavis/AGENTS.md'],
404
+ '.opencode': ['.opencode/.ai-rules-install.json', '.opencode/AGENTS.md'],
405
+ };
406
+
407
+ function otherToolInstallPresent(cwd, exceptRoot) {
408
+ return Object.entries(TOOL_INSTALL_MARKERS).some(([root, markers]) => {
409
+ if (root === exceptRoot) {
410
+ return false;
411
+ }
412
+ return markers.some((rel) => fs.existsSync(path.join(cwd, rel)));
413
+ });
414
+ }
415
+
390
416
  function listPresetNames(presetsRoot) {
391
417
  if (!fs.existsSync(presetsRoot)) {
392
418
  return [];
@@ -487,6 +513,53 @@ function resolvePresetName(tool, preset, packageRoot) {
487
513
  return { name, base, presetsRoot };
488
514
  }
489
515
 
516
+ function loadReleasedStacks(platform) {
517
+ if (platform === 'cursor' || platform === 'claude') {
518
+ return null;
519
+ }
520
+ const contractPath = path.join(getPackageRoot(), 'presets', platform, 'platform-contract.json');
521
+ if (!fs.existsSync(contractPath)) {
522
+ return [];
523
+ }
524
+ try {
525
+ const contract = JSON.parse(fs.readFileSync(contractPath, 'utf8'));
526
+ return Array.isArray(contract.releasedStacks) ? contract.releasedStacks : [];
527
+ } catch {
528
+ return [];
529
+ }
530
+ }
531
+
532
+ function cmdInitMulti(preset, cwdOption) {
533
+ const presetName = preset === undefined || preset === '' ? DEFAULT_PRESET : preset;
534
+ const invalid = validatePresetName(presetName);
535
+ if (invalid) {
536
+ console.error(invalid);
537
+ process.exit(1);
538
+ }
539
+
540
+ const installed = [];
541
+ const skipped = [];
542
+ for (const tool of MULTI_INSTALL_ORDER) {
543
+ const released = loadReleasedStacks(tool);
544
+ if (released && released.length > 0 && !released.includes(presetName)) {
545
+ skipped.push(tool);
546
+ console.log(
547
+ `Skipping ${tool}: preset "${presetName}" is not released yet (released: ${released.join(', ')})`,
548
+ );
549
+ continue;
550
+ }
551
+ console.log(`\n=== init ${tool} --preset ${presetName} ===`);
552
+ cmdInit(tool, presetName, cwdOption);
553
+ installed.push(tool);
554
+ }
555
+ if (installed.length === 0) {
556
+ console.error(`multi: no platforms installed for preset "${presetName}".`);
557
+ process.exit(1);
558
+ }
559
+ const skipNote = skipped.length > 0 ? `; skipped ${skipped.join(', ')}` : '';
560
+ console.log(`\nDone. multi installed ${installed.join(', ')}${skipNote}`);
561
+ }
562
+
490
563
  function cmdInit(tool, preset, cwdOption) {
491
564
  if (tool === 'mavis') {
492
565
  cmdInitMavis({
@@ -501,9 +574,21 @@ function cmdInit(tool, preset, cwdOption) {
501
574
  });
502
575
  return;
503
576
  }
577
+ if (tool === 'opencode') {
578
+ cmdInitOpencode({
579
+ preset,
580
+ cwdOption,
581
+ helpers: {
582
+ resolveTargetCwd,
583
+ seedDocsSpecsIfAbsent,
584
+ getPackageRoot,
585
+ },
586
+ });
587
+ return;
588
+ }
504
589
  const cfg = PRESETS[tool];
505
590
  if (!cfg) {
506
- console.error(`Unknown tool: ${tool}. Use cursor, claude, or mavis.`);
591
+ console.error(`Unknown tool: ${tool}. Use cursor, claude, mavis, or opencode.`);
507
592
  process.exit(1);
508
593
  }
509
594
 
@@ -685,13 +770,20 @@ function cmdClean(tool, cwdOption) {
685
770
  if (tool === 'mavis') {
686
771
  cmdCleanMavis({
687
772
  cwdOption,
688
- helpers: { resolveTargetCwd },
773
+ helpers: { resolveTargetCwd, otherToolInstallPresent },
774
+ });
775
+ return;
776
+ }
777
+ if (tool === 'opencode') {
778
+ cmdCleanOpencode({
779
+ cwdOption,
780
+ helpers: { resolveTargetCwd, otherToolInstallPresent },
689
781
  });
690
782
  return;
691
783
  }
692
784
  const cfg = PRESETS[tool];
693
785
  if (!cfg) {
694
- console.error(`Unknown tool: ${tool}. Use cursor, claude, or mavis.`);
786
+ console.error(`Unknown tool: ${tool}. Use cursor, claude, mavis, or opencode.`);
695
787
  process.exit(1);
696
788
  }
697
789
  const cwd = resolveTargetCwd(cwdOption);
@@ -728,6 +820,10 @@ function cmdClean(tool, cwdOption) {
728
820
  }
729
821
 
730
822
  for (const destRel of Object.values(cfg.repoRootFiles || {})) {
823
+ if (destRel === 'AGENTS.md' && otherToolInstallPresent(cwd, toolRoot)) {
824
+ console.log('Kept shared AGENTS.md (another tool install is still present)');
825
+ continue;
826
+ }
731
827
  removeFileIfExists(path.join(cwd, destRel));
732
828
  removedParts.push(destRel);
733
829
  }
@@ -760,16 +856,26 @@ function main() {
760
856
  const { command, tool, preset } = normalizeInitClean(parsed);
761
857
 
762
858
  if (command === 'init') {
763
- if (!tool || !TOOLS.has(tool)) {
764
- console.error('Missing or invalid tool. Use: init cursor|claude|mavis [--preset next]');
859
+ if (!tool || !INIT_TARGETS.has(tool)) {
860
+ console.error(
861
+ 'Missing or invalid tool. Use: init cursor|claude|mavis|opencode|multi [--preset next]',
862
+ );
765
863
  process.exit(1);
766
864
  }
865
+ if (tool === 'multi') {
866
+ cmdInitMulti(preset, parsed.cwd);
867
+ return;
868
+ }
767
869
  cmdInit(tool, preset, parsed.cwd);
768
870
  return;
769
871
  }
770
872
  if (command === 'clean') {
873
+ if (tool === 'multi') {
874
+ console.error('clean multi is not supported. Clean each tool: cursor, claude, mavis, opencode.');
875
+ process.exit(1);
876
+ }
771
877
  if (!tool || !TOOLS.has(tool)) {
772
- console.error('Missing or invalid tool. Use: clean cursor|claude|mavis');
878
+ console.error('Missing or invalid tool. Use: clean cursor|claude|mavis|opencode');
773
879
  process.exit(1);
774
880
  }
775
881
  cmdClean(tool, parsed.cwd);
@@ -374,7 +374,7 @@ function removeEmptyDirs(dir) {
374
374
  }
375
375
 
376
376
  function cmdCleanMavis({ cwdOption, helpers }) {
377
- const { resolveTargetCwd } = helpers;
377
+ const { resolveTargetCwd, otherToolInstallPresent } = helpers;
378
378
  const cwd = resolveTargetCwd(cwdOption);
379
379
  const manifestPath = path.join(cwd, MANIFEST_REL);
380
380
  if (!fs.existsSync(manifestPath)) {
@@ -409,6 +409,10 @@ function cmdCleanMavis({ cwdOption, helpers }) {
409
409
  continue;
410
410
  }
411
411
  const current = sha256File(abs);
412
+ if (rel === 'AGENTS.md' && otherToolInstallPresent && otherToolInstallPresent(cwd, '.mavis')) {
413
+ console.log('Kept shared AGENTS.md (another tool install is still present)');
414
+ continue;
415
+ }
412
416
  if (current === installedHash) {
413
417
  fs.unlinkSync(abs);
414
418
  } else {