bmad-method 6.0.4 → 6.0.5-next.0

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 (252) hide show
  1. package/.augment/code_review_guidelines.yaml +2 -42
  2. package/.claude/skills/bmad-os-findings-triage/SKILL.md +6 -0
  3. package/.claude/skills/bmad-os-findings-triage/prompts/agent-prompt.md +104 -0
  4. package/.claude/skills/bmad-os-findings-triage/prompts/instructions.md +286 -0
  5. package/.claude/skills/bmad-os-review-pr/SKILL.md +1 -1
  6. package/.claude/skills/bmad-os-review-pr/prompts/instructions.md +63 -6
  7. package/.claude/skills/bmad-os-review-prompt/SKILL.md +177 -0
  8. package/.github/workflows/publish.yaml +243 -0
  9. package/CONTRIBUTING.md +1 -1
  10. package/README_CN.md +121 -0
  11. package/docs/_STYLE_GUIDE.md +10 -10
  12. package/docs/explanation/brainstorming.md +1 -1
  13. package/docs/explanation/party-mode.md +1 -1
  14. package/docs/explanation/preventing-agent-conflicts.md +1 -1
  15. package/docs/explanation/project-context.md +15 -15
  16. package/docs/explanation/quick-flow.md +9 -9
  17. package/docs/how-to/established-projects.md +7 -7
  18. package/docs/how-to/get-answers-about-bmad.md +2 -2
  19. package/docs/how-to/install-bmad.md +16 -6
  20. package/docs/how-to/project-context.md +2 -2
  21. package/docs/how-to/quick-fixes.md +5 -5
  22. package/docs/how-to/shard-large-documents.md +1 -1
  23. package/docs/how-to/upgrade-to-v6.md +8 -5
  24. package/docs/index.md +1 -1
  25. package/docs/reference/agents.md +14 -14
  26. package/docs/reference/commands.md +64 -70
  27. package/docs/reference/testing.md +1 -1
  28. package/docs/reference/workflow-map.md +19 -19
  29. package/docs/tutorials/getting-started.md +34 -34
  30. package/docs/zh-cn/404.md +9 -0
  31. package/docs/zh-cn/_STYLE_GUIDE.md +370 -0
  32. package/docs/zh-cn/explanation/advanced-elicitation.md +62 -0
  33. package/docs/zh-cn/explanation/adversarial-review.md +71 -0
  34. package/docs/zh-cn/explanation/brainstorming.md +43 -0
  35. package/docs/zh-cn/explanation/established-projects-faq.md +60 -0
  36. package/docs/zh-cn/explanation/party-mode.md +79 -0
  37. package/docs/zh-cn/explanation/preventing-agent-conflicts.md +137 -0
  38. package/docs/zh-cn/explanation/project-context.md +176 -0
  39. package/docs/zh-cn/explanation/quick-flow.md +93 -0
  40. package/docs/zh-cn/explanation/why-solutioning-matters.md +90 -0
  41. package/docs/zh-cn/how-to/customize-bmad.md +182 -0
  42. package/docs/zh-cn/how-to/established-projects.md +134 -0
  43. package/docs/zh-cn/how-to/get-answers-about-bmad.md +144 -0
  44. package/docs/zh-cn/how-to/install-bmad.md +105 -0
  45. package/docs/zh-cn/how-to/non-interactive-installation.md +181 -0
  46. package/docs/zh-cn/how-to/project-context.md +152 -0
  47. package/docs/zh-cn/how-to/quick-fixes.md +140 -0
  48. package/docs/zh-cn/how-to/shard-large-documents.md +86 -0
  49. package/docs/zh-cn/how-to/upgrade-to-v6.md +120 -0
  50. package/docs/zh-cn/index.md +69 -0
  51. package/docs/zh-cn/reference/agents.md +41 -0
  52. package/docs/zh-cn/reference/commands.md +166 -0
  53. package/docs/zh-cn/reference/modules.md +94 -0
  54. package/docs/zh-cn/reference/testing.md +122 -0
  55. package/docs/zh-cn/reference/workflow-map.md +104 -0
  56. package/docs/zh-cn/roadmap.mdx +152 -0
  57. package/docs/zh-cn/tutorials/getting-started.md +300 -0
  58. package/package.json +1 -1
  59. package/src/bmm/agents/analyst.agent.yaml +1 -1
  60. package/src/bmm/agents/bmad-skill-manifest.yaml +39 -0
  61. package/src/bmm/agents/dev.agent.yaml +2 -2
  62. package/src/bmm/agents/pm.agent.yaml +1 -1
  63. package/src/bmm/agents/qa.agent.yaml +1 -1
  64. package/src/bmm/agents/quick-flow-solo-dev.agent.yaml +6 -2
  65. package/src/bmm/agents/sm.agent.yaml +4 -4
  66. package/src/bmm/agents/tech-writer/bmad-skill-manifest.yaml +3 -0
  67. package/src/bmm/agents/tech-writer/tech-writer.agent.yaml +1 -1
  68. package/src/bmm/module-help.csv +11 -10
  69. package/src/bmm/workflows/1-analysis/create-product-brief/bmad-skill-manifest.yaml +3 -0
  70. package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-02-vision.md +1 -1
  71. package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-03-users.md +1 -1
  72. package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-04-metrics.md +1 -1
  73. package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-05-scope.md +1 -1
  74. package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-06-complete.md +1 -1
  75. package/src/bmm/workflows/1-analysis/research/bmad-skill-manifest.yaml +14 -0
  76. package/src/bmm/workflows/2-plan-workflows/create-prd/bmad-skill-manifest.yaml +14 -0
  77. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-02-discovery.md +1 -1
  78. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-02b-vision.md +1 -1
  79. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-02c-executive-summary.md +1 -1
  80. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-03-success.md +1 -1
  81. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-04-journeys.md +1 -1
  82. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-05-domain.md +1 -1
  83. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-06-innovation.md +1 -1
  84. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-07-project-type.md +1 -1
  85. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-08-scoping.md +1 -1
  86. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-09-functional.md +1 -1
  87. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-10-nonfunctional.md +1 -1
  88. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-11-polish.md +1 -1
  89. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-12-complete.md +1 -1
  90. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-01-discovery.md +1 -1
  91. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-02-review.md +1 -1
  92. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-01-discovery.md +1 -1
  93. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-10-smart-validation.md +1 -1
  94. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-11-holistic-quality-validation.md +1 -1
  95. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-13-report-complete.md +1 -1
  96. package/src/bmm/workflows/2-plan-workflows/create-ux-design/bmad-skill-manifest.yaml +3 -0
  97. package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-02-discovery.md +1 -1
  98. package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-03-core-experience.md +2 -2
  99. package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-04-emotional-response.md +2 -2
  100. package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-05-inspiration.md +2 -2
  101. package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-06-design-system.md +2 -2
  102. package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-07-defining-experience.md +2 -2
  103. package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-08-visual-foundation.md +2 -2
  104. package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-09-design-directions.md +2 -2
  105. package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-10-user-journeys.md +2 -2
  106. package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-11-component-strategy.md +2 -2
  107. package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-12-ux-patterns.md +2 -2
  108. package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-13-responsive-accessibility.md +2 -2
  109. package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-14-complete.md +1 -1
  110. package/src/bmm/workflows/3-solutioning/check-implementation-readiness/bmad-skill-manifest.yaml +3 -0
  111. package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-06-final-assessment.md +1 -1
  112. package/src/bmm/workflows/3-solutioning/create-architecture/bmad-skill-manifest.yaml +3 -0
  113. package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-02-context.md +2 -2
  114. package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-03-starter.md +2 -2
  115. package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-04-decisions.md +2 -2
  116. package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-05-patterns.md +2 -2
  117. package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-06-structure.md +2 -2
  118. package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-07-validation.md +2 -2
  119. package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-08-complete.md +1 -1
  120. package/src/bmm/workflows/3-solutioning/create-epics-and-stories/bmad-skill-manifest.yaml +3 -0
  121. package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-01-validate-prerequisites.md +1 -1
  122. package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-02-design-epics.md +1 -1
  123. package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-03-create-stories.md +1 -1
  124. package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-04-final-validation.md +2 -2
  125. package/src/bmm/workflows/4-implementation/code-review/bmad-skill-manifest.yaml +3 -0
  126. package/src/bmm/workflows/4-implementation/code-review/discover-inputs.md +88 -0
  127. package/src/bmm/workflows/4-implementation/code-review/workflow.md +271 -0
  128. package/src/bmm/workflows/4-implementation/correct-course/bmad-skill-manifest.yaml +3 -0
  129. package/src/bmm/workflows/4-implementation/correct-course/checklist.md +1 -1
  130. package/src/bmm/workflows/4-implementation/correct-course/{instructions.md → workflow.md} +79 -12
  131. package/src/bmm/workflows/4-implementation/create-story/bmad-skill-manifest.yaml +3 -0
  132. package/src/bmm/workflows/4-implementation/create-story/checklist.md +9 -10
  133. package/src/bmm/workflows/4-implementation/create-story/discover-inputs.md +88 -0
  134. package/src/bmm/workflows/4-implementation/create-story/workflow.md +388 -0
  135. package/src/bmm/workflows/4-implementation/dev-story/bmad-skill-manifest.yaml +3 -0
  136. package/src/bmm/workflows/4-implementation/dev-story/{instructions.xml → workflow.md} +49 -2
  137. package/src/bmm/workflows/4-implementation/retrospective/bmad-skill-manifest.yaml +3 -0
  138. package/src/bmm/workflows/4-implementation/retrospective/{instructions.md → workflow.md} +64 -23
  139. package/src/bmm/workflows/4-implementation/sprint-planning/bmad-skill-manifest.yaml +3 -0
  140. package/src/bmm/workflows/4-implementation/sprint-planning/sprint-status-template.yaml +1 -0
  141. package/src/bmm/workflows/4-implementation/sprint-planning/{instructions.md → workflow.md} +55 -10
  142. package/src/bmm/workflows/4-implementation/sprint-status/bmad-skill-manifest.yaml +3 -0
  143. package/src/bmm/workflows/4-implementation/sprint-status/{instructions.md → workflow.md} +45 -8
  144. package/src/bmm/workflows/bmad-quick-flow/bmad-quick-dev-new-preview/SKILL.md +6 -0
  145. package/src/bmm/workflows/bmad-quick-flow/bmad-quick-dev-new-preview/bmad-skill-manifest.yaml +1 -0
  146. package/src/bmm/workflows/bmad-quick-flow/bmad-quick-dev-new-preview/steps/step-01-clarify-and-route.md +54 -0
  147. package/src/bmm/workflows/bmad-quick-flow/bmad-quick-dev-new-preview/steps/step-02-plan.md +39 -0
  148. package/src/bmm/workflows/bmad-quick-flow/bmad-quick-dev-new-preview/steps/step-03-implement.md +35 -0
  149. package/src/bmm/workflows/bmad-quick-flow/bmad-quick-dev-new-preview/steps/step-04-review.md +55 -0
  150. package/src/bmm/workflows/bmad-quick-flow/bmad-quick-dev-new-preview/steps/step-05-present.md +19 -0
  151. package/src/bmm/workflows/bmad-quick-flow/bmad-quick-dev-new-preview/tech-spec-template.md +90 -0
  152. package/src/bmm/workflows/bmad-quick-flow/bmad-quick-dev-new-preview/workflow.md +84 -0
  153. package/src/bmm/workflows/bmad-quick-flow/quick-dev/bmad-skill-manifest.yaml +3 -0
  154. package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-05-adversarial-review.md +8 -14
  155. package/src/bmm/workflows/bmad-quick-flow/quick-dev/workflow.md +1 -1
  156. package/src/bmm/workflows/bmad-quick-flow/quick-spec/bmad-skill-manifest.yaml +3 -0
  157. package/src/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-04-review.md +4 -6
  158. package/src/bmm/workflows/bmad-quick-flow/quick-spec/workflow.md +1 -1
  159. package/src/bmm/workflows/document-project/bmad-skill-manifest.yaml +3 -0
  160. package/src/bmm/workflows/document-project/instructions.md +5 -7
  161. package/src/bmm/workflows/document-project/workflow.md +39 -0
  162. package/src/bmm/workflows/document-project/workflows/deep-dive-instructions.md +0 -1
  163. package/src/bmm/workflows/document-project/workflows/deep-dive-workflow.md +42 -0
  164. package/src/bmm/workflows/document-project/workflows/full-scan-instructions.md +0 -1
  165. package/src/bmm/workflows/document-project/workflows/full-scan-workflow.md +42 -0
  166. package/src/bmm/workflows/generate-project-context/bmad-skill-manifest.yaml +3 -0
  167. package/src/bmm/workflows/generate-project-context/steps/step-02-generate.md +2 -2
  168. package/src/bmm/workflows/qa-generate-e2e-tests/bmad-skill-manifest.yaml +3 -0
  169. package/src/bmm/workflows/qa-generate-e2e-tests/checklist.md +1 -1
  170. package/src/bmm/workflows/qa-generate-e2e-tests/{instructions.md → workflow.md} +40 -7
  171. package/src/core/agents/bmad-master.agent.yaml +1 -1
  172. package/src/core/agents/bmad-skill-manifest.yaml +3 -0
  173. package/src/core/module-help.csv +3 -3
  174. package/src/core/module.yaml +1 -1
  175. package/src/core/tasks/bmad-help/SKILL.md +6 -0
  176. package/src/core/tasks/bmad-help/bmad-skill-manifest.yaml +1 -0
  177. package/src/core/tasks/{help.md → bmad-help/workflow.md} +6 -4
  178. package/src/core/tasks/bmad-review-adversarial-general/SKILL.md +6 -0
  179. package/src/core/tasks/bmad-review-adversarial-general/bmad-skill-manifest.yaml +1 -0
  180. package/src/core/tasks/bmad-review-adversarial-general/workflow.md +32 -0
  181. package/src/core/tasks/bmad-review-edge-case-hunter/SKILL.md +6 -0
  182. package/src/core/tasks/bmad-review-edge-case-hunter/bmad-skill-manifest.yaml +1 -0
  183. package/src/core/tasks/bmad-review-edge-case-hunter/workflow.md +62 -0
  184. package/src/core/tasks/bmad-skill-manifest.yaml +19 -0
  185. package/src/core/workflows/advanced-elicitation/bmad-skill-manifest.yaml +3 -0
  186. package/src/core/workflows/advanced-elicitation/workflow.md +138 -0
  187. package/src/core/workflows/brainstorming/bmad-skill-manifest.yaml +3 -0
  188. package/src/core/workflows/brainstorming/steps/step-03-technique-execution.md +1 -1
  189. package/src/core/workflows/brainstorming/workflow.md +1 -1
  190. package/src/core/workflows/party-mode/bmad-skill-manifest.yaml +3 -0
  191. package/src/utility/agent-components/activation-steps.txt +2 -2
  192. package/src/utility/agent-components/handler-multi.txt +1 -2
  193. package/test/adversarial-review-tests/README.md +3 -3
  194. package/test/adversarial-review-tests/test-cases.yaml +2 -2
  195. package/test/fixtures/agent-schema/valid/menu/multiple-menu-items.agent.yaml +1 -1
  196. package/test/fixtures/agent-schema/valid/menu-commands/all-command-types.agent.yaml +1 -1
  197. package/test/fixtures/agent-schema/valid/menu-commands/multiple-commands.agent.yaml +1 -2
  198. package/test/fixtures/file-refs-csv/valid/bmm-style.csv +1 -1
  199. package/test/test-file-refs-csv.js +1 -1
  200. package/test/test-install-to-bmad.js +154 -0
  201. package/test/test-installation-components.js +1586 -2
  202. package/test/test-workflow-path-regex.js +88 -0
  203. package/tools/cli/installers/lib/core/installer.js +34 -1
  204. package/tools/cli/installers/lib/core/manifest-generator.js +328 -35
  205. package/tools/cli/installers/lib/ide/_base-ide.js +24 -15
  206. package/tools/cli/installers/lib/ide/_config-driven.js +472 -53
  207. package/tools/cli/installers/lib/ide/manager.js +23 -61
  208. package/tools/cli/installers/lib/ide/platform-codes.yaml +108 -30
  209. package/tools/cli/installers/lib/ide/shared/agent-command-generator.js +1 -0
  210. package/tools/cli/installers/lib/ide/shared/bmad-artifacts.js +7 -0
  211. package/tools/cli/installers/lib/ide/shared/path-utils.js +68 -3
  212. package/tools/cli/installers/lib/ide/shared/skill-manifest.js +90 -0
  213. package/tools/cli/installers/lib/ide/shared/task-tool-command-generator.js +2 -0
  214. package/tools/cli/installers/lib/ide/shared/workflow-command-generator.js +6 -145
  215. package/tools/cli/installers/lib/modules/manager.js +9 -132
  216. package/tools/cli/lib/agent/compiler.js +1 -10
  217. package/tools/cli/lib/agent-analyzer.js +2 -14
  218. package/tools/cli/lib/yaml-xml-builder.js +1 -18
  219. package/tools/docs/native-skills-migration-checklist.md +281 -0
  220. package/tools/platform-codes.yaml +1 -1
  221. package/tools/schema/agent.js +1 -3
  222. package/tools/validate-file-refs.js +2 -0
  223. package/website/astro.config.mjs +24 -3
  224. package/website/src/content/config.ts +2 -1
  225. package/website/src/content/i18n/zh-CN.json +28 -0
  226. package/src/bmm/workflows/4-implementation/code-review/instructions.xml +0 -227
  227. package/src/bmm/workflows/4-implementation/code-review/workflow.yaml +0 -43
  228. package/src/bmm/workflows/4-implementation/correct-course/workflow.yaml +0 -53
  229. package/src/bmm/workflows/4-implementation/create-story/instructions.xml +0 -346
  230. package/src/bmm/workflows/4-implementation/create-story/workflow.yaml +0 -52
  231. package/src/bmm/workflows/4-implementation/dev-story/workflow.yaml +0 -20
  232. package/src/bmm/workflows/4-implementation/retrospective/workflow.yaml +0 -52
  233. package/src/bmm/workflows/4-implementation/sprint-planning/workflow.yaml +0 -47
  234. package/src/bmm/workflows/4-implementation/sprint-status/workflow.yaml +0 -25
  235. package/src/bmm/workflows/document-project/workflow.yaml +0 -22
  236. package/src/bmm/workflows/document-project/workflows/deep-dive.yaml +0 -31
  237. package/src/bmm/workflows/document-project/workflows/full-scan.yaml +0 -31
  238. package/src/bmm/workflows/qa-generate-e2e-tests/workflow.yaml +0 -42
  239. package/src/core/tasks/review-adversarial-general.xml +0 -49
  240. package/src/core/tasks/review-edge-case-hunter.xml +0 -63
  241. package/src/core/tasks/workflow.xml +0 -235
  242. package/src/core/workflows/advanced-elicitation/workflow.xml +0 -118
  243. package/src/utility/agent-components/handler-validate-workflow.txt +0 -7
  244. package/src/utility/agent-components/handler-workflow.txt +0 -10
  245. package/tools/cli/installers/lib/ide/codex.js +0 -440
  246. package/tools/cli/installers/lib/ide/github-copilot.js +0 -699
  247. package/tools/cli/installers/lib/ide/kilo.js +0 -269
  248. package/tools/cli/installers/lib/ide/rovodev.js +0 -257
  249. package/tools/cli/installers/lib/ide/templates/combined/default-workflow-yaml.md +0 -14
  250. package/tools/cli/installers/lib/ide/templates/combined/kiro-workflow-yaml.md +0 -15
  251. package/tools/cli/installers/lib/ide/templates/workflow-command-template.md +0 -13
  252. package/tools/cli/installers/lib/ide/templates/workflow-commander.md +0 -5
