@bonesofspring/ai-rules 0.2.22 → 0.2.24

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 (429) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +10 -2
  3. package/bin/cli.js +56 -9
  4. package/bin/mavis-install.js +441 -0
  5. package/bin/opencode-install.js +531 -0
  6. package/package.json +17 -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 +5 -3
  11. package/presets/_shared/core/meta/preset-token-budget.md +3 -0
  12. package/presets/_shared/core/meta/preset-twin-sync.md +32 -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 +5 -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 +32 -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 +5 -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 +32 -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 +5 -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 +32 -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 +5 -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 +32 -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 +5 -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 +32 -0
  38. package/presets/claude/next/REPO_AGENTS.md +10 -5
  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 +5 -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 +32 -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 +5 -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 +32 -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 +5 -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 +32 -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 +5 -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 +32 -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 +5 -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 +32 -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 +5 -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 +32 -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 +5 -3
  74. package/presets/cursor/go/rules/preset-token-budget.mdc +3 -0
  75. package/presets/cursor/go/rules/preset-twin-sync.mdc +32 -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 +5 -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 +32 -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 +5 -3
  84. package/presets/cursor/java/rules/preset-token-budget.mdc +3 -0
  85. package/presets/cursor/java/rules/preset-twin-sync.mdc +32 -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 +5 -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 +32 -0
  91. package/presets/cursor/next/REPO_AGENTS.md +10 -5
  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 +5 -3
  97. package/presets/cursor/next/rules/preset-token-budget.mdc +3 -0
  98. package/presets/cursor/next/rules/preset-twin-sync.mdc +32 -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 +5 -3
  102. package/presets/cursor/nuxt/rules/preset-token-budget.mdc +3 -0
  103. package/presets/cursor/nuxt/rules/preset-twin-sync.mdc +32 -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 +5 -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 +32 -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 +5 -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 +32 -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 +5 -3
  117. package/presets/cursor/svelte/rules/preset-token-budget.mdc +3 -0
  118. package/presets/cursor/svelte/rules/preset-twin-sync.mdc +32 -0
  119. package/presets/mavis/README.md +60 -0
  120. package/presets/mavis/next/MAVIS.md +67 -0
  121. package/presets/mavis/next/MCP.md +36 -0
  122. package/presets/mavis/next/README.md +15 -0
  123. package/presets/mavis/next/REPO_AGENTS.md +96 -0
  124. package/presets/mavis/next/adapter-map.json +959 -0
  125. package/presets/mavis/next/agents/README.md +206 -0
  126. package/presets/mavis/next/agents/accessibility-reviewer.md +61 -0
  127. package/presets/mavis/next/agents/api-contract-reviewer.md +57 -0
  128. package/presets/mavis/next/agents/build-verifier.md +112 -0
  129. package/presets/mavis/next/agents/ci-investigator.md +63 -0
  130. package/presets/mavis/next/agents/code-reviewer.md +61 -0
  131. package/presets/mavis/next/agents/codebase-analyzer.md +21 -0
  132. package/presets/mavis/next/agents/debugger.md +80 -0
  133. package/presets/mavis/next/agents/feature-developer.md +101 -0
  134. package/presets/mavis/next/agents/migration-specialist.md +67 -0
  135. package/presets/mavis/next/agents/mockup-reviewer.md +53 -0
  136. package/presets/mavis/next/agents/openspec-author.md +157 -0
  137. package/presets/mavis/next/agents/performance-auditor.md +68 -0
  138. package/presets/mavis/next/agents/playwright-test-generator.md +28 -0
  139. package/presets/mavis/next/agents/playwright-test-healer.md +28 -0
  140. package/presets/mavis/next/agents/playwright-test-planner.md +21 -0
  141. package/presets/mavis/next/agents/qa-tester.md +52 -0
  142. package/presets/mavis/next/agents/security-reviewer.md +54 -0
  143. package/presets/mavis/next/agents/solution-architect.md +68 -0
  144. package/presets/mavis/next/agents/task-analyst.md +166 -0
  145. package/presets/mavis/next/agents/task-router.md +178 -0
  146. package/presets/mavis/next/agents/tech-writer.md +57 -0
  147. package/presets/mavis/next/agents/unit-test-generator.md +31 -0
  148. package/presets/mavis/next/agents/unit-test-healer.md +32 -0
  149. package/presets/mavis/next/agents/unit-test-planner.md +54 -0
  150. package/presets/mavis/next/commands/README.md +49 -0
  151. package/presets/mavis/next/commands/spec-start.md +24 -0
  152. package/presets/mavis/next/commands/task-continue.md +50 -0
  153. package/presets/mavis/next/commands/task.md +50 -0
  154. package/presets/mavis/next/commands/technical-retro.md +80 -0
  155. package/presets/mavis/next/hooks/README.md +22 -0
  156. package/presets/mavis/next/hooks/chain-team-phases.sh +845 -0
  157. package/presets/mavis/next/mcp.json +19 -0
  158. package/presets/mavis/next/rules/README.md +16 -0
  159. package/presets/mavis/next/rules/agent-team-intake.md +11 -0
  160. package/presets/mavis/next/rules/agent-team-orchestrator.md +210 -0
  161. package/presets/mavis/next/rules/ai-local-overlay.md +37 -0
  162. package/presets/mavis/next/rules/anti-sycophancy-discipline.md +23 -0
  163. package/presets/mavis/next/rules/api-services.md +72 -0
  164. package/presets/mavis/next/rules/architecture-boundaries-ui.md +9 -0
  165. package/presets/mavis/next/rules/architecture-boundaries.md +86 -0
  166. package/presets/mavis/next/rules/arrow-functions.md +25 -0
  167. package/presets/mavis/next/rules/code-quality-and-refactoring.md +40 -0
  168. package/presets/mavis/next/rules/code-review-mr.md +40 -0
  169. package/presets/mavis/next/rules/css-property-order-stylelint.md +5 -0
  170. package/presets/mavis/next/rules/design-guidance.md +99 -0
  171. package/presets/mavis/next/rules/feature-delivery-workflow.md +49 -0
  172. package/presets/mavis/next/rules/http-client.md +55 -0
  173. package/presets/mavis/next/rules/layer-barrel-exports.md +68 -0
  174. package/presets/mavis/next/rules/mcp-usage.md +86 -0
  175. package/presets/mavis/next/rules/mockup-review.md +107 -0
  176. package/presets/mavis/next/rules/navigation-router-stack.md +56 -0
  177. package/presets/mavis/next/rules/navigation-router-ui.md +10 -0
  178. package/presets/mavis/next/rules/next-app-core.md +29 -0
  179. package/presets/mavis/next/rules/next-app-router.md +44 -0
  180. package/presets/mavis/next/rules/no-props-spread.md +56 -0
  181. package/presets/mavis/next/rules/no-type-assertion-as-import-export.md +51 -0
  182. package/presets/mavis/next/rules/package-manager.md +11 -0
  183. package/presets/mavis/next/rules/playwright-agents.md +67 -0
  184. package/presets/mavis/next/rules/post-change-lint.md +35 -0
  185. package/presets/mavis/next/rules/preset-layering.md +27 -0
  186. package/presets/mavis/next/rules/preset-no-cross-stack-leakage.md +90 -0
  187. package/presets/mavis/next/rules/preset-pr-checklist.md +36 -0
  188. package/presets/mavis/next/rules/preset-token-budget.md +39 -0
  189. package/presets/mavis/next/rules/preset-twin-sync.md +81 -0
  190. package/presets/mavis/next/rules/product-specs-authoring.md +112 -0
  191. package/presets/mavis/next/rules/product-specs.md +56 -0
  192. package/presets/mavis/next/rules/public-imports.md +50 -0
  193. package/presets/mavis/next/rules/react-a11y-coding.md +31 -0
  194. package/presets/mavis/next/rules/react-next-anti-hallucination.md +60 -0
  195. package/presets/mavis/next/rules/react-ui.md +105 -0
  196. package/presets/mavis/next/rules/reference-features.md +45 -0
  197. package/presets/mavis/next/rules/security-next.md +45 -0
  198. package/presets/mavis/next/rules/store-rtk.md +78 -0
  199. package/presets/mavis/next/rules/technical-retro.md +11 -0
  200. package/presets/mavis/next/rules/tests-e2e-structure.md +72 -0
  201. package/presets/mavis/next/rules/tests-unit.md +72 -0
  202. package/presets/mavis/next/rules/types-jsdoc.md +43 -0
  203. package/presets/mavis/next/rules/ux-design.md +99 -0
  204. package/presets/mavis/next/skills/README.md +21 -0
  205. package/presets/mavis/next/skills/ci-investigation/SKILL.md +39 -0
  206. package/presets/mavis/next/skills/code-review/SKILL.md +39 -0
  207. package/presets/mavis/next/skills/debug-investigation/SKILL.md +26 -0
  208. package/presets/mavis/next/skills/feature-delivery/SKILL.md +34 -0
  209. package/presets/mavis/next/skills/mockup-review/SKILL.md +24 -0
  210. package/presets/mavis/next/skills/playwright-e2e/SKILL.md +28 -0
  211. package/presets/mavis/next/skills/react-performance/SKILL.md +39 -0
  212. package/presets/mavis/next/skills/spec-authoring/SKILL.md +21 -0
  213. package/presets/mavis/next/skills/spec-discovery/SKILL.md +53 -0
  214. package/presets/mavis/next/skills/technical-retro/SKILL.md +49 -0
  215. package/presets/mavis/next/skills/unit-testing/SKILL.md +29 -0
  216. package/presets/mavis/next/skills/ux-design/SKILL.md +31 -0
  217. package/presets/mavis/next/skills/write-adr/SKILL.md +36 -0
  218. package/presets/mavis/next/team/README.md +148 -0
  219. package/presets/mavis/next/team/conventions.md +21 -0
  220. package/presets/mavis/next/team/fixtures/artifact-manifest.example.json +79 -0
  221. package/presets/mavis/next/team/fixtures/bugfix-standard.json +25 -0
  222. package/presets/mavis/next/team/fixtures/feature-full.json +29 -0
  223. package/presets/mavis/next/team/fixtures/feature-light.json +27 -0
  224. package/presets/mavis/next/team/fixtures/feature-with-figma-url.json +17 -0
  225. package/presets/mavis/next/team/fixtures/feature-with-ux-no-figma.json +17 -0
  226. package/presets/mavis/next/team/fixtures/memlog.example.md +9 -0
  227. package/presets/mavis/next/team/fixtures/metrics-scenarios/tasks/human-gate/metrics.json +69 -0
  228. package/presets/mavis/next/team/fixtures/metrics-scenarios/tasks/missing-ledger/status.json +5 -0
  229. package/presets/mavis/next/team/fixtures/metrics-scenarios/tasks/parallel-receipts/metrics.json +79 -0
  230. package/presets/mavis/next/team/fixtures/metrics-scenarios/tasks/serial-retry/metrics.json +124 -0
  231. package/presets/mavis/next/team/fixtures/metrics-scenarios/tasks/validation-failed/metrics.json +124 -0
  232. package/presets/mavis/next/team/fixtures/metrics.example.json +54 -0
  233. package/presets/mavis/next/team/fixtures/mockup-review-fail-embedded-status.json +8 -0
  234. package/presets/mavis/next/team/fixtures/mockup-review-standalone.json +14 -0
  235. package/presets/mavis/next/team/fixtures/ux-design-standalone.json +15 -0
  236. package/presets/mavis/next/team/tasks/.gitkeep +0 -0
  237. package/presets/mavis/platform-contract.json +131 -0
  238. package/presets/opencode/README.md +61 -0
  239. package/presets/opencode/next/MCP.md +36 -0
  240. package/presets/opencode/next/OPENCODE.md +65 -0
  241. package/presets/opencode/next/README.md +16 -0
  242. package/presets/opencode/next/REPO_AGENTS.md +97 -0
  243. package/presets/opencode/next/adapter-map.json +959 -0
  244. package/presets/opencode/next/agents/README.md +201 -0
  245. package/presets/opencode/next/agents/accessibility-reviewer.md +73 -0
  246. package/presets/opencode/next/agents/api-contract-reviewer.md +69 -0
  247. package/presets/opencode/next/agents/build-verifier.md +124 -0
  248. package/presets/opencode/next/agents/ci-investigator.md +71 -0
  249. package/presets/opencode/next/agents/code-reviewer.md +73 -0
  250. package/presets/opencode/next/agents/codebase-analyzer.md +33 -0
  251. package/presets/opencode/next/agents/debugger.md +88 -0
  252. package/presets/opencode/next/agents/feature-developer.md +109 -0
  253. package/presets/opencode/next/agents/migration-specialist.md +79 -0
  254. package/presets/opencode/next/agents/mockup-reviewer.md +65 -0
  255. package/presets/opencode/next/agents/openspec-author.md +169 -0
  256. package/presets/opencode/next/agents/performance-auditor.md +80 -0
  257. package/presets/opencode/next/agents/playwright-test-generator.md +36 -0
  258. package/presets/opencode/next/agents/playwright-test-healer.md +36 -0
  259. package/presets/opencode/next/agents/playwright-test-planner.md +33 -0
  260. package/presets/opencode/next/agents/qa-tester.md +60 -0
  261. package/presets/opencode/next/agents/security-reviewer.md +66 -0
  262. package/presets/opencode/next/agents/solution-architect.md +80 -0
  263. package/presets/opencode/next/agents/task-analyst.md +178 -0
  264. package/presets/opencode/next/agents/task-router.md +190 -0
  265. package/presets/opencode/next/agents/tech-writer.md +69 -0
  266. package/presets/opencode/next/agents/unit-test-generator.md +39 -0
  267. package/presets/opencode/next/agents/unit-test-healer.md +40 -0
  268. package/presets/opencode/next/agents/unit-test-planner.md +66 -0
  269. package/presets/opencode/next/commands/README.md +49 -0
  270. package/presets/opencode/next/commands/spec-start.md +32 -0
  271. package/presets/opencode/next/commands/task-continue.md +58 -0
  272. package/presets/opencode/next/commands/task.md +58 -0
  273. package/presets/opencode/next/commands/technical-retro.md +88 -0
  274. package/presets/opencode/next/hooks/README.md +22 -0
  275. package/presets/opencode/next/hooks/chain-team-phases.sh +845 -0
  276. package/presets/opencode/next/opencode.json +33 -0
  277. package/presets/opencode/next/rules/README.md +20 -0
  278. package/presets/opencode/next/rules/agent-team-intake.md +11 -0
  279. package/presets/opencode/next/rules/agent-team-orchestrator.md +214 -0
  280. package/presets/opencode/next/rules/ai-local-overlay.md +37 -0
  281. package/presets/opencode/next/rules/anti-sycophancy-discipline.md +23 -0
  282. package/presets/opencode/next/rules/api-services.md +72 -0
  283. package/presets/opencode/next/rules/architecture-boundaries-ui.md +9 -0
  284. package/presets/opencode/next/rules/architecture-boundaries.md +86 -0
  285. package/presets/opencode/next/rules/arrow-functions.md +25 -0
  286. package/presets/opencode/next/rules/code-quality-and-refactoring.md +40 -0
  287. package/presets/opencode/next/rules/code-review-mr.md +40 -0
  288. package/presets/opencode/next/rules/css-property-order-stylelint.md +5 -0
  289. package/presets/opencode/next/rules/design-guidance.md +99 -0
  290. package/presets/opencode/next/rules/feature-delivery-workflow.md +49 -0
  291. package/presets/opencode/next/rules/http-client.md +55 -0
  292. package/presets/opencode/next/rules/layer-barrel-exports.md +68 -0
  293. package/presets/opencode/next/rules/mcp-usage.md +86 -0
  294. package/presets/opencode/next/rules/mockup-review.md +107 -0
  295. package/presets/opencode/next/rules/navigation-router-stack.md +56 -0
  296. package/presets/opencode/next/rules/navigation-router-ui.md +10 -0
  297. package/presets/opencode/next/rules/next-app-core.md +29 -0
  298. package/presets/opencode/next/rules/next-app-router.md +44 -0
  299. package/presets/opencode/next/rules/no-props-spread.md +56 -0
  300. package/presets/opencode/next/rules/no-type-assertion-as-import-export.md +51 -0
  301. package/presets/opencode/next/rules/package-manager.md +11 -0
  302. package/presets/opencode/next/rules/playwright-agents.md +67 -0
  303. package/presets/opencode/next/rules/post-change-lint.md +35 -0
  304. package/presets/opencode/next/rules/preset-layering.md +27 -0
  305. package/presets/opencode/next/rules/preset-no-cross-stack-leakage.md +90 -0
  306. package/presets/opencode/next/rules/preset-pr-checklist.md +36 -0
  307. package/presets/opencode/next/rules/preset-token-budget.md +39 -0
  308. package/presets/opencode/next/rules/preset-twin-sync.md +81 -0
  309. package/presets/opencode/next/rules/product-specs-authoring.md +112 -0
  310. package/presets/opencode/next/rules/product-specs.md +56 -0
  311. package/presets/opencode/next/rules/public-imports.md +50 -0
  312. package/presets/opencode/next/rules/react-a11y-coding.md +31 -0
  313. package/presets/opencode/next/rules/react-next-anti-hallucination.md +60 -0
  314. package/presets/opencode/next/rules/react-ui.md +105 -0
  315. package/presets/opencode/next/rules/reference-features.md +45 -0
  316. package/presets/opencode/next/rules/security-next.md +45 -0
  317. package/presets/opencode/next/rules/store-rtk.md +78 -0
  318. package/presets/opencode/next/rules/technical-retro.md +11 -0
  319. package/presets/opencode/next/rules/tests-e2e-structure.md +72 -0
  320. package/presets/opencode/next/rules/tests-unit.md +72 -0
  321. package/presets/opencode/next/rules/types-jsdoc.md +43 -0
  322. package/presets/opencode/next/rules/ux-design.md +99 -0
  323. package/presets/opencode/next/skills/README.md +21 -0
  324. package/presets/opencode/next/skills/ci-investigation/SKILL.md +44 -0
  325. package/presets/opencode/next/skills/code-review/SKILL.md +44 -0
  326. package/presets/opencode/next/skills/debug-investigation/SKILL.md +59 -0
  327. package/presets/opencode/next/skills/feature-delivery/SKILL.md +39 -0
  328. package/presets/opencode/next/skills/mockup-review/SKILL.md +29 -0
  329. package/presets/opencode/next/skills/playwright-e2e/SKILL.md +33 -0
  330. package/presets/opencode/next/skills/react-performance/SKILL.md +44 -0
  331. package/presets/opencode/next/skills/spec-authoring/SKILL.md +26 -0
  332. package/presets/opencode/next/skills/spec-discovery/SKILL.md +58 -0
  333. package/presets/opencode/next/skills/technical-retro/SKILL.md +54 -0
  334. package/presets/opencode/next/skills/unit-testing/SKILL.md +34 -0
  335. package/presets/opencode/next/skills/ux-design/SKILL.md +36 -0
  336. package/presets/opencode/next/skills/write-adr/SKILL.md +41 -0
  337. package/presets/opencode/next/team/README.md +148 -0
  338. package/presets/opencode/next/team/conventions.md +21 -0
  339. package/presets/opencode/next/team/fixtures/artifact-manifest.example.json +79 -0
  340. package/presets/opencode/next/team/fixtures/bugfix-standard.json +25 -0
  341. package/presets/opencode/next/team/fixtures/feature-full.json +29 -0
  342. package/presets/opencode/next/team/fixtures/feature-light.json +27 -0
  343. package/presets/opencode/next/team/fixtures/feature-with-figma-url.json +17 -0
  344. package/presets/opencode/next/team/fixtures/feature-with-ux-no-figma.json +17 -0
  345. package/presets/opencode/next/team/fixtures/memlog.example.md +9 -0
  346. package/presets/opencode/next/team/fixtures/metrics-scenarios/tasks/human-gate/metrics.json +69 -0
  347. package/presets/opencode/next/team/fixtures/metrics-scenarios/tasks/missing-ledger/status.json +5 -0
  348. package/presets/opencode/next/team/fixtures/metrics-scenarios/tasks/parallel-receipts/metrics.json +79 -0
  349. package/presets/opencode/next/team/fixtures/metrics-scenarios/tasks/serial-retry/metrics.json +124 -0
  350. package/presets/opencode/next/team/fixtures/metrics-scenarios/tasks/validation-failed/metrics.json +124 -0
  351. package/presets/opencode/next/team/fixtures/metrics.example.json +54 -0
  352. package/presets/opencode/next/team/fixtures/mockup-review-fail-embedded-status.json +8 -0
  353. package/presets/opencode/next/team/fixtures/mockup-review-standalone.json +14 -0
  354. package/presets/opencode/next/team/fixtures/ux-design-standalone.json +15 -0
  355. package/presets/opencode/next/team/tasks/.gitkeep +0 -0
  356. package/presets/opencode/platform-contract.json +131 -0
  357. package/scripts/capture-cli-golden.mjs +48 -0
  358. package/scripts/check-chain-hook-coverage.sh +2 -0
  359. package/scripts/check-mavis-adapter-map.mjs +294 -0
  360. package/scripts/check-mavis-local-overlay.mjs +56 -0
  361. package/scripts/check-mavis-platform-contract.mjs +388 -0
  362. package/scripts/check-mavis-token-budget.mjs +48 -0
  363. package/scripts/check-opencode-adapter-map.mjs +294 -0
  364. package/scripts/check-opencode-local-overlay.mjs +56 -0
  365. package/scripts/check-opencode-platform-contract.mjs +388 -0
  366. package/scripts/check-opencode-token-budget.mjs +48 -0
  367. package/scripts/check-preset-leakage.sh +64 -3
  368. package/scripts/check-preset-structure.sh +108 -0
  369. package/scripts/check-shared-core-drift.sh +18 -0
  370. package/scripts/check-task-router-intents.sh +15 -2
  371. package/scripts/fixtures/cli-golden/claude/next.json +130 -0
  372. package/scripts/fixtures/cli-golden/cursor/next.json +132 -0
  373. package/scripts/fixtures/cli-golden/mavis/next.json +125 -0
  374. package/scripts/fixtures/cli-golden/opencode/next.json +125 -0
  375. package/scripts/fixtures/mavis-adapter-map/invalid-unmapped/cursor/AGENTS.md +1 -0
  376. package/scripts/fixtures/mavis-adapter-map/invalid-unmapped/cursor/rules/extra.mdc +1 -0
  377. package/scripts/fixtures/mavis-adapter-map/invalid-unmapped/cursor/rules/sample.mdc +2 -0
  378. package/scripts/fixtures/mavis-adapter-map/invalid-unmapped/mavis/MAVIS.md +1 -0
  379. package/scripts/fixtures/mavis-adapter-map/invalid-unmapped/mavis/adapter-map.json +26 -0
  380. package/scripts/fixtures/mavis-adapter-map/invalid-unmapped/mavis/rules/sample.md +2 -0
  381. package/scripts/fixtures/mavis-adapter-map/valid/cursor/AGENTS.md +1 -0
  382. package/scripts/fixtures/mavis-adapter-map/valid/cursor/rules/sample.mdc +2 -0
  383. package/scripts/fixtures/mavis-adapter-map/valid/mavis/MAVIS.md +1 -0
  384. package/scripts/fixtures/mavis-adapter-map/valid/mavis/adapter-map.json +26 -0
  385. package/scripts/fixtures/mavis-adapter-map/valid/mavis/rules/sample.md +2 -0
  386. package/scripts/fixtures/mavis-platform-contract/invalid-minimax-destination.json +131 -0
  387. package/scripts/fixtures/mavis-platform-contract/invalid-missing-capability.json +126 -0
  388. package/scripts/fixtures/mavis-platform-contract/invalid-released-unknown-stack.json +133 -0
  389. package/scripts/fixtures/mavis-platform-contract/invalid-unknown-native-path.json +131 -0
  390. package/scripts/fixtures/mavis-platform-contract/invalid-version-pin.json +132 -0
  391. package/scripts/fixtures/mavis-platform-contract/valid.json +131 -0
  392. package/scripts/fixtures/mavis-probe/AGENTS.md +6 -0
  393. package/scripts/fixtures/mavis-probe/agents/probe-agent.md +6 -0
  394. package/scripts/fixtures/mavis-probe/fake-mcode.mjs +98 -0
  395. package/scripts/fixtures/mavis-probe/output.schema.json +28 -0
  396. package/scripts/fixtures/mavis-probe/rules/probe.md +5 -0
  397. package/scripts/fixtures/mavis-probe/skills/probe/SKILL.md +11 -0
  398. package/scripts/fixtures/opencode-adapter-map/invalid-unmapped/cursor/AGENTS.md +1 -0
  399. package/scripts/fixtures/opencode-adapter-map/invalid-unmapped/cursor/rules/extra.mdc +1 -0
  400. package/scripts/fixtures/opencode-adapter-map/invalid-unmapped/cursor/rules/sample.mdc +2 -0
  401. package/scripts/fixtures/opencode-adapter-map/invalid-unmapped/opencode/OPENCODE.md +1 -0
  402. package/scripts/fixtures/opencode-adapter-map/invalid-unmapped/opencode/adapter-map.json +26 -0
  403. package/scripts/fixtures/opencode-adapter-map/invalid-unmapped/opencode/rules/sample.md +2 -0
  404. package/scripts/fixtures/opencode-adapter-map/valid/cursor/AGENTS.md +1 -0
  405. package/scripts/fixtures/opencode-adapter-map/valid/cursor/rules/sample.mdc +2 -0
  406. package/scripts/fixtures/opencode-adapter-map/valid/opencode/OPENCODE.md +1 -0
  407. package/scripts/fixtures/opencode-adapter-map/valid/opencode/adapter-map.json +26 -0
  408. package/scripts/fixtures/opencode-adapter-map/valid/opencode/rules/sample.md +2 -0
  409. package/scripts/fixtures/opencode-platform-contract/invalid-home-destination.json +131 -0
  410. package/scripts/fixtures/opencode-platform-contract/invalid-missing-capability.json +126 -0
  411. package/scripts/fixtures/opencode-platform-contract/invalid-released-unknown-stack.json +133 -0
  412. package/scripts/fixtures/opencode-platform-contract/invalid-unknown-native-path.json +131 -0
  413. package/scripts/fixtures/opencode-platform-contract/invalid-version-pin.json +132 -0
  414. package/scripts/fixtures/opencode-platform-contract/valid.json +131 -0
  415. package/scripts/generate-mavis-next.mjs +706 -0
  416. package/scripts/generate-opencode-next.mjs +831 -0
  417. package/scripts/lib/cli-golden.mjs +50 -0
  418. package/scripts/lib/discover-hooks.mjs +94 -0
  419. package/scripts/probe-mavis-capabilities.mjs +480 -0
  420. package/scripts/sync-dogfood-mavis.sh +90 -0
  421. package/scripts/sync-dogfood-opencode.sh +85 -0
  422. package/scripts/test-agent-task-metrics-hooks.mjs +25 -16
  423. package/scripts/test-chain-team-phases-coverage.mjs +15 -7
  424. package/scripts/test-cli-init-clean.mjs +367 -0
  425. package/scripts/test-cli-mcp-merge.mjs +23 -0
  426. package/scripts/test-mavis-context-budget.mjs +55 -0
  427. package/scripts/test-mavis-orchestration.mjs +649 -0
  428. package/scripts/test-opencode-context-budget.mjs +53 -0
  429. package/scripts/test-probe-mavis-capabilities.mjs +205 -0
