@bonesofspring/ai-rules 0.2.2 → 0.2.4

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 (295) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/README.md +27 -4
  3. package/bin/cli.js +285 -72
  4. package/package.json +3 -2
  5. package/presets/claude/ios-swift/CLAUDE.md +28 -20
  6. package/presets/claude/ios-swift/MCP.md +14 -0
  7. package/presets/claude/ios-swift/README.md +18 -15
  8. package/presets/claude/ios-swift/agents/README.md +55 -0
  9. package/presets/claude/ios-swift/agents/accessibility-reviewer.md +67 -0
  10. package/presets/claude/ios-swift/agents/api-contract-reviewer.md +72 -0
  11. package/presets/claude/ios-swift/agents/build-verifier.md +64 -0
  12. package/presets/claude/ios-swift/agents/ci-investigator.md +73 -0
  13. package/presets/claude/ios-swift/agents/code-reviewer.md +75 -0
  14. package/presets/claude/ios-swift/agents/debugger.md +72 -0
  15. package/presets/claude/ios-swift/agents/feature-developer.md +35 -0
  16. package/presets/claude/ios-swift/agents/migration-specialist.md +73 -0
  17. package/presets/claude/ios-swift/agents/performance-auditor.md +72 -0
  18. package/presets/claude/ios-swift/agents/qa-tester.md +65 -0
  19. package/presets/claude/ios-swift/agents/security-reviewer.md +69 -0
  20. package/presets/claude/ios-swift/agents/solution-architect.md +17 -0
  21. package/presets/claude/ios-swift/agents/task-analyst.md +25 -0
  22. package/presets/claude/ios-swift/agents/task-router.md +62 -0
  23. package/presets/claude/ios-swift/agents/tech-writer.md +63 -0
  24. package/presets/claude/ios-swift/agents/unit-test-generator.md +54 -0
  25. package/presets/claude/ios-swift/agents/unit-test-healer.md +53 -0
  26. package/presets/claude/ios-swift/agents/unit-test-planner.md +64 -0
  27. package/presets/claude/ios-swift/agents/xcuitest-test-generator.md +47 -0
  28. package/presets/claude/ios-swift/agents/xcuitest-test-healer.md +47 -0
  29. package/presets/claude/ios-swift/agents/xcuitest-test-planner.md +67 -0
  30. package/presets/claude/ios-swift/commands/README.md +12 -2
  31. package/presets/claude/ios-swift/commands/feature-continue.md +51 -0
  32. package/presets/claude/ios-swift/commands/feature-start.md +30 -0
  33. package/presets/claude/ios-swift/commands/task-continue.md +49 -0
  34. package/presets/claude/ios-swift/commands/task.md +50 -0
  35. package/presets/claude/ios-swift/commands/technical-retro.md +58 -0
  36. package/presets/claude/ios-swift/hooks/README.md +10 -0
  37. package/presets/claude/ios-swift/hooks/chain-team-phases.sh +382 -0
  38. package/presets/claude/ios-swift/hooks/guard-shell-command.sh +79 -0
  39. package/presets/claude/ios-swift/mcp.json +12 -0
  40. package/presets/claude/ios-swift/rules/README.md +25 -14
  41. package/presets/claude/ios-swift/rules/api-and-data/README.md +2 -1
  42. package/presets/claude/ios-swift/rules/api-and-data/networking.md +2 -2
  43. package/presets/claude/ios-swift/rules/api-and-data/persistence.md +30 -0
  44. package/presets/claude/ios-swift/rules/architecture/README.md +3 -1
  45. package/presets/claude/ios-swift/rules/architecture/feature-delivery.md +10 -2
  46. package/presets/claude/ios-swift/rules/architecture/module-public-api.md +25 -0
  47. package/presets/claude/ios-swift/rules/architecture/reference-features.md +50 -0
  48. package/presets/claude/ios-swift/rules/stack/ios-app-core.md +2 -1
  49. package/presets/claude/ios-swift/rules/testing/ui.md +2 -0
  50. package/presets/claude/ios-swift/rules/tooling-and-review/README.md +6 -1
  51. package/presets/claude/ios-swift/rules/tooling-and-review/agent-team-intake.md +18 -0
  52. package/presets/claude/ios-swift/rules/tooling-and-review/agent-team-orchestrator.md +47 -0
  53. package/presets/claude/ios-swift/rules/tooling-and-review/code-review.md +5 -0
  54. package/presets/claude/ios-swift/rules/tooling-and-review/post-change-build.md +5 -0
  55. package/presets/claude/ios-swift/rules/tooling-and-review/security-ios.md +36 -0
  56. package/presets/claude/ios-swift/rules/tooling-and-review/technical-retro.md +14 -0
  57. package/presets/claude/ios-swift/rules/tooling-and-review/xcode-tooling.md +24 -0
  58. package/presets/claude/ios-swift/rules/ui-and-accessibility/README.md +2 -1
  59. package/presets/claude/ios-swift/rules/ui-and-accessibility/navigation.md +28 -0
  60. package/presets/claude/ios-swift/skills/README.md +13 -0
  61. package/presets/claude/ios-swift/skills/ci-investigation/SKILL.md +39 -0
  62. package/presets/claude/ios-swift/skills/code-review/SKILL.md +27 -0
  63. package/presets/claude/ios-swift/skills/debug-investigation/SKILL.md +30 -0
  64. package/presets/claude/ios-swift/skills/feature-delivery/SKILL.md +27 -0
  65. package/presets/claude/ios-swift/skills/technical-retro/SKILL.md +10 -0
  66. package/presets/claude/ios-swift/skills/unit-testing/SKILL.md +32 -0
  67. package/presets/claude/ios-swift/skills/xcuitest-e2e/SKILL.md +33 -0
  68. package/presets/claude/ios-swift/team/README.md +27 -0
  69. package/presets/claude/ios-swift/team/fixtures/bugfix-standard.json +33 -0
  70. package/presets/claude/ios-swift/team/fixtures/feature-full.json +48 -0
  71. package/presets/claude/ios-swift/team/fixtures/feature-light.json +36 -0
  72. package/presets/claude/next/CLAUDE.md +29 -5
  73. package/presets/claude/next/MCP.md +16 -0
  74. package/presets/claude/next/README.md +12 -0
  75. package/presets/claude/next/agents/README.md +155 -1
  76. package/presets/claude/next/agents/accessibility-reviewer.md +65 -0
  77. package/presets/claude/next/agents/api-contract-reviewer.md +69 -0
  78. package/presets/claude/next/agents/build-verifier.md +64 -0
  79. package/presets/claude/next/agents/ci-investigator.md +62 -0
  80. package/presets/claude/next/agents/code-reviewer.md +63 -0
  81. package/presets/claude/next/agents/debugger.md +63 -0
  82. package/presets/claude/next/agents/feature-developer.md +27 -0
  83. package/presets/claude/next/agents/migration-specialist.md +69 -0
  84. package/presets/claude/next/agents/performance-auditor.md +68 -0
  85. package/presets/claude/next/agents/qa-tester.md +56 -0
  86. package/presets/claude/next/agents/security-reviewer.md +64 -0
  87. package/presets/claude/next/agents/solution-architect.md +70 -0
  88. package/presets/claude/next/agents/task-analyst.md +111 -0
  89. package/presets/claude/next/agents/task-router.md +94 -0
  90. package/presets/claude/next/agents/tech-writer.md +61 -0
  91. package/presets/claude/next/agents/unit-test-generator.md +37 -0
  92. package/presets/claude/next/agents/unit-test-healer.md +38 -0
  93. package/presets/claude/next/agents/unit-test-planner.md +62 -0
  94. package/presets/claude/next/commands/README.md +10 -2
  95. package/presets/claude/next/commands/feature-continue.md +51 -0
  96. package/presets/claude/next/commands/feature-start.md +30 -0
  97. package/presets/claude/next/commands/task-continue.md +49 -0
  98. package/presets/claude/next/commands/task.md +50 -0
  99. package/presets/claude/next/commands/technical-retro.md +58 -0
  100. package/presets/claude/next/hooks/README.md +5 -2
  101. package/presets/claude/next/hooks/chain-team-phases.sh +380 -0
  102. package/presets/claude/next/hooks/guard-shell-command.sh +77 -0
  103. package/presets/claude/next/mcp.json +20 -0
  104. package/presets/claude/next/rules/README.md +42 -11
  105. package/presets/claude/next/rules/api-and-data/README.md +7 -1
  106. package/presets/claude/next/rules/api-and-data/api-services.md +57 -0
  107. package/presets/claude/next/rules/api-and-data/http-client.md +40 -0
  108. package/presets/claude/next/rules/api-and-data/store-rtk.md +65 -0
  109. package/presets/claude/next/rules/architecture/README.md +11 -2
  110. package/presets/claude/next/rules/architecture/architecture-boundaries-ui.md +15 -0
  111. package/presets/claude/next/rules/architecture/architecture-boundaries.md +75 -0
  112. package/presets/claude/next/rules/architecture/feature-delivery-workflow.md +79 -0
  113. package/presets/claude/next/rules/architecture/layer-barrel-exports.md +58 -0
  114. package/presets/claude/next/rules/architecture/public-imports.md +46 -0
  115. package/presets/claude/next/rules/architecture/reference-features.md +37 -0
  116. package/presets/claude/next/rules/stack/README.md +10 -1
  117. package/presets/claude/next/rules/stack/arrow-functions.md +45 -0
  118. package/presets/claude/next/rules/stack/navigation-router-ui.md +15 -0
  119. package/presets/claude/next/rules/stack/navigation-router.md +64 -0
  120. package/presets/claude/next/rules/stack/next-app-core.md +33 -0
  121. package/presets/claude/next/rules/stack/next-app-router.md +36 -0
  122. package/presets/claude/next/rules/stack/no-type-assertion.md +59 -0
  123. package/presets/claude/next/rules/stack/types-jsdoc.md +37 -0
  124. package/presets/claude/next/rules/testing/README.md +9 -1
  125. package/presets/claude/next/rules/testing/playwright-agents.md +74 -0
  126. package/presets/claude/next/rules/testing/tests-e2e-structure.md +52 -0
  127. package/presets/claude/next/rules/testing/tests-unit.md +66 -0
  128. package/presets/claude/next/rules/tooling-and-review/README.md +12 -1
  129. package/presets/claude/next/rules/tooling-and-review/agent-team-intake.md +15 -0
  130. package/presets/claude/next/rules/tooling-and-review/agent-team-orchestrator.md +145 -0
  131. package/presets/claude/next/rules/tooling-and-review/code-quality.md +42 -0
  132. package/presets/claude/next/rules/tooling-and-review/code-review-mr.md +30 -0
  133. package/presets/claude/next/rules/tooling-and-review/package-manager.md +11 -0
  134. package/presets/claude/next/rules/tooling-and-review/post-change-lint.md +44 -0
  135. package/presets/claude/next/rules/ui-and-accessibility/README.md +10 -1
  136. package/presets/claude/next/rules/ui-and-accessibility/css-property-order.md +14 -0
  137. package/presets/claude/next/rules/ui-and-accessibility/no-props-spread.md +57 -0
  138. package/presets/claude/next/rules/ui-and-accessibility/react-a11y-coding.md +37 -0
  139. package/presets/claude/next/rules/ui-and-accessibility/react-ui.md +91 -0
  140. package/presets/claude/next/skills/README.md +11 -1
  141. package/presets/claude/next/skills/ci-investigation/SKILL.md +36 -0
  142. package/presets/claude/next/skills/code-review/SKILL.md +26 -0
  143. package/presets/claude/next/skills/debug-investigation/SKILL.md +28 -0
  144. package/presets/claude/next/skills/feature-delivery/SKILL.md +15 -0
  145. package/presets/claude/next/skills/playwright-e2e/SKILL.md +31 -0
  146. package/presets/claude/next/skills/technical-retro/SKILL.md +40 -0
  147. package/presets/claude/next/skills/unit-testing/SKILL.md +32 -0
  148. package/presets/claude/next/team/README.md +105 -0
  149. package/presets/claude/next/team/fixtures/bugfix-standard.json +15 -0
  150. package/presets/claude/next/team/fixtures/feature-full.json +16 -0
  151. package/presets/claude/next/team/fixtures/feature-light.json +17 -0
  152. package/presets/claude/next/team/tasks/.gitkeep +1 -0
  153. package/presets/cursor/ios-swift/AGENTS.md +47 -0
  154. package/presets/cursor/ios-swift/BUGBOT.md +15 -0
  155. package/presets/cursor/ios-swift/MCP.md +16 -0
  156. package/presets/cursor/ios-swift/README.md +27 -7
  157. package/presets/cursor/ios-swift/agents/README.md +55 -0
  158. package/presets/cursor/ios-swift/agents/accessibility-reviewer.md +67 -0
  159. package/presets/cursor/ios-swift/agents/api-contract-reviewer.md +72 -0
  160. package/presets/cursor/ios-swift/agents/build-verifier.md +64 -0
  161. package/presets/cursor/ios-swift/agents/ci-investigator.md +73 -0
  162. package/presets/cursor/ios-swift/agents/code-reviewer.md +75 -0
  163. package/presets/cursor/ios-swift/agents/debugger.md +72 -0
  164. package/presets/cursor/ios-swift/agents/feature-developer.md +35 -0
  165. package/presets/cursor/ios-swift/agents/migration-specialist.md +73 -0
  166. package/presets/cursor/ios-swift/agents/performance-auditor.md +72 -0
  167. package/presets/cursor/ios-swift/agents/qa-tester.md +65 -0
  168. package/presets/cursor/ios-swift/agents/security-reviewer.md +69 -0
  169. package/presets/cursor/ios-swift/agents/solution-architect.md +17 -0
  170. package/presets/cursor/ios-swift/agents/task-analyst.md +25 -0
  171. package/presets/cursor/ios-swift/agents/task-router.md +62 -0
  172. package/presets/cursor/ios-swift/agents/tech-writer.md +63 -0
  173. package/presets/cursor/ios-swift/agents/unit-test-generator.md +54 -0
  174. package/presets/cursor/ios-swift/agents/unit-test-healer.md +53 -0
  175. package/presets/cursor/ios-swift/agents/unit-test-planner.md +64 -0
  176. package/presets/cursor/ios-swift/agents/xcuitest-test-generator.md +47 -0
  177. package/presets/cursor/ios-swift/agents/xcuitest-test-healer.md +47 -0
  178. package/presets/cursor/ios-swift/agents/xcuitest-test-planner.md +67 -0
  179. package/presets/cursor/ios-swift/commands/README.md +49 -1
  180. package/presets/cursor/ios-swift/commands/feature-continue.md +19 -0
  181. package/presets/cursor/ios-swift/commands/feature-start.md +33 -0
  182. package/presets/cursor/ios-swift/commands/task-continue.md +49 -0
  183. package/presets/cursor/ios-swift/commands/task.md +50 -0
  184. package/presets/cursor/ios-swift/commands/technical-retro.md +81 -0
  185. package/presets/cursor/ios-swift/hooks/README.md +8 -0
  186. package/presets/cursor/ios-swift/hooks/chain-team-phases.sh +382 -0
  187. package/presets/cursor/ios-swift/hooks/guard-shell-command.sh +79 -0
  188. package/presets/cursor/ios-swift/hooks.json +17 -0
  189. package/presets/cursor/ios-swift/mcp.json +11 -0
  190. package/presets/cursor/ios-swift/rules/README.md +45 -13
  191. package/presets/cursor/ios-swift/rules/agent-team-intake.mdc +16 -0
  192. package/presets/cursor/ios-swift/rules/agent-team-orchestrator.mdc +85 -0
  193. package/presets/cursor/ios-swift/rules/code-review-mr.mdc +1 -0
  194. package/presets/cursor/ios-swift/rules/feature-delivery-workflow.mdc +1 -1
  195. package/presets/cursor/ios-swift/rules/ios-app-core.mdc +2 -1
  196. package/presets/cursor/ios-swift/rules/module-public-api.mdc +26 -0
  197. package/presets/cursor/ios-swift/rules/navigation-coordinators.mdc +29 -0
  198. package/presets/cursor/ios-swift/rules/networking-services.mdc +2 -2
  199. package/presets/cursor/ios-swift/rules/persistence-data.mdc +31 -0
  200. package/presets/cursor/ios-swift/rules/reference-features.mdc +53 -0
  201. package/presets/cursor/ios-swift/rules/security-ios.mdc +35 -0
  202. package/presets/cursor/ios-swift/rules/technical-retro.mdc +12 -0
  203. package/presets/cursor/ios-swift/rules/tests-ui.mdc +1 -0
  204. package/presets/cursor/ios-swift/rules/xcode-tooling.mdc +20 -0
  205. package/presets/cursor/ios-swift/skills/README.md +13 -0
  206. package/presets/cursor/ios-swift/skills/ci-investigation/SKILL.md +39 -0
  207. package/presets/cursor/ios-swift/skills/code-review/SKILL.md +27 -0
  208. package/presets/cursor/ios-swift/skills/debug-investigation/SKILL.md +30 -0
  209. package/presets/cursor/ios-swift/skills/feature-delivery/SKILL.md +27 -0
  210. package/presets/cursor/ios-swift/skills/technical-retro/SKILL.md +10 -0
  211. package/presets/cursor/ios-swift/skills/unit-testing/SKILL.md +32 -0
  212. package/presets/cursor/ios-swift/skills/xcuitest-e2e/SKILL.md +33 -0
  213. package/presets/cursor/ios-swift/team/README.md +31 -0
  214. package/presets/cursor/ios-swift/team/fixtures/bugfix-standard.json +33 -0
  215. package/presets/cursor/ios-swift/team/fixtures/feature-full.json +48 -0
  216. package/presets/cursor/ios-swift/team/fixtures/feature-light.json +36 -0
  217. package/presets/cursor/next/AGENTS.md +36 -0
  218. package/presets/cursor/next/BUGBOT.md +14 -0
  219. package/presets/cursor/next/MCP.md +16 -0
  220. package/presets/cursor/next/agents/README.md +165 -0
  221. package/presets/cursor/next/agents/accessibility-reviewer.md +67 -0
  222. package/presets/cursor/next/agents/api-contract-reviewer.md +71 -0
  223. package/presets/cursor/next/agents/build-verifier.md +66 -0
  224. package/presets/cursor/next/agents/ci-investigator.md +64 -0
  225. package/presets/cursor/next/agents/code-reviewer.md +64 -0
  226. package/presets/cursor/next/agents/debugger.md +64 -0
  227. package/presets/cursor/next/agents/feature-developer.md +28 -0
  228. package/presets/cursor/next/agents/migration-specialist.md +71 -0
  229. package/presets/cursor/next/agents/performance-auditor.md +70 -0
  230. package/presets/cursor/next/agents/playwright-test-generator.md +27 -0
  231. package/presets/cursor/next/agents/playwright-test-healer.md +27 -0
  232. package/presets/cursor/next/agents/playwright-test-planner.md +28 -0
  233. package/presets/cursor/next/agents/qa-tester.md +58 -0
  234. package/presets/cursor/next/agents/security-reviewer.md +66 -0
  235. package/presets/cursor/next/agents/solution-architect.md +71 -0
  236. package/presets/cursor/next/agents/task-analyst.md +112 -0
  237. package/presets/cursor/next/agents/task-router.md +95 -0
  238. package/presets/cursor/next/agents/tech-writer.md +62 -0
  239. package/presets/cursor/next/agents/unit-test-generator.md +39 -0
  240. package/presets/cursor/next/agents/unit-test-healer.md +40 -0
  241. package/presets/cursor/next/agents/unit-test-planner.md +64 -0
  242. package/presets/cursor/next/commands/README.md +49 -1
  243. package/presets/cursor/next/commands/feature-continue.md +19 -0
  244. package/presets/cursor/next/commands/feature-start.md +33 -0
  245. package/presets/cursor/next/commands/task-continue.md +49 -0
  246. package/presets/cursor/next/commands/task.md +50 -0
  247. package/presets/cursor/next/commands/technical-retro.md +81 -0
  248. package/presets/cursor/next/hooks/README.md +8 -0
  249. package/presets/cursor/next/hooks/chain-team-phases.sh +380 -0
  250. package/presets/cursor/next/hooks/guard-shell-command.sh +77 -0
  251. package/presets/cursor/next/hooks.json +17 -0
  252. package/presets/cursor/next/mcp.json +19 -0
  253. package/presets/cursor/next/rules/README.md +67 -0
  254. package/presets/cursor/next/rules/agent-team-intake.mdc +14 -0
  255. package/presets/cursor/next/rules/agent-team-orchestrator.mdc +147 -0
  256. package/presets/cursor/next/rules/api-services.mdc +12 -10
  257. package/presets/cursor/next/rules/architecture-boundaries-ui.mdc +15 -0
  258. package/presets/cursor/next/rules/architecture-boundaries.mdc +31 -12
  259. package/presets/cursor/next/rules/arrow-functions.mdc +46 -0
  260. package/presets/cursor/next/rules/code-quality-and-refactoring.mdc +5 -4
  261. package/presets/cursor/next/rules/code-review-mr.mdc +21 -40
  262. package/presets/cursor/next/rules/css-property-order-stylelint.mdc +16 -0
  263. package/presets/cursor/next/rules/feature-delivery-workflow.mdc +76 -0
  264. package/presets/cursor/next/rules/http-client.mdc +42 -0
  265. package/presets/cursor/next/rules/layer-barrel-exports.mdc +59 -0
  266. package/presets/cursor/next/rules/navigation-router-stack.mdc +62 -0
  267. package/presets/cursor/next/rules/navigation-router-ui.mdc +16 -0
  268. package/presets/cursor/next/rules/next-app-core.mdc +18 -61
  269. package/presets/cursor/next/rules/next-app-router.mdc +36 -0
  270. package/presets/cursor/next/rules/no-props-spread.mdc +27 -4
  271. package/presets/cursor/next/rules/no-type-assertion-as-import-export.mdc +60 -0
  272. package/presets/cursor/next/rules/package-manager.mdc +16 -0
  273. package/presets/cursor/next/rules/playwright-agents.mdc +2 -1
  274. package/presets/cursor/next/rules/post-change-lint.mdc +40 -0
  275. package/presets/cursor/next/rules/public-imports.mdc +48 -0
  276. package/presets/cursor/next/rules/react-a11y-coding.mdc +37 -0
  277. package/presets/cursor/next/rules/react-ui.mdc +33 -3
  278. package/presets/cursor/next/rules/reference-features.mdc +39 -0
  279. package/presets/cursor/next/rules/store-rtk.mdc +13 -6
  280. package/presets/cursor/next/rules/technical-retro.mdc +12 -0
  281. package/presets/cursor/next/rules/tests-unit.mdc +30 -10
  282. package/presets/cursor/next/rules/types-jsdoc.mdc +42 -0
  283. package/presets/cursor/next/skills/README.md +15 -0
  284. package/presets/cursor/next/skills/ci-investigation/SKILL.md +36 -0
  285. package/presets/cursor/next/skills/code-review/SKILL.md +26 -0
  286. package/presets/cursor/next/skills/debug-investigation/SKILL.md +28 -0
  287. package/presets/cursor/next/skills/feature-delivery/SKILL.md +15 -0
  288. package/presets/cursor/next/skills/playwright-e2e/SKILL.md +31 -0
  289. package/presets/cursor/next/skills/technical-retro/SKILL.md +40 -0
  290. package/presets/cursor/next/skills/unit-testing/SKILL.md +32 -0
  291. package/presets/cursor/next/team/README.md +109 -0
  292. package/presets/cursor/next/team/fixtures/bugfix-standard.json +15 -0
  293. package/presets/cursor/next/team/fixtures/feature-full.json +16 -0
  294. package/presets/cursor/next/team/fixtures/feature-light.json +17 -0
  295. package/presets/cursor/next/team/tasks/.gitkeep +0 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,65 @@