@@ -1,10 +1,13 @@
1
+ const os = require('node:os');
1
2
  const path = require('node:path');
2
3
  const fs = require('fs-extra');
4
+ const yaml = require('yaml');
3
5
  const { BaseIdeSetup } = require('./_base-ide');
4
6
  const prompts = require('../../../lib/prompts');
5
7
  const { AgentCommandGenerator } = require('./shared/agent-command-generator');
6
8
  const { WorkflowCommandGenerator } = require('./shared/workflow-command-generator');
7
9
  const { TaskToolCommandGenerator } = require('./shared/task-tool-command-generator');
10
+ const csv = require('csv-parse/sync');
8
11
 
9
12
  /**
10
13
  * Config-driven IDE setup handler
@@ -24,6 +27,34 @@ class ConfigDrivenIdeSetup extends BaseIdeSetup {
24
27
  super(platformCode, platformConfig.name, platformConfig.preferred);
25
28
  this.platformConfig = platformConfig;
26
29
  this.installerConfig = platformConfig.installer || null;
30
+
31
+ // Set configDir from target_dir so base-class detect() works
32
+ if (this.installerConfig?.target_dir) {
33
+ this.configDir = this.installerConfig.target_dir;
34
+ }
35
+ }
36
+
37
+ /**
38
+ * Detect whether this IDE already has configuration in the project.
39
+ * For skill_format platforms, checks for bmad-prefixed entries in target_dir
40
+ * (matching old codex.js behavior) instead of just checking directory existence.
41
+ * @param {string} projectDir - Project directory
42
+ * @returns {Promise<boolean>}
43
+ */
44
+ async detect(projectDir) {
45
+ if (this.installerConfig?.skill_format && this.configDir) {
46
+ const dir = path.join(projectDir || process.cwd(), this.configDir);
47
+ if (await fs.pathExists(dir)) {
48
+ try {
49
+ const entries = await fs.readdir(dir);
50
+ return entries.some((e) => typeof e === 'string' && e.startsWith('bmad'));
51
+ } catch {
52
+ return false;
53
+ }
54
+ }
55
+ return false;
56
+ }
57
+ return super.detect(projectDir);
27
58
  }