package/CHANGELOG.md CHANGED
@@ -2,6 +2,23 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ### OpenCode platform (experimental Next-only)
6
+
7
+ - 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/**`.
8
+ - 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.
9
+ - 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).
10
+ - 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`.
11
+ - 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.
12
+ - Consumers: re-run `npx @bonesofspring/ai-rules init opencode --preset next` after publish. Cursor/Claude/Mavis installs unchanged.
13
+
14
+ ### Mavis platform (MiniMax Code, experimental Next-only)
15
+
16
+ - 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/**`.
17
+ - Source: `presets/mavis/next/` derived from `presets/cursor/next` (`adapter-map.json`, `generate-mavis-next.mjs`). `platform-contract.json` `releasedStacks: ["next"]`; nine other stacks deferred (WP-F).
18
+ - Semi-auto orchestration: `chain-team-phases.sh` on `.mavis/team`; no shipped `hooks.json`. Human gates via `task-continue` → hook `end_human_gate`. Agents upsert `artifact-manifest.json` only — hook owns `status.json` / `metrics.json`.
19
+ - Docs: [`docs/MAVIS.md`](docs/MAVIS.md) (consumer), [`docs/MAVIS-COMPATIBILITY.md`](docs/MAVIS-COMPATIBILITY.md) (probe evidence). Gates: `check-mavis-*`, `test-mavis-*` wired into `check:preset-structure`.
20
+ - Consumers: re-run `npx @bonesofspring/ai-rules init mavis --preset next` after publish. Cursor/Claude installs unchanged.
21
+
5
22
  ### Chain-team-phases hook coverage + pipeline race fixes
6
23
 
7
24
  - `chain-team-phases.sh` (all 20 stack × platform hooks) now covers every agent that ships in its stack's `agents/` directory:
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @bonesofspring/ai-rules
2
2
 
3
- Presets for Cursor and Claude Code: rules, commands, plus optional `agents`, `hooks`, `skills`, team artifacts, and MCP configs when the preset includes them. For Claude: `CLAUDE.md`. Install from npm into a project so you don’t have to copy files out of the repo by hand.
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
 
@@ -8,7 +8,11 @@ Node 18+.
8
8
  # from the project root
9
9
  npx @bonesofspring/ai-rules init cursor --preset next
10
10
  npx @bonesofspring/ai-rules init claude --preset next
11
+ npx @bonesofspring/ai-rules init mavis --preset next
12
+ npx @bonesofspring/ai-rules init opencode --preset next
11
13
  npx @bonesofspring/ai-rules clean cursor
14
+ npx @bonesofspring/ai-rules clean mavis
15
+ npx @bonesofspring/ai-rules clean opencode
12
16
  ```
13
17
 
14
18
  Global: `npm i -g @bonesofspring/ai-rules`, then `ai-rules ...`.
@@ -54,6 +58,10 @@ Where things go on `init`:
54
58
  | **repo-root agents** | `REPO_AGENTS.md` → **`<cwd>/AGENTS.md`** | same |
55
59
  | **docs/specs seed** | When `<cwd>/docs/specs/` is **absent**, copy INDEX stub + `_templates/*` from `presets/_shared/assets/docs-specs/` (never overwrite existing INDEX) | same |
56
60
 
61
+ **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).
62
+
63
+ **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/**`. Last `init` wins on root `AGENTS.md` if several tools are installed. See [`docs/OPENCODE.md`](docs/OPENCODE.md), [`presets/opencode/README.md`](presets/opencode/README.md), and [`docs/OPENCODE-COMPATIBILITY.md`](docs/OPENCODE-COMPATIBILITY.md).
64
+
57
65
  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).
58
66
 
59
67
  ## Product specs (`docs/specs/`)
@@ -121,6 +129,6 @@ Presets are developed in this monorepo under `presets/`. If you add or change ru
121
129
  - **Dogfood / drift scripts:** [`scripts/sync-dogfood-cursor.sh`](scripts/sync-dogfood-cursor.sh) (also syncs root `AGENTS.md` from `REPO_AGENTS.md`; seeds `team/conventions.md` if absent), [`scripts/check-shared-core-drift.sh`](scripts/check-shared-core-drift.sh). Published npm `files` include `scripts/` so consumers can run `check-product-specs.sh` from the package.
122
130
  - **Preset structure CI gates** (exit non-zero on FAIL): `yarn check:preset-structure` (or `bash scripts/check-preset-structure.sh`) — twin map, session-start budget (Option A), leakage, shared-core drift (`AI_RULES_DRIFT_FAIL=1`)
123
131
  - **Opt-in rule eval:** `yarn check:rule-eval` + `.github/workflows/rule-eval.yml` (`workflow_dispatch` + paths-scoped PR) — **not** wired into `check:preset-structure`
124
- - **CLI note:** `_shared` is not an installable `--preset`; `init` copies only `presets/cursor/<name>/` or `presets/claude/<name>/`
132
+ - **CLI note:** `_shared` is not an installable `--preset`; `init` copies `presets/cursor/<name>/`, `presets/claude/<name>/`, or `presets/mavis/<name>/` when the stack is in `releasedStacks`
125
133
 
126
134
  MIT.
package/bin/cli.js CHANGED
@@ -4,11 +4,13 @@
4
4
  */