1
+ # Changelog
2
+
3
+ ## Unreleased
4
+
5
+ ### Breaking
6
+
7
+ - **Deprecated rule stubs removed** (Cursor + Claude `next`): `types-public-imports`, `api-public-imports`, `no-cross-component-styles-import` / `component-styles`. Use `public-imports` and `react-ui` instead.
8
+ - **`next` preset — post-change-lint no longer always-on:** Cursor `post-change-lint.mdc` and Claude twin are **requestable** (not session-start / `alwaysApply`). Load explicitly after code edits via skill `feature-delivery` or agent `build-verifier`. Session-start / alwaysApply is now **3** rules: `next-app-core`, `package-manager`, `code-quality-and-refactoring`. Workspace dogfood `.cursor/rules/post-change-lint.mdc` synced.
9
+
10
+ ### Added
11
+
12
+ - **MCP configs in presets** (`next` + `ios-swift`, Cursor + Claude): `mcp.json` + `MCP.md`. Cursor → `.cursor/mcp.json`; Claude → project-root `.mcp.json`. **next:** Context7, Playwright, Chrome DevTools, Figma (remote). **ios-swift:** Context7 + Figma. CLI `init`/`clean` manage these paths.
13
+ - **Cursor + Claude `ios-swift` — full agent-team parity with `next`:** **21** agents (Playwright trio → `xcuitest-test-{planner,generator,healer}`), **7** skills (`xcuitest-e2e`), **5** slash commands, `hooks.json` + iOS-adapted `chain-team-phases.sh` (Cursor) / hook scripts + README (Claude), `team/fixtures/` ×3, `AGENTS.md` (Cursor) / thin `CLAUDE.md` (≤35 lines).
14
+ - **ios-swift rules:** agent-team intake/orchestrator, `xcode-tooling`, `reference-features`, domain rules (`navigation-coordinators`, `persistence-data`, `security-ios`, `module-public-api`), `technical-retro` alias; **21** rule topics (+ README). CLI init copies agents, hooks, skills, team, `AGENTS.md`.
15
+ - **ios-swift retro follow-ups:** `build-verifier` preset checks (chain ≠ next; ban Playwright/`lint:js` handoffs); enriched 16 priority agent prompts + 6 skills; dogfood checklist (5 scenarios) in `AGENTS.md` / `reference-features`; Cursor-only **`BUGBOT.md`** (iOS review priorities).
16
+
17
+ ### Changed
18
+
19
+ - **Agent team slug bootstrap:** `/task` and `/feature-start` (Cursor + Claude, `next` + `ios-swift`) create `.cursor|claude/team/tasks/<slug>/` via **Write**, not Shell `mkdir` — avoids Cursor sandbox `Operation not permitted` (esp. macOS Desktop/Documents). Orchestrator + `team/README` + `task-router` document the rule.
20
+ - **Token model (ios-swift + next):** both presets use **3** alwaysApply / session-start rules (~77 / ~59 body lines). Post-change verification is **requestable** — ios: `post-change-build`; next: `post-change-lint`. Orchestrator, intake, code-review, feature-delivery, tooling rules load on-demand (`paths:` / description).
21
+ - Claude `next`: `agent-team-orchestrator` and `code-review-mr` use `paths:` (on-demand) — session-start matches the 3-rule budget above.
22
+ - Cursor `next` agents: all pipeline agents set **`readonly: false`** so they can write `.cursor/team/**`. Production/app restrictions remain in prompt bodies (Cursor `readonly: true` blocks all file writes, including team artifacts).
23
+ - **ios-swift:** `networking-services` HTTP-only (persistence split out); soft AC-19 for thin aliases (`agent-team-intake`, `technical-retro`); `feature-developer` requires stack-specific hook handoff forks.
24
+
25
+ ### Notes
26
+
27
+ - **P2 optional (ios-swift):** Remaining polish: feature-delivery matrix enrichment, swift-conventions body cap. (`BUGBOT.md` shipped.)
28
+
29
+ ## 0.2.2
30
+
31
+ ### Breaking
32
+
33
+ - **`clean` is selective:** removes only CLI-managed paths (`rules`, `commands`, optional `agents`/`hooks`/`skills`/`team`, plus Cursor `hooks.json` / `BUGBOT.md` / `AGENTS.md`, Claude `CLAUDE.md`). Does **not** wipe the entire `.cursor/` or `.claude/` directory.
34
+
35
+ ### Added
36
+
37
+ - Cursor `next`: `architecture-boundaries-ui.mdc`, `navigation-router-ui.mdc` (slim UI-edit rules); Claude equivalents under `architecture/` and `stack/`.
38
+ - Cursor/Claude `next`: `AGENTS.md` on Cursor init; team `fixtures/` for pipeline profiles; pipeline profiles (`full` / `standard` / `light`) in `task-router`.
39
+ - Claude `next`: `hooks/chain-team-phases.sh` feature parity with Cursor (tool paths only differ).
40
+
41
+ ### Changed
42
+
43
+ - Narrower globs for full `architecture-boundaries` / `navigation-router(-stack)` vs UI slim rules; `layer-barrel-exports` → `index.ts`; styles colocation consolidated into `react-ui` (stubs remain).
44
+ - README documents `AGENTS.md` and selective `clean`.
45
+
46
+ ## 0.2.0
47
+
48
+ ### Breaking
49
+
50
+ - **Import rules merged:** `types-public-imports.mdc` and `api-public-imports.mdc` → **`public-imports.mdc`** (Claude: `architecture/public-imports.md`). Old filenames remain as deprecated stubs for one release cycle.
51
+ - **`feature-delivery-flow.mdc` removed** — content merged into `feature-delivery-workflow.mdc`.
52
+ - **`agent-team-intake`** no longer always-on (Cursor: `alwaysApply: false`; Claude: `paths:` on commands/team). Use orchestrator or `/task`.
53
+
54
+ ### Changed
55
+
56
+ - Slimmed always-on rules: `next-app-core`, `code-quality-and-refactoring`, `post-change-lint`, `package-manager` (~9 KB baseline vs ~21 KB).
57
+ - Narrowed globs: `css-property-order-stylelint`, `no-type-assertion-as-import-export`, `reference-features`, `public-imports`.
58
+ - `css-property-order` stub — property list delegated to Stylelint `--fix`.
59
+ - Slimmed `task-router` agent; pipeline JSON examples moved to `agents/README.md`.
60
+ - Agents reference skills as SSOT; scoped lint for `feature-developer` when next step is `build-verifier`.
61
+ - Orchestrator: explicit fast-path when to skip pipeline.
62
+
63
+ ## 0.1.42
64
+
65
+ Prior releases — see git history.
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 for Claude `CLAUDE.md` and `skills` / `agents` / `hooks` when the preset includes them. Install from npm into a project so you don’t have to copy files out of the repo by hand.
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.
4
4
 
