@bonesofspring/ai-rules 0.2.21 → 0.2.23

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 (363) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +6 -2
  3. package/bin/cli.js +32 -8
  4. package/bin/mavis-install.js +441 -0
  5. package/package.json +9 -2
  6. package/presets/_shared/core/agent-team/agent-artifact-contracts.md +2 -0
  7. package/presets/_shared/core/meta/preset-pr-checklist.md +1 -0
  8. package/presets/_shared/core/meta/preset-twin-sync.md +17 -1
  9. package/presets/claude/android-kotlin/agents/build-verifier.md +2 -0
  10. package/presets/claude/android-kotlin/agents/code-reviewer.md +2 -0
  11. package/presets/claude/android-kotlin/agents/debugger.md +1 -0
  12. package/presets/claude/android-kotlin/agents/feature-developer.md +3 -0
  13. package/presets/claude/android-kotlin/agents/qa-tester.md +2 -0
  14. package/presets/claude/android-kotlin/agents/task-router.md +4 -0
  15. package/presets/claude/android-kotlin/hooks/chain-team-phases.sh +51 -11
  16. package/presets/claude/android-kotlin/rules/tooling-and-review/preset-pr-checklist.md +1 -0
  17. package/presets/claude/android-kotlin/rules/tooling-and-review/preset-twin-sync.md +17 -1
  18. package/presets/claude/go/agents/build-verifier.md +4 -0
  19. package/presets/claude/go/agents/code-reviewer.md +4 -0
  20. package/presets/claude/go/agents/debugger.md +4 -0
  21. package/presets/claude/go/agents/feature-developer.md +5 -0
  22. package/presets/claude/go/agents/qa-tester.md +4 -0
  23. package/presets/claude/go/agents/task-router.md +4 -0
  24. package/presets/claude/go/hooks/chain-team-phases.sh +51 -11
  25. package/presets/claude/go/rules/tooling-and-review/preset-pr-checklist.md +1 -0
  26. package/presets/claude/go/rules/tooling-and-review/preset-twin-sync.md +17 -1
  27. package/presets/claude/ios-swift/agents/build-verifier.md +2 -0
  28. package/presets/claude/ios-swift/agents/code-reviewer.md +2 -0
  29. package/presets/claude/ios-swift/agents/debugger.md +1 -0
  30. package/presets/claude/ios-swift/agents/feature-developer.md +3 -0
  31. package/presets/claude/ios-swift/agents/qa-tester.md +2 -0
  32. package/presets/claude/ios-swift/agents/task-router.md +4 -0
  33. package/presets/claude/ios-swift/hooks/chain-team-phases.sh +51 -11
  34. package/presets/claude/ios-swift/rules/tooling-and-review/preset-pr-checklist.md +1 -0
  35. package/presets/claude/ios-swift/rules/tooling-and-review/preset-twin-sync.md +17 -1
  36. package/presets/claude/java/agents/build-verifier.md +4 -0
  37. package/presets/claude/java/agents/code-reviewer.md +4 -0
  38. package/presets/claude/java/agents/debugger.md +4 -0
  39. package/presets/claude/java/agents/feature-developer.md +5 -0
  40. package/presets/claude/java/agents/qa-tester.md +4 -0
  41. package/presets/claude/java/agents/task-router.md +4 -0
  42. package/presets/claude/java/hooks/chain-team-phases.sh +51 -11
  43. package/presets/claude/java/rules/tooling-and-review/preset-pr-checklist.md +1 -0
  44. package/presets/claude/java/rules/tooling-and-review/preset-twin-sync.md +17 -1
  45. package/presets/claude/mcp-ts/agents/build-verifier.md +4 -0
  46. package/presets/claude/mcp-ts/agents/feature-developer.md +5 -0
  47. package/presets/claude/mcp-ts/agents/task-router.md +1 -1
  48. package/presets/claude/mcp-ts/hooks/chain-team-phases.sh +51 -11
  49. package/presets/claude/mcp-ts/rules/tooling-and-review/preset-pr-checklist.md +1 -0
  50. package/presets/claude/mcp-ts/rules/tooling-and-review/preset-twin-sync.md +17 -1
  51. package/presets/claude/next/agents/build-verifier.md +2 -0
  52. package/presets/claude/next/agents/code-reviewer.md +2 -0
  53. package/presets/claude/next/agents/debugger.md +4 -0
  54. package/presets/claude/next/agents/feature-developer.md +3 -0
  55. package/presets/claude/next/agents/qa-tester.md +4 -0
  56. package/presets/claude/next/agents/unit-test-generator.md +1 -1
  57. package/presets/claude/next/agents/unit-test-planner.md +1 -1
  58. package/presets/claude/next/hooks/chain-team-phases.sh +51 -11
  59. package/presets/claude/next/rules/api-and-data/http-client.md +1 -1
  60. package/presets/claude/next/rules/architecture/reference-features.md +1 -1
  61. package/presets/claude/next/rules/testing/README.md +1 -1
  62. package/presets/claude/next/rules/testing/tests-e2e-structure.md +2 -0
  63. package/presets/claude/next/rules/testing/tests-unit.md +3 -5
  64. package/presets/claude/next/rules/tooling-and-review/preset-pr-checklist.md +1 -0
  65. package/presets/claude/next/rules/tooling-and-review/preset-twin-sync.md +17 -1
  66. package/presets/claude/next/rules/ui-and-accessibility/react-ui.md +1 -1
  67. package/presets/claude/next/skills/playwright-e2e/SKILL.md +5 -3
  68. package/presets/claude/next/skills/unit-testing/SKILL.md +6 -4
  69. package/presets/claude/nuxt/agents/build-verifier.md +2 -0
  70. package/presets/claude/nuxt/agents/code-reviewer.md +2 -0
  71. package/presets/claude/nuxt/agents/debugger.md +4 -0
  72. package/presets/claude/nuxt/agents/feature-developer.md +3 -0
  73. package/presets/claude/nuxt/agents/qa-tester.md +4 -0
  74. package/presets/claude/nuxt/hooks/chain-team-phases.sh +51 -11
  75. package/presets/claude/nuxt/rules/tooling-and-review/preset-pr-checklist.md +1 -0
  76. package/presets/claude/nuxt/rules/tooling-and-review/preset-twin-sync.md +17 -1
  77. package/presets/claude/php-hexagonal/agents/build-verifier.md +4 -0
  78. package/presets/claude/php-hexagonal/agents/code-reviewer.md +4 -0
  79. package/presets/claude/php-hexagonal/agents/debugger.md +4 -0
  80. package/presets/claude/php-hexagonal/agents/feature-developer.md +5 -0
  81. package/presets/claude/php-hexagonal/agents/qa-tester.md +4 -0
  82. package/presets/claude/php-hexagonal/agents/task-router.md +4 -0
  83. package/presets/claude/php-hexagonal/hooks/chain-team-phases.sh +51 -11
  84. package/presets/claude/php-hexagonal/rules/tooling-and-review/preset-pr-checklist.md +1 -0
  85. package/presets/claude/php-hexagonal/rules/tooling-and-review/preset-twin-sync.md +17 -1
  86. package/presets/claude/php-laravel/agents/build-verifier.md +4 -0
  87. package/presets/claude/php-laravel/agents/code-reviewer.md +4 -0
  88. package/presets/claude/php-laravel/agents/debugger.md +4 -0
  89. package/presets/claude/php-laravel/agents/feature-developer.md +5 -0
  90. package/presets/claude/php-laravel/agents/qa-tester.md +4 -0
  91. package/presets/claude/php-laravel/agents/task-router.md +1 -0
  92. package/presets/claude/php-laravel/hooks/chain-team-phases.sh +51 -11
  93. package/presets/claude/php-laravel/rules/tooling-and-review/preset-pr-checklist.md +1 -0
  94. package/presets/claude/php-laravel/rules/tooling-and-review/preset-twin-sync.md +17 -1
  95. package/presets/claude/svelte/agents/build-verifier.md +2 -0
  96. package/presets/claude/svelte/agents/code-reviewer.md +2 -0
  97. package/presets/claude/svelte/agents/debugger.md +4 -0
  98. package/presets/claude/svelte/agents/feature-developer.md +3 -0
  99. package/presets/claude/svelte/agents/qa-tester.md +4 -0
  100. package/presets/claude/svelte/hooks/chain-team-phases.sh +51 -11
  101. package/presets/claude/svelte/rules/tooling-and-review/preset-pr-checklist.md +1 -0
  102. package/presets/claude/svelte/rules/tooling-and-review/preset-twin-sync.md +17 -1
  103. package/presets/cursor/android-kotlin/agents/build-verifier.md +2 -0
  104. package/presets/cursor/android-kotlin/agents/code-reviewer.md +2 -0
  105. package/presets/cursor/android-kotlin/agents/debugger.md +1 -0
  106. package/presets/cursor/android-kotlin/agents/feature-developer.md +3 -0
  107. package/presets/cursor/android-kotlin/agents/qa-tester.md +2 -0
  108. package/presets/cursor/android-kotlin/agents/task-router.md +4 -0
  109. package/presets/cursor/android-kotlin/hooks/chain-team-phases.sh +51 -11
  110. package/presets/cursor/android-kotlin/rules/preset-pr-checklist.mdc +1 -0
  111. package/presets/cursor/android-kotlin/rules/preset-twin-sync.mdc +17 -1
  112. package/presets/cursor/go/agents/build-verifier.md +4 -0
  113. package/presets/cursor/go/agents/code-reviewer.md +4 -0
  114. package/presets/cursor/go/agents/debugger.md +4 -0
  115. package/presets/cursor/go/agents/feature-developer.md +5 -0
  116. package/presets/cursor/go/agents/qa-tester.md +4 -0
  117. package/presets/cursor/go/agents/task-router.md +4 -0
  118. package/presets/cursor/go/hooks/chain-team-phases.sh +51 -11
  119. package/presets/cursor/go/rules/preset-pr-checklist.mdc +1 -0
  120. package/presets/cursor/go/rules/preset-twin-sync.mdc +17 -1
  121. package/presets/cursor/ios-swift/agents/build-verifier.md +2 -0
  122. package/presets/cursor/ios-swift/agents/code-reviewer.md +2 -0
  123. package/presets/cursor/ios-swift/agents/debugger.md +1 -0
  124. package/presets/cursor/ios-swift/agents/feature-developer.md +3 -0
  125. package/presets/cursor/ios-swift/agents/qa-tester.md +2 -0
  126. package/presets/cursor/ios-swift/agents/task-router.md +4 -0
  127. package/presets/cursor/ios-swift/hooks/chain-team-phases.sh +51 -11
  128. package/presets/cursor/ios-swift/rules/preset-pr-checklist.mdc +1 -0
  129. package/presets/cursor/ios-swift/rules/preset-twin-sync.mdc +17 -1
  130. package/presets/cursor/java/agents/build-verifier.md +4 -0
  131. package/presets/cursor/java/agents/code-reviewer.md +4 -0
  132. package/presets/cursor/java/agents/debugger.md +4 -0
  133. package/presets/cursor/java/agents/feature-developer.md +5 -0
  134. package/presets/cursor/java/agents/qa-tester.md +4 -0
  135. package/presets/cursor/java/agents/task-router.md +4 -0
  136. package/presets/cursor/java/hooks/chain-team-phases.sh +51 -11
  137. package/presets/cursor/java/rules/preset-pr-checklist.mdc +1 -0
  138. package/presets/cursor/java/rules/preset-twin-sync.mdc +17 -1
  139. package/presets/cursor/mcp-ts/agents/build-verifier.md +4 -0
  140. package/presets/cursor/mcp-ts/agents/feature-developer.md +5 -0
  141. package/presets/cursor/mcp-ts/agents/task-router.md +1 -1
  142. package/presets/cursor/mcp-ts/hooks/chain-team-phases.sh +51 -11
  143. package/presets/cursor/mcp-ts/rules/preset-pr-checklist.mdc +1 -0
  144. package/presets/cursor/mcp-ts/rules/preset-twin-sync.mdc +17 -1
  145. package/presets/cursor/next/agents/build-verifier.md +2 -0
  146. package/presets/cursor/next/agents/code-reviewer.md +2 -0
  147. package/presets/cursor/next/agents/debugger.md +4 -0
  148. package/presets/cursor/next/agents/feature-developer.md +3 -0
  149. package/presets/cursor/next/agents/qa-tester.md +4 -0
  150. package/presets/cursor/next/agents/unit-test-generator.md +1 -1
  151. package/presets/cursor/next/agents/unit-test-planner.md +1 -1
  152. package/presets/cursor/next/hooks/chain-team-phases.sh +51 -11
  153. package/presets/cursor/next/rules/http-client.mdc +1 -1
  154. package/presets/cursor/next/rules/preset-pr-checklist.mdc +1 -0
  155. package/presets/cursor/next/rules/preset-twin-sync.mdc +17 -1
  156. package/presets/cursor/next/rules/react-ui.mdc +1 -1
  157. package/presets/cursor/next/rules/reference-features.mdc +1 -1
  158. package/presets/cursor/next/rules/tests-e2e-structure.mdc +2 -0
  159. package/presets/cursor/next/rules/tests-unit.mdc +3 -5
  160. package/presets/cursor/next/skills/playwright-e2e/SKILL.md +5 -3
  161. package/presets/cursor/next/skills/unit-testing/SKILL.md +6 -4
  162. package/presets/cursor/nuxt/agents/build-verifier.md +2 -0
  163. package/presets/cursor/nuxt/agents/code-reviewer.md +2 -0
  164. package/presets/cursor/nuxt/agents/debugger.md +4 -0
  165. package/presets/cursor/nuxt/agents/feature-developer.md +3 -0
  166. package/presets/cursor/nuxt/agents/qa-tester.md +4 -0
  167. package/presets/cursor/nuxt/hooks/chain-team-phases.sh +51 -11
  168. package/presets/cursor/nuxt/rules/preset-pr-checklist.mdc +1 -0
  169. package/presets/cursor/nuxt/rules/preset-twin-sync.mdc +17 -1
  170. package/presets/cursor/php-hexagonal/agents/build-verifier.md +4 -0
  171. package/presets/cursor/php-hexagonal/agents/code-reviewer.md +4 -0
  172. package/presets/cursor/php-hexagonal/agents/debugger.md +4 -0
  173. package/presets/cursor/php-hexagonal/agents/feature-developer.md +5 -0
  174. package/presets/cursor/php-hexagonal/agents/qa-tester.md +4 -0
  175. package/presets/cursor/php-hexagonal/agents/task-router.md +4 -0
  176. package/presets/cursor/php-hexagonal/hooks/chain-team-phases.sh +51 -11
  177. package/presets/cursor/php-hexagonal/rules/preset-pr-checklist.mdc +1 -0
  178. package/presets/cursor/php-hexagonal/rules/preset-twin-sync.mdc +17 -1
  179. package/presets/cursor/php-laravel/agents/build-verifier.md +4 -0
  180. package/presets/cursor/php-laravel/agents/code-reviewer.md +4 -0
  181. package/presets/cursor/php-laravel/agents/debugger.md +4 -0
  182. package/presets/cursor/php-laravel/agents/feature-developer.md +5 -0
  183. package/presets/cursor/php-laravel/agents/qa-tester.md +4 -0
  184. package/presets/cursor/php-laravel/agents/task-router.md +1 -0
  185. package/presets/cursor/php-laravel/hooks/chain-team-phases.sh +51 -11
  186. package/presets/cursor/php-laravel/rules/preset-pr-checklist.mdc +1 -0
  187. package/presets/cursor/php-laravel/rules/preset-twin-sync.mdc +17 -1
  188. package/presets/cursor/svelte/agents/build-verifier.md +2 -0
  189. package/presets/cursor/svelte/agents/code-reviewer.md +2 -0
  190. package/presets/cursor/svelte/agents/debugger.md +4 -0
  191. package/presets/cursor/svelte/agents/feature-developer.md +3 -0
  192. package/presets/cursor/svelte/agents/qa-tester.md +4 -0
  193. package/presets/cursor/svelte/hooks/chain-team-phases.sh +51 -11
  194. package/presets/cursor/svelte/rules/preset-pr-checklist.mdc +1 -0
  195. package/presets/cursor/svelte/rules/preset-twin-sync.mdc +17 -1
  196. package/presets/mavis/README.md +60 -0
  197. package/presets/mavis/next/MAVIS.md +67 -0
  198. package/presets/mavis/next/MCP.md +36 -0
  199. package/presets/mavis/next/README.md +15 -0
  200. package/presets/mavis/next/REPO_AGENTS.md +94 -0
  201. package/presets/mavis/next/adapter-map.json +959 -0
  202. package/presets/mavis/next/agents/README.md +206 -0
  203. package/presets/mavis/next/agents/accessibility-reviewer.md +61 -0
  204. package/presets/mavis/next/agents/api-contract-reviewer.md +57 -0
  205. package/presets/mavis/next/agents/build-verifier.md +110 -0
  206. package/presets/mavis/next/agents/ci-investigator.md +63 -0
  207. package/presets/mavis/next/agents/code-reviewer.md +61 -0
  208. package/presets/mavis/next/agents/codebase-analyzer.md +21 -0
  209. package/presets/mavis/next/agents/debugger.md +80 -0
  210. package/presets/mavis/next/agents/feature-developer.md +101 -0
  211. package/presets/mavis/next/agents/migration-specialist.md +67 -0
  212. package/presets/mavis/next/agents/mockup-reviewer.md +53 -0
  213. package/presets/mavis/next/agents/openspec-author.md +157 -0
  214. package/presets/mavis/next/agents/performance-auditor.md +68 -0
  215. package/presets/mavis/next/agents/playwright-test-generator.md +28 -0
  216. package/presets/mavis/next/agents/playwright-test-healer.md +28 -0
  217. package/presets/mavis/next/agents/playwright-test-planner.md +21 -0
  218. package/presets/mavis/next/agents/qa-tester.md +52 -0
  219. package/presets/mavis/next/agents/security-reviewer.md +54 -0
  220. package/presets/mavis/next/agents/solution-architect.md +68 -0
  221. package/presets/mavis/next/agents/task-analyst.md +166 -0
  222. package/presets/mavis/next/agents/task-router.md +178 -0
  223. package/presets/mavis/next/agents/tech-writer.md +57 -0
  224. package/presets/mavis/next/agents/unit-test-generator.md +31 -0
  225. package/presets/mavis/next/agents/unit-test-healer.md +32 -0
  226. package/presets/mavis/next/agents/unit-test-planner.md +54 -0
  227. package/presets/mavis/next/commands/README.md +49 -0
  228. package/presets/mavis/next/commands/spec-start.md +24 -0
  229. package/presets/mavis/next/commands/task-continue.md +50 -0
  230. package/presets/mavis/next/commands/task.md +50 -0
  231. package/presets/mavis/next/commands/technical-retro.md +80 -0
  232. package/presets/mavis/next/hooks/README.md +22 -0
  233. package/presets/mavis/next/hooks/chain-team-phases.sh +845 -0
  234. package/presets/mavis/next/mcp.json +19 -0
  235. package/presets/mavis/next/rules/README.md +16 -0
  236. package/presets/mavis/next/rules/agent-team-intake.md +11 -0
  237. package/presets/mavis/next/rules/agent-team-orchestrator.md +210 -0
  238. package/presets/mavis/next/rules/ai-local-overlay.md +37 -0
  239. package/presets/mavis/next/rules/anti-sycophancy-discipline.md +23 -0
  240. package/presets/mavis/next/rules/api-services.md +72 -0
  241. package/presets/mavis/next/rules/architecture-boundaries-ui.md +9 -0
  242. package/presets/mavis/next/rules/architecture-boundaries.md +86 -0
  243. package/presets/mavis/next/rules/arrow-functions.md +25 -0
  244. package/presets/mavis/next/rules/code-quality-and-refactoring.md +40 -0
  245. package/presets/mavis/next/rules/code-review-mr.md +40 -0
  246. package/presets/mavis/next/rules/css-property-order-stylelint.md +5 -0
  247. package/presets/mavis/next/rules/design-guidance.md +99 -0
  248. package/presets/mavis/next/rules/feature-delivery-workflow.md +49 -0
  249. package/presets/mavis/next/rules/http-client.md +55 -0
  250. package/presets/mavis/next/rules/layer-barrel-exports.md +68 -0
  251. package/presets/mavis/next/rules/mcp-usage.md +86 -0
  252. package/presets/mavis/next/rules/mockup-review.md +107 -0
  253. package/presets/mavis/next/rules/navigation-router-stack.md +56 -0
  254. package/presets/mavis/next/rules/navigation-router-ui.md +10 -0
  255. package/presets/mavis/next/rules/next-app-core.md +29 -0
  256. package/presets/mavis/next/rules/next-app-router.md +44 -0
  257. package/presets/mavis/next/rules/no-props-spread.md +56 -0
  258. package/presets/mavis/next/rules/no-type-assertion-as-import-export.md +51 -0
  259. package/presets/mavis/next/rules/package-manager.md +11 -0
  260. package/presets/mavis/next/rules/playwright-agents.md +67 -0
  261. package/presets/mavis/next/rules/post-change-lint.md +35 -0
  262. package/presets/mavis/next/rules/preset-layering.md +27 -0
  263. package/presets/mavis/next/rules/preset-no-cross-stack-leakage.md +90 -0
  264. package/presets/mavis/next/rules/preset-pr-checklist.md +35 -0
  265. package/presets/mavis/next/rules/preset-token-budget.md +36 -0
  266. package/presets/mavis/next/rules/preset-twin-sync.md +65 -0
  267. package/presets/mavis/next/rules/product-specs-authoring.md +112 -0
  268. package/presets/mavis/next/rules/product-specs.md +56 -0
  269. package/presets/mavis/next/rules/public-imports.md +50 -0
  270. package/presets/mavis/next/rules/react-a11y-coding.md +31 -0
  271. package/presets/mavis/next/rules/react-next-anti-hallucination.md +60 -0
  272. package/presets/mavis/next/rules/react-ui.md +105 -0
  273. package/presets/mavis/next/rules/reference-features.md +45 -0
  274. package/presets/mavis/next/rules/security-next.md +45 -0
  275. package/presets/mavis/next/rules/store-rtk.md +78 -0
  276. package/presets/mavis/next/rules/technical-retro.md +11 -0
  277. package/presets/mavis/next/rules/tests-e2e-structure.md +72 -0
  278. package/presets/mavis/next/rules/tests-unit.md +72 -0
  279. package/presets/mavis/next/rules/types-jsdoc.md +43 -0
  280. package/presets/mavis/next/rules/ux-design.md +99 -0
  281. package/presets/mavis/next/skills/README.md +21 -0
  282. package/presets/mavis/next/skills/ci-investigation/SKILL.md +39 -0
  283. package/presets/mavis/next/skills/code-review/SKILL.md +39 -0
  284. package/presets/mavis/next/skills/debug-investigation/SKILL.md +26 -0
  285. package/presets/mavis/next/skills/feature-delivery/SKILL.md +34 -0
  286. package/presets/mavis/next/skills/mockup-review/SKILL.md +24 -0
  287. package/presets/mavis/next/skills/playwright-e2e/SKILL.md +28 -0
  288. package/presets/mavis/next/skills/react-performance/SKILL.md +39 -0
  289. package/presets/mavis/next/skills/spec-authoring/SKILL.md +21 -0
  290. package/presets/mavis/next/skills/spec-discovery/SKILL.md +53 -0
  291. package/presets/mavis/next/skills/technical-retro/SKILL.md +49 -0
  292. package/presets/mavis/next/skills/unit-testing/SKILL.md +29 -0
  293. package/presets/mavis/next/skills/ux-design/SKILL.md +31 -0
  294. package/presets/mavis/next/skills/write-adr/SKILL.md +36 -0
  295. package/presets/mavis/next/team/README.md +148 -0
  296. package/presets/mavis/next/team/conventions.md +21 -0
  297. package/presets/mavis/next/team/fixtures/artifact-manifest.example.json +79 -0
  298. package/presets/mavis/next/team/fixtures/bugfix-standard.json +25 -0
  299. package/presets/mavis/next/team/fixtures/feature-full.json +29 -0
  300. package/presets/mavis/next/team/fixtures/feature-light.json +27 -0
  301. package/presets/mavis/next/team/fixtures/feature-with-figma-url.json +17 -0
  302. package/presets/mavis/next/team/fixtures/feature-with-ux-no-figma.json +17 -0
  303. package/presets/mavis/next/team/fixtures/memlog.example.md +9 -0
  304. package/presets/mavis/next/team/fixtures/metrics-scenarios/tasks/human-gate/metrics.json +69 -0
  305. package/presets/mavis/next/team/fixtures/metrics-scenarios/tasks/missing-ledger/status.json +5 -0
  306. package/presets/mavis/next/team/fixtures/metrics-scenarios/tasks/parallel-receipts/metrics.json +79 -0
  307. package/presets/mavis/next/team/fixtures/metrics-scenarios/tasks/serial-retry/metrics.json +124 -0
  308. package/presets/mavis/next/team/fixtures/metrics-scenarios/tasks/validation-failed/metrics.json +124 -0
  309. package/presets/mavis/next/team/fixtures/metrics.example.json +54 -0
  310. package/presets/mavis/next/team/fixtures/mockup-review-fail-embedded-status.json +8 -0
  311. package/presets/mavis/next/team/fixtures/mockup-review-standalone.json +14 -0
  312. package/presets/mavis/next/team/fixtures/ux-design-standalone.json +15 -0
  313. package/presets/mavis/next/team/tasks/.gitkeep +0 -0
  314. package/presets/mavis/platform-contract.json +131 -0
  315. package/scripts/capture-cli-golden.mjs +44 -0
  316. package/scripts/check-chain-hook-coverage.sh +1 -0
  317. package/scripts/check-mavis-adapter-map.mjs +294 -0
  318. package/scripts/check-mavis-local-overlay.mjs +56 -0
  319. package/scripts/check-mavis-platform-contract.mjs +388 -0
  320. package/scripts/check-mavis-token-budget.mjs +48 -0
  321. package/scripts/check-preset-leakage.sh +35 -3
  322. package/scripts/check-preset-structure.sh +73 -0
  323. package/scripts/check-preset-token-budget.sh +100 -0
  324. package/scripts/check-shared-core-drift.sh +18 -0
  325. package/scripts/check-task-router-intents.sh +154 -0
  326. package/scripts/fixtures/cli-golden/claude/next.json +130 -0
  327. package/scripts/fixtures/cli-golden/cursor/next.json +132 -0
  328. package/scripts/fixtures/cli-golden/mavis/next.json +125 -0
  329. package/scripts/fixtures/mavis-adapter-map/invalid-unmapped/cursor/AGENTS.md +1 -0
  330. package/scripts/fixtures/mavis-adapter-map/invalid-unmapped/cursor/rules/extra.mdc +1 -0
  331. package/scripts/fixtures/mavis-adapter-map/invalid-unmapped/cursor/rules/sample.mdc +2 -0
  332. package/scripts/fixtures/mavis-adapter-map/invalid-unmapped/mavis/MAVIS.md +1 -0
  333. package/scripts/fixtures/mavis-adapter-map/invalid-unmapped/mavis/adapter-map.json +26 -0
  334. package/scripts/fixtures/mavis-adapter-map/invalid-unmapped/mavis/rules/sample.md +2 -0
  335. package/scripts/fixtures/mavis-adapter-map/valid/cursor/AGENTS.md +1 -0
  336. package/scripts/fixtures/mavis-adapter-map/valid/cursor/rules/sample.mdc +2 -0
  337. package/scripts/fixtures/mavis-adapter-map/valid/mavis/MAVIS.md +1 -0
  338. package/scripts/fixtures/mavis-adapter-map/valid/mavis/adapter-map.json +26 -0
  339. package/scripts/fixtures/mavis-adapter-map/valid/mavis/rules/sample.md +2 -0
  340. package/scripts/fixtures/mavis-platform-contract/invalid-minimax-destination.json +131 -0
  341. package/scripts/fixtures/mavis-platform-contract/invalid-missing-capability.json +126 -0
  342. package/scripts/fixtures/mavis-platform-contract/invalid-released-unknown-stack.json +133 -0
  343. package/scripts/fixtures/mavis-platform-contract/invalid-unknown-native-path.json +131 -0
  344. package/scripts/fixtures/mavis-platform-contract/invalid-version-pin.json +132 -0
  345. package/scripts/fixtures/mavis-platform-contract/valid.json +131 -0
  346. package/scripts/fixtures/mavis-probe/AGENTS.md +6 -0
  347. package/scripts/fixtures/mavis-probe/agents/probe-agent.md +6 -0
  348. package/scripts/fixtures/mavis-probe/fake-mcode.mjs +98 -0
  349. package/scripts/fixtures/mavis-probe/output.schema.json +28 -0
  350. package/scripts/fixtures/mavis-probe/rules/probe.md +5 -0
  351. package/scripts/fixtures/mavis-probe/skills/probe/SKILL.md +11 -0
  352. package/scripts/generate-mavis-next.mjs +704 -0
  353. package/scripts/lib/cli-golden.mjs +50 -0
  354. package/scripts/lib/discover-hooks.mjs +72 -0
  355. package/scripts/probe-mavis-capabilities.mjs +480 -0
  356. package/scripts/test-agent-task-metrics-hooks.mjs +120 -16
  357. package/scripts/test-chain-team-phases-coverage.mjs +110 -8
  358. package/scripts/test-cli-init-clean.mjs +256 -0
  359. package/scripts/test-cli-mcp-merge.mjs +23 -0
  360. package/scripts/test-mavis-context-budget.mjs +55 -0
  361. package/scripts/test-mavis-orchestration.mjs +649 -0
  362. package/scripts/test-probe-mavis-capabilities.mjs +205 -0
  363. package/scripts/test-task-router-intents-fixtures.mjs +109 -0