28
59
 
29
60
  /**
@@ -39,8 +70,8 @@ class ConfigDrivenIdeSetup extends BaseIdeSetup {
39
70
  const conflict = await this.findAncestorConflict(projectDir);
40
71
  if (conflict) {
41
72
  await prompts.log.error(
42
- `Found existing BMAD commands in ancestor installation: ${conflict}\n` +
43
- ` ${this.name} inherits commands from parent directories, so this would cause duplicates.\n` +
73
+ `Found existing BMAD skills in ancestor installation: ${conflict}\n` +
74
+ ` ${this.name} inherits skills from parent directories, so this would cause duplicates.\n` +
44
75
  ` Please remove the BMAD files from that directory first:\n` +
45
76
  ` rm -rf "${conflict}"/bmad*`,
46
77
  );
@@ -86,39 +117,48 @@ class ConfigDrivenIdeSetup extends BaseIdeSetup {
86
117
  async installToTarget(projectDir, bmadDir, config, options) {
87
118
  const { target_dir, template_type, artifact_types } = config;
88
119
 
89
- // Skip targets with explicitly empty artifact_types array
120
+ // Skip targets with explicitly empty artifact_types and no verbatim skills
90
121
  // This prevents creating empty directories when no artifacts will be written
91
- if (Array.isArray(artifact_types) && artifact_types.length === 0) {
92
- return { success: true, results: { agents: 0, workflows: 0, tasks: 0, tools: 0 } };
122
+ const skipStandardArtifacts = Array.isArray(artifact_types) && artifact_types.length === 0;
123
+ if (skipStandardArtifacts && !config.skill_format) {
124
+ return { success: true, results: { agents: 0, workflows: 0, tasks: 0, tools: 0, skills: 0 } };
93
125
  }
94
126
 
95
127
  const targetPath = path.join(projectDir, target_dir);
96
128
  await this.ensureDir(targetPath);
97
129
 
98
130
  const selectedModules = options.selectedModules || [];
99
- const results = { agents: 0, workflows: 0, tasks: 0, tools: 0 };
131
+ const results = { agents: 0, workflows: 0, tasks: 0, tools: 0, skills: 0 };
132
+
133
+ // Install standard artifacts (agents, workflows, tasks, tools)
134
+ if (!skipStandardArtifacts) {
135
+ // Install agents
136
+ if (!artifact_types || artifact_types.includes('agents')) {
137
+ const agentGen = new AgentCommandGenerator(this.bmadFolderName);
138
+ const { artifacts } = await agentGen.collectAgentArtifacts(bmadDir, selectedModules);
139
+ results.agents = await this.writeAgentArtifacts(targetPath, artifacts, template_type, config);
140
+ }
100
141
 
101
- // Install agents
102
- if (!artifact_types || artifact_types.includes('agents')) {
103
- const agentGen = new AgentCommandGenerator(this.bmadFolderName);
104
- const { artifacts } = await agentGen.collectAgentArtifacts(bmadDir, selectedModules);
105
- results.agents = await this.writeAgentArtifacts(targetPath, artifacts, template_type, config);
106
- }
142
+ // Install workflows
143
+ if (!artifact_types || artifact_types.includes('workflows')) {
144
+ const workflowGen = new WorkflowCommandGenerator(this.bmadFolderName);
145
+ const { artifacts } = await workflowGen.collectWorkflowArtifacts(bmadDir);
146
+ results.workflows = await this.writeWorkflowArtifacts(targetPath, artifacts, template_type, config);
147
+ }
107
148
 
108
- // Install workflows
109
- if (!artifact_types || artifact_types.includes('workflows')) {
110
- const workflowGen = new WorkflowCommandGenerator(this.bmadFolderName);
111
- const { artifacts } = await workflowGen.collectWorkflowArtifacts(bmadDir);
112
- results.workflows = await this.writeWorkflowArtifacts(targetPath, artifacts, template_type, config);
149
+ // Install tasks and tools using template system (supports TOML for Gemini, MD for others)
150
+ if (!artifact_types || artifact_types.includes('tasks') || artifact_types.includes('tools')) {
151
+ const taskToolGen = new TaskToolCommandGenerator(this.bmadFolderName);
152
+ const { artifacts } = await taskToolGen.collectTaskToolArtifacts(bmadDir);
153
+ const taskToolResult = await this.writeTaskToolArtifacts(targetPath, artifacts, template_type, config);
154
+ results.tasks = taskToolResult.tasks || 0;
155
+ results.tools = taskToolResult.tools || 0;
156
+ }
113
157
  }
114
158
 
115
- // Install tasks and tools using template system (supports TOML for Gemini, MD for others)
116
- if (!artifact_types || artifact_types.includes('tasks') || artifact_types.includes('tools')) {
117
- const taskToolGen = new TaskToolCommandGenerator(this.bmadFolderName);
118
- const { artifacts } = await taskToolGen.collectTaskToolArtifacts(bmadDir);
119
- const taskToolResult = await this.writeTaskToolArtifacts(targetPath, artifacts, template_type, config);
120
- results.tasks = taskToolResult.tasks || 0;
121
- results.tools = taskToolResult.tools || 0;
159
+ // Install verbatim skills (type: skill)
160
+ if (config.skill_format) {
161
+ results.skills = await this.installVerbatimSkills(projectDir, bmadDir, targetPath, config);
122
162
  }
123
163
 
124
164
  await this.printSummary(results, target_dir, options);
@@ -134,7 +174,7 @@ class ConfigDrivenIdeSetup extends BaseIdeSetup {
134
174
  * @returns {Promise<Object>} Installation result
135
175
  */