5
5
  Node 18+.
6
6
 
@@ -13,9 +13,27 @@ npx @bonesofspring/ai-rules clean cursor
13
13
 
14
14
  Global: `npm i -g @bonesofspring/ai-rules`, then `ai-rules ...`.
15
15
 
16
- `init` merges into the current directory: dirs are created, matching files are **overwritten**. `--preset` and the subcommand can be in either order, e.g. `--preset=next init cursor`.
16
+ `init` merges into the **current working directory** (or `--cwd <dir>`): dirs are created, matching files are **overwritten**. `--preset` defaults to **`next`**. Supported forms:
17
17
 
18
- `clean cursor` / `clean claude` removes what this CLI installs: for Cursor, the entire `.cursor` directory; for Claude, `.claude/rules`, `.claude/commands`, `skills`, `agents`, `hooks`, and `CLAUDE.md` when present. Anything else under `.claude` is left alone.
18
+ ```bash
19
+ npx @bonesofspring/ai-rules init cursor --preset next
20
+ npx @bonesofspring/ai-rules init cursor next
21
+ npx @bonesofspring/ai-rules init cursor # preset next by default
22
+ npx @bonesofspring/ai-rules cursor init --preset next
23
+ ```
24
+
25
+ If `.cursor` does not appear, check the command output for errors and confirm you run init from the **target project root** (where the app lives), not from `node_modules`. Success ends with: `Done. .cursor installed at <absolute-path>`.
26
+
27
+ ### `clean` (breaking vs older wipe behavior)
28
+
29
+ `clean cursor` / `clean claude` removes **only CLI-managed paths** — not the entire `.cursor/` or `.claude/` tree:
30
+
31
+ - `rules/`, `commands/`
32
+ - optional dirs when present: `agents/`, `hooks/`, `skills/`, `team/`
33
+ - Cursor root files: `hooks.json`, `BUGBOT.md`, `AGENTS.md`, `MCP.md`, `mcp.json`
34
+ - Claude: `CLAUDE.md`, `MCP.md` under `.claude/`; project `.mcp.json` at repo root
35
+
36
+ Any other files you added under `.cursor/` or `.claude/` (notes, local overrides, IDE state) are **left intact**. Older releases that deleted the whole tool directory are no longer the behavior.
19
37
 
