bmad-method 6.0.3 → 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/.claude/skills/bmad-os-root-cause-analysis/SKILL.md +12 -0
- package/.claude/skills/bmad-os-root-cause-analysis/prompts/instructions.md +74 -0
- package/.github/ISSUE_TEMPLATE/config.yaml +1 -1
- package/.github/ISSUE_TEMPLATE/documentation.yaml +1 -1
- package/.github/workflows/publish.yaml +243 -0
- package/CHANGELOG.md +32 -0
- package/CONTRIBUTING.md +1 -1
- package/README.md +8 -8
- 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 +2 -2
- 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 -2
- 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-01-session-setup.md +31 -18
- package/src/core/workflows/brainstorming/steps/step-01b-continue.md +1 -1
- package/src/core/workflows/brainstorming/steps/step-03-technique-execution.md +3 -3
- package/src/core/workflows/brainstorming/steps/step-04-idea-organization.md +2 -2
- package/src/core/workflows/brainstorming/workflow.md +5 -3
- package/src/core/workflows/party-mode/bmad-skill-manifest.yaml +3 -0
- package/src/core/workflows/party-mode/workflow.md +1 -1
- 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/install-messages.yaml +1 -1
- package/tools/cli/installers/lib/core/installer.js +34 -1
- package/tools/cli/installers/lib/core/manifest-generator.js +332 -41
- package/tools/cli/installers/lib/ide/_base-ide.js +24 -15
- package/tools/cli/installers/lib/ide/_config-driven.js +547 -53
- package/tools/cli/installers/lib/ide/manager.js +26 -62
- package/tools/cli/installers/lib/ide/platform-codes.yaml +116 -29
- 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/ide/templates/agent-command-template.md +1 -1
- package/tools/cli/installers/lib/ide/templates/combined/default-workflow.md +1 -1
- package/tools/cli/installers/lib/ide/templates/combined/gemini-workflow-yaml.toml +1 -1
- package/tools/cli/installers/lib/ide/templates/combined/gemini-workflow.toml +1 -1
- package/tools/cli/installers/lib/ide/templates/combined/opencode-agent.md +1 -1
- package/tools/cli/installers/lib/ide/templates/combined/opencode-task.md +0 -1
- package/tools/cli/installers/lib/ide/templates/combined/opencode-tool.md +0 -1
- package/tools/cli/installers/lib/ide/templates/combined/opencode-workflow-yaml.md +0 -1
- package/tools/cli/installers/lib/ide/templates/combined/opencode-workflow.md +0 -1
- 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/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,17 +30,35 @@ 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
|
-
* Clean text for CSV output by normalizing whitespace
|
|
54
|
+
* Clean text for CSV output by normalizing whitespace.
|
|
55
|
+
* Note: Quote escaping is handled by escapeCsv() at write time.
|
|
28
56
|
* @param {string} text - Text to clean
|
|
29
|
-
* @returns {string} Cleaned text
|
|
57
|
+
* @returns {string} Cleaned text
|
|
30
58
|
*/
|
|
31
59
|
cleanForCSV(text) {
|
|
32
60
|
if (!text) return '';
|
|
33
|
-
return text
|
|
34
|
-
.trim()
|
|
35
|
-
.replaceAll(/\s+/g, ' ') // Normalize all whitespace (including newlines) to single space
|
|
36
|
-
.replaceAll('"', '""'); // Escape quotes for CSV
|
|
61
|
+
return text.trim().replaceAll(/\s+/g, ' '); // Normalize all whitespace (including newlines) to single space
|
|
37
62
|
}
|
|
38
63
|
|
|
39
64
|
/**
|
|
@@ -80,6 +105,12 @@ class ManifestGenerator {
|
|
|
80
105
|
// Filter out any undefined/null values from IDE list
|
|
81
106
|
this.selectedIdes = resolvedIdes.filter((ide) => ide && typeof ide === 'string');
|
|
82
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
|
+
|
|
83
114
|
// Collect workflow data
|
|
84
115
|
await this.collectWorkflows(selectedModules);
|
|
85
116
|
|
|
@@ -96,6 +127,7 @@ class ManifestGenerator {
|
|
|
96
127
|
const manifestFiles = [
|
|
97
128
|
await this.writeMainManifest(cfgDir),
|
|
98
129
|
await this.writeWorkflowManifest(cfgDir),
|
|
130
|
+
await this.writeSkillManifest(cfgDir),
|
|
99
131
|
await this.writeAgentManifest(cfgDir),
|
|
100
132
|
await this.writeTaskManifest(cfgDir),
|
|
101
133
|
await this.writeToolManifest(cfgDir),
|
|
@@ -103,6 +135,7 @@ class ManifestGenerator {
|
|
|
103
135
|
];
|
|
104
136
|
|
|
105
137
|
return {
|
|
138
|
+
skills: this.skills.length,
|
|
106
139
|
workflows: this.workflows.length,
|
|
107
140
|
agents: this.agents.length,
|
|
108
141
|
tasks: this.tasks.length,
|
|
@@ -112,6 +145,169 @@ class ManifestGenerator {
|
|
|
112
145
|
};
|
|
113
146
|
}
|
|
114
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
|
+
|
|
115
311
|
/**
|
|
116
312
|
* Collect all workflows from core and selected modules
|
|
117
313
|
* Scans the INSTALLED bmad directory, not the source
|
|
@@ -126,16 +322,20 @@ class ManifestGenerator {
|
|
|
126
322
|
if (await fs.pathExists(modulePath)) {
|
|
127
323
|
const moduleWorkflows = await this.getWorkflowsFromPath(modulePath, moduleName);
|
|
128
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);
|
|
129
329
|
}
|
|
130
330
|
}
|
|
131
331
|
}
|
|
132
332
|
|
|
133
333
|
/**
|
|
134
|
-
* Recursively find and parse workflow.
|
|
334
|
+
* Recursively find and parse workflow.md files
|
|
135
335
|
*/
|
|
136
|
-
async getWorkflowsFromPath(basePath, moduleName) {
|
|
336
|
+
async getWorkflowsFromPath(basePath, moduleName, subDir = 'workflows') {
|
|
137
337
|
const workflows = [];
|
|
138
|
-
const workflowsPath = path.join(basePath,
|
|
338
|
+
const workflowsPath = path.join(basePath, subDir);
|
|
139
339
|
const debug = process.env.BMAD_DEBUG_MANIFEST === 'true';
|
|
140
340
|
|
|
141
341
|
if (debug) {
|
|
@@ -149,22 +349,25 @@ class ManifestGenerator {
|
|
|
149
349
|
return workflows;
|
|
150
350
|
}
|
|
151
351
|
|
|
152
|
-
// Recursively find workflow.
|
|
352
|
+
// Recursively find workflow.md files
|
|
153
353
|
const findWorkflows = async (dir, relativePath = '') => {
|
|
354
|
+
// Skip directories already claimed as skills
|
|
355
|
+
if (this.skillClaimedDirs && this.skillClaimedDirs.has(dir)) return;
|
|
356
|
+
|
|
154
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);
|
|
155
360
|
|
|
156
361
|
for (const entry of entries) {
|
|
157
362
|
const fullPath = path.join(dir, entry.name);
|
|
158
363
|
|
|
159
364
|
if (entry.isDirectory()) {
|
|
365
|
+
// Skip directories claimed by collectSkills
|
|
366
|
+
if (this.skillClaimedDirs && this.skillClaimedDirs.has(fullPath)) continue;
|
|
160
367
|
// Recurse into subdirectories
|
|
161
368
|
const newRelativePath = relativePath ? `${relativePath}/${entry.name}` : entry.name;
|
|
162
369
|
await findWorkflows(fullPath, newRelativePath);
|
|
163
|
-
} else if (
|
|
164
|
-
entry.name === 'workflow.yaml' ||
|
|
165
|
-
entry.name === 'workflow.md' ||
|
|
166
|
-
(entry.name.startsWith('workflow-') && entry.name.endsWith('.md'))
|
|
167
|
-
) {
|
|
370
|
+
} else if (entry.name === 'workflow.md' || (entry.name.startsWith('workflow-') && entry.name.endsWith('.md'))) {
|
|
168
371
|
// Parse workflow file (both YAML and MD formats)
|
|
169
372
|
if (debug) {
|
|
170
373
|
console.log(`[DEBUG] Found workflow file: ${fullPath}`);
|
|
@@ -174,21 +377,15 @@ class ManifestGenerator {
|
|
|
174
377
|
const rawContent = await fs.readFile(fullPath, 'utf8');
|
|
175
378
|
const content = rawContent.replaceAll('\r\n', '\n').replaceAll('\r', '\n');
|
|
176
379
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
// Parse MD workflow with YAML frontmatter
|
|
183
|
-
const frontmatterMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
184
|
-
if (!frontmatterMatch) {
|
|
185
|
-
if (debug) {
|
|
186
|
-
console.log(`[DEBUG] Skipped (no frontmatter): ${fullPath}`);
|
|
187
|
-
}
|
|
188
|
-
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}`);
|
|
189
385
|
}
|
|
190
|
-
|
|
386
|
+
continue; // Skip MD files without frontmatter
|
|
191
387
|
}
|
|
388
|
+
const workflow = yaml.parse(frontmatterMatch[1]);
|
|
192
389
|
|
|
193
390
|
if (debug) {
|
|
194
391
|
console.log(`[DEBUG] Parsed: name="${workflow.name}", description=${workflow.description ? 'OK' : 'MISSING'}`);
|
|
@@ -214,8 +411,8 @@ class ManifestGenerator {
|
|
|
214
411
|
// Build relative path for installation
|
|
215
412
|
const installPath =
|
|
216
413
|
moduleName === 'core'
|
|
217
|
-
? `${this.bmadFolderName}/core
|
|
218
|
-
: `${this.bmadFolderName}/${moduleName}
|
|
414
|
+
? `${this.bmadFolderName}/core/${subDir}/${relativePath}/${entry.name}`
|
|
415
|
+
: `${this.bmadFolderName}/${moduleName}/${subDir}/${relativePath}/${entry.name}`;
|
|
219
416
|
|
|
220
417
|
// Workflows with standalone: false are filtered out above
|
|
221
418
|
workflows.push({
|
|
@@ -223,6 +420,7 @@ class ManifestGenerator {
|
|
|
223
420
|
description: this.cleanForCSV(workflow.description),
|
|
224
421
|
module: moduleName,
|
|
225
422
|
path: installPath,
|
|
423
|
+
canonicalId: this.getCanonicalId(skillManifest, entry.name),
|
|
226
424
|
});
|
|
227
425
|
|
|
228
426
|
// Add to files list
|
|
@@ -294,13 +492,19 @@ class ManifestGenerator {
|
|
|
294
492
|
* Only includes compiled .md files (not .agent.yaml source files)
|
|
295
493
|
*/
|
|
296
494
|
async getAgentsFromDir(dirPath, moduleName, relativePath = '') {
|
|
495
|
+
// Skip directories claimed by collectSkills
|
|
496
|
+
if (this.skillClaimedDirs && this.skillClaimedDirs.has(dirPath)) return [];
|
|
297
497
|
const agents = [];
|
|
298
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);
|
|
299
501
|
|
|
300
502
|
for (const entry of entries) {
|
|
301
503
|
const fullPath = path.join(dirPath, entry.name);
|
|
302
504
|
|
|
303
505
|
if (entry.isDirectory()) {
|
|
506
|
+
// Skip directories claimed by collectSkills
|
|
507
|
+
if (this.skillClaimedDirs && this.skillClaimedDirs.has(fullPath)) continue;
|
|
304
508
|
// Recurse into subdirectories
|
|
305
509
|
const newRelativePath = relativePath ? `${relativePath}/${entry.name}` : entry.name;
|
|
306
510
|
const subDirAgents = await this.getAgentsFromDir(fullPath, moduleName, newRelativePath);
|
|
@@ -351,6 +555,7 @@ class ManifestGenerator {
|
|
|
351
555
|
principles: principlesMatch ? this.cleanForCSV(principlesMatch[1]) : '',
|
|
352
556
|
module: moduleName,
|
|
353
557
|
path: installPath,
|
|
558
|
+
canonicalId: this.getCanonicalId(skillManifest, entry.name),
|
|
354
559
|
});
|
|
355
560
|
|
|
356
561
|
// Add to files list
|
|
@@ -388,8 +593,12 @@ class ManifestGenerator {
|
|
|
388
593
|
* Get tasks from a directory
|
|
389
594
|
*/
|
|
390
595
|
async getTasksFromDir(dirPath, moduleName) {
|
|
596
|
+
// Skip directories claimed by collectSkills
|
|
597
|
+
if (this.skillClaimedDirs && this.skillClaimedDirs.has(dirPath)) return [];
|
|
391
598
|
const tasks = [];
|
|
392
599
|
const files = await fs.readdir(dirPath);
|
|
600
|
+
// Load skill manifest for this directory (if present)
|
|
601
|
+
const skillManifest = await this.loadSkillManifest(dirPath);
|
|
393
602
|
|
|
394
603
|
for (const file of files) {
|
|
395
604
|
// Check for both .xml and .md files
|
|
@@ -449,6 +658,7 @@ class ManifestGenerator {
|
|
|
449
658
|
module: moduleName,
|
|
450
659
|
path: installPath,
|
|
451
660
|
standalone: standalone,
|
|
661
|
+
canonicalId: this.getCanonicalId(skillManifest, file),
|
|
452
662
|
});
|
|
453
663
|
|
|
454
664
|
// Add to files list
|
|
@@ -486,8 +696,12 @@ class ManifestGenerator {
|
|
|
486
696
|
* Get tools from a directory
|
|
487
697
|
*/
|
|
488
698
|
async getToolsFromDir(dirPath, moduleName) {
|
|
699
|
+
// Skip directories claimed by collectSkills
|
|
700
|
+
if (this.skillClaimedDirs && this.skillClaimedDirs.has(dirPath)) return [];
|
|
489
701
|
const tools = [];
|
|
490
702
|
const files = await fs.readdir(dirPath);
|
|
703
|
+
// Load skill manifest for this directory (if present)
|
|
704
|
+
const skillManifest = await this.loadSkillManifest(dirPath);
|
|
491
705
|
|
|
492
706
|
for (const file of files) {
|
|
493
707
|
// Check for both .xml and .md files
|
|
@@ -547,6 +761,7 @@ class ManifestGenerator {
|
|
|
547
761
|
module: moduleName,
|
|
548
762
|
path: installPath,
|
|
549
763
|
standalone: standalone,
|
|
764
|
+
canonicalId: this.getCanonicalId(skillManifest, file),
|
|
550
765
|
});
|
|
551
766
|
|
|
552
767
|
// Add to files list
|
|
@@ -737,8 +952,8 @@ class ManifestGenerator {
|
|
|
737
952
|
const csvPath = path.join(cfgDir, 'workflow-manifest.csv');
|
|
738
953
|
const escapeCsv = (value) => `"${String(value ?? '').replaceAll('"', '""')}"`;
|
|
739
954
|
|
|
740
|
-
// Create CSV header - standalone column removed,
|
|
741
|
-
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';
|
|
742
957
|
|
|
743
958
|
// Build workflows map from discovered workflows only
|
|
744
959
|
// Old entries are NOT preserved - the manifest reflects what actually exists on disk
|
|
@@ -752,12 +967,19 @@ class ManifestGenerator {
|
|
|
752
967
|
description: workflow.description,
|
|
753
968
|
module: workflow.module,
|
|
754
969
|
path: workflow.path,
|
|
970
|
+
canonicalId: workflow.canonicalId || '',
|
|
755
971
|
});
|
|
756
972
|
}
|
|
757
973
|
|
|
758
974
|
// Write all workflows
|
|
759
975
|
for (const [, value] of allWorkflows) {
|
|
760
|
-
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(',');
|
|
761
983
|
csv += row + '\n';
|
|
762
984
|
}
|
|
763
985
|
|
|
@@ -765,6 +987,32 @@ class ManifestGenerator {
|
|
|
765
987
|
return csvPath;
|
|
766
988
|
}
|
|
767
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
|
+
|
|
768
1016
|
/**
|
|
769
1017
|
* Write agent manifest CSV
|
|
770
1018
|
* @returns {string} Path to the manifest file
|
|
@@ -786,8 +1034,8 @@ class ManifestGenerator {
|
|
|
786
1034
|
}
|
|
787
1035
|
}
|
|
788
1036
|
|
|
789
|
-
// Create CSV header with persona fields
|
|
790
|
-
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';
|
|
791
1039
|
|
|
792
1040
|
// Combine existing and new agents, preferring new data for duplicates
|
|
793
1041
|
const allAgents = new Map();
|
|
@@ -812,6 +1060,7 @@ class ManifestGenerator {
|
|
|
812
1060
|
principles: agent.principles,
|
|
813
1061
|
module: agent.module,
|
|
814
1062
|
path: agent.path,
|
|
1063
|
+
canonicalId: agent.canonicalId || '',
|
|
815
1064
|
});
|
|
816
1065
|
}
|
|
817
1066
|
|
|
@@ -829,6 +1078,7 @@ class ManifestGenerator {
|
|
|
829
1078
|
escapeCsv(record.principles),
|
|
830
1079
|
escapeCsv(record.module),
|
|
831
1080
|
escapeCsv(record.path),
|
|
1081
|
+
escapeCsv(record.canonicalId),
|
|
832
1082
|
].join(',');
|
|
833
1083
|
csvContent += row + '\n';
|
|
834
1084
|
}
|
|
@@ -858,8 +1108,8 @@ class ManifestGenerator {
|
|
|
858
1108
|
}
|
|
859
1109
|
}
|
|
860
1110
|
|
|
861
|
-
// Create CSV header with standalone
|
|
862
|
-
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';
|
|
863
1113
|
|
|
864
1114
|
// Combine existing and new tasks
|
|
865
1115
|
const allTasks = new Map();
|
|
@@ -879,6 +1129,7 @@ class ManifestGenerator {
|
|
|
879
1129
|
module: task.module,
|
|
880
1130
|
path: task.path,
|
|
881
1131
|
standalone: task.standalone,
|
|
1132
|
+
canonicalId: task.canonicalId || '',
|
|
882
1133
|
});
|
|
883
1134
|
}
|
|
884
1135
|
|
|
@@ -891,6 +1142,7 @@ class ManifestGenerator {
|
|
|
891
1142
|
escapeCsv(record.module),
|
|
892
1143
|
escapeCsv(record.path),
|
|
893
1144
|
escapeCsv(record.standalone),
|
|
1145
|
+
escapeCsv(record.canonicalId),
|
|
894
1146
|
].join(',');
|
|
895
1147
|
csvContent += row + '\n';
|
|
896
1148
|
}
|
|
@@ -920,8 +1172,8 @@ class ManifestGenerator {
|
|
|
920
1172
|
}
|
|
921
1173
|
}
|
|
922
1174
|
|
|
923
|
-
// Create CSV header with standalone
|
|
924
|
-
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';
|
|
925
1177
|
|
|
926
1178
|
// Combine existing and new tools
|
|
927
1179
|
const allTools = new Map();
|
|
@@ -941,6 +1193,7 @@ class ManifestGenerator {
|
|
|
941
1193
|
module: tool.module,
|
|
942
1194
|
path: tool.path,
|
|
943
1195
|
standalone: tool.standalone,
|
|
1196
|
+
canonicalId: tool.canonicalId || '',
|
|
944
1197
|
});
|
|
945
1198
|
}
|
|
946
1199
|
|
|
@@ -953,6 +1206,7 @@ class ManifestGenerator {
|
|
|
953
1206
|
escapeCsv(record.module),
|
|
954
1207
|
escapeCsv(record.path),
|
|
955
1208
|
escapeCsv(record.standalone),
|
|
1209
|
+
escapeCsv(record.canonicalId),
|
|
956
1210
|
].join(',');
|
|
957
1211
|
csvContent += row + '\n';
|
|
958
1212
|
}
|
|
@@ -1067,8 +1321,14 @@ class ManifestGenerator {
|
|
|
1067
1321
|
const hasTasks = await fs.pathExists(path.join(modulePath, 'tasks'));
|
|
1068
1322
|
const hasTools = await fs.pathExists(path.join(modulePath, 'tools'));
|
|
1069
1323
|
|
|
1070
|
-
//
|
|
1071
|
-
|
|
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) {
|
|
1072
1332
|
modules.push(entry.name);
|
|
1073
1333
|
}
|
|
1074
1334
|
}
|
|
@@ -1078,6 +1338,37 @@ class ManifestGenerator {
|
|
|
1078
1338
|
|
|
1079
1339
|
return modules;
|
|
1080
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
|
+
}
|
|
1081
1372
|
}
|
|
1082
1373
|
|
|
1083
1374
|
module.exports = { ManifestGenerator };
|