5
5
  const fs = require('fs');
6
6
  const path = require('path');
7
+ const { cmdInitMavis, cmdCleanMavis } = require('./mavis-install');
8
+ const { cmdInitOpencode, cmdCleanOpencode } = require('./opencode-install');
7
9
 
8
10
  /** Single path segment: letters, digits, dot, underscore, hyphen; no separators or "..". */
9
11
  const PRESET_NAME_RE = /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/;
10
12
  const DEFAULT_PRESET = 'next';
11
- const TOOLS = new Set(['cursor', 'claude']);
13
+ const TOOLS = new Set(['cursor', 'claude', 'mavis', 'opencode']);
12
14
 
13
15
  const PRESETS = {
14
16
  cursor: {
@@ -51,9 +53,9 @@ function printHelp() {
51
53
  console.log(`@bonesofspring/ai-rules
52
54
 
53
55
  Usage:
54
- ai-rules init <cursor|claude> [--preset <name>]
55
- ai-rules init <cursor|claude> <preset-name>
56
- ai-rules clean <cursor|claude> [--cwd <dir>]
56
+ ai-rules init <cursor|claude|mavis|opencode> [--preset <name>]
57
+ ai-rules init <cursor|claude|mavis|opencode> <preset-name>
58
+ ai-rules clean <cursor|claude|mavis|opencode> [--cwd <dir>]
57
59
 
58
60
  Options:
59
61
  --preset <name> Preset name (default: ${DEFAULT_PRESET})
@@ -66,7 +68,9 @@ Notes:
66
68
  copied to a timestamped *.bak.* then replaced with the preset file. JSONC is not supported).
67
69
  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.
68
70
  Claude init copies rules, commands, skills, agents, hooks, team, CLAUDE.md, MCP.md, and mcp.json → .mcp.json (project root).
69
- Both tools also copy REPO_AGENTS.md → <cwd>/AGENTS.md (repo-root cross-tool agents file; overwrite).
71
+ Mavis init copies into .mavis/ (ai-rules-owned) plus REPO_AGENTS.md → <cwd>/AGENTS.md; MCP merges into .mavis/mcp.json only (never ~/.minimax/**).
72
+ OpenCode init copies into .opencode/ plus REPO_AGENTS.md → <cwd>/AGENTS.md; MCP merges into <cwd>/opencode.json (never ~/.config/opencode/**).
73
+ All init targets also copy REPO_AGENTS.md → <cwd>/AGENTS.md (repo-root cross-tool agents file; overwrite).
70
74
  When <cwd>/docs/specs/ is absent, init also seeds INDEX.md stub + _templates/* from package assets (never overwrites an existing INDEX).
71
75
  clean removes tool dirs/files and <cwd>/AGENTS.md (shared across tools — re-init the other tool to restore).
72
76
  Command forms: "init cursor --preset next", "init cursor next", "--preset next init cursor", "cursor init --preset next".
@@ -93,6 +97,10 @@ Examples:
93
97
  npx @bonesofspring/ai-rules init claude --preset mcp-ts
94
98
  npx @bonesofspring/ai-rules init claude --preset php-hexagonal
95
99
  npx @bonesofspring/ai-rules init claude --preset php-laravel
100
+ npx @bonesofspring/ai-rules init mavis --preset next
101
+ npx @bonesofspring/ai-rules init opencode --preset next
102
+ npx @bonesofspring/ai-rules clean mavis
103
+ npx @bonesofspring/ai-rules clean opencode
96
104
  npx @bonesofspring/ai-rules clean cursor
97
105
  `);
98
106
  }
@@ -484,9 +492,34 @@ function resolvePresetName(tool, preset, packageRoot) {
484
492
  }
485
493
 
486
494
  function cmdInit(tool, preset, cwdOption) {
495
+ if (tool === 'mavis') {
496
+ cmdInitMavis({
497
+ preset,
498
+ cwdOption,
499
+ helpers: {
500
+ resolveTargetCwd,
501
+ seedDocsSpecsIfAbsent,
502
+ installMcpJson,
503
+ getPackageRoot,
504
+ },
505
+ });
506
+ return;
507
+ }
508
+ if (tool === 'opencode') {
509
+ cmdInitOpencode({
510
+ preset,
511
+ cwdOption,
512
+ helpers: {
513
+ resolveTargetCwd,
514
+ seedDocsSpecsIfAbsent,
515
+ getPackageRoot,
516
+ },
517
+ });
518
+ return;
519
+ }
487
520
  const cfg = PRESETS[tool];
488
521
  if (!cfg) {
489
- console.error(`Unknown tool: ${tool}. Use cursor or claude.`);
522
+ console.error(`Unknown tool: ${tool}. Use cursor, claude, mavis, or opencode.`);
490
523
  process.exit(1);
491
524
  }
492
525
 
@@ -665,9 +698,23 @@ function rollbackInit(createdPaths, toolRootExisted, toolRootAbs) {
665
698
  }
666
699
 
667
700
  function cmdClean(tool, cwdOption) {
701
+ if (tool === 'mavis') {
702
+ cmdCleanMavis({
703
+ cwdOption,
704
+ helpers: { resolveTargetCwd },
705
+ });
706
+ return;
707
+ }
708
+ if (tool === 'opencode') {
709
+ cmdCleanOpencode({
710
+ cwdOption,
711
+ helpers: { resolveTargetCwd },
712
+ });
713
+ return;
714
+ }
668
715
  const cfg = PRESETS[tool];
669
716
  if (!cfg) {
670
- console.error(`Unknown tool: ${tool}. Use cursor or claude.`);
717
+ console.error(`Unknown tool: ${tool}. Use cursor, claude, mavis, or opencode.`);
671
718
  process.exit(1);
672
719
  }
673
720
  const cwd = resolveTargetCwd(cwdOption);
@@ -737,7 +784,7 @@ function main() {
737
784
 
738
785
  if (command === 'init') {
739
786
  if (!tool || !TOOLS.has(tool)) {
740
- console.error('Missing or invalid tool. Use: init cursor|claude [--preset next]');
787
+ console.error('Missing or invalid tool. Use: init cursor|claude|mavis|opencode [--preset next]');
741
788
  process.exit(1);
742
789
  }
743
790
  cmdInit(tool, preset, parsed.cwd);
@@ -745,7 +792,7 @@ function main() {
745
792
  }
746
793
  if (command === 'clean') {
747
794
  if (!tool || !TOOLS.has(tool)) {
748
- console.error('Missing or invalid tool. Use: clean cursor|claude');
795
+ console.error('Missing or invalid tool. Use: clean cursor|claude|mavis|opencode');
749
796
  process.exit(1);
750
797
  }
751
798
  cmdClean(tool, parsed.cwd);
@@ -0,0 +1,441 @@
1
+ /**
2
+ * Manifest-owned Mavis init/clean. Does not write ~/.minimax/**.
3
+ */
4
+ const crypto = require('crypto');
5
+ const fs = require('fs');
6
+ const path = require('path');
7
+
8
+ const MANIFEST_REL = path.join('.mavis', '.ai-rules-install.json');
9
+ const CONTRACT_REL = path.join('presets', 'mavis', 'platform-contract.json');
10
+ const SKIP_STACK_ROOT = new Set(['adapter-map.json', 'README.md']);
11
+
12
+ function sha256File(filePath) {
13
+ return crypto.createHash('sha256').update(fs.readFileSync(filePath)).digest('hex');
14
+ }
15
+
16
+ function failPhase() {
17
+ return process.env.AI_RULES_MAVIS_FAIL_PHASE || '';
18
+ }
19
+
20
+ function throwIfPhase(name) {
21
+ if (failPhase() === name) {
22
+ throw new Error(`injected failure at ${name}`);
23
+ }
24
+ }
25
+
26
+ function loadJson(filePath) {
27
+ return JSON.parse(fs.readFileSync(filePath, 'utf8'));
28
+ }
29
+
30
+ function walkFiles(root) {
31
+ const files = [];
32
+ const visit = (dir) => {
33
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
34
+ const full = path.join(dir, entry.name);
35
+ if (entry.isDirectory()) {
36
+ visit(full);
37
+ } else if (entry.isFile()) {
38
+ files.push(path.relative(root, full).split(path.sep).join('/'));
39
+ }
40
+ }
41
+ };
42
+ if (fs.existsSync(root)) {
43
+ visit(root);
44
+ }
45
+ return files.sort();
46
+ }
47
+
48
+ function writeAtomicCopy(source, dest) {
49
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
50
+ const tmp = `${dest}.ai-rules-tmp`;
51
+ fs.copyFileSync(source, tmp);
52
+ if (dest.endsWith('.sh')) {
53
+ fs.chmodSync(tmp, 0o755);
54
+ }
55
+ fs.renameSync(tmp, dest);
56
+ }
57
+
58
+ function writeAtomicText(dest, text) {
59
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
60
+ const tmp = `${dest}.ai-rules-tmp`;
61
+ fs.writeFileSync(tmp, text);
62
+ fs.renameSync(tmp, dest);
63
+ }
64
+
65
+ function loadContract(packageRoot) {
66
+ const contractPath = path.join(packageRoot, CONTRACT_REL);
67
+ if (!fs.existsSync(contractPath)) {
68
+ throw new Error(`Mavis platform contract missing: ${contractPath}`);
69
+ }
70
+ return loadJson(contractPath);
71
+ }
72
+
73
+ function packageVersion(packageRoot) {
74
+ return loadJson(path.join(packageRoot, 'package.json')).version;
75
+ }
76
+
77
+ function buildPlan({ contract, sourceBase, cwd }) {
78
+ const files = [];
79
+ const seen = new Set();
80
+ const addFile = (source, destRel) => {
81
+ if (seen.has(destRel)) {
82
+ return;
83
+ }
84
+ seen.add(destRel);
85
+ files.push({
86
+ source,
87
+ dest: path.join(cwd, destRel),
88
+ rel: destRel,
89
+ });
90
+ };
91
+
92
+ for (const entry of contract.entryFiles || []) {
93
+ const source = path.join(sourceBase, entry.source);
94
+ if (fs.existsSync(source)) {
95
+ addFile(source, entry.destination);
96
+ }
97
+ }
98
+
99
+ for (const mapping of contract.directoryMappings || []) {
100
+ const sourceDir = path.join(sourceBase, mapping.source);
101
+ if (!fs.existsSync(sourceDir)) {
102
+ continue;
103
+ }
104
+ for (const rel of walkFiles(sourceDir)) {
105
+ addFile(path.join(sourceDir, rel), `${mapping.destination}/${rel}`);
106
+ }
107
+ }
108
+
109
+ const mcpMd = path.join(sourceBase, 'MCP.md');
110
+ if (fs.existsSync(mcpMd)) {
111
+ addFile(mcpMd, path.join(contract.managedRoot, 'MCP.md'));
112
+ }
113
+
114
+ const mcpSource = path.join(sourceBase, contract.mcp.source);
115
+ const mcp = fs.existsSync(mcpSource)
116
+ ? {
117
+ source: mcpSource,
118
+ dest: path.join(cwd, contract.mcp.fallbackDestination),
119
+ rel: contract.mcp.fallbackDestination,
120
+ }
121
+ : null;
122
+
123
+ for (const skip of SKIP_STACK_ROOT) {
124
+ const skipped = path.join(sourceBase, skip);
125
+ if (fs.existsSync(skipped)) {
126
+ const accidental = files.find((item) => item.source === skipped);
127
+ if (accidental) {
128
+ throw new Error(`refusing to install stack-root ${skip}`);
129
+ }
130
+ }
131
+ }
132
+
133
+ return { files, mcp };
134
+ }
135
+
136
+ function capabilityModes(contract) {
137
+ const modes = {};
138
+ for (const [key, value] of Object.entries(contract.nativeCapabilities || {})) {
139
+ modes[key] = value.status;
140
+ }
141
+ return modes;
142
+ }
143
+
144
+ function shippedMcpIds(mcpSource) {
145
+ if (!mcpSource || !fs.existsSync(mcpSource)) {
146
+ return [];
147
+ }
148
+ const parsed = loadJson(mcpSource);
149
+ if (!parsed || typeof parsed.mcpServers !== 'object' || parsed.mcpServers === null) {
150
+ return [];
151
+ }
152
+ return Object.keys(parsed.mcpServers);
153
+ }
154
+
155
+ function previousManifest(cwd) {
156
+ const manifestPath = path.join(cwd, MANIFEST_REL);
157
+ if (!fs.existsSync(manifestPath)) {
158
+ return null;
159
+ }
160
+ try {
161
+ return loadJson(manifestPath);
162
+ } catch {
163
+ return null;
164
+ }
165
+ }
166
+
167
+ function restoreRollback(overwritten, created, rollbackRoot, mavisRoot, mavisExisted) {
168
+ for (const item of overwritten) {
169
+ try {
170
+ if (fs.existsSync(item.backup)) {
171
+ fs.mkdirSync(path.dirname(item.dest), { recursive: true });
172
+ fs.copyFileSync(item.backup, item.dest);
173
+ }
174
+ } catch {
175
+ // Best-effort restore; caller already reports the failure.
176
+ }
177
+ }
178
+ const createdPaths = [...created].sort((a, b) => b.length - a.length);
179
+ for (const dest of createdPaths) {
180
+ try {
181
+ if (!fs.existsSync(dest)) {
182
+ continue;
183
+ }
184
+ const stat = fs.lstatSync(dest);
185
+ if (stat.isDirectory()) {
186
+ fs.rmSync(dest, { recursive: true, force: true });
187
+ } else {
188
+ fs.unlinkSync(dest);
189
+ }
190
+ } catch {
191
+ // Best-effort.
192
+ }
193
+ }
194
+ if (fs.existsSync(rollbackRoot)) {
195
+ fs.rmSync(rollbackRoot, { recursive: true, force: true });
196
+ }
197
+ if (!mavisExisted && fs.existsSync(mavisRoot)) {
198
+ fs.rmSync(mavisRoot, { recursive: true, force: true });
199
+ } else if (mavisExisted && fs.existsSync(mavisRoot)) {
200
+ removeEmptyDirs(mavisRoot);
201
+ }
202
+ }
203
+
204
+ function cmdInitMavis({ preset, cwdOption, helpers }) {
205
+ const { resolveTargetCwd, seedDocsSpecsIfAbsent, installMcpJson, getPackageRoot } = helpers;
206
+ const packageRoot = getPackageRoot();
207
+ const cwd = resolveTargetCwd(cwdOption);
208
+ const contract = loadContract(packageRoot);
209
+ const stack = preset || 'next';
210
+ const releasedStacks = Array.isArray(contract.releasedStacks) ? contract.releasedStacks : [];
211
+ if (releasedStacks.length > 0 && !releasedStacks.includes(stack)) {
212
+ console.error(`Preset "${stack}" for mavis is not released yet.`);
213
+ console.error(`Released stacks: ${releasedStacks.join(', ')}`);
214
+ console.error('Additional stacks ship after the pilot human gate (WP-F).');
215
+ process.exit(1);
216
+ }
217
+ const sourceBase = path.join(packageRoot, contract.sourceRoot, stack);
218
+ if (!fs.existsSync(sourceBase)) {
219
+ console.error(`Preset "${stack}" for mavis not found.`);
220
+ console.error(`Looked in: ${sourceBase}`);
221
+ process.exit(1);
222
+ }
223
+
224
+ const mavisRoot = path.join(cwd, contract.managedRoot);
225
+ const mavisExisted = fs.existsSync(mavisRoot);
226
+ const docsSpecsDir = path.join(cwd, 'docs', 'specs');
227
+ const docsSpecsExisted = fs.existsSync(docsSpecsDir);
228
+ const prior = previousManifest(cwd);
229
+ const runId = new Date().toISOString().replace(/[:.]/g, '-');
230
+ const rollbackRoot = path.join(mavisRoot, '.rollback', runId);
231
+ const created = new Set();
232
+ const overwritten = [];
233
+
234
+ try {
235
+ throwIfPhase('validate');
236
+ const plan = buildPlan({ contract, sourceBase, cwd });
237
+ for (const item of plan.files) {
238
+ if (!fs.existsSync(item.source)) {
239
+ throw new Error(`Source missing: ${item.source}`);
240
+ }
241
+ }
242
+
243
+ throwIfPhase('snapshot');
244
+ for (const item of plan.files) {
245
+ if (!fs.existsSync(item.dest)) {
246
+ continue;
247
+ }
248
+ const backup = path.join(rollbackRoot, item.rel);
249
+ fs.mkdirSync(path.dirname(backup), { recursive: true });
250
+ fs.copyFileSync(item.dest, backup);
251
+ overwritten.push({ dest: item.dest, backup });
252
+ const priorHash = prior && prior.managedFiles ? prior.managedFiles[item.rel] : null;
253
+ const currentHash = sha256File(item.dest);
254
+ if (priorHash && priorHash !== currentHash) {
255
+ const stamp = new Date().toISOString().replace(/[:.]/g, '-');
256
+ const reported = `${item.dest}.bak.${stamp}`;
257
+ fs.copyFileSync(item.dest, reported);
258
+ console.warn(`Modified managed file ${item.rel} backed up to ${reported} before overwrite.`);
259
+ }
260
+ }
261
+ if (plan.mcp && fs.existsSync(plan.mcp.dest)) {
262
+ const backup = path.join(rollbackRoot, plan.mcp.rel);
263
+ fs.mkdirSync(path.dirname(backup), { recursive: true });
264
+ fs.copyFileSync(plan.mcp.dest, backup);
265
+ overwritten.push({ dest: plan.mcp.dest, backup });
266
+ }
267
+
268
+ throwIfPhase('write');
269
+ for (const item of plan.files) {
270
+ if (!fs.existsSync(item.dest)) {
271
+ created.add(item.dest);
272
+ }
273
+ writeAtomicCopy(item.source, item.dest);
274
+ console.log(`Copied ${path.basename(item.source)} → ${item.rel}`);
275
+ }
276
+
277
+ throwIfPhase('mcp');
278
+ if (plan.mcp) {
279
+ if (!fs.existsSync(plan.mcp.dest)) {
280
+ created.add(plan.mcp.dest);
281
+ }
282
+ installMcpJson(plan.mcp.source, plan.mcp.dest, plan.mcp.rel);
283
+ console.log(
284
+ 'MCP fallback staged at .mavis/mcp.json. Import it in MiniMax Code MCP JSON mode; do not write ~/.minimax/mcp.json from this CLI.',
285
+ );
286
+ }
287
+
288
+ throwIfPhase('docs');
289
+ const seeded = seedDocsSpecsIfAbsent(packageRoot, cwd);
290
+ if (seeded && !docsSpecsExisted) {
291
+ created.add(docsSpecsDir);
292
+ }
293
+
294
+ throwIfPhase('manifest');
295
+ const managedFiles = {};
296
+ for (const item of plan.files) {
297
+ managedFiles[item.rel] = sha256File(item.dest);
298
+ }
299
+ if (plan.mcp && fs.existsSync(plan.mcp.dest)) {
300
+ managedFiles[plan.mcp.rel] = sha256File(plan.mcp.dest);
301
+ }
302
+ const manifest = {
303
+ schemaVersion: 1,
304
+ packageVersion: packageVersion(packageRoot),
305
+ platform: 'mavis',
306
+ preset: stack,
307
+ installedAt: new Date().toISOString(),
308
+ managedFiles,
309
+ managedDirectories: (contract.directoryMappings || []).map((entry) => entry.destination),
310
+ shippedMcpServerIds: plan.mcp ? shippedMcpIds(plan.mcp.source) : [],
311
+ docsSeed: seeded
312
+ ? { seeded: true }
313
+ : { seeded: false, reason: docsSpecsExisted ? 'directory-exists' : 'assets-missing' },
314
+ capabilityModes: capabilityModes(contract),
315
+ };
316
+ const manifestAbs = path.join(cwd, MANIFEST_REL);
317
+ if (!fs.existsSync(manifestAbs)) {
318
+ created.add(manifestAbs);
319
+ }
320
+ writeAtomicText(manifestAbs, `${JSON.stringify(manifest, null, 2)}\n`);
321
+
322
+ if (fs.existsSync(rollbackRoot)) {
323
+ fs.rmSync(rollbackRoot, { recursive: true, force: true });
324
+ }
325
+ const rollbackParent = path.join(mavisRoot, '.rollback');
326
+ if (fs.existsSync(rollbackParent) && fs.readdirSync(rollbackParent).length === 0) {
327
+ fs.rmdirSync(rollbackParent);
328
+ }
329
+ } catch (error) {
330
+ restoreRollback(overwritten, created, rollbackRoot, mavisRoot, mavisExisted);
331
+ const message = error instanceof Error ? error.message : String(error);
332
+ console.error(`init failed: ${message}`);
333
+ process.exit(1);
334
+ }
335
+
336
+ console.log(`Done. .mavis installed at ${mavisRoot} (preset: ${stack})`);
337
+ }
338
+
339
+ function isPlainObject(value) {
340
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
341
+ }
342
+
343
+ function stripShippedMcp(mcpAbs, shippedIds) {
344
+ if (!fs.existsSync(mcpAbs) || shippedIds.length === 0) {
345
+ return;
346
+ }
347
+ let parsed;
348
+ try {
349
+ parsed = loadJson(mcpAbs);
350
+ } catch {
351
+ console.warn(`Preserved ${mcpAbs} (not valid JSON); shipped MCP keys not stripped.`);
352
+ return;
353
+ }
354
+ if (!isPlainObject(parsed) || !isPlainObject(parsed.mcpServers)) {
355
+ return;
356
+ }
357
+ const nextServers = { ...parsed.mcpServers };
358
+ for (const id of shippedIds) {
359
+ delete nextServers[id];
360
+ }
361
+ writeAtomicText(mcpAbs, `${JSON.stringify({ ...parsed, mcpServers: nextServers }, null, 2)}\n`);
362
+ }
363
+
364
+ function removeEmptyDirs(dir) {
365
+ if (!fs.existsSync(dir) || !fs.statSync(dir).isDirectory()) {
366
+ return;
367
+ }
368
+ for (const name of fs.readdirSync(dir)) {
369
+ removeEmptyDirs(path.join(dir, name));
370
+ }
371
+ if (fs.readdirSync(dir).length === 0) {
372
+ fs.rmdirSync(dir);
373
+ }
374
+ }
375
+
376
+ function cmdCleanMavis({ cwdOption, helpers }) {
377
+ const { resolveTargetCwd } = helpers;
378
+ const cwd = resolveTargetCwd(cwdOption);
379
+ const manifestPath = path.join(cwd, MANIFEST_REL);
380
+ if (!fs.existsSync(manifestPath)) {
381
+ console.error(
382
+ 'clean mavis: missing .mavis/.ai-rules-install.json; nothing removed (fail-safe).',
383
+ );
384
+ process.exit(1);
385
+ }
386
+ let manifest;
387
+ try {
388
+ manifest = loadJson(manifestPath);
389
+ } catch {
390
+ console.error(
391
+ 'clean mavis: invalid .mavis/.ai-rules-install.json; nothing removed (fail-safe).',
392
+ );
393
+ process.exit(1);
394
+ }
395
+ if (!manifest || manifest.platform !== 'mavis' || !isPlainObject(manifest.managedFiles)) {
396
+ console.error(
397
+ 'clean mavis: install manifest is not a Mavis ownership record; nothing removed.',
398
+ );
399
+ process.exit(1);
400
+ }
401
+
402
+ const preserved = [];
403
+ for (const [rel, installedHash] of Object.entries(manifest.managedFiles)) {
404
+ if (rel === MANIFEST_REL) {
405
+ continue;
406
+ }
407
+ const abs = path.join(cwd, rel);
408
+ if (!fs.existsSync(abs)) {
409
+ continue;
410
+ }
411
+ const current = sha256File(abs);
412
+ if (current === installedHash) {
413
+ fs.unlinkSync(abs);
414
+ } else {
415
+ preserved.push(rel);
416
+ console.warn(`Preserved modified managed file ${rel}`);
417
+ }
418
+ }
419
+
420
+ if (preserved.includes('.mavis/mcp.json') && Array.isArray(manifest.shippedMcpServerIds)) {
421
+ stripShippedMcp(path.join(cwd, '.mavis', 'mcp.json'), manifest.shippedMcpServerIds);
422
+ }
423
+
424
+ for (const dirRel of [...(manifest.managedDirectories || [])].sort((a, b) => b.length - a.length)) {
425
+ removeEmptyDirs(path.join(cwd, dirRel));
426
+ }
427
+
428
+ fs.unlinkSync(manifestPath);
429
+ removeEmptyDirs(path.join(cwd, '.mavis'));
430
+ if (fs.existsSync(path.join(cwd, '.mavis')) && fs.readdirSync(path.join(cwd, '.mavis')).length === 0) {
431
+ fs.rmdirSync(path.join(cwd, '.mavis'));
432
+ }
433
+
434
+ console.log(
435
+ preserved.length > 0
436
+ ? `clean mavis: removed unchanged managed files; preserved ${preserved.join(', ')}`
437
+ : 'clean mavis: removed unchanged managed files',
438
+ );
439
+ }
440
+
441
+ module.exports = { cmdInitMavis, cmdCleanMavis, MANIFEST_REL };