bmad-method 6.0.1 → 6.0.2
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/.claude/skills/bmad-os-audit-file-refs/SKILL.md +6 -0
- package/.claude/skills/bmad-os-audit-file-refs/prompts/instructions.md +59 -0
- package/.claude/skills/bmad-os-changelog-social/SKILL.md +1 -2
- package/.claude/skills/bmad-os-diataxis-style-fix/SKILL.md +1 -2
- package/.claude/skills/bmad-os-draft-changelog/SKILL.md +1 -2
- package/.claude/skills/bmad-os-gh-triage/SKILL.md +1 -7
- package/.claude/skills/bmad-os-release-module/SKILL.md +1 -2
- package/.claude/skills/bmad-os-review-pr/SKILL.md +6 -0
- package/{tools/maintainer/review-pr.md → .claude/skills/bmad-os-review-pr/prompts/instructions.md} +5 -16
- package/.prettierignore +3 -0
- package/CHANGELOG.md +37 -0
- package/README.md +13 -1
- package/docs/how-to/customize-bmad.md +14 -14
- package/docs/how-to/established-projects.md +15 -3
- package/docs/how-to/get-answers-about-bmad.md +39 -8
- package/docs/how-to/install-bmad.md +13 -4
- package/docs/how-to/non-interactive-installation.md +1 -1
- package/docs/how-to/quick-fixes.md +1 -1
- package/docs/index.md +10 -4
- package/docs/reference/commands.md +21 -1
- package/docs/reference/workflow-map.md +29 -62
- package/docs/roadmap.mdx +136 -0
- package/docs/tutorials/getting-started.md +69 -15
- package/package.json +2 -2
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-01-init.md +2 -2
- package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-01b-continue.md +3 -3
- 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/create-product-brief/workflow.md +1 -1
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-01-init.md +2 -2
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-02-domain-analysis.md +2 -2
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-03-competitive-landscape.md +2 -2
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-04-regulatory-focus.md +2 -2
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-05-technical-trends.md +1 -1
- package/src/bmm/workflows/1-analysis/research/domain-steps/step-06-research-synthesis.md +2 -1
- package/src/bmm/workflows/1-analysis/research/market-steps/step-01-init.md +2 -2
- package/src/bmm/workflows/1-analysis/research/market-steps/step-02-customer-behavior.md +2 -2
- package/src/bmm/workflows/1-analysis/research/market-steps/step-03-customer-pain-points.md +2 -2
- package/src/bmm/workflows/1-analysis/research/market-steps/step-04-customer-decisions.md +2 -2
- package/src/bmm/workflows/1-analysis/research/market-steps/step-06-research-completion.md +2 -1
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-01-init.md +2 -2
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-02-technical-overview.md +2 -2
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-03-integration-patterns.md +2 -2
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-04-architectural-patterns.md +2 -2
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-05-implementation-research.md +2 -2
- package/src/bmm/workflows/1-analysis/research/technical-steps/step-06-research-synthesis.md +2 -1
- package/src/bmm/workflows/1-analysis/research/workflow-domain-research.md +1 -1
- package/src/bmm/workflows/1-analysis/research/workflow-market-research.md +1 -1
- package/src/bmm/workflows/1-analysis/research/workflow-technical-research.md +1 -1
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-01b-continue.md +2 -3
- 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 +2 -2
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-04-journeys.md +2 -2
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-05-domain.md +2 -2
- package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-06-innovation.md +2 -2
- 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 +3 -3
- 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-v/step-v-13-report-complete.md +1 -1
- package/src/bmm/workflows/2-plan-workflows/create-prd/workflow-create-prd.md +1 -1
- package/src/bmm/workflows/2-plan-workflows/create-prd/workflow-edit-prd.md +1 -1
- package/src/bmm/workflows/2-plan-workflows/create-prd/workflow-validate-prd.md +1 -1
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-01-init.md +2 -2
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-01b-continue.md +3 -3
- package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-02-discovery.md +2 -2
- 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/2-plan-workflows/create-ux-design/workflow.md +2 -2
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-06-final-assessment.md +1 -1
- package/src/bmm/workflows/3-solutioning/check-implementation-readiness/workflow.md +2 -2
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-01-init.md +2 -2
- package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-01b-continue.md +11 -2
- 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 +3 -5
- 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-architecture/workflow.md +3 -3
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-04-final-validation.md +1 -1
- package/src/bmm/workflows/3-solutioning/create-epics-and-stories/workflow.md +1 -1
- package/src/bmm/workflows/4-implementation/code-review/workflow.yaml +1 -2
- package/src/bmm/workflows/4-implementation/correct-course/workflow.yaml +1 -2
- package/src/bmm/workflows/4-implementation/create-story/checklist.md +2 -2
- package/src/bmm/workflows/4-implementation/create-story/workflow.yaml +1 -2
- package/src/bmm/workflows/4-implementation/dev-story/workflow.yaml +1 -2
- package/src/bmm/workflows/4-implementation/retrospective/workflow.yaml +1 -2
- package/src/bmm/workflows/4-implementation/sprint-planning/workflow.yaml +1 -1
- package/src/bmm/workflows/4-implementation/sprint-status/workflow.yaml +1 -1
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-01-mode-detection.md +6 -6
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-02-context-gathering.md +1 -1
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-03-execute.md +1 -1
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-04-self-check.md +1 -1
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/steps/step-05-adversarial-review.md +1 -1
- package/src/bmm/workflows/bmad-quick-flow/quick-dev/workflow.md +2 -2
- package/src/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-01-understand.md +4 -6
- package/src/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-02-investigate.md +1 -2
- package/src/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-03-generate.md +1 -2
- package/src/bmm/workflows/bmad-quick-flow/quick-spec/workflow.md +2 -2
- package/src/bmm/workflows/document-project/workflow.yaml +1 -1
- package/src/bmm/workflows/generate-project-context/steps/step-01-discover.md +1 -1
- package/src/bmm/workflows/generate-project-context/steps/step-02-generate.md +1 -1
- package/src/bmm/workflows/generate-project-context/workflow.md +2 -2
- package/src/bmm/workflows/{qa/automate → qa-generate-e2e-tests}/workflow.yaml +2 -4
- package/src/core/tasks/editorial-review-prose.xml +1 -1
- package/src/core/tasks/editorial-review-structure.xml +1 -2
- package/src/core/tasks/help.md +3 -2
- package/src/core/tasks/index-docs.xml +1 -1
- package/src/core/tasks/review-adversarial-general.xml +2 -1
- package/src/core/tasks/shard-doc.xml +1 -1
- package/src/core/workflows/advanced-elicitation/workflow.xml +1 -0
- package/src/core/workflows/brainstorming/workflow.md +1 -1
- package/src/core/workflows/party-mode/workflow.md +1 -1
- package/tools/cli/installers/lib/ide/_config-driven.js +0 -1
- package/tools/cli/installers/lib/ide/codex.js +195 -181
- package/tools/cli/installers/lib/ide/github-copilot.js +0 -1
- package/tools/cli/installers/lib/ide/manager.js +3 -3
- package/tools/cli/installers/lib/ide/platform-codes.yaml +11 -4
- package/tools/cli/installers/lib/ide/rovodev.js +257 -0
- package/tools/cli/installers/lib/ide/shared/task-tool-command-generator.js +0 -1
- package/tools/cli/installers/lib/ide/templates/agent-command-template.md +0 -1
- package/tools/cli/installers/lib/ide/templates/combined/default-agent.md +0 -1
- package/tools/cli/installers/lib/ide/templates/combined/default-workflow-yaml.md +0 -1
- package/tools/cli/installers/lib/ide/templates/combined/default-workflow.md +0 -1
- package/tools/cli/installers/lib/ide/templates/workflow-command-template.md +0 -1
- package/tools/cli/installers/lib/ide/templates/workflow-commander.md +0 -1
- package/tools/cli/lib/ui.js +1 -1
- package/tools/platform-codes.yaml +12 -12
- package/tools/validate-doc-links.js +20 -6
- package/website/astro.config.mjs +1 -0
- package/website/src/rehype-markdown-links.js +9 -1
- package/website/src/styles/custom.css +296 -0
- package/.claude/skills/bmad-os-gh-triage/README.md +0 -14
- package/.claude/skills/bmad-os-release-module/README.md +0 -24
- package/tools/maintainer/review-pr-README.md +0 -55
- /package/src/bmm/workflows/{qa/automate → qa-generate-e2e-tests}/checklist.md +0 -0
- /package/src/bmm/workflows/{qa/automate → qa-generate-e2e-tests}/instructions.md +0 -0
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
const path = require('node:path');
|
|
2
|
+
const fs = require('fs-extra');
|
|
3
|
+
const yaml = require('yaml');
|
|
4
|
+
const { BaseIdeSetup } = require('./_base-ide');
|
|
5
|
+
const prompts = require('../../../lib/prompts');
|
|
6
|
+
const { AgentCommandGenerator } = require('./shared/agent-command-generator');
|
|
7
|
+
const { WorkflowCommandGenerator } = require('./shared/workflow-command-generator');
|
|
8
|
+
const { TaskToolCommandGenerator } = require('./shared/task-tool-command-generator');
|
|
9
|
+
const { toDashPath } = require('./shared/path-utils');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Rovo Dev IDE setup handler
|
|
13
|
+
*
|
|
14
|
+
* Custom installer that writes .md workflow files to .rovodev/workflows/
|
|
15
|
+
* and generates .rovodev/prompts.yml to register them with Rovo Dev's /prompts feature.
|
|
16
|
+
*
|
|
17
|
+
* prompts.yml format (per Rovo Dev docs):
|
|
18
|
+
* prompts:
|
|
19
|
+
* - name: bmad-bmm-create-prd
|
|
20
|
+
* description: "PRD workflow..."
|
|
21
|
+
* content_file: workflows/bmad-bmm-create-prd.md
|
|
22
|
+
*/
|
|
23
|
+
class RovoDevSetup extends BaseIdeSetup {
|
|
24
|
+
constructor() {
|
|
25
|
+
super('rovo-dev', 'Rovo Dev', false);
|
|
26
|
+
this.rovoDir = '.rovodev';
|
|
27
|
+
this.workflowsDir = 'workflows';
|
|
28
|
+
this.promptsFile = 'prompts.yml';
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Setup Rovo Dev configuration
|
|
33
|
+
* @param {string} projectDir - Project directory
|
|
34
|
+
* @param {string} bmadDir - BMAD installation directory
|
|
35
|
+
* @param {Object} options - Setup options
|
|
36
|
+
* @returns {Promise<Object>} Setup result with { success, results: { agents, workflows, tasks, tools } }
|
|
37
|
+
*/
|
|
38
|
+
async setup(projectDir, bmadDir, options = {}) {
|
|
39
|
+
if (!options.silent) await prompts.log.info(`Setting up ${this.name}...`);
|
|
40
|
+
|
|
41
|
+
// Clean up any old BMAD installation first
|
|
42
|
+
await this.cleanup(projectDir, options);
|
|
43
|
+
|
|
44
|
+
const workflowsPath = path.join(projectDir, this.rovoDir, this.workflowsDir);
|
|
45
|
+
await this.ensureDir(workflowsPath);
|
|
46
|
+
|
|
47
|
+
const selectedModules = options.selectedModules || [];
|
|
48
|
+
const writtenFiles = [];
|
|
49
|
+
|
|
50
|
+
// Generate and write agent launchers
|
|
51
|
+
const agentGen = new AgentCommandGenerator(this.bmadFolderName);
|
|
52
|
+
const { artifacts: agentArtifacts } = await agentGen.collectAgentArtifacts(bmadDir, selectedModules);
|
|
53
|
+
const agentCount = await agentGen.writeDashArtifacts(workflowsPath, agentArtifacts);
|
|
54
|
+
this._collectPromptEntries(writtenFiles, agentArtifacts, ['agent-launcher'], 'agent');
|
|
55
|
+
|
|
56
|
+
// Generate and write workflow commands
|
|
57
|
+
const workflowGen = new WorkflowCommandGenerator(this.bmadFolderName);
|
|
58
|
+
const { artifacts: workflowArtifacts } = await workflowGen.collectWorkflowArtifacts(bmadDir);
|
|
59
|
+
const workflowCount = await workflowGen.writeDashArtifacts(workflowsPath, workflowArtifacts);
|
|
60
|
+
this._collectPromptEntries(writtenFiles, workflowArtifacts, ['workflow-command'], 'workflow');
|
|
61
|
+
|
|
62
|
+
// Generate and write task/tool commands
|
|
63
|
+
const taskToolGen = new TaskToolCommandGenerator(this.bmadFolderName);
|
|
64
|
+
const { artifacts: taskToolArtifacts, counts: taskToolCounts } = await taskToolGen.collectTaskToolArtifacts(bmadDir);
|
|
65
|
+
await taskToolGen.writeDashArtifacts(workflowsPath, taskToolArtifacts);
|
|
66
|
+
const taskCount = taskToolCounts.tasks || 0;
|
|
67
|
+
const toolCount = taskToolCounts.tools || 0;
|
|
68
|
+
this._collectPromptEntries(writtenFiles, taskToolArtifacts, ['task', 'tool']);
|
|
69
|
+
|
|
70
|
+
// Generate prompts.yml manifest (only if we have entries to write)
|
|
71
|
+
if (writtenFiles.length > 0) {
|
|
72
|
+
await this.generatePromptsYml(projectDir, writtenFiles);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (!options.silent) {
|
|
76
|
+
await prompts.log.success(
|
|
77
|
+
`${this.name} configured: ${agentCount} agents, ${workflowCount} workflows, ${taskCount} tasks, ${toolCount} tools`,
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
success: true,
|
|
83
|
+
results: {
|
|
84
|
+
agents: agentCount,
|
|
85
|
+
workflows: workflowCount,
|
|
86
|
+
tasks: taskCount,
|
|
87
|
+
tools: toolCount,
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Collect prompt entries from artifacts into writtenFiles array
|
|
94
|
+
* @param {Array} writtenFiles - Target array to push entries into
|
|
95
|
+
* @param {Array} artifacts - Artifacts from a generator's collect method
|
|
96
|
+
* @param {string[]} acceptedTypes - Artifact types to include (e.g., ['agent-launcher'])
|
|
97
|
+
* @param {string} [fallbackSuffix] - Suffix for fallback description; defaults to artifact.type
|
|
98
|
+
*/
|
|
99
|
+
_collectPromptEntries(writtenFiles, artifacts, acceptedTypes, fallbackSuffix) {
|
|
100
|
+
for (const artifact of artifacts) {
|
|
101
|
+
if (!acceptedTypes.includes(artifact.type)) continue;
|
|
102
|
+
const flatName = toDashPath(artifact.relativePath);
|
|
103
|
+
writtenFiles.push({
|
|
104
|
+
name: path.basename(flatName, '.md'),
|
|
105
|
+
description: artifact.description || `${artifact.name} ${fallbackSuffix || artifact.type}`,
|
|
106
|
+
contentFile: `${this.workflowsDir}/${flatName}`,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Generate .rovodev/prompts.yml manifest
|
|
113
|
+
* Merges with existing user entries -- strips entries with names starting 'bmad-',
|
|
114
|
+
* appends new BMAD entries, and writes back.
|
|
115
|
+
*
|
|
116
|
+
* @param {string} projectDir - Project directory
|
|
117
|
+
* @param {Array<Object>} writtenFiles - Array of { name, description, contentFile }
|
|
118
|
+
*/
|
|
119
|
+
async generatePromptsYml(projectDir, writtenFiles) {
|
|
120
|
+
const promptsPath = path.join(projectDir, this.rovoDir, this.promptsFile);
|
|
121
|
+
let existingPrompts = [];
|
|
122
|
+
|
|
123
|
+
// Read existing prompts.yml and preserve non-BMAD entries
|
|
124
|
+
if (await this.pathExists(promptsPath)) {
|
|
125
|
+
try {
|
|
126
|
+
const content = await this.readFile(promptsPath);
|
|
127
|
+
const parsed = yaml.parse(content);
|
|
128
|
+
if (parsed && Array.isArray(parsed.prompts)) {
|
|
129
|
+
// Keep only non-BMAD entries (entries whose name does NOT start with bmad-)
|
|
130
|
+
existingPrompts = parsed.prompts.filter((entry) => !entry.name || !entry.name.startsWith('bmad-'));
|
|
131
|
+
}
|
|
132
|
+
} catch {
|
|
133
|
+
// If parsing fails, start fresh but preserve file safety
|
|
134
|
+
existingPrompts = [];
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Build new BMAD entries (prefix description with name so /prompts list is scannable)
|
|
139
|
+
const bmadEntries = writtenFiles.map((file) => ({
|
|
140
|
+
name: file.name,
|
|
141
|
+
description: `${file.name} - ${file.description}`,
|
|
142
|
+
content_file: file.contentFile,
|
|
143
|
+
}));
|
|
144
|
+
|
|
145
|
+
// Merge: user entries first, then BMAD entries
|
|
146
|
+
const allPrompts = [...existingPrompts, ...bmadEntries];
|
|
147
|
+
|
|
148
|
+
const config = { prompts: allPrompts };
|
|
149
|
+
const yamlContent = yaml.stringify(config, { lineWidth: 0 });
|
|
150
|
+
await this.writeFile(promptsPath, yamlContent);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Cleanup Rovo Dev configuration
|
|
155
|
+
* Removes bmad-* files from .rovodev/workflows/ and strips BMAD entries from prompts.yml
|
|
156
|
+
* @param {string} projectDir - Project directory
|
|
157
|
+
* @param {Object} options - Cleanup options
|
|
158
|
+
*/
|
|
159
|
+
async cleanup(projectDir, options = {}) {
|
|
160
|
+
const workflowsPath = path.join(projectDir, this.rovoDir, this.workflowsDir);
|
|
161
|
+
|
|
162
|
+
// Remove all bmad-* entries from workflows dir (aligned with detect() predicate)
|
|
163
|
+
if (await this.pathExists(workflowsPath)) {
|
|
164
|
+
const entries = await fs.readdir(workflowsPath);
|
|
165
|
+
for (const entry of entries) {
|
|
166
|
+
if (entry.startsWith('bmad-')) {
|
|
167
|
+
await fs.remove(path.join(workflowsPath, entry));
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Clean BMAD entries from prompts.yml (preserve user entries)
|
|
173
|
+
const promptsPath = path.join(projectDir, this.rovoDir, this.promptsFile);
|
|
174
|
+
if (await this.pathExists(promptsPath)) {
|
|
175
|
+
try {
|
|
176
|
+
const content = await this.readFile(promptsPath);
|
|
177
|
+
const parsed = yaml.parse(content) || {};
|
|
178
|
+
|
|
179
|
+
if (Array.isArray(parsed.prompts)) {
|
|
180
|
+
const originalCount = parsed.prompts.length;
|
|
181
|
+
parsed.prompts = parsed.prompts.filter((entry) => !entry.name || !entry.name.startsWith('bmad-'));
|
|
182
|
+
const removedCount = originalCount - parsed.prompts.length;
|
|
183
|
+
|
|
184
|
+
if (removedCount > 0) {
|
|
185
|
+
if (parsed.prompts.length === 0) {
|
|
186
|
+
// If no entries remain, remove the file entirely
|
|
187
|
+
await fs.remove(promptsPath);
|
|
188
|
+
} else {
|
|
189
|
+
await this.writeFile(promptsPath, yaml.stringify(parsed, { lineWidth: 0 }));
|
|
190
|
+
}
|
|
191
|
+
if (!options.silent) {
|
|
192
|
+
await prompts.log.message(`Removed ${removedCount} BMAD entries from ${this.promptsFile}`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
} catch {
|
|
197
|
+
// If parsing fails, leave file as-is
|
|
198
|
+
if (!options.silent) {
|
|
199
|
+
await prompts.log.warn(`Warning: Could not parse ${this.promptsFile} for cleanup`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Remove empty .rovodev directories
|
|
205
|
+
if (await this.pathExists(workflowsPath)) {
|
|
206
|
+
const remaining = await fs.readdir(workflowsPath);
|
|
207
|
+
if (remaining.length === 0) {
|
|
208
|
+
await fs.remove(workflowsPath);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const rovoDirPath = path.join(projectDir, this.rovoDir);
|
|
213
|
+
if (await this.pathExists(rovoDirPath)) {
|
|
214
|
+
const remaining = await fs.readdir(rovoDirPath);
|
|
215
|
+
if (remaining.length === 0) {
|
|
216
|
+
await fs.remove(rovoDirPath);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Detect whether Rovo Dev configuration exists in the project
|
|
223
|
+
* Checks for .rovodev/ dir with bmad files or bmad entries in prompts.yml
|
|
224
|
+
* @param {string} projectDir - Project directory
|
|
225
|
+
* @returns {boolean}
|
|
226
|
+
*/
|
|
227
|
+
async detect(projectDir) {
|
|
228
|
+
const workflowsPath = path.join(projectDir, this.rovoDir, this.workflowsDir);
|
|
229
|
+
|
|
230
|
+
// Check for bmad files in workflows dir
|
|
231
|
+
if (await fs.pathExists(workflowsPath)) {
|
|
232
|
+
const entries = await fs.readdir(workflowsPath);
|
|
233
|
+
if (entries.some((entry) => entry.startsWith('bmad-'))) {
|
|
234
|
+
return true;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Check for bmad entries in prompts.yml
|
|
239
|
+
const promptsPath = path.join(projectDir, this.rovoDir, this.promptsFile);
|
|
240
|
+
if (await fs.pathExists(promptsPath)) {
|
|
241
|
+
try {
|
|
242
|
+
const content = await fs.readFile(promptsPath, 'utf8');
|
|
243
|
+
const parsed = yaml.parse(content);
|
|
244
|
+
if (parsed && Array.isArray(parsed.prompts)) {
|
|
245
|
+
return parsed.prompts.some((entry) => entry.name && entry.name.startsWith('bmad-'));
|
|
246
|
+
}
|
|
247
|
+
} catch {
|
|
248
|
+
// If parsing fails, check raw content
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
return false;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
module.exports = { RovoDevSetup };
|
package/tools/cli/lib/ui.js
CHANGED
|
@@ -582,7 +582,7 @@ class UI {
|
|
|
582
582
|
/**
|
|
583
583
|
* Prompt for tool/IDE selection (called after module configuration)
|
|
584
584
|
* Uses a split prompt approach:
|
|
585
|
-
* 1. Recommended tools - standard multiselect for
|
|
585
|
+
* 1. Recommended tools - standard multiselect for preferred tools
|
|
586
586
|
* 2. Additional tools - autocompleteMultiselect with search capability
|
|
587
587
|
* @param {string} projectDir - Project directory to check for existing IDEs
|
|
588
588
|
* @param {Object} options - Command-line options
|
|
@@ -18,12 +18,6 @@ platforms:
|
|
|
18
18
|
category: cli
|
|
19
19
|
description: "Anthropic's official CLI for Claude"
|
|
20
20
|
|
|
21
|
-
windsurf:
|
|
22
|
-
name: "Windsurf"
|
|
23
|
-
preferred: true
|
|
24
|
-
category: ide
|
|
25
|
-
description: "AI-powered IDE with cascade flows"
|
|
26
|
-
|
|
27
21
|
cursor:
|
|
28
22
|
name: "Cursor"
|
|
29
23
|
preferred: true
|
|
@@ -43,6 +37,12 @@ platforms:
|
|
|
43
37
|
category: ide
|
|
44
38
|
description: "OpenCode terminal coding assistant"
|
|
45
39
|
|
|
40
|
+
codebuddy:
|
|
41
|
+
name: "CodeBuddy"
|
|
42
|
+
preferred: false
|
|
43
|
+
category: ide
|
|
44
|
+
description: "Tencent Cloud Code Assistant - AI-powered coding companion"
|
|
45
|
+
|
|
46
46
|
auggie:
|
|
47
47
|
name: "Auggie"
|
|
48
48
|
preferred: false
|
|
@@ -55,12 +55,6 @@ platforms:
|
|
|
55
55
|
category: ide
|
|
56
56
|
description: "Enhanced Cline fork"
|
|
57
57
|
|
|
58
|
-
rovo:
|
|
59
|
-
name: "Rovo"
|
|
60
|
-
preferred: false
|
|
61
|
-
category: ide
|
|
62
|
-
description: "Atlassian's AI coding assistant"
|
|
63
|
-
|
|
64
58
|
rovo-dev:
|
|
65
59
|
name: "Rovo Dev"
|
|
66
60
|
preferred: false
|
|
@@ -127,6 +121,12 @@ platforms:
|
|
|
127
121
|
category: ide
|
|
128
122
|
description: "AI coding tool"
|
|
129
123
|
|
|
124
|
+
windsurf:
|
|
125
|
+
name: "Windsurf"
|
|
126
|
+
preferred: false
|
|
127
|
+
category: ide
|
|
128
|
+
description: "AI-powered IDE with cascade flows"
|
|
129
|
+
|
|
130
130
|
# Platform categories
|
|
131
131
|
categories:
|
|
132
132
|
ide:
|
|
@@ -51,7 +51,7 @@ function getMarkdownFiles(dir) {
|
|
|
51
51
|
|
|
52
52
|
if (entry.isDirectory()) {
|
|
53
53
|
walk(fullPath);
|
|
54
|
-
} else if (entry.isFile() && entry.name.endsWith('.md')) {
|
|
54
|
+
} else if (entry.isFile() && (entry.name.endsWith('.md') || entry.name.endsWith('.mdx'))) {
|
|
55
55
|
files.push(fullPath);
|
|
56
56
|
}
|
|
57
57
|
}
|
|
@@ -120,10 +120,13 @@ function resolveLink(siteRelativePath, sourceFile) {
|
|
|
120
120
|
if (!resolved.startsWith(DOCS_ROOT + path.sep) && resolved !== DOCS_ROOT) return null;
|
|
121
121
|
if (fs.existsSync(resolved) && fs.statSync(resolved).isFile()) return resolved;
|
|
122
122
|
if (fs.existsSync(resolved + '.md')) return resolved + '.md';
|
|
123
|
-
|
|
123
|
+
if (fs.existsSync(resolved + '.mdx')) return resolved + '.mdx';
|
|
124
|
+
// Directory: check for index.md or index.mdx
|
|
124
125
|
if (fs.existsSync(resolved) && fs.statSync(resolved).isDirectory()) {
|
|
125
126
|
const indexFile = path.join(resolved, 'index.md');
|
|
127
|
+
const indexMdxFile = path.join(resolved, 'index.mdx');
|
|
126
128
|
if (fs.existsSync(indexFile)) return indexFile;
|
|
129
|
+
if (fs.existsSync(indexMdxFile)) return indexMdxFile;
|
|
127
130
|
}
|
|
128
131
|
return null;
|
|
129
132
|
}
|
|
@@ -134,12 +137,17 @@ function resolveLink(siteRelativePath, sourceFile) {
|
|
|
134
137
|
}
|
|
135
138
|
|
|
136
139
|
if (checkPath.endsWith('/')) {
|
|
137
|
-
// Could be file.md or directory/index.md
|
|
138
|
-
const
|
|
140
|
+
// Could be file.md, file.mdx, or directory/index.md/mdx
|
|
141
|
+
const baseName = checkPath.slice(0, -1);
|
|
142
|
+
const asMd = path.join(DOCS_ROOT, baseName + '.md');
|
|
143
|
+
const asMdx = path.join(DOCS_ROOT, baseName + '.mdx');
|
|
139
144
|
const asIndex = path.join(DOCS_ROOT, checkPath, 'index.md');
|
|
145
|
+
const asIndexMdx = path.join(DOCS_ROOT, checkPath, 'index.mdx');
|
|
140
146
|
|
|
141
|
-
if (fs.existsSync(
|
|
147
|
+
if (fs.existsSync(asMd)) return asMd;
|
|
148
|
+
if (fs.existsSync(asMdx)) return asMdx;
|
|
142
149
|
if (fs.existsSync(asIndex)) return asIndex;
|
|
150
|
+
if (fs.existsSync(asIndexMdx)) return asIndexMdx;
|
|
143
151
|
return null;
|
|
144
152
|
}
|
|
145
153
|
|
|
@@ -151,10 +159,16 @@ function resolveLink(siteRelativePath, sourceFile) {
|
|
|
151
159
|
const withMd = direct + '.md';
|
|
152
160
|
if (fs.existsSync(withMd)) return withMd;
|
|
153
161
|
|
|
154
|
-
//
|
|
162
|
+
// Try with .mdx extension
|
|
163
|
+
const withMdx = direct + '.mdx';
|
|
164
|
+
if (fs.existsSync(withMdx)) return withMdx;
|
|
165
|
+
|
|
166
|
+
// Directory without trailing slash: check for index.md or index.mdx
|
|
155
167
|
if (fs.existsSync(direct) && fs.statSync(direct).isDirectory()) {
|
|
156
168
|
const indexFile = path.join(direct, 'index.md');
|
|
169
|
+
const indexMdxFile = path.join(direct, 'index.mdx');
|
|
157
170
|
if (fs.existsSync(indexFile)) return indexFile;
|
|
171
|
+
if (fs.existsSync(indexMdxFile)) return indexMdxFile;
|
|
158
172
|
}
|
|
159
173
|
|
|
160
174
|
return null;
|
package/website/astro.config.mjs
CHANGED
|
@@ -101,11 +101,19 @@ export function findFirstDelimiter(str) {
|
|
|
101
101
|
/** Walk up from a file path to find the content docs directory. */
|
|
102
102
|
export function detectContentDir(filePath) {
|
|
103
103
|
const segments = filePath.split(path.sep);
|
|
104
|
-
// Look for src/content/docs in the path
|
|
104
|
+
// Look for src/content/docs in the path (standard Astro)
|
|
105
105
|
for (let i = segments.length - 1; i >= 2; i--) {
|
|
106
106
|
if (segments[i - 2] === 'src' && segments[i - 1] === 'content' && segments[i] === 'docs') {
|
|
107
107
|
return segments.slice(0, i + 1).join(path.sep);
|
|
108
108
|
}
|
|
109
109
|
}
|
|
110
|
+
// Also check for a standalone 'docs' directory (BMAD project structure)
|
|
111
|
+
// Path format: .../bmm/docs/file.mdx or .../bmm/website/...
|
|
112
|
+
for (let i = segments.length - 1; i >= 0; i--) {
|
|
113
|
+
if (segments[i] === 'docs') {
|
|
114
|
+
// Found docs directory - use its parent as the content root
|
|
115
|
+
return segments.slice(0, i + 1).join(path.sep);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
110
118
|
return null;
|
|
111
119
|
}
|