package/CHANGELOG.md CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ### Mavis platform (MiniMax Code, experimental Next-only)
6
+
7
+ - 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/**`.
8
+ - 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).
9
+ - 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`.
10
+ - 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`.
11
+ - Consumers: re-run `npx @bonesofspring/ai-rules init mavis --preset next` after publish. Cursor/Claude installs unchanged.
12
+
5
13
  ### Chain-team-phases hook coverage + pipeline race fixes
6
14
 
7
15
  - `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, and **Mavis / MiniMax Code (experimental Next-only)**:
4
4
 
5
5
  Node 18+.
6
6
 
@@ -8,7 +8,9 @@ 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
11
12
  npx @bonesofspring/ai-rules clean cursor
13
+ npx @bonesofspring/ai-rules clean mavis
12
14
  ```
13
15
 
14
16
  Global: `npm i -g @bonesofspring/ai-rules`, then `ai-rules ...`.
@@ -54,6 +56,8 @@ Where things go on `init`:
54
56
  | **repo-root agents** | `REPO_AGENTS.md` → **`<cwd>/AGENTS.md`** | same |
55
57
  | **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
58
 
59
+ **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
+
57
61
  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
62
 
59
63
  ## Product specs (`docs/specs/`)
@@ -121,6 +125,6 @@ Presets are developed in this monorepo under `presets/`. If you add or change ru
121
125
  - **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
126
  - **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
127
  - **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>/`
128
+ - **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
129
 
126
130
  MIT.
package/bin/cli.js CHANGED
@@ -4,11 +4,12 @@
4
4
  */