20
38
  Where things go on `init`:
21
39
 
@@ -23,7 +41,12 @@ Where things go on `init`:
23
41
  |---|--------|--------|
24
42
  | rules | `.cursor/rules` | `.claude/rules` |
25
43
  | commands | `.cursor/commands` | `.claude/commands` |
26
- | other | | root `CLAUDE.md` → `.claude/CLAUDE.md`; folders `skills`, `agents`, `hooks` → under `.claude/` with the same names |
44
+ | agents | `.cursor/agents` | `.claude/agents` |
45
+ | hooks | `.cursor/hooks`, `.cursor/hooks.json` | `.claude/hooks` |
46
+ | skills | `.cursor/skills` | `.claude/skills` |
47
+ | team artifacts template | `.cursor/team` | `.claude/team` |
48
+ | MCP | `mcp.json` → `.cursor/mcp.json`, `MCP.md` → `.cursor/` | `mcp.json` → **`.mcp.json`** (project root), `MCP.md` → `.claude/` |
49
+ | other | `BUGBOT.md`, `AGENTS.md` → `.cursor/` | `CLAUDE.md` → `.claude/CLAUDE.md` |
27
50
 
28
51
  The package ships presets including **`next`** (Next.js stack) and **`ios-swift`** (iOS apps on Swift / SwiftUI). Other preset names: see `presets/` in the [repo](https://github.com/bonesofspring/ai-rules). Name is a single path segment, no `/` or `..`.
29
52
 
package/bin/cli.js CHANGED
@@ -5,51 +5,95 @@
5
5
  const fs = require('fs');
6
6
  const path = require('path');
7
7
 
8
- const packageRoot = path.join(__dirname, '..');
9
-
10
8
  /** Single path segment: letters, digits, dot, underscore, hyphen; no separators or "..". */
11
9
  const PRESET_NAME_RE = /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/;
10
+ const DEFAULT_PRESET = 'next';
11
+ const TOOLS = new Set(['cursor', 'claude']);
12
12
 
13
13
  const PRESETS = {
14
14
  cursor: {
15
15
  rulesDir: '.cursor/rules',
16
16
  commandsDir: '.cursor/commands',
17
17
  relBase: ['presets', 'cursor'],
18
+ optionalCursorDirs: ['agents', 'hooks', 'skills', 'team'],
19
+ hooksJsonSrc: 'hooks.json',
20
+ /** Project MCP → `.cursor/mcp.json` */
21
+ mcpJsonSrc: 'mcp.json',
22
+ mcpJsonDest: '.cursor/mcp.json',
23
+ toolRootFiles: ['BUGBOT.md', 'AGENTS.md', 'MCP.md'],
18
24
  },
19
25
  claude: {
20
26
  rulesDir: '.claude/rules',
21
27
  commandsDir: '.claude/commands',
22
28
  relBase: ['presets', 'claude'],
23
- /** Optional dirs under preset root → under `.claude/` (recursive copy). */
24
- optionalClaudeDirs: ['skills', 'agents', 'hooks'],
25
- /** Copied from preset root to `.claude/CLAUDE.md` when present. */
29
+ optionalClaudeDirs: ['skills', 'agents', 'hooks', 'team'],
26
30
  claudeMdSrc: 'CLAUDE.md',
31
+ /** Project MCP lives at repo root (Claude Code project scope), not under `.claude/`. */
32
+ mcpJsonSrc: 'mcp.json',
33
+ mcpJsonDest: '.mcp.json',
34
+ toolRootFiles: ['MCP.md'],
27
35
  },
28
36
  };
29
37
 
38
+ function getPackageRoot() {
39
+ try {
40
+ return path.dirname(require.resolve('@bonesofspring/ai-rules/package.json'));
41
+ } catch {
42
+ return path.join(__dirname, '..');
43
+ }
44
+ }
45
+
30
46
  function printHelp() {
31
47
  console.log(`@bonesofspring/ai-rules
32
48
 
33
49
  Usage:
34
- ai-rules init <cursor|claude> --preset <name> Copy preset rules and commands into the current directory
35
- ai-rules clean <cursor|claude> Remove preset target rules and commands directories
50
+ ai-rules init <cursor|claude> [--preset <name>]
51
+ ai-rules init <cursor|claude> <preset-name>
52
+ ai-rules clean <cursor|claude> [--cwd <dir>]
53
+
54
+ Options:
55
+ --preset <name> Preset name (default: ${DEFAULT_PRESET})
56
+ --cwd <dir> Target project directory (default: current working directory)
36
57
 
37
58
  Notes:
38
- init merges into existing target folders; same-named files are overwritten.
39
- clean cursor removes the entire .cursor directory (if present).
40
- Flags may appear before or after the subcommand (e.g. --preset next init cursor).
59
+ init merges into the target directory; same-named files are overwritten.
60
+ Cursor init copies rules, commands, agents, hooks, skills, team, hooks.json, BUGBOT.md, AGENTS.md, MCP.md, mcp.json → .cursor/mcp.json.
61
+ Claude init copies rules, commands, skills, agents, hooks, team, CLAUDE.md, MCP.md, and mcp.json .mcp.json (project root).
62
+ Command forms: "init cursor --preset next", "init cursor next", "--preset next init cursor", "cursor init --preset next".
41
63
 
42
64
  Examples:
43
65
  npx @bonesofspring/ai-rules init cursor --preset next
66
+ npx @bonesofspring/ai-rules init cursor next
67
+ npx @bonesofspring/ai-rules init cursor --preset ios-swift
68
+ npx @bonesofspring/ai-rules init claude
44
69
  npx @bonesofspring/ai-rules init claude --preset ios-swift
45
- npx @bonesofspring/ai-rules clean claude
70
+ npx @bonesofspring/ai-rules clean cursor
46
71
  `);
47
72
  }
48
73
 
49
74
  function parseArgs(argv) {
50
- const args = { _: [] };
75
+ const args = { _: [], cwd: undefined, preset: undefined, presetError: undefined };
51
76
  for (let i = 0; i < argv.length; i++) {
52
77
  const a = argv[i];
78
+ if (a === '--cwd') {
79
+ const value = argv[i + 1];
80
+ if (value === undefined || value.startsWith('-')) {
81
+ args.cwdError = 'Missing value for --cwd';
82
+ continue;
83
+ }
84
+ args.cwd = value;
85
+ i++;
86
+ continue;
87
+ }
88
+ if (a.startsWith('--cwd=')) {
89
+ const value = a.slice('--cwd='.length);
90
+ if (value === '') {
91
+ args.cwdError = 'Missing value after --cwd=';
92
+ continue;
93
+ }
94
+ args.cwd = value;
95
+ continue;
96
+ }
53
97
  if (a === '--preset') {
54
98
  const value = argv[i + 1];
55
99
  if (value === undefined || value.startsWith('-')) {
@@ -70,17 +114,53 @@ function parseArgs(argv) {
70
114
  args.preset = value;
71
115
  continue;
72
116
  }
117
+ if (a === '-h' || a === '--help') {
118
+ args.help = true;
119
+ continue;
120
+ }
73
121
  args._.push(a);
74
122
  }
75
123
  return args;
76
124
  }
77
125
 
126
+ /**
127
+ * Supports: init cursor, cursor init, init cursor next (positional preset).
128
+ */
129
+ function normalizeInitClean(parsed) {
130
+ const positional = [...parsed._];
131
+ let command;
132
+ let tool;
133
+ let presetFromPositional;
134
+
135
+ if (positional.length >= 2 && TOOLS.has(positional[0]) && positional[1] === 'init') {
136
+ command = 'init';
137
+ tool = positional[0];
138
+ presetFromPositional = positional[2];
139
+ } else if (positional.length >= 2 && positional[0] === 'init' && TOOLS.has(positional[1])) {
140
+ command = 'init';
141
+ tool = positional[1];
142
+ presetFromPositional = positional[2];
143
+ } else if (positional.length >= 2 && positional[0] === 'clean' && TOOLS.has(positional[1])) {
144
+ command = 'clean';
145
+ tool = positional[1];
146
+ } else if (positional.length >= 1) {
147
+ command = positional[0];
148
+ tool = positional[1];
149
+ if (command === 'init' && positional[2] && PRESET_NAME_RE.test(positional[2])) {
150
+ presetFromPositional = positional[2];
151
+ }
152
+ }
153
+
154
+ const preset = parsed.preset || presetFromPositional;
155
+ return { command, tool, preset };
156
+ }
157
+
78
158
  /**
79
159
  * @returns {string | null} Error message or null if valid.
80
160
  */
81
161
  function validatePresetName(preset) {
82
162
  if (preset === undefined || preset === '') {
83
- return 'Missing --preset <name>';
163
+ return 'Missing preset name (use --preset <name>, e.g. --preset next)';
84
164
  }
85
165
  if (!PRESET_NAME_RE.test(preset) || preset.includes('..')) {
86
166
  return (
@@ -91,9 +171,6 @@ function validatePresetName(preset) {
91
171
  return null;
92
172
  }
93
173
 
94
- /**
95
- * Ensures resolved preset dir stays under the tool presets root (defense in depth).
96
- */
97
174
  function assertPresetDirInsideRoot(presetsRoot, presetBase) {
98
175
  const root = path.resolve(presetsRoot);
99
176
  const resolved = path.resolve(presetBase);
@@ -117,10 +194,17 @@ function copyDir(src, dest) {
117
194
  copyDir(from, to);
118
195
  } else {
119
196
  fs.copyFileSync(from, to);
197
+ if (e.name.endsWith('.sh')) {
198
+ fs.chmodSync(to, 0o755);
199
+ }
120
200
  }
121
201
  }
122
202
  }
123
203
 
204
+ function getOptionalDirs(cfg) {
205
+ return cfg.optionalCursorDirs || cfg.optionalClaudeDirs || [];
206
+ }
207
+
124
208
  function removeDirIfExists(dir) {
125
209
  if (fs.existsSync(dir)) {
126
210
  fs.rmSync(dir, { recursive: true, force: true });
@@ -133,76 +217,171 @@ function removeFileIfExists(filePath) {
133
217
  }
134
218
  }
135
219
 
220
+ function listPresetNames(presetsRoot) {
221
+ if (!fs.existsSync(presetsRoot)) {
222
+ return [];
223
+ }
224
+ return fs
225
+ .readdirSync(presetsRoot, { withFileTypes: true })
226
+ .filter((e) => e.isDirectory())
227
+ .map((e) => e.name)
228
+ .filter((name) => PRESET_NAME_RE.test(name));
229
+ }
230
+
136
231
  function presetHasAnySource(base, cfg) {
137
232
  const rulesSrc = path.join(base, 'rules');
138
233
  const commandsSrc = path.join(base, 'commands');
139
234
  if (fs.existsSync(rulesSrc) || fs.existsSync(commandsSrc)) {
140
235
  return true;
141
236
  }
142
- if (cfg.optionalClaudeDirs) {
143
- for (const name of cfg.optionalClaudeDirs) {
144
- if (fs.existsSync(path.join(base, name))) {
145
- return true;
146
- }
237
+ for (const name of getOptionalDirs(cfg)) {
238
+ if (fs.existsSync(path.join(base, name))) {
239
+ return true;
147
240
  }
148
241
  }
149
242
  if (cfg.claudeMdSrc && fs.existsSync(path.join(base, cfg.claudeMdSrc))) {
150
243
  return true;
151
244
  }
245
+ if (cfg.hooksJsonSrc && fs.existsSync(path.join(base, cfg.hooksJsonSrc))) {
246
+ return true;
247
+ }
248
+ if (cfg.mcpJsonSrc && fs.existsSync(path.join(base, cfg.mcpJsonSrc))) {
249
+ return true;
250
+ }
251
+ for (const name of cfg.toolRootFiles || []) {
252
+ if (fs.existsSync(path.join(base, name))) {
253
+ return true;
254
+ }
255
+ }
152
256
  return false;
153
257
  }
154
258
 
155
- function cmdInit(tool, preset) {
156
- const cfg = PRESETS[tool];
157
- if (!cfg) {
158
- console.error(`Unknown tool: ${tool}. Use cursor or claude.`);
259
+ function resolveTargetCwd(cwdOption) {
260
+ const cwd = cwdOption ? path.resolve(cwdOption) : process.cwd();
261
+ if (!fs.existsSync(cwd)) {
262
+ console.error(`Target directory does not exist: ${cwd}`);
159
263
  process.exit(1);
160
264
  }
161
- const nameErr = validatePresetName(preset);
265
+ if (!fs.statSync(cwd).isDirectory()) {
266
+ console.error(`Target path is not a directory: ${cwd}`);
267
+ process.exit(1);
268
+ }
269
+ return cwd;
270
+ }
271
+
272
+ function resolvePresetName(tool, preset, packageRoot) {
273
+ const cfg = PRESETS[tool];
274
+ const presetsRoot = path.join(packageRoot, ...cfg.relBase);
275
+ let name = preset || DEFAULT_PRESET;
276
+
277
+ const nameErr = validatePresetName(name);
162
278
  if (nameErr) {
163
279
  console.error(nameErr);
164
280
  process.exit(1);
165
281
  }
166
- const presetsRoot = path.join(packageRoot, ...cfg.relBase);
167
- const base = path.join(presetsRoot, preset);
282
+
283
+ let base = path.join(presetsRoot, name);
284
+ if (!presetHasAnySource(base, cfg)) {
285
+ const available = listPresetNames(presetsRoot);
286
+ if (!preset && available.includes(DEFAULT_PRESET)) {
287
+ name = DEFAULT_PRESET;
288
+ base = path.join(presetsRoot, name);
289
+ } else {
290
+ console.error(`Preset "${name}" for ${tool} not found.`);
291
+ console.error(`Looked in: ${base}`);
292
+ console.error(`Package root: ${packageRoot}`);
293
+ if (available.length > 0) {
294
+ console.error(`Available presets: ${available.join(', ')}`);
295
+ } else {
296
+ console.error(`No presets directory at: ${presetsRoot}`);
297
+ console.error(
298
+ 'The installed package may be incomplete. Reinstall @bonesofspring/ai-rules or run from the package source.',
299
+ );
300
+ }
301
+ process.exit(1);
302
+ }
303
+ }
304
+
168
305
  assertPresetDirInsideRoot(presetsRoot, base);
306
+ return { name, base, presetsRoot };
307
+ }
308
+
309
+ function cmdInit(tool, preset, cwdOption) {
310
+ const cfg = PRESETS[tool];
311
+ if (!cfg) {
312
+ console.error(`Unknown tool: ${tool}. Use cursor or claude.`);
313
+ process.exit(1);
314
+ }
315
+
316
+ const packageRoot = getPackageRoot();
317
+ const cwd = resolveTargetCwd(cwdOption);
318
+ const { name: presetName, base } = resolvePresetName(tool, preset, packageRoot);
169
319
 
170
320
  const rulesSrc = path.join(base, 'rules');
171
321
  const commandsSrc = path.join(base, 'commands');
172
- const cwd = process.cwd();
322
+ const toolRoot = tool === 'cursor' ? '.cursor' : '.claude';
323
+ const toolRootAbs = path.join(cwd, toolRoot);
173
324
 
174
- if (!presetHasAnySource(base, cfg)) {
175
- console.error(`Preset "${preset}" for ${tool} not found under ${base}`);
176
- process.exit(1);
177
- }
325
+ fs.mkdirSync(toolRootAbs, { recursive: true });
326
+
327
+ let copiedSteps = 0;
178
328
 
179
329
  try {
180
330
  if (tool === 'claude' && cfg.claudeMdSrc) {
181
331
  const mdFrom = path.join(base, cfg.claudeMdSrc);
182
332
  if (fs.existsSync(mdFrom)) {
183
- const claudeRoot = path.join(cwd, '.claude');
184
- fs.mkdirSync(claudeRoot, { recursive: true });
185
- fs.copyFileSync(mdFrom, path.join(claudeRoot, 'CLAUDE.md'));
186
- console.log('Copied CLAUDE.md → .claude/CLAUDE.md');
333
+ fs.copyFileSync(mdFrom, path.join(toolRootAbs, 'CLAUDE.md'));
334
+ console.log(`Copied CLAUDE.md ${path.join(toolRoot, 'CLAUDE.md')}`);
335
+ copiedSteps++;
187
336
  }
188
337
  }
189
338
 
190
339
  if (fs.existsSync(rulesSrc)) {
191
340
  copyDir(rulesSrc, path.join(cwd, cfg.rulesDir));
192
341
  console.log(`Copied rules → ${cfg.rulesDir}`);
342
+ copiedSteps++;
193
343
  }
194
344
  if (fs.existsSync(commandsSrc)) {
195
345
  copyDir(commandsSrc, path.join(cwd, cfg.commandsDir));
196
346
  console.log(`Copied commands → ${cfg.commandsDir}`);
347
+ copiedSteps++;
348
+ }
349
+
350
+ for (const name of getOptionalDirs(cfg)) {
351
+ const src = path.join(base, name);
352
+ if (fs.existsSync(src)) {
353
+ copyDir(src, path.join(toolRootAbs, name));
354
+ console.log(`Copied ${name}/ → ${toolRoot}/${name}/`);
355
+ copiedSteps++;
356
+ }
197
357
  }
198
358
 
199
- if (tool === 'claude' && cfg.optionalClaudeDirs) {
200
- for (const name of cfg.optionalClaudeDirs) {
201
- const src = path.join(base, name);
202
- if (fs.existsSync(src)) {
203
- copyDir(src, path.join(cwd, '.claude', name));
204
- console.log(`Copied ${name}/ → .claude/${name}/`);
205
- }
359
+ if (tool === 'cursor' && cfg.hooksJsonSrc) {
360
+ const hooksFrom = path.join(base, cfg.hooksJsonSrc);
361
+ if (fs.existsSync(hooksFrom)) {
362
+ fs.copyFileSync(hooksFrom, path.join(toolRootAbs, 'hooks.json'));
363
+ console.log(`Copied hooks.json → ${toolRoot}/hooks.json`);
364
+ copiedSteps++;
365
+ }
366
+ }
367
+
368
+ if (cfg.mcpJsonSrc && cfg.mcpJsonDest) {
369
+ const mcpFrom = path.join(base, cfg.mcpJsonSrc);
370
+ if (fs.existsSync(mcpFrom)) {
371
+ const mcpDestAbs = path.join(cwd, cfg.mcpJsonDest);
372
+ fs.mkdirSync(path.dirname(mcpDestAbs), { recursive: true });
373
+ fs.copyFileSync(mcpFrom, mcpDestAbs);
374
+ console.log(`Copied ${cfg.mcpJsonSrc} → ${cfg.mcpJsonDest}`);
375
+ copiedSteps++;
376
+ }
377
+ }
378
+
379
+ for (const name of cfg.toolRootFiles || []) {
380
+ const from = path.join(base, name);
381
+ if (fs.existsSync(from)) {
382
+ fs.copyFileSync(from, path.join(toolRootAbs, name));
383
+ console.log(`Copied ${name} → ${toolRoot}/${name}`);
384
+ copiedSteps++;
206
385
  }
207
386
  }
208
387
  } catch (err) {
@@ -210,66 +389,100 @@ function cmdInit(tool, preset) {
210
389
  console.error(`init failed: ${msg}`);
211
390
  process.exit(1);
212
391
  }
392
+
393
+ if (copiedSteps === 0) {
394
+ console.error(`init failed: preset "${presetName}" had no files to copy from ${base}`);
395
+ process.exit(1);
396
+ }
397
+
398
+ if (!fs.existsSync(toolRootAbs)) {
399
+ console.error(`init failed: ${toolRootAbs} was not created`);
400
+ process.exit(1);
401
+ }
402
+
403
+ console.log(`Done. ${toolRoot} installed at ${toolRootAbs} (preset: ${presetName})`);
213
404
  }
214
405
 
215
- function cmdClean(tool) {
406
+ function cmdClean(tool, cwdOption) {
216
407
  const cfg = PRESETS[tool];
217
408
  if (!cfg) {
218
409
  console.error(`Unknown tool: ${tool}. Use cursor or claude.`);
219
410
  process.exit(1);
220
411
  }
221
- const cwd = process.cwd();
222
- if (tool === 'cursor') {
223
- removeDirIfExists(path.join(cwd, '.cursor'));
224
- console.log('Removed .cursor (if present)');
225
- return;
226
- }
412
+ const cwd = resolveTargetCwd(cwdOption);
413
+ const toolRoot = tool === 'cursor' ? '.cursor' : '.claude';
414
+ const removedParts = [cfg.rulesDir, cfg.commandsDir];
415
+
227
416
  removeDirIfExists(path.join(cwd, cfg.rulesDir));
228
417
  removeDirIfExists(path.join(cwd, cfg.commandsDir));
229
- if (tool === 'claude' && cfg.optionalClaudeDirs) {
230
- for (const name of cfg.optionalClaudeDirs) {
231
- removeDirIfExists(path.join(cwd, '.claude', name));
232
- }
233
- removeFileIfExists(path.join(cwd, '.claude', 'CLAUDE.md'));
234
- }
235
- console.log(
236
- `Removed ${cfg.rulesDir} and ${cfg.commandsDir}` +
237
- (tool === 'claude' && cfg.optionalClaudeDirs
238
- ? `, optional .claude/{${cfg.optionalClaudeDirs.join(',')}}, and .claude/CLAUDE.md`
239
- : '') +
240
- ' (if present)',
241
- );
418
+
419
+ const optionalDirs = getOptionalDirs(cfg);
420
+ for (const name of optionalDirs) {
421
+ removeDirIfExists(path.join(cwd, toolRoot, name));
422
+ removedParts.push(`${toolRoot}/${name}`);
423
+ }
424
+
425
+ if (cfg.claudeMdSrc) {
426
+ removeFileIfExists(path.join(cwd, toolRoot, 'CLAUDE.md'));
427
+ removedParts.push(`${toolRoot}/CLAUDE.md`);
428
+ }
429
+
430
+ if (cfg.hooksJsonSrc) {
431
+ removeFileIfExists(path.join(cwd, toolRoot, 'hooks.json'));
432
+ removedParts.push(`${toolRoot}/hooks.json`);
433
+ }
434
+
435
+ if (cfg.mcpJsonDest) {
436
+ removeFileIfExists(path.join(cwd, cfg.mcpJsonDest));
437
+ removedParts.push(cfg.mcpJsonDest);
438
+ }
439
+
440
+ for (const name of cfg.toolRootFiles || []) {
441
+ removeFileIfExists(path.join(cwd, toolRoot, name));
442
+ removedParts.push(`${toolRoot}/${name}`);
443
+ }
444
+
445
+ console.log(`Removed ${removedParts.join(', ')} (if present)`);
242
446
  }
243
447
 
244
448
  function main() {
245
449
  const argv = process.argv.slice(2);
246
- if (argv.length === 0 || argv.includes('-h') || argv.includes('--help')) {
450
+ if (argv.length === 0) {
247
451
  printHelp();
248
452
  process.exit(0);
249
453
  }
250
454
 
251
455
  const parsed = parseArgs(argv);
252
- const [command, tool] = parsed._;
456
+ if (parsed.help) {
457
+ printHelp();
458
+ process.exit(0);
459
+ }
253
460
 
254
461
  if (parsed.presetError) {
255
462
  console.error(parsed.presetError);
256
463
  process.exit(1);
257
464
  }
465
+ if (parsed.cwdError) {
466
+ console.error(parsed.cwdError);
467
+ process.exit(1);
468
+ }
469
+
470
+ const { command, tool, preset } = normalizeInitClean(parsed);
258
471
 
259
472
  if (command === 'init') {
260
- if (!tool) {
261
- console.error('Missing <cursor|claude> after init.');
473
+ if (!tool || !TOOLS.has(tool)) {
474
+ console.error('Missing or invalid tool. Use: init cursor|claude [--preset next]');
262
475
  process.exit(1);
263
476
  }
264
- cmdInit(tool, parsed.preset);
477
+ cmdInit(tool, preset, parsed.cwd);
265
478
  return;
266
479
  }
267
480
  if (command === 'clean') {
268
- if (!tool) {
269
- console.error('Missing <cursor|claude> after clean.');
481
+ if (!tool || !TOOLS.has(tool)) {
482
+ console.error('Missing or invalid tool. Use: clean cursor|claude');
270
483
  process.exit(1);
271
484
  }
272
- cmdClean(tool);
485
+ cmdClean(tool, parsed.cwd);
273
486
  return;
274
487
  }
275
488
 
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@bonesofspring/ai-rules",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
4
4
  "description": "Presets of Cursor and Claude rules/commands for Revy Ross personal use",
5
5
  "license": "MIT",
6
6
  "author": "Revy Ross",
7
7
  "repository": {
8
8
  "type": "git",
9
- "url": "https://github.com/bonesofspring/ai-rules.git"
9
+ "url": "git+https://github.com/bonesofspring/ai-rules.git"
10
10
  },
11
11
  "keywords": [
12
12
  "cursor",
@@ -20,6 +20,7 @@
20
20
  },
21
21
  "files": [
22
22
  "README.md",
23
+ "CHANGELOG.md",
23
24
  "bin",
24
25
  "presets"
25
26
  ],