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.
- package/.augment/code_review_guidelines.yaml +2 -42
- package/.claude/skills/bmad-os-findings-triage/SKILL.md +6 -0
- package/.claude/skills/bmad-os-findings-triage/prompts/agent-prompt.md +104 -0
- package/.claude/skills/bmad-os-findings-triage/prompts/instructions.md +286 -0
- package/.claude/skills/bmad-os-review-pr/SKILL.md +1 -1
- package/.claude/skills/bmad-os-review-pr/prompts/instructions.md +63 -6
- package/.claude/skills/bmad-os-review-prompt/SKILL.md +177 -0
- package/.github/workflows/publish.yaml +243 -0
- package/CONTRIBUTING.md +1 -1
- package/README_CN.md +121 -0
- package/docs/_STYLE_GUIDE.md +10 -10
- package/docs/explanation/brainstorming.md +1 -1
- package/docs/explanation/party-mode.md +1 -1
- package/docs/explanation/preventing-agent-conflicts.md +1 -1
- package/docs/explanation/project-context.md +15 -15
- package/docs/explanation/quick-flow.md +9 -9
- package/docs/how-to/established-projects.md +7 -7
- package/docs/how-to/get-answers-about-bmad.md +2 -2
- package/docs/how-to/install-bmad.md +16 -6
- package/docs/how-to/project-context.md +2 -2
- package/docs/how-to/quick-fixes.md +5 -5
- package/docs/how-to/shard-large-documents.md +1 -1
- package/docs/how-to/upgrade-to-v6.md +8 -5
- package/docs/index.md +1 -1
- package/docs/reference/agents.md +14 -14
- package/docs/reference/commands.md +64 -70
- package/docs/reference/testing.md +1 -1
- package/docs/reference/workflow-map.md +19 -19
- package/docs/tutorials/getting-started.md +34 -34
- package/docs/zh-cn/404.md +9 -0
- package/docs/zh-cn/_STYLE_GUIDE.md +370 -0
- package/docs/zh-cn/explanation/advanced-elicitation.md +62 -0
- package/docs/zh-cn/explanation/adversarial-review.md +71 -0
- package/docs/zh-cn/explanation/brainstorming.md +43 -0
- package/docs/zh-cn/explanation/established-projects-faq.md +60 -0
- package/docs/zh-cn/explanation/party-mode.md +79 -0
- package/docs/zh-cn/explanation/preventing-agent-conflicts.md +137 -0
- package/docs/zh-cn/explanation/project-context.md +176 -0
- package/docs/zh-cn/explanation/quick-flow.md +93 -0
- package/docs/zh-cn/explanation/why-solutioning-matters.md +90 -0
- package/docs/zh-cn/how-to/customize-bmad.md +182 -0
- package/docs/zh-cn/how-to/established-projects.md +134 -0
- package/docs/zh-cn/how-to/get-answers-about-bmad.md +144 -0
- package/docs/zh-cn/how-to/install-bmad.md +105 -0
- package/docs/zh-cn/how-to/non-interactive-installation.md +181 -0
- package/docs/zh-cn/how-to/project-context.md +152 -0
- package/docs/zh-cn/how-to/quick-fixes.md +140 -0
- package/docs/zh-cn/how-to/shard-large-documents.md +86 -0
- package/docs/zh-cn/how-to/upgrade-to-v6.md +120 -0
- package/docs/zh-cn/index.md +69 -0
- package/docs/zh-cn/reference/agents.md +41 -0
- package/docs/zh-cn/reference/commands.md +166 -0
- package/docs/zh-cn/reference/modules.md +94 -0
- package/docs/zh-cn/reference/testing.md +122 -0
- package/docs/zh-cn/reference/workflow-map.md +104 -0
- package/docs/zh-cn/roadmap.mdx +152 -0
- package/docs/zh-cn/tutorials/getting-started.md +300 -0
- package/package.json +1 -1
- package/src/bmm/agents/analyst.agent.yaml +1 -1
- package/src/bmm/agents/bmad-skill-manifest.yaml +39 -0
- package/src/bmm/agents/dev.agent.yaml +2 -2
- package/src/bmm/agents/pm.agent.yaml +1 -1
- package/src/bmm/agents/qa.agent.yaml +1 -1
- package/src/bmm/agents/quick-flow-solo-dev.agent.yaml +6 -2
- package/src/bmm/agents/sm.agent.yaml +4 -4
- package/src/bmm/agents/tech-writer/bmad-skill-manifest.yaml +3 -0
- package/src/bmm/agents/tech-writer/tech-writer.agent.yaml +1 -1
- package/src/bmm/module-help.csv +11 -10
- package/src/bmm/workflows/1-analysis/create-product-brief/bmad-skill-manifest.yaml +3 -0
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-02-vision.md +1 -1
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-03-users.md +1 -1
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-04-metrics.md +1 -1
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-05-scope.md +1 -1
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-06-complete.md +1 -1
- package/src/bmm/workflows/1-analysis/research/bmad-skill-manifest.yaml +14 -0
- package/src/bmm/workflows/2-plan-workflows/create-prd/bmad-skill-manifest.yaml +14 -0
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-02-discovery.md +1 -1
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-02b-vision.md +1 -1
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-02c-executive-summary.md +1 -1
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-03-success.md +1 -1
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-04-journeys.md +1 -1
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-05-domain.md +1 -1
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-06-innovation.md +1 -1
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-07-project-type.md +1 -1
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-08-scoping.md +1 -1
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-09-functional.md +1 -1
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-10-nonfunctional.md +1 -1
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-11-polish.md +1 -1
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-12-complete.md +1 -1
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-01-discovery.md +1 -1
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-02-review.md +1 -1
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-01-discovery.md +1 -1
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-10-smart-validation.md +1 -1
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-11-holistic-quality-validation.md +1 -1
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-13-report-complete.md +1 -1
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/bmad-skill-manifest.yaml +3 -0
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-02-discovery.md +1 -1
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-03-core-experience.md +2 -2
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-04-emotional-response.md +2 -2
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-05-inspiration.md +2 -2
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-06-design-system.md +2 -2
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-07-defining-experience.md +2 -2
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-08-visual-foundation.md +2 -2
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-09-design-directions.md +2 -2
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-10-user-journeys.md +2 -2
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-11-component-strategy.md +2 -2
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-12-ux-patterns.md +2 -2
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-13-responsive-accessibility.md +2 -2
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-14-complete.md +1 -1
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/bmad-skill-manifest.yaml +3 -0
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-06-final-assessment.md +1 -1
- package/src/bmm/workflows/3-solutioning/create-architecture/bmad-skill-manifest.yaml +3 -0
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-02-context.md +2 -2
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-03-starter.md +2 -2
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-04-decisions.md +2 -2
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-05-patterns.md +2 -2
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-06-structure.md +2 -2
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-07-validation.md +2 -2
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-08-complete.md +1 -1
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/bmad-skill-manifest.yaml +3 -0
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-01-validate-prerequisites.md +1 -1
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-02-design-epics.md +1 -1
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-03-create-stories.md +1 -1
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-04-final-validation.md +2 -2
- package/src/bmm/workflows/4-implementation/code-review/bmad-skill-manifest.yaml +3 -0
- package/src/bmm/workflows/4-implementation/code-review/discover-inputs.md +88 -0
- package/src/bmm/workflows/4-implementation/code-review/workflow.md +271 -0
- package/src/bmm/workflows/4-implementation/correct-course/bmad-skill-manifest.yaml +3 -0
- package/src/bmm/workflows/4-implementation/correct-course/checklist.md +1 -1
- package/src/bmm/workflows/4-implementation/correct-course/{instructions.md → workflow.md} +79 -12
- package/src/bmm/workflows/4-implementation/create-story/bmad-skill-manifest.yaml +3 -0
- package/src/bmm/workflows/4-implementation/create-story/checklist.md +9 -10
- package/src/bmm/workflows/4-implementation/create-story/discover-inputs.md +88 -0
- package/src/bmm/workflows/4-implementation/create-story/workflow.md +388 -0
- package/src/bmm/workflows/4-implementation/dev-story/bmad-skill-manifest.yaml +3 -0
- package/src/bmm/workflows/4-implementation/dev-story/{instructions.xml → workflow.md} +49 -2
- package/src/bmm/workflows/4-implementation/retrospective/bmad-skill-manifest.yaml +3 -0
- package/src/bmm/workflows/4-implementation/retrospective/{instructions.md → workflow.md} +64 -23
- package/src/bmm/workflows/4-implementation/sprint-planning/bmad-skill-manifest.yaml +3 -0
- package/src/bmm/workflows/4-implementation/sprint-planning/sprint-status-template.yaml +1 -0
- package/src/bmm/workflows/4-implementation/sprint-planning/{instructions.md → workflow.md} +55 -10
- package/src/bmm/workflows/4-implementation/sprint-status/bmad-skill-manifest.yaml +3 -0
- package/src/bmm/workflows/4-implementation/sprint-status/{instructions.md → workflow.md} +45 -8
- package/src/bmm/workflows/bmad-quick-flow/bmad-quick-dev-new-preview/SKILL.md +6 -0
- package/src/bmm/workflows/bmad-quick-flow/bmad-quick-dev-new-preview/bmad-skill-manifest.yaml +1 -0
- package/src/bmm/workflows/bmad-quick-flow/bmad-quick-dev-new-preview/steps/step-01-clarify-and-route.md +54 -0
- package/src/bmm/workflows/bmad-quick-flow/bmad-quick-dev-new-preview/steps/step-02-plan.md +39 -0
- package/src/bmm/workflows/bmad-quick-flow/bmad-quick-dev-new-preview/steps/step-03-implement.md +35 -0
- package/src/bmm/workflows/bmad-quick-flow/bmad-quick-dev-new-preview/steps/step-04-review.md +55 -0
- package/src/bmm/workflows/bmad-quick-flow/bmad-quick-dev-new-preview/steps/step-05-present.md +19 -0
- package/src/bmm/workflows/bmad-quick-flow/bmad-quick-dev-new-preview/tech-spec-template.md +90 -0
- package/src/bmm/workflows/bmad-quick-flow/bmad-quick-dev-new-preview/workflow.md +84 -0
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/bmad-skill-manifest.yaml +3 -0
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-05-adversarial-review.md +8 -14
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/workflow.md +1 -1
- package/src/bmm/workflows/bmad-quick-flow/quick-spec/bmad-skill-manifest.yaml +3 -0
- package/src/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-04-review.md +4 -6
- package/src/bmm/workflows/bmad-quick-flow/quick-spec/workflow.md +1 -1
- package/src/bmm/workflows/document-project/bmad-skill-manifest.yaml +3 -0
- package/src/bmm/workflows/document-project/instructions.md +5 -7
- package/src/bmm/workflows/document-project/workflow.md +39 -0
- package/src/bmm/workflows/document-project/workflows/deep-dive-instructions.md +0 -1
- package/src/bmm/workflows/document-project/workflows/deep-dive-workflow.md +42 -0
- package/src/bmm/workflows/document-project/workflows/full-scan-instructions.md +0 -1
- package/src/bmm/workflows/document-project/workflows/full-scan-workflow.md +42 -0
- package/src/bmm/workflows/generate-project-context/bmad-skill-manifest.yaml +3 -0
- package/src/bmm/workflows/generate-project-context/steps/step-02-generate.md +2 -2
- package/src/bmm/workflows/qa-generate-e2e-tests/bmad-skill-manifest.yaml +3 -0
- package/src/bmm/workflows/qa-generate-e2e-tests/checklist.md +1 -1
- package/src/bmm/workflows/qa-generate-e2e-tests/{instructions.md → workflow.md} +40 -7
- package/src/core/agents/bmad-master.agent.yaml +1 -1
- package/src/core/agents/bmad-skill-manifest.yaml +3 -0
- package/src/core/module-help.csv +3 -3
- package/src/core/module.yaml +1 -1
- package/src/core/tasks/bmad-help/SKILL.md +6 -0
- package/src/core/tasks/bmad-help/bmad-skill-manifest.yaml +1 -0
- package/src/core/tasks/{help.md → bmad-help/workflow.md} +6 -4
- package/src/core/tasks/bmad-review-adversarial-general/SKILL.md +6 -0
- package/src/core/tasks/bmad-review-adversarial-general/bmad-skill-manifest.yaml +1 -0
- package/src/core/tasks/bmad-review-adversarial-general/workflow.md +32 -0
- package/src/core/tasks/bmad-review-edge-case-hunter/SKILL.md +6 -0
- package/src/core/tasks/bmad-review-edge-case-hunter/bmad-skill-manifest.yaml +1 -0
- package/src/core/tasks/bmad-review-edge-case-hunter/workflow.md +62 -0
- package/src/core/tasks/bmad-skill-manifest.yaml +19 -0
- package/src/core/workflows/advanced-elicitation/bmad-skill-manifest.yaml +3 -0
- package/src/core/workflows/advanced-elicitation/workflow.md +138 -0
- package/src/core/workflows/brainstorming/bmad-skill-manifest.yaml +3 -0
- package/src/core/workflows/brainstorming/steps/step-03-technique-execution.md +1 -1
- package/src/core/workflows/brainstorming/workflow.md +1 -1
- package/src/core/workflows/party-mode/bmad-skill-manifest.yaml +3 -0
- package/src/utility/agent-components/activation-steps.txt +2 -2
- package/src/utility/agent-components/handler-multi.txt +1 -2
- package/test/adversarial-review-tests/README.md +3 -3
- package/test/adversarial-review-tests/test-cases.yaml +2 -2
- package/test/fixtures/agent-schema/valid/menu/multiple-menu-items.agent.yaml +1 -1
- package/test/fixtures/agent-schema/valid/menu-commands/all-command-types.agent.yaml +1 -1
- package/test/fixtures/agent-schema/valid/menu-commands/multiple-commands.agent.yaml +1 -2
- package/test/fixtures/file-refs-csv/valid/bmm-style.csv +1 -1
- package/test/test-file-refs-csv.js +1 -1
- package/test/test-install-to-bmad.js +154 -0
- package/test/test-installation-components.js +1586 -2
- package/test/test-workflow-path-regex.js +88 -0
- package/tools/cli/installers/lib/core/installer.js +34 -1
- package/tools/cli/installers/lib/core/manifest-generator.js +328 -35
- package/tools/cli/installers/lib/ide/_base-ide.js +24 -15
- package/tools/cli/installers/lib/ide/_config-driven.js +472 -53
- package/tools/cli/installers/lib/ide/manager.js +23 -61
- package/tools/cli/installers/lib/ide/platform-codes.yaml +108 -30
- package/tools/cli/installers/lib/ide/shared/agent-command-generator.js +1 -0
- package/tools/cli/installers/lib/ide/shared/bmad-artifacts.js +7 -0
- package/tools/cli/installers/lib/ide/shared/path-utils.js +68 -3
- package/tools/cli/installers/lib/ide/shared/skill-manifest.js +90 -0
- package/tools/cli/installers/lib/ide/shared/task-tool-command-generator.js +2 -0
- package/tools/cli/installers/lib/ide/shared/workflow-command-generator.js +6 -145
- package/tools/cli/installers/lib/modules/manager.js +9 -132
- package/tools/cli/lib/agent/compiler.js +1 -10
- package/tools/cli/lib/agent-analyzer.js +2 -14
- package/tools/cli/lib/yaml-xml-builder.js +1 -18
- package/tools/docs/native-skills-migration-checklist.md +281 -0
- package/tools/platform-codes.yaml +1 -1
- package/tools/schema/agent.js +1 -3
- package/tools/validate-file-refs.js +2 -0
- package/website/astro.config.mjs +24 -3
- package/website/src/content/config.ts +2 -1
- package/website/src/content/i18n/zh-CN.json +28 -0
- package/src/bmm/workflows/4-implementation/code-review/instructions.xml +0 -227
- package/src/bmm/workflows/4-implementation/code-review/workflow.yaml +0 -43
- package/src/bmm/workflows/4-implementation/correct-course/workflow.yaml +0 -53
- package/src/bmm/workflows/4-implementation/create-story/instructions.xml +0 -346
- package/src/bmm/workflows/4-implementation/create-story/workflow.yaml +0 -52
- package/src/bmm/workflows/4-implementation/dev-story/workflow.yaml +0 -20
- package/src/bmm/workflows/4-implementation/retrospective/workflow.yaml +0 -52
- package/src/bmm/workflows/4-implementation/sprint-planning/workflow.yaml +0 -47
- package/src/bmm/workflows/4-implementation/sprint-status/workflow.yaml +0 -25
- package/src/bmm/workflows/document-project/workflow.yaml +0 -22
- package/src/bmm/workflows/document-project/workflows/deep-dive.yaml +0 -31
- package/src/bmm/workflows/document-project/workflows/full-scan.yaml +0 -31
- package/src/bmm/workflows/qa-generate-e2e-tests/workflow.yaml +0 -42
- package/src/core/tasks/review-adversarial-general.xml +0 -49
- package/src/core/tasks/review-edge-case-hunter.xml +0 -63
- package/src/core/tasks/workflow.xml +0 -235
- package/src/core/workflows/advanced-elicitation/workflow.xml +0 -118
- package/src/utility/agent-components/handler-validate-workflow.txt +0 -7
- package/src/utility/agent-components/handler-workflow.txt +0 -10
- package/tools/cli/installers/lib/ide/codex.js +0 -440
- package/tools/cli/installers/lib/ide/github-copilot.js +0 -699
- package/tools/cli/installers/lib/ide/kilo.js +0 -269
- package/tools/cli/installers/lib/ide/rovodev.js +0 -257
- package/tools/cli/installers/lib/ide/templates/combined/default-workflow-yaml.md +0 -14
- package/tools/cli/installers/lib/ide/templates/combined/kiro-workflow-yaml.md +0 -15
- package/tools/cli/installers/lib/ide/templates/workflow-command-template.md +0 -13
- 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.
|
|
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,
|
|
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.
|
|
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
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
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
|
-
|
|
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
|
|
216
|
-
: `${this.bmadFolderName}/${moduleName}
|
|
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,
|
|
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 = [
|
|
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
|
|
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
|
|
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
|
-
//
|
|
1069
|
-
|
|
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 };
|