136
176
  async installToMultipleTargets(projectDir, bmadDir, targets, options) {
137
- const allResults = { agents: 0, workflows: 0, tasks: 0, tools: 0 };
177
+ const allResults = { agents: 0, workflows: 0, tasks: 0, tools: 0, skills: 0 };
138
178
 
139
179
  for (const target of targets) {
140
180
  const result = await this.installToTarget(projectDir, bmadDir, target, options);
@@ -143,6 +183,7 @@ class ConfigDrivenIdeSetup extends BaseIdeSetup {
143
183
  allResults.workflows += result.results.workflows || 0;
144
184
  allResults.tasks += result.results.tasks || 0;
145
185
  allResults.tools += result.results.tools || 0;
186
+ allResults.skills += result.results.skills || 0;
146
187
  }
147
188
  }
148
189
 
@@ -165,8 +206,13 @@ class ConfigDrivenIdeSetup extends BaseIdeSetup {
165
206
  for (const artifact of artifacts) {
166
207
  const content = this.renderTemplate(template, artifact);
167
208
  const filename = this.generateFilename(artifact, 'agent', extension);
168
- const filePath = path.join(targetPath, filename);
169
- await this.writeFile(filePath, content);
209
+
210
+ if (config.skill_format) {
211
+ await this.writeSkillFile(targetPath, artifact, content);
212
+ } else {
213
+ const filePath = path.join(targetPath, filename);
214
+ await this.writeFile(filePath, content);
215
+ }
170
216
  count++;
171
217
  }
172
218
 
@@ -186,20 +232,17 @@ class ConfigDrivenIdeSetup extends BaseIdeSetup {
186
232
 
187
233
  for (const artifact of artifacts) {
188
234
  if (artifact.type === 'workflow-command') {
189
- // Use different template based on workflow type (YAML vs MD)
190
- // Default to 'default' template type, but allow override via config
191
- const workflowTemplateType = artifact.isYamlWorkflow
192
- ? config.yaml_workflow_template || `${templateType}-workflow-yaml`
193
- : config.md_workflow_template || `${templateType}-workflow`;
194
-
195
- // Fall back to default templates if specific ones don't exist
196
- const finalTemplateType = artifact.isYamlWorkflow ? 'default-workflow-yaml' : 'default-workflow';
197
- // workflowTemplateType already contains full name (e.g., 'gemini-workflow-yaml'), so pass empty artifactType
198
- const { content: template, extension } = await this.loadTemplate(workflowTemplateType, '', config, finalTemplateType);
235
+ const workflowTemplateType = config.md_workflow_template || `${templateType}-workflow`;
236
+ const { content: template, extension } = await this.loadTemplate(workflowTemplateType, '', config, 'default-workflow');
199
237
  const content = this.renderTemplate(template, artifact);
200
238
  const filename = this.generateFilename(artifact, 'workflow', extension);
201
- const filePath = path.join(targetPath, filename);
202
- await this.writeFile(filePath, content);
239
+
240
+ if (config.skill_format) {
241
+ await this.writeSkillFile(targetPath, artifact, content);
242
+ } else {
243
+ const filePath = path.join(targetPath, filename);
244
+ await this.writeFile(filePath, content);
245
+ }
203
246
  count++;
204
247
  }
205
248
  }
@@ -241,8 +284,13 @@ class ConfigDrivenIdeSetup extends BaseIdeSetup {
241
284
 
242
285
  const content = this.renderTemplate(template, artifact);
243
286
  const filename = this.generateFilename(artifact, artifact.type, extension);
244
- const filePath = path.join(targetPath, filename);
245
- await this.writeFile(filePath, content);
287
+
288
+ if (config.skill_format) {
289
+ await this.writeSkillFile(targetPath, artifact, content);
290
+ } else {
291
+ const filePath = path.join(targetPath, filename);
292
+ await this.writeFile(filePath, content);
293
+ }
246
294
 
247
295
  if (artifact.type === 'task') {
248
296
  taskCount++;
@@ -409,20 +457,144 @@ LOAD and execute from: {project-root}/{{bmadFolderName}}/{{path}}
409
457
  // No default
410
458
  }
411
459
 
412
- let rendered = template
460
+ // Replace _bmad placeholder with actual folder name BEFORE inserting paths,
461
+ // so that paths containing '_bmad' are not corrupted by the blanket replacement.
462
+ let rendered = template.replaceAll('_bmad', this.bmadFolderName);
463
+
464
+ // Replace {{bmadFolderName}} placeholder if present
465
+ rendered = rendered.replaceAll('{{bmadFolderName}}', this.bmadFolderName);
466
+
467
+ rendered = rendered
413
468
  .replaceAll('{{name}}', artifact.name || '')
414
469
  .replaceAll('{{module}}', artifact.module || 'core')
415
470
  .replaceAll('{{path}}', pathToUse)
416
471
  .replaceAll('{{description}}', artifact.description || `${artifact.name} ${artifact.type || ''}`)
417
472
  .replaceAll('{{workflow_path}}', pathToUse);
418
473
 
419
- // Replace _bmad placeholder with actual folder name
420
- rendered = rendered.replaceAll('_bmad', this.bmadFolderName);
474
+ return rendered;
475
+ }
421
476
 
422
- // Replace {{bmadFolderName}} placeholder if present
423
- rendered = rendered.replaceAll('{{bmadFolderName}}', this.bmadFolderName);
477
+ /**
478
+ * Write artifact as a skill directory with SKILL.md inside.
479
+ * Writes artifact as a skill directory with SKILL.md inside.
480
+ * @param {string} targetPath - Base skills directory
481
+ * @param {Object} artifact - Artifact data
482
+ * @param {string} content - Rendered template content
483
+ */
484
+ async writeSkillFile(targetPath, artifact, content) {
485
+ const { resolveSkillName } = require('./shared/path-utils');
424
486
 
425
- return rendered;
487
+ // Get the skill name (prefers canonicalId, falls back to path-derived) and remove .md
488
+ const flatName = resolveSkillName(artifact);
489
+ const skillName = path.basename(flatName.replace(/\.md$/, ''));
490
+
491
+ if (!skillName) {
492
+ throw new Error(`Cannot derive skill name for artifact: ${artifact.relativePath || JSON.stringify(artifact)}`);
493
+ }
494
+
495
+ // Create skill directory
496
+ const skillDir = path.join(targetPath, skillName);
497
+ await this.ensureDir(skillDir);
498
+
499
+ // Transform content: rewrite frontmatter for skills format
500
+ const skillContent = this.transformToSkillFormat(content, skillName);
501
+
502
+ await this.writeFile(path.join(skillDir, 'SKILL.md'), skillContent);
503
+ }
504
+
505
+ /**
506
+ * Transform artifact content to Agent Skills format.
507
+ * Rewrites frontmatter to contain only unquoted name and description.
508
+ * @param {string} content - Original content with YAML frontmatter
509
+ * @param {string} skillName - Skill name (must match directory name)
510
+ * @returns {string} Transformed content
511
+ */
512
+ transformToSkillFormat(content, skillName) {
513
+ // Normalize line endings
514
+ content = content.replaceAll('\r\n', '\n').replaceAll('\r', '\n');
515
+
516
+ // Parse frontmatter
517
+ const fmMatch = content.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
518
+ if (!fmMatch) {
519
+ // No frontmatter -- wrap with minimal frontmatter
520
+ const fm = yaml.stringify({ name: skillName, description: skillName }).trimEnd();
521
+ return `---\n${fm}\n---\n\n${content}`;
522
+ }
523
+
524
+ const frontmatter = fmMatch[1];
525
+ const body = fmMatch[2];
526
+
527
+ // Parse frontmatter with yaml library to extract description
528
+ let description;
529
+ try {
530
+ const parsed = yaml.parse(frontmatter);
531
+ const rawDesc = parsed?.description;
532
+ description = typeof rawDesc === 'string' && rawDesc ? rawDesc : `${skillName} skill`;
533
+ } catch {
534
+ description = `${skillName} skill`;
535
+ }
536
+
537
+ // Build new frontmatter with only name and description, unquoted
538
+ const newFrontmatter = yaml.stringify({ name: skillName, description: String(description) }, { lineWidth: 0 }).trimEnd();
539
+ return `---\n${newFrontmatter}\n---\n${body}`;
540
+ }
541
+
542
+ /**
543
+ * Install a custom agent launcher.
544
+ * For skill_format platforms, produces <skillDir>/SKILL.md.
545
+ * For flat platforms, produces a single file in target_dir.
546
+ * @param {string} projectDir - Project directory
547
+ * @param {string} agentName - Agent name (e.g., "fred-commit-poet")
548
+ * @param {string} agentPath - Path to compiled agent (relative to project root)
549
+ * @param {Object} metadata - Agent metadata
550
+ * @returns {Object|null} Info about created file/skill
551
+ */
552
+ async installCustomAgentLauncher(projectDir, agentName, agentPath, metadata) {
553
+ if (!this.installerConfig?.target_dir) return null;
554
+
555
+ const { customAgentDashName } = require('./shared/path-utils');
556
+ const targetPath = path.join(projectDir, this.installerConfig.target_dir);
557
+ await this.ensureDir(targetPath);
558
+
559
+ // Build artifact to reuse existing template rendering.
560
+ // The default-agent template already includes the _bmad/ prefix before {{path}},
561
+ // but agentPath is relative to project root (e.g. "_bmad/custom/agents/fred.md").
562
+ // Strip the bmadFolderName prefix so the template doesn't produce a double path.
563
+ const bmadPrefix = this.bmadFolderName + '/';
564
+ const normalizedPath = agentPath.startsWith(bmadPrefix) ? agentPath.slice(bmadPrefix.length) : agentPath;
565
+
566
+ const artifact = {
567
+ type: 'agent-launcher',
568
+ name: agentName,
569
+ description: metadata?.description || `${agentName} agent`,
570
+ agentPath: normalizedPath,
571
+ relativePath: normalizedPath,
572
+ module: 'custom',
573
+ };
574
+
575
+ const { content: template } = await this.loadTemplate(
576
+ this.installerConfig.template_type || 'default',
577
+ 'agent',
578
+ this.installerConfig,
579
+ 'default-agent',
580
+ );
581
+ const content = this.renderTemplate(template, artifact);
582
+
583
+ if (this.installerConfig.skill_format) {
584
+ const skillName = customAgentDashName(agentName).replace(/\.md$/, '');
585
+ const skillDir = path.join(targetPath, skillName);
586
+ await this.ensureDir(skillDir);
587
+ const skillContent = this.transformToSkillFormat(content, skillName);
588
+ const skillPath = path.join(skillDir, 'SKILL.md');
589
+ await this.writeFile(skillPath, skillContent);
590
+ return { path: path.relative(projectDir, skillPath), command: `$${skillName}` };
591
+ }
592
+
593
+ // Flat file output
594
+ const filename = customAgentDashName(agentName);
595
+ const filePath = path.join(targetPath, filename);
596
+ await this.writeFile(filePath, content);
597
+ return { path: path.relative(projectDir, filePath), command: agentName };
426
598
  }
427
599
 
428
600
  /**
@@ -433,10 +605,11 @@ LOAD and execute from: {project-root}/{{bmadFolderName}}/{{path}}
433
605
  * @returns {string} Generated filename
434
606
  */
435
607
  generateFilename(artifact, artifactType, extension = '.md') {
436
- const { toDashPath } = require('./shared/path-utils');
608
+ const { resolveSkillName } = require('./shared/path-utils');
437
609
 
438
610
  // Reuse central logic to ensure consistent naming conventions
439
- const standardName = toDashPath(artifact.relativePath);
611
+ // Prefers canonicalId from manifest when available, falls back to path-derived name
612
+ const standardName = resolveSkillName(artifact);
440
613
 
441
614
  // Clean up potential double extensions from source files (e.g. .yaml.md, .xml.md -> .md)
442
615
  // This handles any extensions that might slip through toDashPath()
@@ -452,6 +625,80 @@ LOAD and execute from: {project-root}/{{bmadFolderName}}/{{path}}
452
625
  return baseName.replace(/\.md$/, extension);
453
626
  }
454
627
 
628
+ /**
629
+ * Install verbatim skill directories (type: skill entries from skill-manifest.csv).
630
+ * Copies the entire source directory as-is into the IDE skill directory.
631
+ * The source SKILL.md is used directly — no frontmatter transformation or file generation.
632
+ * @param {string} projectDir - Project directory
633
+ * @param {string} bmadDir - BMAD installation directory
634
+ * @param {string} targetPath - Target skills directory
635
+ * @param {Object} config - Installation configuration
636
+ * @returns {Promise<number>} Count of skills installed
637
+ */
638
+ async installVerbatimSkills(projectDir, bmadDir, targetPath, config) {
639
+ const bmadFolderName = path.basename(bmadDir);
640
+ const bmadPrefix = bmadFolderName + '/';
641
+ const csvPath = path.join(bmadDir, '_config', 'skill-manifest.csv');
642
+
643
+ if (!(await fs.pathExists(csvPath))) return 0;
644
+
645
+ const csvContent = await fs.readFile(csvPath, 'utf8');
646
+ const records = csv.parse(csvContent, {
647
+ columns: true,
648
+ skip_empty_lines: true,
649
+ });
650
+
651
+ let count = 0;
652
+
653
+ for (const record of records) {
654
+ const canonicalId = record.canonicalId;
655
+ if (!canonicalId) continue;
656
+
657
+ // Derive source directory from path column
658
+ // path is like "_bmad/bmm/workflows/bmad-quick-flow/bmad-quick-dev-new-preview/SKILL.md"
659
+ // Strip bmadFolderName prefix and join with bmadDir, then get dirname
660
+ const relativePath = record.path.startsWith(bmadPrefix) ? record.path.slice(bmadPrefix.length) : record.path;
661
+ const sourceFile = path.join(bmadDir, relativePath);
662
+ const sourceDir = path.dirname(sourceFile);
663
+
664
+ if (!(await fs.pathExists(sourceDir))) continue;
665
+
666
+ // Clean target before copy to prevent stale files
667
+ const skillDir = path.join(targetPath, canonicalId);
668
+ await fs.remove(skillDir);
669
+ await fs.ensureDir(skillDir);
670
+
671
+ // Copy all skill files, filtering OS/editor artifacts recursively
672
+ const skipPatterns = new Set(['.DS_Store', 'Thumbs.db', 'desktop.ini']);
673
+ const skipSuffixes = ['~', '.swp', '.swo', '.bak'];
674
+ const filter = (src) => {
675
+ const name = path.basename(src);
676
+ if (src === sourceDir) return true;
677
+ if (skipPatterns.has(name)) return false;
678
+ if (name.startsWith('.') && name !== '.gitkeep') return false;
679
+ if (skipSuffixes.some((s) => name.endsWith(s))) return false;
680
+ return true;
681
+ };
682
+ await fs.copy(sourceDir, skillDir, { filter });
683
+
684
+ count++;
685
+ }
686
+
687
+ // Post-install cleanup: remove _bmad/ directories for skills with install_to_bmad === "false"
688
+ for (const record of records) {
689
+ if (record.install_to_bmad === 'false') {
690
+ const relativePath = record.path.startsWith(bmadPrefix) ? record.path.slice(bmadPrefix.length) : record.path;
691
+ const sourceFile = path.join(bmadDir, relativePath);
692
+ const sourceDir = path.dirname(sourceFile);
693
+ if (await fs.pathExists(sourceDir)) {
694
+ await fs.remove(sourceDir);
695
+ }
696
+ }
697
+ }
698
+
699
+ return count;
700
+ }
701
+
455
702
  /**
456
703
  * Print installation summary
457
704
  * @param {Object} results - Installation results
@@ -464,6 +711,7 @@ LOAD and execute from: {project-root}/{{bmadFolderName}}/{{path}}
464
711
  if (results.workflows > 0) parts.push(`${results.workflows} workflows`);
465
712
  if (results.tasks > 0) parts.push(`${results.tasks} tasks`);
466
713
  if (results.tools > 0) parts.push(`${results.tools} tools`);
714
+ if (results.skills > 0) parts.push(`${results.skills} skills`);
467
715
  await prompts.log.success(`${this.name} configured: ${parts.join(', ')} → ${targetDir}`);
468
716
  }
469
717
 
@@ -476,11 +724,30 @@ LOAD and execute from: {project-root}/{{bmadFolderName}}/{{path}}
476
724
  if (this.installerConfig?.legacy_targets) {
477
725
  if (!options.silent) await prompts.log.message(' Migrating legacy directories...');
478
726
  for (const legacyDir of this.installerConfig.legacy_targets) {
479
- await this.cleanupTarget(projectDir, legacyDir, options);
480
- await this.removeEmptyParents(projectDir, legacyDir);
727
+ if (this.isGlobalPath(legacyDir)) {
728
+ await this.warnGlobalLegacy(legacyDir, options);
729
+ } else {
730
+ await this.cleanupTarget(projectDir, legacyDir, options);
731
+ await this.removeEmptyParents(projectDir, legacyDir);
732
+ }
481
733
  }
482
734
  }
483
735
 
736
+ // Strip BMAD markers from copilot-instructions.md if present
737
+ if (this.name === 'github-copilot') {
738
+ await this.cleanupCopilotInstructions(projectDir, options);
739
+ }
740
+
741
+ // Strip BMAD modes from .kilocodemodes if present
742
+ if (this.name === 'kilo') {
743
+ await this.cleanupKiloModes(projectDir, options);
744
+ }
745
+
746
+ // Strip BMAD entries from .rovodev/prompts.yml if present
747
+ if (this.name === 'rovo-dev') {
748
+ await this.cleanupRovoDevPrompts(projectDir, options);
749
+ }
750
+
484
751
  // Clean all target directories
485
752
  if (this.installerConfig?.targets) {
486
753
  const parentDirs = new Set();
@@ -501,6 +768,41 @@ LOAD and execute from: {project-root}/{{bmadFolderName}}/{{path}}
501
768
  }
502
769
  }
503
770
 
771
+ /**
772
+ * Check if a path is global (starts with ~ or is absolute)
773
+ * @param {string} p - Path to check
774
+ * @returns {boolean}
775
+ */
776
+ isGlobalPath(p) {
777
+ return p.startsWith('~') || path.isAbsolute(p);
778
+ }
779
+
780
+ /**
781
+ * Warn about stale BMAD files in a global legacy directory (never auto-deletes)
782
+ * @param {string} legacyDir - Legacy directory path (may start with ~)
783
+ * @param {Object} options - Options (silent, etc.)
784
+ */
785
+ async warnGlobalLegacy(legacyDir, options = {}) {
786
+ try {
787
+ const expanded = legacyDir.startsWith('~/')
788
+ ? path.join(os.homedir(), legacyDir.slice(2))
789
+ : legacyDir === '~'
790
+ ? os.homedir()
791
+ : legacyDir;
792
+
793
+ if (!(await fs.pathExists(expanded))) return;
794
+
795
+ const entries = await fs.readdir(expanded);
796
+ const bmadFiles = entries.filter((e) => typeof e === 'string' && e.startsWith('bmad'));
797
+
798
+ if (bmadFiles.length > 0 && !options.silent) {
799
+ await prompts.log.warn(`Found ${bmadFiles.length} stale BMAD file(s) in ${expanded}. Remove manually: rm ${expanded}/bmad-*`);
800
+ }
801
+ } catch {
802
+ // Errors reading global paths are silently ignored
803
+ }
804
+ }
805
+
504
806
  /**
505
807
  * Cleanup a specific target directory
506
808
  * @param {string} projectDir - Project directory
@@ -532,7 +834,7 @@ LOAD and execute from: {project-root}/{{bmadFolderName}}/{{path}}
532
834
  if (!entry || typeof entry !== 'string') {
533
835
  continue;
534
836
  }
535
- if (entry.startsWith('bmad')) {
837
+ if (entry.startsWith('bmad') && !entry.startsWith('bmad-os-')) {
536
838
  const entryPath = path.join(targetPath, entry);
537
839
  try {
538
840
  await fs.remove(entryPath);
@@ -559,6 +861,121 @@ LOAD and execute from: {project-root}/{{bmadFolderName}}/{{path}}
559
861
  }
560
862
  }
561
863
  }
864
+ /**
865
+ * Strip BMAD-owned content from .github/copilot-instructions.md.
866
+ * The old custom installer injected content between <!-- BMAD:START --> and <!-- BMAD:END --> markers.
867
+ * Deletes the file if nothing remains. Restores .bak backup if one exists.
868
+ */
869
+ async cleanupCopilotInstructions(projectDir, options = {}) {
870
+ const filePath = path.join(projectDir, '.github', 'copilot-instructions.md');
871
+
872
+ if (!(await fs.pathExists(filePath))) return;
873
+
874
+ try {
875
+ const content = await fs.readFile(filePath, 'utf8');
876
+ const startIdx = content.indexOf('<!-- BMAD:START -->');
877
+ const endIdx = content.indexOf('<!-- BMAD:END -->');
878
+
879
+ if (startIdx === -1 || endIdx === -1 || endIdx <= startIdx) return;
880
+
881
+ const cleaned = content.slice(0, startIdx) + content.slice(endIdx + '<!-- BMAD:END -->'.length);
882
+
883
+ if (cleaned.trim().length === 0) {
884
+ await fs.remove(filePath);
885
+ const backupPath = `${filePath}.bak`;
886
+ if (await fs.pathExists(backupPath)) {
887
+ await fs.rename(backupPath, filePath);
888
+ if (!options.silent) await prompts.log.message(' Restored copilot-instructions.md from backup');
889
+ }
890
+ } else {
891
+ await fs.writeFile(filePath, cleaned, 'utf8');
892
+ const backupPath = `${filePath}.bak`;
893
+ if (await fs.pathExists(backupPath)) await fs.remove(backupPath);
894
+ }
895
+
896
+ if (!options.silent) await prompts.log.message(' Cleaned BMAD markers from copilot-instructions.md');
897
+ } catch {
898
+ if (!options.silent) await prompts.log.warn(' Warning: Could not clean BMAD markers from copilot-instructions.md');
899
+ }
900
+ }
901
+
902
+ /**
903
+ * Strip BMAD-owned modes from .kilocodemodes.
904
+ * The old custom kilo.js installer added modes with slug starting with 'bmad-'.
905
+ * Parses YAML, filters out BMAD modes, rewrites. Leaves file as-is on parse failure.
906
+ */
907
+ async cleanupKiloModes(projectDir, options = {}) {
908
+ const kiloModesPath = path.join(projectDir, '.kilocodemodes');
909
+
910
+ if (!(await fs.pathExists(kiloModesPath))) return;
911
+
912
+ const content = await fs.readFile(kiloModesPath, 'utf8');
913
+
914
+ let config;
915
+ try {
916
+ config = yaml.parse(content) || {};
917
+ } catch {
918
+ if (!options.silent) await prompts.log.warn(' Warning: Could not parse .kilocodemodes for cleanup');
919
+ return;
920
+ }
921
+
922
+ if (!Array.isArray(config.customModes)) return;
923
+
924
+ const originalCount = config.customModes.length;
925
+ config.customModes = config.customModes.filter((mode) => mode && (!mode.slug || !mode.slug.startsWith('bmad-')));
926
+ const removedCount = originalCount - config.customModes.length;
927
+
928
+ if (removedCount > 0) {
929
+ try {
930
+ await fs.writeFile(kiloModesPath, yaml.stringify(config, { lineWidth: 0 }));
931
+ if (!options.silent) await prompts.log.message(` Removed ${removedCount} BMAD modes from .kilocodemodes`);
932
+ } catch {
933
+ if (!options.silent) await prompts.log.warn(' Warning: Could not write .kilocodemodes during cleanup');
934
+ }
935
+ }
936
+ }
937
+
938
+ /**
939
+ * Strip BMAD-owned entries from .rovodev/prompts.yml.
940
+ * The old custom rovodev.js installer registered workflows in prompts.yml.
941
+ * Parses YAML, filters out entries with name starting with 'bmad-', rewrites.
942
+ * Removes the file if no entries remain.
943
+ */
944
+ async cleanupRovoDevPrompts(projectDir, options = {}) {
945
+ const promptsPath = path.join(projectDir, '.rovodev', 'prompts.yml');
946
+
947
+ if (!(await fs.pathExists(promptsPath))) return;
948
+
949
+ const content = await fs.readFile(promptsPath, 'utf8');
950
+
951
+ let config;
952
+ try {
953
+ config = yaml.parse(content) || {};
954
+ } catch {
955
+ if (!options.silent) await prompts.log.warn(' Warning: Could not parse prompts.yml for cleanup');
956
+ return;
957
+ }
958
+
959
+ if (!Array.isArray(config.prompts)) return;
960
+
961
+ const originalCount = config.prompts.length;
962
+ config.prompts = config.prompts.filter((entry) => entry && (!entry.name || !entry.name.startsWith('bmad-')));
963
+ const removedCount = originalCount - config.prompts.length;
964
+
965
+ if (removedCount > 0) {
966
+ try {
967
+ if (config.prompts.length === 0) {
968
+ await fs.remove(promptsPath);
969
+ } else {
970
+ await fs.writeFile(promptsPath, yaml.stringify(config, { lineWidth: 0 }));
971
+ }
972
+ if (!options.silent) await prompts.log.message(` Removed ${removedCount} BMAD entries from prompts.yml`);
973
+ } catch {
974
+ if (!options.silent) await prompts.log.warn(' Warning: Could not write prompts.yml during cleanup');
975
+ }
976
+ }
977
+ }
978
+
562
979
  /**
563
980
  * Check ancestor directories for existing BMAD files in the same target_dir.
564
981
  * IDEs like Claude Code inherit commands from parent directories, so an existing
@@ -579,7 +996,9 @@ LOAD and execute from: {project-root}/{{bmadFolderName}}/{{path}}
579
996
  try {
580
997
  if (await fs.pathExists(candidatePath)) {
581
998
  const entries = await fs.readdir(candidatePath);
582
- const hasBmad = entries.some((e) => typeof e === 'string' && e.toLowerCase().startsWith('bmad'));
999
+ const hasBmad = entries.some(
1000
+ (e) => typeof e === 'string' && e.toLowerCase().startsWith('bmad') && !e.toLowerCase().startsWith('bmad-os-'),
1001
+ );
583
1002
  if (hasBmad) {
584
1003
  return candidatePath;
585
1004
  }