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
@@ -5,6 +5,12 @@ const crypto = require('node:crypto');
5
5
  const csv = require('csv-parse/sync');
6
6
  const { getSourcePath, getModulePath } = require('../../../lib/project-root');
7
7
  const prompts = require('../../../lib/prompts');
8
+ const {
9
+ loadSkillManifest: loadSkillManifestShared,
10
+ getCanonicalId: getCanonicalIdShared,
11
+ getArtifactType: getArtifactTypeShared,
12
+ getInstallToBmad: getInstallToBmadShared,
13
+ } = require('../ide/shared/skill-manifest');
8
14
 
9
15
  // Load package.json for version info
10
16
  const packageJson = require('../../../../../package.json');
@@ -15,6 +21,7 @@ const packageJson = require('../../../../../package.json');
15
21
  class ManifestGenerator {
16
22
  constructor() {
17
23
  this.workflows = [];
24
+ this.skills = [];
18
25
  this.agents = [];
19
26
  this.tasks = [];
20
27
  this.tools = [];
@@ -23,6 +30,26 @@ class ManifestGenerator {
23
30
  this.selectedIdes = [];
24
31
  }
25
32
 
33
+ /** Delegate to shared skill-manifest module */
34
+ async loadSkillManifest(dirPath) {
35
+ return loadSkillManifestShared(dirPath);
36
+ }
37
+
38
+ /** Delegate to shared skill-manifest module */
39
+ getCanonicalId(manifest, filename) {
40
+ return getCanonicalIdShared(manifest, filename);
41
+ }
42
+
43
+ /** Delegate to shared skill-manifest module */
44
+ getArtifactType(manifest, filename) {
45
+ return getArtifactTypeShared(manifest, filename);
46
+ }
47
+
48
+ /** Delegate to shared skill-manifest module */
49
+ getInstallToBmad(manifest, filename) {
50
+ return getInstallToBmadShared(manifest, filename);
51
+ }
52
+
26
53
  /**
27
54
  * Clean text for CSV output by normalizing whitespace.
28
55
  * Note: Quote escaping is handled by escapeCsv() at write time.
@@ -78,6 +105,12 @@ class ManifestGenerator {
78
105
  // Filter out any undefined/null values from IDE list
79
106
  this.selectedIdes = resolvedIdes.filter((ide) => ide && typeof ide === 'string');
80
107
 
108
+ // Reset files list (defensive: prevent stale data if instance is reused)
109
+ this.files = [];
110
+
111
+ // Collect skills first (populates skillClaimedDirs before legacy collectors run)
112
+ await this.collectSkills();
113
+
81
114
  // Collect workflow data
82
115
  await this.collectWorkflows(selectedModules);
83
116
 
@@ -94,6 +127,7 @@ class ManifestGenerator {
94
127
  const manifestFiles = [
95
128
  await this.writeMainManifest(cfgDir),
96
129
  await this.writeWorkflowManifest(cfgDir),
130
+ await this.writeSkillManifest(cfgDir),
97
131
  await this.writeAgentManifest(cfgDir),
98
132
  await this.writeTaskManifest(cfgDir),
99
133
  await this.writeToolManifest(cfgDir),
@@ -101,6 +135,7 @@ class ManifestGenerator {
101
135
  ];
102
136
 
103
137
  return {
138
+ skills: this.skills.length,
104
139
  workflows: this.workflows.length,
105
140
  agents: this.agents.length,
106
141
  tasks: this.tasks.length,
@@ -110,6 +145,169 @@ class ManifestGenerator {
110
145
  };
111
146
  }
112
147
 
148
+ /**
149
+ * Recursively walk a module directory tree, collecting skill directories.
150
+ * A skill directory is one that contains both a bmad-skill-manifest.yaml with
151
+ * type: skill AND a SKILL.md file with name/description frontmatter.
152
+ * Populates this.skills[] and this.skillClaimedDirs (Set of absolute paths).
153
+ */
154
+ async collectSkills() {
155
+ this.skills = [];
156
+ this.skillClaimedDirs = new Set();
157
+ const debug = process.env.BMAD_DEBUG_MANIFEST === 'true';
158
+
159
+ for (const moduleName of this.updatedModules) {
160
+ const modulePath = path.join(this.bmadDir, moduleName);
161
+ if (!(await fs.pathExists(modulePath))) continue;
162
+
163
+ // Recursive walk skipping . and _ prefixed dirs
164
+ const walk = async (dir) => {
165
+ let entries;
166
+ try {
167
+ entries = await fs.readdir(dir, { withFileTypes: true });
168
+ } catch {
169
+ return;
170
+ }
171
+
172
+ // Check this directory for skill manifest
173
+ const manifest = await this.loadSkillManifest(dir);
174
+
175
+ // Determine if this directory is a skill (type: skill in manifest)
176
+ const skillFile = 'SKILL.md';
177
+ const artifactType = this.getArtifactType(manifest, skillFile);
178
+
179
+ if (artifactType === 'skill') {
180
+ const skillMdPath = path.join(dir, 'SKILL.md');
181
+ const dirName = path.basename(dir);
182
+
183
+ // Validate and parse SKILL.md
184
+ const skillMeta = await this.parseSkillMd(skillMdPath, dir, dirName, debug);
185
+
186
+ if (skillMeta) {
187
+ // Build path relative from module root (points to SKILL.md — the permanent entrypoint)
188
+ const relativePath = path.relative(modulePath, dir).split(path.sep).join('/');
189
+ const installPath = relativePath
190
+ ? `${this.bmadFolderName}/${moduleName}/${relativePath}/${skillFile}`
191
+ : `${this.bmadFolderName}/${moduleName}/${skillFile}`;
192
+
193
+ // Skills derive canonicalId from directory name — never from manifest
194
+ if (manifest && manifest.__single && manifest.__single.canonicalId) {
195
+ console.warn(
196
+ `Warning: Skill manifest at ${dir}/bmad-skill-manifest.yaml contains canonicalId — this field is ignored for skills (directory name is the canonical ID)`,
197
+ );
198
+ }
199
+ const canonicalId = dirName;
200
+
201
+ this.skills.push({
202
+ name: skillMeta.name,
203
+ description: this.cleanForCSV(skillMeta.description),
204
+ module: moduleName,
205
+ path: installPath,
206
+ canonicalId,
207
+ install_to_bmad: this.getInstallToBmad(manifest, skillFile),
208
+ });
209
+
210
+ // Add to files list
211
+ this.files.push({
212
+ type: 'skill',
213
+ name: skillMeta.name,
214
+ module: moduleName,
215
+ path: installPath,
216
+ });
217
+
218
+ this.skillClaimedDirs.add(dir);
219
+
220
+ if (debug) {
221
+ console.log(`[DEBUG] collectSkills: claimed skill "${skillMeta.name}" as ${canonicalId} at ${dir}`);
222
+ }
223
+ }
224
+ }
225
+
226
+ // Warn if manifest says type:skill but directory was not claimed
227
+ if (manifest && !this.skillClaimedDirs.has(dir)) {
228
+ let hasSkillType = false;
229
+ if (manifest.__single) {
230
+ hasSkillType = manifest.__single.type === 'skill';
231
+ } else {
232
+ for (const key of Object.keys(manifest)) {
233
+ if (manifest[key]?.type === 'skill') {
234
+ hasSkillType = true;
235
+ break;
236
+ }
237
+ }
238
+ }
239
+ if (hasSkillType && debug) {
240
+ console.log(`[DEBUG] collectSkills: dir has type:skill manifest but failed validation: ${dir}`);
241
+ }
242
+ }
243
+
244
+ // Recurse into subdirectories
245
+ for (const entry of entries) {
246
+ if (!entry.isDirectory()) continue;
247
+ if (entry.name.startsWith('.') || entry.name.startsWith('_')) continue;
248
+ await walk(path.join(dir, entry.name));
249
+ }
250
+ };
251
+
252
+ await walk(modulePath);
253
+ }
254
+
255
+ if (debug) {
256
+ console.log(`[DEBUG] collectSkills: total skills found: ${this.skills.length}, claimed dirs: ${this.skillClaimedDirs.size}`);
257
+ }
258
+ }
259
+
260
+ /**
261
+ * Parse and validate SKILL.md for a skill directory.
262
+ * Returns parsed frontmatter object with name/description, or null if invalid.
263
+ * @param {string} skillMdPath - Absolute path to SKILL.md
264
+ * @param {string} dir - Skill directory path (for error messages)
265
+ * @param {string} dirName - Expected name (must match frontmatter name)
266
+ * @param {boolean} debug - Whether to emit debug-level messages
267
+ * @returns {Promise<Object|null>} Parsed frontmatter or null
268
+ */
269
+ async parseSkillMd(skillMdPath, dir, dirName, debug = false) {
270
+ if (!(await fs.pathExists(skillMdPath))) {
271
+ if (debug) console.log(`[DEBUG] parseSkillMd: "${dir}" is missing SKILL.md — skipping`);
272
+ return null;
273
+ }
274
+
275
+ try {
276
+ const rawContent = await fs.readFile(skillMdPath, 'utf8');
277
+ const content = rawContent.replaceAll('\r\n', '\n').replaceAll('\r', '\n');
278
+
279
+ const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
280
+ if (frontmatterMatch) {
281
+ const skillMeta = yaml.parse(frontmatterMatch[1]);
282
+
283
+ if (
284
+ !skillMeta ||
285
+ typeof skillMeta !== 'object' ||
286
+ typeof skillMeta.name !== 'string' ||
287
+ typeof skillMeta.description !== 'string' ||
288
+ !skillMeta.name ||
289
+ !skillMeta.description
290
+ ) {
291
+ if (debug) console.log(`[DEBUG] parseSkillMd: SKILL.md in "${dir}" is missing name or description (or wrong type) — skipping`);
292
+ return null;
293
+ }
294
+
295
+ if (skillMeta.name !== dirName) {
296
+ console.error(`Error: SKILL.md name "${skillMeta.name}" does not match directory name "${dirName}" — skipping`);
297
+ return null;
298
+ }
299
+
300
+ return skillMeta;
301
+ }
302
+
303
+ if (debug) console.log(`[DEBUG] parseSkillMd: SKILL.md in "${dir}" has no frontmatter — skipping`);
304
+ return null;
305
+ } catch (error) {
306
+ if (debug) console.log(`[DEBUG] parseSkillMd: failed to parse SKILL.md in "${dir}": ${error.message} — skipping`);
307
+ return null;
308
+ }
309
+ }
310
+
113
311
  /**
114
312
  * Collect all workflows from core and selected modules
115
313
  * Scans the INSTALLED bmad directory, not the source
@@ -124,16 +322,20 @@ class ManifestGenerator {
124
322
  if (await fs.pathExists(modulePath)) {
125
323
  const moduleWorkflows = await this.getWorkflowsFromPath(modulePath, moduleName);
126
324
  this.workflows.push(...moduleWorkflows);
325
+
326
+ // Also scan tasks/ for type:skill entries (skills can live anywhere)
327
+ const tasksSkills = await this.getWorkflowsFromPath(modulePath, moduleName, 'tasks');
328
+ this.workflows.push(...tasksSkills);
127
329
  }
128
330
  }
129
331
  }
130
332
 
131
333
  /**
132
- * Recursively find and parse workflow.yaml and workflow.md files
334
+ * Recursively find and parse workflow.md files
133
335
  */
134
- async getWorkflowsFromPath(basePath, moduleName) {
336
+ async getWorkflowsFromPath(basePath, moduleName, subDir = 'workflows') {
135
337
  const workflows = [];
136
- const workflowsPath = path.join(basePath, 'workflows');
338
+ const workflowsPath = path.join(basePath, subDir);
137
339
  const debug = process.env.BMAD_DEBUG_MANIFEST === 'true';
138
340
 
139
341
  if (debug) {
@@ -147,22 +349,25 @@ class ManifestGenerator {
147
349
  return workflows;
148
350
  }
149
351
 
150
- // Recursively find workflow.yaml files
352
+ // Recursively find workflow.md files
151
353
  const findWorkflows = async (dir, relativePath = '') => {
354
+ // Skip directories already claimed as skills
355
+ if (this.skillClaimedDirs && this.skillClaimedDirs.has(dir)) return;
356
+
152
357
  const entries = await fs.readdir(dir, { withFileTypes: true });
358
+ // Load skill manifest for this directory (if present)
359
+ const skillManifest = await this.loadSkillManifest(dir);
153
360
 
154
361
  for (const entry of entries) {
155
362
  const fullPath = path.join(dir, entry.name);
156
363
 
157
364
  if (entry.isDirectory()) {
365
+ // Skip directories claimed by collectSkills
366
+ if (this.skillClaimedDirs && this.skillClaimedDirs.has(fullPath)) continue;
158
367
  // Recurse into subdirectories
159
368
  const newRelativePath = relativePath ? `${relativePath}/${entry.name}` : entry.name;
160
369
  await findWorkflows(fullPath, newRelativePath);
161
- } else if (
162
- entry.name === 'workflow.yaml' ||
163
- entry.name === 'workflow.md' ||
164
- (entry.name.startsWith('workflow-') && entry.name.endsWith('.md'))
165
- ) {
370
+ } else if (entry.name === 'workflow.md' || (entry.name.startsWith('workflow-') && entry.name.endsWith('.md'))) {
166
371
  // Parse workflow file (both YAML and MD formats)
167
372
  if (debug) {
168
373
  console.log(`[DEBUG] Found workflow file: ${fullPath}`);
@@ -172,21 +377,15 @@ class ManifestGenerator {
172
377
  const rawContent = await fs.readFile(fullPath, 'utf8');
173
378
  const content = rawContent.replaceAll('\r\n', '\n').replaceAll('\r', '\n');
174
379
 
175
- let workflow;
176
- if (entry.name === 'workflow.yaml') {
177
- // Parse YAML workflow
178
- workflow = yaml.parse(content);
179
- } else {
180
- // Parse MD workflow with YAML frontmatter
181
- const frontmatterMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
182
- if (!frontmatterMatch) {
183
- if (debug) {
184
- console.log(`[DEBUG] Skipped (no frontmatter): ${fullPath}`);
185
- }
186
- continue; // Skip MD files without frontmatter
380
+ // Parse MD workflow with YAML frontmatter
381
+ const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
382
+ if (!frontmatterMatch) {
383
+ if (debug) {
384
+ console.log(`[DEBUG] Skipped (no frontmatter): ${fullPath}`);
187
385
  }
188
- workflow = yaml.parse(frontmatterMatch[1]);
386
+ continue; // Skip MD files without frontmatter
189
387
  }
388
+ const workflow = yaml.parse(frontmatterMatch[1]);
190
389
 
191
390
  if (debug) {
192
391
  console.log(`[DEBUG] Parsed: name="${workflow.name}", description=${workflow.description ? 'OK' : 'MISSING'}`);
@@ -212,8 +411,8 @@ class ManifestGenerator {
212
411
  // Build relative path for installation
213
412
  const installPath =
214
413
  moduleName === 'core'
215
- ? `${this.bmadFolderName}/core/workflows/${relativePath}/${entry.name}`
216
- : `${this.bmadFolderName}/${moduleName}/workflows/${relativePath}/${entry.name}`;
414
+ ? `${this.bmadFolderName}/core/${subDir}/${relativePath}/${entry.name}`
415
+ : `${this.bmadFolderName}/${moduleName}/${subDir}/${relativePath}/${entry.name}`;
217
416
 
218
417
  // Workflows with standalone: false are filtered out above
219
418
  workflows.push({
@@ -221,6 +420,7 @@ class ManifestGenerator {
221
420
  description: this.cleanForCSV(workflow.description),
222
421
  module: moduleName,
223
422
  path: installPath,
423
+ canonicalId: this.getCanonicalId(skillManifest, entry.name),
224
424
  });
225
425
 
226
426
  // Add to files list
@@ -292,13 +492,19 @@ class ManifestGenerator {
292
492
  * Only includes compiled .md files (not .agent.yaml source files)
293
493
  */
294
494
  async getAgentsFromDir(dirPath, moduleName, relativePath = '') {
495
+ // Skip directories claimed by collectSkills
496
+ if (this.skillClaimedDirs && this.skillClaimedDirs.has(dirPath)) return [];
295
497
  const agents = [];
296
498
  const entries = await fs.readdir(dirPath, { withFileTypes: true });
499
+ // Load skill manifest for this directory (if present)
500
+ const skillManifest = await this.loadSkillManifest(dirPath);
297
501
 
298
502
  for (const entry of entries) {
299
503
  const fullPath = path.join(dirPath, entry.name);
300
504
 
301
505
  if (entry.isDirectory()) {
506
+ // Skip directories claimed by collectSkills
507
+ if (this.skillClaimedDirs && this.skillClaimedDirs.has(fullPath)) continue;
302
508
  // Recurse into subdirectories
303
509
  const newRelativePath = relativePath ? `${relativePath}/${entry.name}` : entry.name;
304
510
  const subDirAgents = await this.getAgentsFromDir(fullPath, moduleName, newRelativePath);
@@ -349,6 +555,7 @@ class ManifestGenerator {
349
555
  principles: principlesMatch ? this.cleanForCSV(principlesMatch[1]) : '',
350
556
  module: moduleName,
351
557
  path: installPath,
558
+ canonicalId: this.getCanonicalId(skillManifest, entry.name),
352
559
  });
353
560
 
354
561
  // Add to files list
@@ -386,8 +593,12 @@ class ManifestGenerator {
386
593
  * Get tasks from a directory
387
594
  */
388
595
  async getTasksFromDir(dirPath, moduleName) {
596
+ // Skip directories claimed by collectSkills
597
+ if (this.skillClaimedDirs && this.skillClaimedDirs.has(dirPath)) return [];
389
598
  const tasks = [];
390
599
  const files = await fs.readdir(dirPath);
600
+ // Load skill manifest for this directory (if present)
601
+ const skillManifest = await this.loadSkillManifest(dirPath);
391
602
 
392
603
  for (const file of files) {
393
604
  // Check for both .xml and .md files
@@ -447,6 +658,7 @@ class ManifestGenerator {
447
658
  module: moduleName,
448
659
  path: installPath,
449
660
  standalone: standalone,
661
+ canonicalId: this.getCanonicalId(skillManifest, file),
450
662
  });
451
663
 
452
664
  // Add to files list
@@ -484,8 +696,12 @@ class ManifestGenerator {
484
696
  * Get tools from a directory
485
697
  */
486
698
  async getToolsFromDir(dirPath, moduleName) {
699
+ // Skip directories claimed by collectSkills
700
+ if (this.skillClaimedDirs && this.skillClaimedDirs.has(dirPath)) return [];
487
701
  const tools = [];
488
702
  const files = await fs.readdir(dirPath);
703
+ // Load skill manifest for this directory (if present)
704
+ const skillManifest = await this.loadSkillManifest(dirPath);
489
705
 
490
706
  for (const file of files) {
491
707
  // Check for both .xml and .md files
@@ -545,6 +761,7 @@ class ManifestGenerator {
545
761
  module: moduleName,
546
762
  path: installPath,
547
763
  standalone: standalone,
764
+ canonicalId: this.getCanonicalId(skillManifest, file),
548
765
  });
549
766
 
550
767
  // Add to files list
@@ -735,8 +952,8 @@ class ManifestGenerator {
735
952
  const csvPath = path.join(cfgDir, 'workflow-manifest.csv');
736
953
  const escapeCsv = (value) => `"${String(value ?? '').replaceAll('"', '""')}"`;
737
954
 
738
- // Create CSV header - standalone column removed, everything is canonicalized to 4 columns
739
- let csv = 'name,description,module,path\n';
955
+ // Create CSV header - standalone column removed, canonicalId added as optional column
956
+ let csv = 'name,description,module,path,canonicalId\n';
740
957
 
741
958
  // Build workflows map from discovered workflows only
742
959
  // Old entries are NOT preserved - the manifest reflects what actually exists on disk
@@ -750,12 +967,19 @@ class ManifestGenerator {
750
967
  description: workflow.description,
751
968
  module: workflow.module,
752
969
  path: workflow.path,
970
+ canonicalId: workflow.canonicalId || '',
753
971
  });
754
972
  }
755
973
 
756
974
  // Write all workflows
757
975
  for (const [, value] of allWorkflows) {
758
- const row = [escapeCsv(value.name), escapeCsv(value.description), escapeCsv(value.module), escapeCsv(value.path)].join(',');
976
+ const row = [
977
+ escapeCsv(value.name),
978
+ escapeCsv(value.description),
979
+ escapeCsv(value.module),
980
+ escapeCsv(value.path),
981
+ escapeCsv(value.canonicalId),
982
+ ].join(',');
759
983
  csv += row + '\n';
760
984
  }
761
985
 
@@ -763,6 +987,32 @@ class ManifestGenerator {
763
987
  return csvPath;
764
988
  }
765
989
 
990
+ /**
991
+ * Write skill manifest CSV
992
+ * @returns {string} Path to the manifest file
993
+ */
994
+ async writeSkillManifest(cfgDir) {
995
+ const csvPath = path.join(cfgDir, 'skill-manifest.csv');
996
+ const escapeCsv = (value) => `"${String(value ?? '').replaceAll('"', '""')}"`;
997
+
998
+ let csvContent = 'canonicalId,name,description,module,path,install_to_bmad\n';
999
+
1000
+ for (const skill of this.skills) {
1001
+ const row = [
1002
+ escapeCsv(skill.canonicalId),
1003
+ escapeCsv(skill.name),
1004
+ escapeCsv(skill.description),
1005
+ escapeCsv(skill.module),
1006
+ escapeCsv(skill.path),
1007
+ escapeCsv(skill.install_to_bmad),
1008
+ ].join(',');
1009
+ csvContent += row + '\n';
1010
+ }
1011
+
1012
+ await fs.writeFile(csvPath, csvContent);
1013
+ return csvPath;
1014
+ }
1015
+
766
1016
  /**
767
1017
  * Write agent manifest CSV
768
1018
  * @returns {string} Path to the manifest file
@@ -784,8 +1034,8 @@ class ManifestGenerator {
784
1034
  }
785
1035
  }
786
1036
 
787
- // Create CSV header with persona fields
788
- let csvContent = 'name,displayName,title,icon,capabilities,role,identity,communicationStyle,principles,module,path\n';
1037
+ // Create CSV header with persona fields and canonicalId
1038
+ let csvContent = 'name,displayName,title,icon,capabilities,role,identity,communicationStyle,principles,module,path,canonicalId\n';
789
1039
 
790
1040
  // Combine existing and new agents, preferring new data for duplicates
791
1041
  const allAgents = new Map();
@@ -810,6 +1060,7 @@ class ManifestGenerator {
810
1060
  principles: agent.principles,
811
1061
  module: agent.module,
812
1062
  path: agent.path,
1063
+ canonicalId: agent.canonicalId || '',
813
1064
  });
814
1065
  }
815
1066
 
@@ -827,6 +1078,7 @@ class ManifestGenerator {
827
1078
  escapeCsv(record.principles),
828
1079
  escapeCsv(record.module),
829
1080
  escapeCsv(record.path),
1081
+ escapeCsv(record.canonicalId),
830
1082
  ].join(',');
831
1083
  csvContent += row + '\n';
832
1084
  }
@@ -856,8 +1108,8 @@ class ManifestGenerator {
856
1108
  }
857
1109
  }
858
1110
 
859
- // Create CSV header with standalone column
860
- let csvContent = 'name,displayName,description,module,path,standalone\n';
1111
+ // Create CSV header with standalone and canonicalId columns
1112
+ let csvContent = 'name,displayName,description,module,path,standalone,canonicalId\n';
861
1113
 
862
1114
  // Combine existing and new tasks
863
1115
  const allTasks = new Map();
@@ -877,6 +1129,7 @@ class ManifestGenerator {
877
1129
  module: task.module,
878
1130
  path: task.path,
879
1131
  standalone: task.standalone,
1132
+ canonicalId: task.canonicalId || '',
880
1133
  });
881
1134
  }
882
1135
 
@@ -889,6 +1142,7 @@ class ManifestGenerator {
889
1142
  escapeCsv(record.module),
890
1143
  escapeCsv(record.path),
891
1144
  escapeCsv(record.standalone),
1145
+ escapeCsv(record.canonicalId),
892
1146
  ].join(',');
893
1147
  csvContent += row + '\n';
894
1148
  }
@@ -918,8 +1172,8 @@ class ManifestGenerator {
918
1172
  }
919
1173
  }
920
1174
 
921
- // Create CSV header with standalone column
922
- let csvContent = 'name,displayName,description,module,path,standalone\n';
1175
+ // Create CSV header with standalone and canonicalId columns
1176
+ let csvContent = 'name,displayName,description,module,path,standalone,canonicalId\n';
923
1177
 
924
1178
  // Combine existing and new tools
925
1179
  const allTools = new Map();
@@ -939,6 +1193,7 @@ class ManifestGenerator {
939
1193
  module: tool.module,
940
1194
  path: tool.path,
941
1195
  standalone: tool.standalone,
1196
+ canonicalId: tool.canonicalId || '',
942
1197
  });
943
1198
  }
944
1199
 
@@ -951,6 +1206,7 @@ class ManifestGenerator {
951
1206
  escapeCsv(record.module),
952
1207
  escapeCsv(record.path),
953
1208
  escapeCsv(record.standalone),
1209
+ escapeCsv(record.canonicalId),
954
1210
  ].join(',');
955
1211
  csvContent += row + '\n';
956
1212
  }
@@ -1065,8 +1321,14 @@ class ManifestGenerator {
1065
1321
  const hasTasks = await fs.pathExists(path.join(modulePath, 'tasks'));
1066
1322
  const hasTools = await fs.pathExists(path.join(modulePath, 'tools'));
1067
1323
 
1068
- // If it has any of these directories, it's likely a module
1069
- if (hasAgents || hasWorkflows || hasTasks || hasTools) {
1324
+ // Check for skill-only modules: recursive scan for bmad-skill-manifest.yaml with type: skill
1325
+ let hasSkills = false;
1326
+ if (!hasAgents && !hasWorkflows && !hasTasks && !hasTools) {
1327
+ hasSkills = await this._hasSkillManifestRecursive(modulePath);
1328
+ }
1329
+
1330
+ // If it has any of these directories or skill manifests, it's likely a module
1331
+ if (hasAgents || hasWorkflows || hasTasks || hasTools || hasSkills) {
1070
1332
  modules.push(entry.name);
1071
1333
  }
1072
1334
  }
@@ -1076,6 +1338,37 @@ class ManifestGenerator {
1076
1338
 
1077
1339
  return modules;
1078
1340
  }
1341
+
1342
+ /**
1343
+ * Recursively check if a directory tree contains a bmad-skill-manifest.yaml with type: skill.
1344
+ * Skips directories starting with . or _.
1345
+ * @param {string} dir - Directory to search
1346
+ * @returns {boolean} True if a skill manifest is found
1347
+ */
1348
+ async _hasSkillManifestRecursive(dir) {
1349
+ let entries;
1350
+ try {
1351
+ entries = await fs.readdir(dir, { withFileTypes: true });
1352
+ } catch {
1353
+ return false;
1354
+ }
1355
+
1356
+ // Check for manifest in this directory
1357
+ const manifest = await this.loadSkillManifest(dir);
1358
+ if (manifest) {
1359
+ const type = this.getArtifactType(manifest, 'workflow.md');
1360
+ if (type === 'skill') return true;
1361
+ }
1362
+
1363
+ // Recurse into subdirectories
1364
+ for (const entry of entries) {
1365
+ if (!entry.isDirectory()) continue;
1366
+ if (entry.name.startsWith('.') || entry.name.startsWith('_')) continue;
1367
+ if (await this._hasSkillManifestRecursive(path.join(dir, entry.name))) return true;
1368
+ }
1369
+
1370
+ return false;
1371
+ }
1079
1372
  }
1080
1373
 
1081
1374
  module.exports = { ManifestGenerator };