bmad-method 6.0.0-Beta.1 → 6.0.0-Beta.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/CHANGELOG.md +8 -1
- package/package.json +1 -1
- package/src/bmm/module-help.csv +31 -31
- package/src/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-04-review.md +1 -1
- package/src/core/module-help.csv +8 -8
- package/tools/cli/installers/lib/core/installer.js +26 -40
- package/tools/cli/installers/lib/ide/_config-driven.js +423 -0
- package/tools/cli/installers/lib/ide/codex.js +40 -12
- package/tools/cli/installers/lib/ide/manager.js +65 -38
- package/tools/cli/installers/lib/ide/platform-codes.js +100 -0
- package/tools/cli/installers/lib/ide/platform-codes.yaml +241 -0
- package/tools/cli/installers/lib/ide/shared/agent-command-generator.js +19 -5
- package/tools/cli/installers/lib/ide/shared/bmad-artifacts.js +5 -0
- package/tools/cli/installers/lib/ide/shared/path-utils.js +166 -50
- package/tools/cli/installers/lib/ide/shared/task-tool-command-generator.js +7 -5
- package/tools/cli/installers/lib/ide/shared/workflow-command-generator.js +21 -3
- package/tools/cli/installers/lib/ide/templates/combined/antigravity.md +8 -0
- package/tools/cli/installers/lib/ide/templates/combined/default-agent.md +15 -0
- package/tools/cli/installers/lib/ide/templates/combined/default-workflow-yaml.md +14 -0
- package/tools/cli/installers/lib/ide/templates/combined/default-workflow.md +6 -0
- package/tools/cli/installers/lib/ide/templates/combined/rovodev.md +9 -0
- package/tools/cli/installers/lib/ide/templates/combined/trae.md +9 -0
- package/tools/cli/installers/lib/ide/templates/combined/windsurf-workflow.md +10 -0
- package/tools/cli/installers/lib/ide/templates/split/gemini/body.md +10 -0
- package/tools/cli/installers/lib/ide/templates/split/gemini/header.toml +2 -0
- package/tools/cli/installers/lib/ide/templates/split/opencode/body.md +10 -0
- package/tools/cli/installers/lib/ide/templates/split/opencode/header.md +4 -0
- package/tools/cli/lib/ui.js +19 -75
- package/tools/cli/installers/lib/ide/STANDARDIZATION_PLAN.md +0 -208
- package/tools/cli/installers/lib/ide/antigravity.js +0 -474
- package/tools/cli/installers/lib/ide/auggie.js +0 -244
- package/tools/cli/installers/lib/ide/claude-code.js +0 -506
- package/tools/cli/installers/lib/ide/cline.js +0 -272
- package/tools/cli/installers/lib/ide/crush.js +0 -149
- package/tools/cli/installers/lib/ide/cursor.js +0 -160
- package/tools/cli/installers/lib/ide/gemini.js +0 -301
- package/tools/cli/installers/lib/ide/github-copilot.js +0 -383
- package/tools/cli/installers/lib/ide/iflow.js +0 -191
- package/tools/cli/installers/lib/ide/opencode.js +0 -257
- package/tools/cli/installers/lib/ide/qwen.js +0 -372
- package/tools/cli/installers/lib/ide/roo.js +0 -273
- package/tools/cli/installers/lib/ide/rovo-dev.js +0 -290
- package/tools/cli/installers/lib/ide/trae.js +0 -313
- package/tools/cli/installers/lib/ide/windsurf.js +0 -258
|
@@ -1,290 +0,0 @@
|
|
|
1
|
-
const path = require('node:path');
|
|
2
|
-
const fs = require('fs-extra');
|
|
3
|
-
const chalk = require('chalk');
|
|
4
|
-
const { BaseIdeSetup } = require('./_base-ide');
|
|
5
|
-
const { AgentCommandGenerator } = require('./shared/agent-command-generator');
|
|
6
|
-
const { WorkflowCommandGenerator } = require('./shared/workflow-command-generator');
|
|
7
|
-
const { TaskToolCommandGenerator } = require('./shared/task-tool-command-generator');
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Rovo Dev IDE setup handler
|
|
11
|
-
*
|
|
12
|
-
* Installs BMAD agents as Rovo Dev subagents in .rovodev/subagents/
|
|
13
|
-
* Installs workflows and tasks/tools as reference guides in .rovodev/
|
|
14
|
-
* Rovo Dev automatically discovers agents and integrates with BMAD like other IDEs
|
|
15
|
-
*/
|
|
16
|
-
class RovoDevSetup extends BaseIdeSetup {
|
|
17
|
-
constructor() {
|
|
18
|
-
super('rovo-dev', 'Atlassian Rovo Dev', false);
|
|
19
|
-
this.configDir = '.rovodev';
|
|
20
|
-
this.subagentsDir = 'subagents';
|
|
21
|
-
this.workflowsDir = 'workflows';
|
|
22
|
-
this.referencesDir = 'references';
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Cleanup old BMAD installation before reinstalling
|
|
27
|
-
* @param {string} projectDir - Project directory
|
|
28
|
-
*/
|
|
29
|
-
async cleanup(projectDir) {
|
|
30
|
-
const rovoDevDir = path.join(projectDir, this.configDir);
|
|
31
|
-
|
|
32
|
-
if (!(await fs.pathExists(rovoDevDir))) {
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// Clean BMAD agents from subagents directory
|
|
37
|
-
const subagentsDir = path.join(rovoDevDir, this.subagentsDir);
|
|
38
|
-
if (await fs.pathExists(subagentsDir)) {
|
|
39
|
-
const entries = await fs.readdir(subagentsDir);
|
|
40
|
-
const bmadFiles = entries.filter((file) => file.startsWith('bmad') && file.endsWith('.md'));
|
|
41
|
-
|
|
42
|
-
for (const file of bmadFiles) {
|
|
43
|
-
await fs.remove(path.join(subagentsDir, file));
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// Clean BMAD workflows from workflows directory
|
|
48
|
-
const workflowsDir = path.join(rovoDevDir, this.workflowsDir);
|
|
49
|
-
if (await fs.pathExists(workflowsDir)) {
|
|
50
|
-
const entries = await fs.readdir(workflowsDir);
|
|
51
|
-
const bmadFiles = entries.filter((file) => file.startsWith('bmad') && file.endsWith('.md'));
|
|
52
|
-
|
|
53
|
-
for (const file of bmadFiles) {
|
|
54
|
-
await fs.remove(path.join(workflowsDir, file));
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Clean BMAD tasks/tools from references directory
|
|
59
|
-
const referencesDir = path.join(rovoDevDir, this.referencesDir);
|
|
60
|
-
if (await fs.pathExists(referencesDir)) {
|
|
61
|
-
const entries = await fs.readdir(referencesDir);
|
|
62
|
-
const bmadFiles = entries.filter((file) => file.startsWith('bmad') && file.endsWith('.md'));
|
|
63
|
-
|
|
64
|
-
for (const file of bmadFiles) {
|
|
65
|
-
await fs.remove(path.join(referencesDir, file));
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Setup Rovo Dev configuration
|
|
72
|
-
* @param {string} projectDir - Project directory
|
|
73
|
-
* @param {string} bmadDir - BMAD installation directory
|
|
74
|
-
* @param {Object} options - Setup options
|
|
75
|
-
*/
|
|
76
|
-
async setup(projectDir, bmadDir, options = {}) {
|
|
77
|
-
console.log(chalk.cyan(`Setting up ${this.name}...`));
|
|
78
|
-
|
|
79
|
-
// Clean up old BMAD installation first
|
|
80
|
-
await this.cleanup(projectDir);
|
|
81
|
-
|
|
82
|
-
// Create .rovodev directory structure
|
|
83
|
-
const rovoDevDir = path.join(projectDir, this.configDir);
|
|
84
|
-
const subagentsDir = path.join(rovoDevDir, this.subagentsDir);
|
|
85
|
-
const workflowsDir = path.join(rovoDevDir, this.workflowsDir);
|
|
86
|
-
const referencesDir = path.join(rovoDevDir, this.referencesDir);
|
|
87
|
-
|
|
88
|
-
await this.ensureDir(subagentsDir);
|
|
89
|
-
await this.ensureDir(workflowsDir);
|
|
90
|
-
await this.ensureDir(referencesDir);
|
|
91
|
-
|
|
92
|
-
// Generate and install agents
|
|
93
|
-
const agentGen = new AgentCommandGenerator(this.bmadFolderName);
|
|
94
|
-
const { artifacts: agentArtifacts } = await agentGen.collectAgentArtifacts(bmadDir, options.selectedModules || []);
|
|
95
|
-
|
|
96
|
-
let agentCount = 0;
|
|
97
|
-
for (const artifact of agentArtifacts) {
|
|
98
|
-
const subagentFilename = `bmad-${artifact.module}-${artifact.name}.md`;
|
|
99
|
-
const targetPath = path.join(subagentsDir, subagentFilename);
|
|
100
|
-
const subagentContent = this.convertToRovoDevSubagent(artifact.content, artifact.name, artifact.module);
|
|
101
|
-
await this.writeFile(targetPath, subagentContent);
|
|
102
|
-
agentCount++;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Generate and install workflows
|
|
106
|
-
const workflowGen = new WorkflowCommandGenerator(this.bmadFolderName);
|
|
107
|
-
const { artifacts: workflowArtifacts, counts: workflowCounts } = await workflowGen.collectWorkflowArtifacts(bmadDir);
|
|
108
|
-
|
|
109
|
-
let workflowCount = 0;
|
|
110
|
-
for (const artifact of workflowArtifacts) {
|
|
111
|
-
if (artifact.type === 'workflow-command') {
|
|
112
|
-
const workflowFilename = path.basename(artifact.relativePath);
|
|
113
|
-
const targetPath = path.join(workflowsDir, workflowFilename);
|
|
114
|
-
await this.writeFile(targetPath, artifact.content);
|
|
115
|
-
workflowCount++;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// Generate and install tasks and tools
|
|
120
|
-
const taskToolGen = new TaskToolCommandGenerator();
|
|
121
|
-
const { tasks: taskCount, tools: toolCount } = await this.generateTaskToolReferences(bmadDir, referencesDir, taskToolGen);
|
|
122
|
-
|
|
123
|
-
// Summary output
|
|
124
|
-
console.log(chalk.green(`✓ ${this.name} configured:`));
|
|
125
|
-
console.log(chalk.dim(` - ${agentCount} agents installed to .rovodev/subagents/`));
|
|
126
|
-
if (workflowCount > 0) {
|
|
127
|
-
console.log(chalk.dim(` - ${workflowCount} workflows installed to .rovodev/workflows/`));
|
|
128
|
-
}
|
|
129
|
-
if (taskCount + toolCount > 0) {
|
|
130
|
-
console.log(
|
|
131
|
-
chalk.dim(` - ${taskCount + toolCount} tasks/tools installed to .rovodev/references/ (${taskCount} tasks, ${toolCount} tools)`),
|
|
132
|
-
);
|
|
133
|
-
}
|
|
134
|
-
console.log(chalk.yellow(`\n Note: Agents are automatically discovered by Rovo Dev`));
|
|
135
|
-
console.log(chalk.dim(` - Access agents by typing @ in Rovo Dev to see available options`));
|
|
136
|
-
console.log(chalk.dim(` - Workflows and references are available in .rovodev/ directory`));
|
|
137
|
-
|
|
138
|
-
return {
|
|
139
|
-
success: true,
|
|
140
|
-
agents: agentCount,
|
|
141
|
-
workflows: workflowCount,
|
|
142
|
-
tasks: taskCount,
|
|
143
|
-
tools: toolCount,
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* Generate task and tool reference guides
|
|
149
|
-
* @param {string} bmadDir - BMAD directory
|
|
150
|
-
* @param {string} referencesDir - References directory
|
|
151
|
-
* @param {TaskToolCommandGenerator} taskToolGen - Generator instance
|
|
152
|
-
*/
|
|
153
|
-
async generateTaskToolReferences(bmadDir, referencesDir, taskToolGen) {
|
|
154
|
-
const tasks = await taskToolGen.loadTaskManifest(bmadDir);
|
|
155
|
-
const tools = await taskToolGen.loadToolManifest(bmadDir);
|
|
156
|
-
|
|
157
|
-
const standaloneTasks = tasks ? tasks.filter((t) => t.standalone === 'true' || t.standalone === true) : [];
|
|
158
|
-
const standaloneTools = tools ? tools.filter((t) => t.standalone === 'true' || t.standalone === true) : [];
|
|
159
|
-
|
|
160
|
-
let taskCount = 0;
|
|
161
|
-
for (const task of standaloneTasks) {
|
|
162
|
-
const commandContent = taskToolGen.generateCommandContent(task, 'task');
|
|
163
|
-
const targetPath = path.join(referencesDir, `bmad-task-${task.module}-${task.name}.md`);
|
|
164
|
-
await this.writeFile(targetPath, commandContent);
|
|
165
|
-
taskCount++;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
let toolCount = 0;
|
|
169
|
-
for (const tool of standaloneTools) {
|
|
170
|
-
const commandContent = taskToolGen.generateCommandContent(tool, 'tool');
|
|
171
|
-
const targetPath = path.join(referencesDir, `bmad-tool-${tool.module}-${tool.name}.md`);
|
|
172
|
-
await this.writeFile(targetPath, commandContent);
|
|
173
|
-
toolCount++;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
return { tasks: taskCount, tools: toolCount };
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Convert BMAD agent launcher to Rovo Dev subagent format
|
|
181
|
-
*
|
|
182
|
-
* Rovo Dev subagents use Markdown files with YAML frontmatter containing:
|
|
183
|
-
* - name: Unique identifier for the subagent
|
|
184
|
-
* - description: One-line description of the subagent's purpose
|
|
185
|
-
* - tools: Array of tools the subagent can use (optional)
|
|
186
|
-
* - model: Specific model for this subagent (optional)
|
|
187
|
-
* - load_memory: Whether to load memory files (optional, defaults to true)
|
|
188
|
-
*
|
|
189
|
-
* @param {string} launcherContent - Original agent launcher content
|
|
190
|
-
* @param {string} agentName - Name of the agent
|
|
191
|
-
* @param {string} moduleName - Name of the module
|
|
192
|
-
* @returns {string} Rovo Dev subagent-formatted content
|
|
193
|
-
*/
|
|
194
|
-
convertToRovoDevSubagent(launcherContent, agentName, moduleName) {
|
|
195
|
-
// Extract metadata from the launcher XML
|
|
196
|
-
const titleMatch = launcherContent.match(/title="([^"]+)"/);
|
|
197
|
-
const title = titleMatch ? titleMatch[1] : this.formatTitle(agentName);
|
|
198
|
-
|
|
199
|
-
const descriptionMatch = launcherContent.match(/description="([^"]+)"/);
|
|
200
|
-
const description = descriptionMatch ? descriptionMatch[1] : `BMAD agent: ${title}`;
|
|
201
|
-
|
|
202
|
-
const roleDefinitionMatch = launcherContent.match(/roleDefinition="([^"]+)"/);
|
|
203
|
-
const roleDefinition = roleDefinitionMatch ? roleDefinitionMatch[1] : `You are a specialized agent for ${title.toLowerCase()} tasks.`;
|
|
204
|
-
|
|
205
|
-
// Extract the main system prompt from the launcher (content after closing tags)
|
|
206
|
-
let systemPrompt = roleDefinition;
|
|
207
|
-
|
|
208
|
-
// Try to extract additional instructions from the launcher content
|
|
209
|
-
const instructionsMatch = launcherContent.match(/<instructions>([\s\S]*?)<\/instructions>/);
|
|
210
|
-
if (instructionsMatch) {
|
|
211
|
-
systemPrompt += '\n\n' + instructionsMatch[1].trim();
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
// Build YAML frontmatter for Rovo Dev subagent
|
|
215
|
-
const frontmatter = {
|
|
216
|
-
name: `bmad-${moduleName}-${agentName}`,
|
|
217
|
-
description: description,
|
|
218
|
-
// Note: tools and model can be added by users in their .rovodev/subagents/*.md files
|
|
219
|
-
// We don't enforce specific tools since BMAD agents are flexible
|
|
220
|
-
};
|
|
221
|
-
|
|
222
|
-
// Create YAML frontmatter string with proper quoting for special characters
|
|
223
|
-
let yamlContent = '---\n';
|
|
224
|
-
yamlContent += `name: ${frontmatter.name}\n`;
|
|
225
|
-
// Quote description to handle colons and other special characters in YAML
|
|
226
|
-
yamlContent += `description: "${frontmatter.description.replaceAll('"', String.raw`\"`)}"\n`;
|
|
227
|
-
yamlContent += '---\n';
|
|
228
|
-
|
|
229
|
-
// Combine frontmatter with system prompt
|
|
230
|
-
const subagentContent = yamlContent + systemPrompt;
|
|
231
|
-
|
|
232
|
-
return subagentContent;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
/**
|
|
236
|
-
* Detect whether Rovo Dev is already configured in the project
|
|
237
|
-
* @param {string} projectDir - Project directory
|
|
238
|
-
* @returns {boolean}
|
|
239
|
-
*/
|
|
240
|
-
async detect(projectDir) {
|
|
241
|
-
const rovoDevDir = path.join(projectDir, this.configDir);
|
|
242
|
-
|
|
243
|
-
if (!(await fs.pathExists(rovoDevDir))) {
|
|
244
|
-
return false;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
// Check for BMAD agents in subagents directory
|
|
248
|
-
const subagentsDir = path.join(rovoDevDir, this.subagentsDir);
|
|
249
|
-
if (await fs.pathExists(subagentsDir)) {
|
|
250
|
-
try {
|
|
251
|
-
const entries = await fs.readdir(subagentsDir);
|
|
252
|
-
if (entries.some((entry) => entry.startsWith('bmad') && entry.endsWith('.md'))) {
|
|
253
|
-
return true;
|
|
254
|
-
}
|
|
255
|
-
} catch {
|
|
256
|
-
// Continue checking other directories
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
// Check for BMAD workflows in workflows directory
|
|
261
|
-
const workflowsDir = path.join(rovoDevDir, this.workflowsDir);
|
|
262
|
-
if (await fs.pathExists(workflowsDir)) {
|
|
263
|
-
try {
|
|
264
|
-
const entries = await fs.readdir(workflowsDir);
|
|
265
|
-
if (entries.some((entry) => entry.startsWith('bmad') && entry.endsWith('.md'))) {
|
|
266
|
-
return true;
|
|
267
|
-
}
|
|
268
|
-
} catch {
|
|
269
|
-
// Continue checking other directories
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
// Check for BMAD tasks/tools in references directory
|
|
274
|
-
const referencesDir = path.join(rovoDevDir, this.referencesDir);
|
|
275
|
-
if (await fs.pathExists(referencesDir)) {
|
|
276
|
-
try {
|
|
277
|
-
const entries = await fs.readdir(referencesDir);
|
|
278
|
-
if (entries.some((entry) => entry.startsWith('bmad') && entry.endsWith('.md'))) {
|
|
279
|
-
return true;
|
|
280
|
-
}
|
|
281
|
-
} catch {
|
|
282
|
-
// Continue
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
return false;
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
module.exports = { RovoDevSetup };
|
|
@@ -1,313 +0,0 @@
|
|
|
1
|
-
const path = require('node:path');
|
|
2
|
-
const fs = require('fs-extra');
|
|
3
|
-
const { BaseIdeSetup } = require('./_base-ide');
|
|
4
|
-
const chalk = require('chalk');
|
|
5
|
-
const { AgentCommandGenerator } = require('./shared/agent-command-generator');
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Trae IDE setup handler
|
|
9
|
-
*/
|
|
10
|
-
class TraeSetup extends BaseIdeSetup {
|
|
11
|
-
constructor() {
|
|
12
|
-
super('trae', 'Trae');
|
|
13
|
-
this.configDir = '.trae';
|
|
14
|
-
this.rulesDir = 'rules';
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Setup Trae IDE configuration
|
|
19
|
-
* @param {string} projectDir - Project directory
|
|
20
|
-
* @param {string} bmadDir - BMAD installation directory
|
|
21
|
-
* @param {Object} options - Setup options
|
|
22
|
-
*/
|
|
23
|
-
async setup(projectDir, bmadDir, options = {}) {
|
|
24
|
-
console.log(chalk.cyan(`Setting up ${this.name}...`));
|
|
25
|
-
|
|
26
|
-
// Create .trae/rules directory
|
|
27
|
-
const traeDir = path.join(projectDir, this.configDir);
|
|
28
|
-
const rulesDir = path.join(traeDir, this.rulesDir);
|
|
29
|
-
|
|
30
|
-
await this.ensureDir(rulesDir);
|
|
31
|
-
|
|
32
|
-
// Clean up any existing BMAD files before reinstalling
|
|
33
|
-
await this.cleanup(projectDir);
|
|
34
|
-
|
|
35
|
-
// Generate agent launchers
|
|
36
|
-
const agentGen = new AgentCommandGenerator(this.bmadFolderName);
|
|
37
|
-
const { artifacts: agentArtifacts } = await agentGen.collectAgentArtifacts(bmadDir, options.selectedModules || []);
|
|
38
|
-
|
|
39
|
-
// Get tasks, tools, and workflows (standalone only)
|
|
40
|
-
const tasks = await this.getTasks(bmadDir, true);
|
|
41
|
-
const tools = await this.getTools(bmadDir, true);
|
|
42
|
-
const workflows = await this.getWorkflows(bmadDir, true);
|
|
43
|
-
|
|
44
|
-
// Process agents as rules with bmad- prefix
|
|
45
|
-
let agentCount = 0;
|
|
46
|
-
for (const artifact of agentArtifacts) {
|
|
47
|
-
const processedContent = await this.createAgentRule(artifact, bmadDir, projectDir);
|
|
48
|
-
|
|
49
|
-
// Use bmad- prefix: bmad-agent-{module}-{name}.md
|
|
50
|
-
const targetPath = path.join(rulesDir, `bmad-agent-${artifact.module}-${artifact.name}.md`);
|
|
51
|
-
await this.writeFile(targetPath, processedContent);
|
|
52
|
-
agentCount++;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Process tasks as rules with bmad- prefix
|
|
56
|
-
let taskCount = 0;
|
|
57
|
-
for (const task of tasks) {
|
|
58
|
-
const content = await this.readFile(task.path);
|
|
59
|
-
const processedContent = this.createTaskRule(task, content);
|
|
60
|
-
|
|
61
|
-
// Use bmad- prefix: bmad-task-{module}-{name}.md
|
|
62
|
-
const targetPath = path.join(rulesDir, `bmad-task-${task.module}-${task.name}.md`);
|
|
63
|
-
await this.writeFile(targetPath, processedContent);
|
|
64
|
-
taskCount++;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// Process tools as rules with bmad- prefix
|
|
68
|
-
let toolCount = 0;
|
|
69
|
-
for (const tool of tools) {
|
|
70
|
-
const content = await this.readFile(tool.path);
|
|
71
|
-
const processedContent = this.createToolRule(tool, content);
|
|
72
|
-
|
|
73
|
-
// Use bmad- prefix: bmad-tool-{module}-{name}.md
|
|
74
|
-
const targetPath = path.join(rulesDir, `bmad-tool-${tool.module}-${tool.name}.md`);
|
|
75
|
-
await this.writeFile(targetPath, processedContent);
|
|
76
|
-
toolCount++;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// Process workflows as rules with bmad- prefix
|
|
80
|
-
let workflowCount = 0;
|
|
81
|
-
for (const workflow of workflows) {
|
|
82
|
-
const content = await this.readFile(workflow.path);
|
|
83
|
-
const processedContent = this.createWorkflowRule(workflow, content);
|
|
84
|
-
|
|
85
|
-
// Use bmad- prefix: bmad-workflow-{module}-{name}.md
|
|
86
|
-
const targetPath = path.join(rulesDir, `bmad-workflow-${workflow.module}-${workflow.name}.md`);
|
|
87
|
-
await this.writeFile(targetPath, processedContent);
|
|
88
|
-
workflowCount++;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const totalRules = agentCount + taskCount + toolCount + workflowCount;
|
|
92
|
-
|
|
93
|
-
console.log(chalk.green(`✓ ${this.name} configured:`));
|
|
94
|
-
console.log(chalk.dim(` - ${agentCount} agent rules created`));
|
|
95
|
-
console.log(chalk.dim(` - ${taskCount} task rules created`));
|
|
96
|
-
console.log(chalk.dim(` - ${toolCount} tool rules created`));
|
|
97
|
-
console.log(chalk.dim(` - ${workflowCount} workflow rules created`));
|
|
98
|
-
console.log(chalk.dim(` - Total: ${totalRules} rules`));
|
|
99
|
-
console.log(chalk.dim(` - Rules directory: ${path.relative(projectDir, rulesDir)}`));
|
|
100
|
-
console.log(chalk.dim(` - Agents can be activated with @{agent-name}`));
|
|
101
|
-
|
|
102
|
-
return {
|
|
103
|
-
success: true,
|
|
104
|
-
rules: totalRules,
|
|
105
|
-
agents: agentCount,
|
|
106
|
-
tasks: taskCount,
|
|
107
|
-
tools: toolCount,
|
|
108
|
-
workflows: workflowCount,
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Create rule content for an agent
|
|
114
|
-
*/
|
|
115
|
-
async createAgentRule(artifact, bmadDir, projectDir) {
|
|
116
|
-
// Strip frontmatter from launcher
|
|
117
|
-
const frontmatterRegex = /^---\s*\n[\s\S]*?\n---\s*\n/;
|
|
118
|
-
const contentWithoutFrontmatter = artifact.content.replace(frontmatterRegex, '').trim();
|
|
119
|
-
|
|
120
|
-
// Extract metadata from launcher content
|
|
121
|
-
const titleMatch = artifact.content.match(/description:\s*"([^"]+)"/);
|
|
122
|
-
const title = titleMatch ? titleMatch[1] : this.formatTitle(artifact.name);
|
|
123
|
-
|
|
124
|
-
// Calculate relative path for reference
|
|
125
|
-
const relativePath = path.relative(projectDir, artifact.sourcePath).replaceAll('\\', '/');
|
|
126
|
-
|
|
127
|
-
let ruleContent = `# ${title} Agent Rule
|
|
128
|
-
|
|
129
|
-
This rule is triggered when the user types \`@${artifact.name}\` and activates the ${title} agent persona.
|
|
130
|
-
|
|
131
|
-
## Agent Activation
|
|
132
|
-
|
|
133
|
-
${contentWithoutFrontmatter}
|
|
134
|
-
|
|
135
|
-
## File Reference
|
|
136
|
-
|
|
137
|
-
The full agent definition is located at: \`${relativePath}\`
|
|
138
|
-
`;
|
|
139
|
-
|
|
140
|
-
return ruleContent;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Create rule content for a task
|
|
145
|
-
*/
|
|
146
|
-
createTaskRule(task, content) {
|
|
147
|
-
// Extract task name from content
|
|
148
|
-
const nameMatch = content.match(/name="([^"]+)"/);
|
|
149
|
-
const taskName = nameMatch ? nameMatch[1] : this.formatTitle(task.name);
|
|
150
|
-
|
|
151
|
-
let ruleContent = `# ${taskName} Task Rule
|
|
152
|
-
|
|
153
|
-
This rule defines the ${taskName} task workflow.
|
|
154
|
-
|
|
155
|
-
## Task Definition
|
|
156
|
-
|
|
157
|
-
When this task is triggered, execute the following workflow:
|
|
158
|
-
|
|
159
|
-
${content}
|
|
160
|
-
|
|
161
|
-
## Usage
|
|
162
|
-
|
|
163
|
-
Reference this task with \`@task-${task.name}\` to execute the defined workflow.
|
|
164
|
-
|
|
165
|
-
## Module
|
|
166
|
-
|
|
167
|
-
Part of the BMAD ${task.module.toUpperCase()} module.
|
|
168
|
-
`;
|
|
169
|
-
|
|
170
|
-
return ruleContent;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* Create rule content for a tool
|
|
175
|
-
*/
|
|
176
|
-
createToolRule(tool, content) {
|
|
177
|
-
// Extract tool name from content
|
|
178
|
-
const nameMatch = content.match(/name="([^"]+)"/);
|
|
179
|
-
const toolName = nameMatch ? nameMatch[1] : this.formatTitle(tool.name);
|
|
180
|
-
|
|
181
|
-
let ruleContent = `# ${toolName} Tool Rule
|
|
182
|
-
|
|
183
|
-
This rule defines the ${toolName} tool.
|
|
184
|
-
|
|
185
|
-
## Tool Definition
|
|
186
|
-
|
|
187
|
-
When this tool is triggered, execute the following:
|
|
188
|
-
|
|
189
|
-
${content}
|
|
190
|
-
|
|
191
|
-
## Usage
|
|
192
|
-
|
|
193
|
-
Reference this tool with \`@tool-${tool.name}\` to execute it.
|
|
194
|
-
|
|
195
|
-
## Module
|
|
196
|
-
|
|
197
|
-
Part of the BMAD ${tool.module.toUpperCase()} module.
|
|
198
|
-
`;
|
|
199
|
-
|
|
200
|
-
return ruleContent;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Create rule content for a workflow
|
|
205
|
-
*/
|
|
206
|
-
createWorkflowRule(workflow, content) {
|
|
207
|
-
let ruleContent = `# ${workflow.name} Workflow Rule
|
|
208
|
-
|
|
209
|
-
This rule defines the ${workflow.name} workflow.
|
|
210
|
-
|
|
211
|
-
## Workflow Description
|
|
212
|
-
|
|
213
|
-
${workflow.description || 'No description provided'}
|
|
214
|
-
|
|
215
|
-
## Workflow Definition
|
|
216
|
-
|
|
217
|
-
${content}
|
|
218
|
-
|
|
219
|
-
## Usage
|
|
220
|
-
|
|
221
|
-
Reference this workflow with \`@workflow-${workflow.name}\` to execute the guided workflow.
|
|
222
|
-
|
|
223
|
-
## Module
|
|
224
|
-
|
|
225
|
-
Part of the BMAD ${workflow.module.toUpperCase()} module.
|
|
226
|
-
`;
|
|
227
|
-
|
|
228
|
-
return ruleContent;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
/**
|
|
232
|
-
* Format agent/task name as title
|
|
233
|
-
*/
|
|
234
|
-
formatTitle(name) {
|
|
235
|
-
return name
|
|
236
|
-
.split('-')
|
|
237
|
-
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
238
|
-
.join(' ');
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
/**
|
|
242
|
-
* Cleanup Trae configuration - surgically remove only BMAD files
|
|
243
|
-
*/
|
|
244
|
-
async cleanup(projectDir) {
|
|
245
|
-
const fs = require('fs-extra');
|
|
246
|
-
const rulesPath = path.join(projectDir, this.configDir, this.rulesDir);
|
|
247
|
-
|
|
248
|
-
if (await fs.pathExists(rulesPath)) {
|
|
249
|
-
// Remove any bmad* files (cleans up old bmad- and bmad: formats)
|
|
250
|
-
const files = await fs.readdir(rulesPath);
|
|
251
|
-
let removed = 0;
|
|
252
|
-
|
|
253
|
-
for (const file of files) {
|
|
254
|
-
if (file.startsWith('bmad') && file.endsWith('.md')) {
|
|
255
|
-
await fs.remove(path.join(rulesPath, file));
|
|
256
|
-
removed++;
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
if (removed > 0) {
|
|
261
|
-
console.log(chalk.dim(` Cleaned up ${removed} existing BMAD rules`));
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
/**
|
|
267
|
-
* Install a custom agent launcher for Trae
|
|
268
|
-
* @param {string} projectDir - Project directory
|
|
269
|
-
* @param {string} agentName - Agent name (e.g., "fred-commit-poet")
|
|
270
|
-
* @param {string} agentPath - Path to compiled agent (relative to project root)
|
|
271
|
-
* @param {Object} metadata - Agent metadata
|
|
272
|
-
* @returns {Object} Installation result
|
|
273
|
-
*/
|
|
274
|
-
async installCustomAgentLauncher(projectDir, agentName, agentPath, metadata) {
|
|
275
|
-
const traeDir = path.join(projectDir, this.configDir);
|
|
276
|
-
const rulesDir = path.join(traeDir, this.rulesDir);
|
|
277
|
-
|
|
278
|
-
// Create .trae/rules directory if it doesn't exist
|
|
279
|
-
await fs.ensureDir(rulesDir);
|
|
280
|
-
|
|
281
|
-
// Create custom agent launcher
|
|
282
|
-
const launcherContent = `# ${agentName} Custom Agent
|
|
283
|
-
|
|
284
|
-
**⚠️ IMPORTANT**: Run @${agentPath} first to load the complete agent!
|
|
285
|
-
|
|
286
|
-
This is a launcher for the custom BMAD agent "${agentName}".
|
|
287
|
-
|
|
288
|
-
## Usage
|
|
289
|
-
1. First run: \`${agentPath}\` to load the complete agent
|
|
290
|
-
2. Then use this rule to activate ${agentName}
|
|
291
|
-
|
|
292
|
-
The agent will follow the persona and instructions from the main agent file.
|
|
293
|
-
|
|
294
|
-
---
|
|
295
|
-
|
|
296
|
-
*Generated by BMAD Method*`;
|
|
297
|
-
|
|
298
|
-
const fileName = `bmad-agent-custom-${agentName.toLowerCase()}.md`;
|
|
299
|
-
const launcherPath = path.join(rulesDir, fileName);
|
|
300
|
-
|
|
301
|
-
// Write the launcher file
|
|
302
|
-
await fs.writeFile(launcherPath, launcherContent, 'utf8');
|
|
303
|
-
|
|
304
|
-
return {
|
|
305
|
-
ide: 'trae',
|
|
306
|
-
path: path.relative(projectDir, launcherPath),
|
|
307
|
-
command: agentName,
|
|
308
|
-
type: 'custom-agent-launcher',
|
|
309
|
-
};
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
module.exports = { TraeSetup };
|