5
5
  const fs = require('fs');
6
6
  const path = require('path');
7
+ const { cmdInitMavis, cmdCleanMavis } = require('./mavis-install');
7
8
 
8
9
  /** Single path segment: letters, digits, dot, underscore, hyphen; no separators or "..". */
9
10
  const PRESET_NAME_RE = /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/;
10
11
  const DEFAULT_PRESET = 'next';
11
- const TOOLS = new Set(['cursor', 'claude']);
12
+ const TOOLS = new Set(['cursor', 'claude', 'mavis']);
12
13
 
13
14
  const PRESETS = {
14
15
  cursor: {
@@ -51,9 +52,9 @@ function printHelp() {
51
52
  console.log(`@bonesofspring/ai-rules
52
53
 
53
54
  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>]
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>]
57
58
 
58
59
  Options:
59
60
  --preset <name> Preset name (default: ${DEFAULT_PRESET})
@@ -66,6 +67,7 @@ Notes:
66
67
  copied to a timestamped *.bak.* then replaced with the preset file. JSONC is not supported).
67
68
  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
69
  Claude init copies rules, commands, skills, agents, hooks, team, CLAUDE.md, MCP.md, and mcp.json → .mcp.json (project root).
70
+ Mavis init copies into .mavis/ (ai-rules-owned) plus REPO_AGENTS.md → <cwd>/AGENTS.md; MCP merges into .mavis/mcp.json only (never ~/.minimax/**).
69
71
  Both tools also copy REPO_AGENTS.md → <cwd>/AGENTS.md (repo-root cross-tool agents file; overwrite).
70
72
  When <cwd>/docs/specs/ is absent, init also seeds INDEX.md stub + _templates/* from package assets (never overwrites an existing INDEX).
71
73
  clean removes tool dirs/files and <cwd>/AGENTS.md (shared across tools — re-init the other tool to restore).
@@ -93,6 +95,8 @@ Examples:
93
95
  npx @bonesofspring/ai-rules init claude --preset mcp-ts
94
96
  npx @bonesofspring/ai-rules init claude --preset php-hexagonal
95
97
  npx @bonesofspring/ai-rules init claude --preset php-laravel
98
+ npx @bonesofspring/ai-rules init mavis --preset next
99
+ npx @bonesofspring/ai-rules clean mavis
96
100
  npx @bonesofspring/ai-rules clean cursor
97
101
  `);
98
102
  }
@@ -484,9 +488,22 @@ function resolvePresetName(tool, preset, packageRoot) {
484
488
  }
485
489
 
486
490
  function cmdInit(tool, preset, cwdOption) {
491
+ if (tool === 'mavis') {
492
+ cmdInitMavis({
493
+ preset,
494
+ cwdOption,
495
+ helpers: {
496
+ resolveTargetCwd,
497
+ seedDocsSpecsIfAbsent,
498
+ installMcpJson,
499
+ getPackageRoot,
500
+ },
501
+ });
502
+ return;
503
+ }
487
504
  const cfg = PRESETS[tool];
488
505
  if (!cfg) {
489
- console.error(`Unknown tool: ${tool}. Use cursor or claude.`);
506
+ console.error(`Unknown tool: ${tool}. Use cursor, claude, or mavis.`);
490
507
  process.exit(1);
491
508
  }
492
509
 
@@ -665,9 +682,16 @@ function rollbackInit(createdPaths, toolRootExisted, toolRootAbs) {
665
682
  }
666
683
 
667
684
  function cmdClean(tool, cwdOption) {
685
+ if (tool === 'mavis') {
686
+ cmdCleanMavis({
687
+ cwdOption,
688
+ helpers: { resolveTargetCwd },
689
+ });
690
+ return;
691
+ }
668
692
  const cfg = PRESETS[tool];
669
693
  if (!cfg) {
670
- console.error(`Unknown tool: ${tool}. Use cursor or claude.`);
694
+ console.error(`Unknown tool: ${tool}. Use cursor, claude, or mavis.`);
671
695
  process.exit(1);
672
696
  }
673
697
  const cwd = resolveTargetCwd(cwdOption);
@@ -737,7 +761,7 @@ function main() {
737
761
 
738
762
  if (command === 'init') {
739
763
  if (!tool || !TOOLS.has(tool)) {
740
- console.error('Missing or invalid tool. Use: init cursor|claude [--preset next]');
764
+ console.error('Missing or invalid tool. Use: init cursor|claude|mavis [--preset next]');
741
765
  process.exit(1);
742
766
  }
743
767
  cmdInit(tool, preset, parsed.cwd);
@@ -745,7 +769,7 @@ function main() {
745
769
  }
746
770
  if (command === 'clean') {
747
771
  if (!tool || !TOOLS.has(tool)) {
748
- console.error('Missing or invalid tool. Use: clean cursor|claude');
772
+ console.error('Missing or invalid tool. Use: clean cursor|claude|mavis');
749
773
  process.exit(1);
750
774
  }
751
775
  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 };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bonesofspring/ai-rules",
3
- "version": "0.2.21",
3
+ "version": "0.2.23",
4
4
  "description": "Presets of Cursor and Claude rules/commands for Revy Ross personal use",
5
5
  "license": "MIT",
6
6
  "author": "Revy Ross",
@@ -38,8 +38,15 @@
38
38
  "check:product-specs:dogfood": "bash scripts/check-product-specs.sh ../../dogfood/mcp-ts-sample",
39
39
  "check:rule-eval": "node scripts/check-rule-eval.mjs",
40
40
  "test:cli-mcp-merge": "node scripts/test-cli-mcp-merge.mjs",
41
+ "test:cli-init-clean": "node scripts/test-cli-init-clean.mjs",
41
42
  "test:chain-coverage": "node scripts/test-chain-team-phases-coverage.mjs",
42
- "test:agent-task-metrics-hooks": "node scripts/test-agent-task-metrics-hooks.mjs"
43
+ "test:agent-task-metrics-hooks": "node scripts/test-agent-task-metrics-hooks.mjs",
44
+ "check:mavis-platform-contract": "node scripts/check-mavis-platform-contract.mjs --self-test",
45
+ "check:mavis-adapter-map": "node scripts/check-mavis-adapter-map.mjs --self-test",
46
+ "check:mavis-token-budget": "node scripts/check-mavis-token-budget.mjs",
47
+ "check:mavis-local-overlay": "node scripts/check-mavis-local-overlay.mjs",
48
+ "test:mavis-context-budget": "node scripts/test-mavis-context-budget.mjs",
49
+ "test:mavis-orchestration": "node scripts/test-mavis-orchestration.mjs"
43
50
  },
44
51
  "engines": {
45
52
  "node": ">=18"
@@ -78,6 +78,8 @@ A producer finishes its step by upserting only its owned artifact entry and term
78
78
 
79
79
  `blocked` is terminal for the producer attempt but non-advancing for the pipeline: the hook persists `status.state` / `phase` as `blocked` and emits no next-agent handoff. A receipt must either carry the active `attemptId` or belong to the step's assigned output entry. Its terminal timestamp must be at or after the active attempt's `startedAt`; otherwise the hook keeps the attempt active in `awaiting_artifact_receipt` and does not advance or retry.
80
80
 
81
+ > **Receipt binding (owner prompts).** Each owning-agent prompt (`feature-developer`, `build-verifier`, `code-reviewer`, `debugger`, `qa-tester` across `cursor/` and `claude/` platforms × 10 stacks) carries the same one-paragraph callout under `## On completion` (or appended as `## Receipt binding` when no `On completion` section exists). When writing the terminal receipt, set `entry.receipt.attemptId = <attemptId supplied by the orchestrator>`. The hook at `chain-team-phases.sh:readBoundReceiptOutcome` rejects entries whose `attemptId` does not match the current attempt, or whose `Date.parse(timestamps.completedAt) < Date.parse(attemptStartedAt)`. A missing or stale attemptId causes `awaiting_artifact_receipt` stalls.
82
+
81
83
  ## Ownership and writes
82
84
 
83
85
  - Agents own their output artifacts and their manifest entries/receipts. They merge by stable `id` and preserve all foreign entries.
@@ -7,6 +7,7 @@ Checklist for PRs that touch `packages/ai-rules/presets/**` (and dogfood `.curso
7
7
  - [ ] **SoT:** edits in `packages/…` (not only root `.cursor/`)
8
8
  - [ ] **Core:** if `_shared/core/**` changed — all `<!-- shared-core: … -->` consumers updated (or documented intentional fork)
9
9
  - [ ] **Twin:** Cursor change → Claude twin **same PR** (**FAIL** if missing on next, nuxt, svelte, ios-swift, android-kotlin, go, java, mcp-ts, php-hexagonal, and php-laravel — see `preset-twin-sync`)
10
+ - [ ] **Mavis derive:** mapped `cursor/<stack>/` change → `mavis/<stack>/` + `adapter-map.json` **same PR** when the stack is in `releasedStacks` (run `generate-mavis-next.mjs` + `check-mavis-adapter-map.mjs` for `next`; see `preset-twin-sync` § Mavis derivation)
10
11
  - [ ] **Mapping:** `claude/<stack>/rules/README.md` mapping table is current
11
12
  - [ ] **Token budget:** Cursor `alwaysApply` ≤ 4 (4th slot reserved for `ai-local-overlay`); Claude session-start exactly 3; meta rules not always-on
12
13
  - [ ] **Local overlay coverage:** every installable stack ships `ai-local-overlay.mdc` (Cursor) and `ai-local-overlay.md` (Claude) with `MANDATORY` + acknowledgement format + `docs/LOCAL-OVERLAY.md` pointer; Claude twin listed in `claude/<stack>/rules/README.md` mapping table. Run `packages/ai-rules/scripts/check-local-overlay.sh`.