bmad-method 6.0.0-Beta.0 → 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/install-messages.yaml +11 -10
- 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,272 +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 { WorkflowCommandGenerator } = require('./shared/workflow-command-generator');
|
|
6
|
-
const { AgentCommandGenerator } = require('./shared/agent-command-generator');
|
|
7
|
-
const { TaskToolCommandGenerator } = require('./shared/task-tool-command-generator');
|
|
8
|
-
const { getAgentsFromBmad, getTasksFromBmad } = require('./shared/bmad-artifacts');
|
|
9
|
-
const { toDashPath, customAgentDashName } = require('./shared/path-utils');
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Cline IDE setup handler
|
|
13
|
-
* Installs BMAD artifacts to .clinerules/workflows with flattened naming
|
|
14
|
-
*/
|
|
15
|
-
class ClineSetup extends BaseIdeSetup {
|
|
16
|
-
constructor() {
|
|
17
|
-
super('cline', 'Cline', false);
|
|
18
|
-
this.configDir = '.clinerules';
|
|
19
|
-
this.workflowsDir = 'workflows';
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Setup Cline IDE configuration
|
|
24
|
-
* @param {string} projectDir - Project directory
|
|
25
|
-
* @param {string} bmadDir - BMAD installation directory
|
|
26
|
-
* @param {Object} options - Setup options
|
|
27
|
-
*/
|
|
28
|
-
async setup(projectDir, bmadDir, options = {}) {
|
|
29
|
-
console.log(chalk.cyan(`Setting up ${this.name}...`));
|
|
30
|
-
|
|
31
|
-
// Create .clinerules/workflows directory
|
|
32
|
-
const clineDir = path.join(projectDir, this.configDir);
|
|
33
|
-
const workflowsDir = path.join(clineDir, this.workflowsDir);
|
|
34
|
-
|
|
35
|
-
await this.ensureDir(workflowsDir);
|
|
36
|
-
|
|
37
|
-
// Clear old BMAD files
|
|
38
|
-
await this.clearOldBmadFiles(workflowsDir);
|
|
39
|
-
|
|
40
|
-
// Collect all artifacts
|
|
41
|
-
const { artifacts, counts } = await this.collectClineArtifacts(projectDir, bmadDir, options);
|
|
42
|
-
|
|
43
|
-
// Write flattened files
|
|
44
|
-
const written = await this.flattenAndWriteArtifacts(artifacts, workflowsDir);
|
|
45
|
-
|
|
46
|
-
console.log(chalk.green(`✓ ${this.name} configured:`));
|
|
47
|
-
console.log(chalk.dim(` - ${counts.agents} agents installed`));
|
|
48
|
-
console.log(chalk.dim(` - ${counts.tasks} tasks installed`));
|
|
49
|
-
console.log(chalk.dim(` - ${counts.workflows} workflow commands installed`));
|
|
50
|
-
if (counts.workflowLaunchers > 0) {
|
|
51
|
-
console.log(chalk.dim(` - ${counts.workflowLaunchers} workflow launchers installed`));
|
|
52
|
-
}
|
|
53
|
-
console.log(chalk.dim(` - ${written} files written to ${path.relative(projectDir, workflowsDir)}`));
|
|
54
|
-
|
|
55
|
-
// Usage instructions
|
|
56
|
-
console.log(chalk.yellow('\n ⚠️ How to Use Cline Workflows'));
|
|
57
|
-
console.log(chalk.cyan(' BMAD workflows are available as slash commands in Cline'));
|
|
58
|
-
console.log(chalk.dim(' Usage:'));
|
|
59
|
-
console.log(chalk.dim(' - Type / to see available commands'));
|
|
60
|
-
console.log(chalk.dim(' - All BMAD items start with "bmad_"'));
|
|
61
|
-
console.log(chalk.dim(' - Example: /bmad_bmm_pm'));
|
|
62
|
-
|
|
63
|
-
return {
|
|
64
|
-
success: true,
|
|
65
|
-
agents: counts.agents,
|
|
66
|
-
tasks: counts.tasks,
|
|
67
|
-
workflows: counts.workflows,
|
|
68
|
-
workflowLaunchers: counts.workflowLaunchers,
|
|
69
|
-
written,
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Detect Cline installation by checking for .clinerules/workflows directory
|
|
75
|
-
*/
|
|
76
|
-
async detect(projectDir) {
|
|
77
|
-
const workflowsDir = path.join(projectDir, this.configDir, this.workflowsDir);
|
|
78
|
-
|
|
79
|
-
if (!(await fs.pathExists(workflowsDir))) {
|
|
80
|
-
return false;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const entries = await fs.readdir(workflowsDir);
|
|
84
|
-
return entries.some((entry) => entry.startsWith('bmad'));
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Collect all artifacts for Cline export
|
|
89
|
-
*/
|
|
90
|
-
async collectClineArtifacts(projectDir, bmadDir, options = {}) {
|
|
91
|
-
const selectedModules = options.selectedModules || [];
|
|
92
|
-
const artifacts = [];
|
|
93
|
-
|
|
94
|
-
// Generate agent launchers
|
|
95
|
-
const agentGen = new AgentCommandGenerator(this.bmadFolderName);
|
|
96
|
-
const { artifacts: agentArtifacts } = await agentGen.collectAgentArtifacts(bmadDir, selectedModules);
|
|
97
|
-
|
|
98
|
-
// Process agent launchers with project-specific paths
|
|
99
|
-
for (const agentArtifact of agentArtifacts) {
|
|
100
|
-
const content = agentArtifact.content;
|
|
101
|
-
|
|
102
|
-
artifacts.push({
|
|
103
|
-
type: 'agent',
|
|
104
|
-
module: agentArtifact.module,
|
|
105
|
-
sourcePath: agentArtifact.sourcePath,
|
|
106
|
-
relativePath: agentArtifact.relativePath,
|
|
107
|
-
content,
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// Get tasks
|
|
112
|
-
const tasks = await getTasksFromBmad(bmadDir, selectedModules);
|
|
113
|
-
for (const task of tasks) {
|
|
114
|
-
const content = await this.readAndProcessWithProject(
|
|
115
|
-
task.path,
|
|
116
|
-
{
|
|
117
|
-
module: task.module,
|
|
118
|
-
name: task.name,
|
|
119
|
-
},
|
|
120
|
-
projectDir,
|
|
121
|
-
);
|
|
122
|
-
|
|
123
|
-
artifacts.push({
|
|
124
|
-
type: 'task',
|
|
125
|
-
module: task.module,
|
|
126
|
-
sourcePath: task.path,
|
|
127
|
-
relativePath: path.join(task.module, 'tasks', `${task.name}.md`),
|
|
128
|
-
content,
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// Get workflows
|
|
133
|
-
const workflowGenerator = new WorkflowCommandGenerator(this.bmadFolderName);
|
|
134
|
-
const { artifacts: workflowArtifacts, counts: workflowCounts } = await workflowGenerator.collectWorkflowArtifacts(bmadDir);
|
|
135
|
-
artifacts.push(...workflowArtifacts);
|
|
136
|
-
|
|
137
|
-
return {
|
|
138
|
-
artifacts,
|
|
139
|
-
counts: {
|
|
140
|
-
agents: agentArtifacts.length,
|
|
141
|
-
tasks: tasks.length,
|
|
142
|
-
workflows: workflowCounts.commands,
|
|
143
|
-
workflowLaunchers: workflowCounts.launchers,
|
|
144
|
-
},
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* Flatten file path to bmad_module_type_name.md format
|
|
150
|
-
* Uses shared toDashPath utility
|
|
151
|
-
*/
|
|
152
|
-
flattenFilename(relativePath) {
|
|
153
|
-
return toDashPath(relativePath);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* Write all artifacts with flattened names
|
|
158
|
-
*/
|
|
159
|
-
async flattenAndWriteArtifacts(artifacts, destDir) {
|
|
160
|
-
let written = 0;
|
|
161
|
-
|
|
162
|
-
for (const artifact of artifacts) {
|
|
163
|
-
const flattenedName = this.flattenFilename(artifact.relativePath);
|
|
164
|
-
const targetPath = path.join(destDir, flattenedName);
|
|
165
|
-
await fs.writeFile(targetPath, artifact.content);
|
|
166
|
-
written++;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
return written;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Clear old BMAD files from the workflows directory
|
|
174
|
-
*/
|
|
175
|
-
async clearOldBmadFiles(destDir) {
|
|
176
|
-
if (!(await fs.pathExists(destDir))) {
|
|
177
|
-
return;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
const entries = await fs.readdir(destDir);
|
|
181
|
-
|
|
182
|
-
for (const entry of entries) {
|
|
183
|
-
if (!entry.startsWith('bmad')) {
|
|
184
|
-
continue;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
const entryPath = path.join(destDir, entry);
|
|
188
|
-
const stat = await fs.stat(entryPath);
|
|
189
|
-
if (stat.isFile()) {
|
|
190
|
-
await fs.remove(entryPath);
|
|
191
|
-
} else if (stat.isDirectory()) {
|
|
192
|
-
await fs.remove(entryPath);
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* Read and process file with project-specific paths
|
|
199
|
-
*/
|
|
200
|
-
async readAndProcessWithProject(filePath, metadata, projectDir) {
|
|
201
|
-
const content = await fs.readFile(filePath, 'utf8');
|
|
202
|
-
return super.processContent(content, metadata, projectDir);
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* Cleanup Cline configuration
|
|
207
|
-
*/
|
|
208
|
-
async cleanup(projectDir) {
|
|
209
|
-
const workflowsDir = path.join(projectDir, this.configDir, this.workflowsDir);
|
|
210
|
-
await this.clearOldBmadFiles(workflowsDir);
|
|
211
|
-
console.log(chalk.dim(`Removed ${this.name} BMAD configuration`));
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
/**
|
|
215
|
-
* Install a custom agent launcher for Cline
|
|
216
|
-
* @param {string} projectDir - Project directory
|
|
217
|
-
* @param {string} agentName - Agent name (e.g., "fred-commit-poet")
|
|
218
|
-
* @param {string} agentPath - Path to compiled agent (relative to project root)
|
|
219
|
-
* @param {Object} metadata - Agent metadata
|
|
220
|
-
* @returns {Object} Installation result
|
|
221
|
-
*/
|
|
222
|
-
async installCustomAgentLauncher(projectDir, agentName, agentPath, metadata) {
|
|
223
|
-
const clineDir = path.join(projectDir, this.configDir);
|
|
224
|
-
const workflowsDir = path.join(clineDir, this.workflowsDir);
|
|
225
|
-
|
|
226
|
-
// Create .clinerules/workflows directory if it doesn't exist
|
|
227
|
-
await fs.ensureDir(workflowsDir);
|
|
228
|
-
|
|
229
|
-
// Create custom agent launcher workflow
|
|
230
|
-
const launcherContent = `name: ${agentName}
|
|
231
|
-
description: Custom BMAD agent: ${agentName}
|
|
232
|
-
|
|
233
|
-
# ${agentName} Custom Agent
|
|
234
|
-
|
|
235
|
-
**⚠️ IMPORTANT**: Run @${agentPath} first to load the complete agent!
|
|
236
|
-
|
|
237
|
-
This is a launcher for the custom BMAD agent "${agentName}".
|
|
238
|
-
|
|
239
|
-
## Usage
|
|
240
|
-
1. First run: \`${agentPath}\` to load the complete agent
|
|
241
|
-
2. Then use this workflow as ${agentName}
|
|
242
|
-
|
|
243
|
-
The agent will follow the persona and instructions from the main agent file.
|
|
244
|
-
|
|
245
|
-
---
|
|
246
|
-
|
|
247
|
-
*Generated by BMAD Method*`;
|
|
248
|
-
|
|
249
|
-
// Use underscore format: bmad_custom_fred-commit-poet.md
|
|
250
|
-
const fileName = customAgentDashName(agentName);
|
|
251
|
-
const launcherPath = path.join(workflowsDir, fileName);
|
|
252
|
-
|
|
253
|
-
// Write the launcher file
|
|
254
|
-
await fs.writeFile(launcherPath, launcherContent, 'utf8');
|
|
255
|
-
|
|
256
|
-
return {
|
|
257
|
-
ide: 'cline',
|
|
258
|
-
path: path.relative(projectDir, launcherPath),
|
|
259
|
-
command: fileName.replace('.md', ''),
|
|
260
|
-
type: 'custom-agent-launcher',
|
|
261
|
-
};
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
/**
|
|
265
|
-
* Utility: Ensure directory exists
|
|
266
|
-
*/
|
|
267
|
-
async ensureDir(dirPath) {
|
|
268
|
-
await fs.ensureDir(dirPath);
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
module.exports = { ClineSetup };
|
|
@@ -1,149 +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
|
-
const { WorkflowCommandGenerator } = require('./shared/workflow-command-generator');
|
|
7
|
-
const { TaskToolCommandGenerator } = require('./shared/task-tool-command-generator');
|
|
8
|
-
const { customAgentColonName } = require('./shared/path-utils');
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Crush IDE setup handler
|
|
12
|
-
* Creates commands in .crush/commands/ directory structure using flat colon naming
|
|
13
|
-
*/
|
|
14
|
-
class CrushSetup extends BaseIdeSetup {
|
|
15
|
-
constructor() {
|
|
16
|
-
super('crush', 'Crush');
|
|
17
|
-
this.configDir = '.crush';
|
|
18
|
-
this.commandsDir = 'commands';
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Setup Crush IDE configuration
|
|
23
|
-
* @param {string} projectDir - Project directory
|
|
24
|
-
* @param {string} bmadDir - BMAD installation directory
|
|
25
|
-
* @param {Object} options - Setup options
|
|
26
|
-
*/
|
|
27
|
-
async setup(projectDir, bmadDir, options = {}) {
|
|
28
|
-
console.log(chalk.cyan(`Setting up ${this.name}...`));
|
|
29
|
-
|
|
30
|
-
// Clean up old BMAD installation first
|
|
31
|
-
await this.cleanup(projectDir);
|
|
32
|
-
|
|
33
|
-
// Create .crush/commands directory
|
|
34
|
-
const crushDir = path.join(projectDir, this.configDir);
|
|
35
|
-
const commandsDir = path.join(crushDir, this.commandsDir);
|
|
36
|
-
await this.ensureDir(commandsDir);
|
|
37
|
-
|
|
38
|
-
// Use underscore format: files written directly to commands dir (no bmad subfolder)
|
|
39
|
-
// Creates: .crush/commands/bmad_bmm_pm.md
|
|
40
|
-
|
|
41
|
-
// Generate agent launchers
|
|
42
|
-
const agentGen = new AgentCommandGenerator(this.bmadFolderName);
|
|
43
|
-
const { artifacts: agentArtifacts } = await agentGen.collectAgentArtifacts(bmadDir, options.selectedModules || []);
|
|
44
|
-
|
|
45
|
-
// Write agent launcher files using flat underscore naming
|
|
46
|
-
// Creates files like: bmad_bmm_pm.md
|
|
47
|
-
const agentCount = await agentGen.writeColonArtifacts(commandsDir, agentArtifacts);
|
|
48
|
-
|
|
49
|
-
// Get ALL workflows using the new workflow command generator
|
|
50
|
-
const workflowGenerator = new WorkflowCommandGenerator(this.bmadFolderName);
|
|
51
|
-
const { artifacts: workflowArtifacts } = await workflowGenerator.collectWorkflowArtifacts(bmadDir);
|
|
52
|
-
|
|
53
|
-
// Write workflow-command artifacts using flat underscore naming
|
|
54
|
-
// Creates files like: bmad_bmm_correct-course.md
|
|
55
|
-
const workflowCount = await workflowGenerator.writeColonArtifacts(commandsDir, workflowArtifacts);
|
|
56
|
-
|
|
57
|
-
// Generate task and tool commands using flat underscore naming
|
|
58
|
-
const taskToolGen = new TaskToolCommandGenerator();
|
|
59
|
-
const taskToolResult = await taskToolGen.generateColonTaskToolCommands(projectDir, bmadDir, commandsDir);
|
|
60
|
-
|
|
61
|
-
console.log(chalk.green(`✓ ${this.name} configured:`));
|
|
62
|
-
console.log(chalk.dim(` - ${agentCount} agent commands created`));
|
|
63
|
-
console.log(chalk.dim(` - ${taskToolResult.tasks} task commands created`));
|
|
64
|
-
console.log(chalk.dim(` - ${taskToolResult.tools} tool commands created`));
|
|
65
|
-
console.log(chalk.dim(` - ${workflowCount} workflow commands created`));
|
|
66
|
-
console.log(chalk.dim(` - Commands directory: ${path.relative(projectDir, commandsDir)}`));
|
|
67
|
-
console.log(chalk.dim('\n Commands can be accessed via Crush command palette'));
|
|
68
|
-
|
|
69
|
-
return {
|
|
70
|
-
success: true,
|
|
71
|
-
agents: agentCount,
|
|
72
|
-
tasks: taskToolResult.tasks || 0,
|
|
73
|
-
tools: taskToolResult.tools || 0,
|
|
74
|
-
workflows: workflowCount,
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Cleanup Crush configuration
|
|
80
|
-
*/
|
|
81
|
-
async cleanup(projectDir) {
|
|
82
|
-
const commandsDir = path.join(projectDir, this.configDir, this.commandsDir);
|
|
83
|
-
|
|
84
|
-
// Remove any bmad* files from the commands directory (cleans up old bmad: and bmad- formats)
|
|
85
|
-
if (await fs.pathExists(commandsDir)) {
|
|
86
|
-
const entries = await fs.readdir(commandsDir);
|
|
87
|
-
for (const entry of entries) {
|
|
88
|
-
if (entry.startsWith('bmad')) {
|
|
89
|
-
await fs.remove(path.join(commandsDir, entry));
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
// Also remove legacy bmad folder if it exists
|
|
94
|
-
const bmadFolder = path.join(commandsDir, 'bmad');
|
|
95
|
-
if (await fs.pathExists(bmadFolder)) {
|
|
96
|
-
await fs.remove(bmadFolder);
|
|
97
|
-
console.log(chalk.dim(`Removed BMAD commands from Crush`));
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Install a custom agent launcher for Crush
|
|
103
|
-
* @param {string} projectDir - Project directory
|
|
104
|
-
* @param {string} agentName - Agent name (e.g., "fred-commit-poet")
|
|
105
|
-
* @param {string} agentPath - Path to compiled agent (relative to project root)
|
|
106
|
-
* @param {Object} metadata - Agent metadata
|
|
107
|
-
* @returns {Object} Installation result
|
|
108
|
-
*/
|
|
109
|
-
async installCustomAgentLauncher(projectDir, agentName, agentPath, metadata) {
|
|
110
|
-
const commandsDir = path.join(projectDir, this.configDir, this.commandsDir);
|
|
111
|
-
|
|
112
|
-
// Create .crush/commands directory if it doesn't exist
|
|
113
|
-
await fs.ensureDir(commandsDir);
|
|
114
|
-
|
|
115
|
-
// Create custom agent launcher
|
|
116
|
-
const launcherContent = `# ${agentName} Custom Agent
|
|
117
|
-
|
|
118
|
-
**⚠️ IMPORTANT**: Run @${agentPath} first to load the complete agent!
|
|
119
|
-
|
|
120
|
-
This is a launcher for the custom BMAD agent "${agentName}".
|
|
121
|
-
|
|
122
|
-
## Usage
|
|
123
|
-
1. First run: \`${agentPath}\` to load the complete agent
|
|
124
|
-
2. Then use this command to activate ${agentName}
|
|
125
|
-
|
|
126
|
-
The agent will follow the persona and instructions from the main agent file.
|
|
127
|
-
|
|
128
|
-
---
|
|
129
|
-
|
|
130
|
-
*Generated by BMAD Method*`;
|
|
131
|
-
|
|
132
|
-
// Use underscore format: bmad_custom_fred-commit-poet.md
|
|
133
|
-
// Written directly to commands dir (no bmad subfolder)
|
|
134
|
-
const launcherName = customAgentColonName(agentName);
|
|
135
|
-
const launcherPath = path.join(commandsDir, launcherName);
|
|
136
|
-
|
|
137
|
-
// Write the launcher file
|
|
138
|
-
await fs.writeFile(launcherPath, launcherContent, 'utf8');
|
|
139
|
-
|
|
140
|
-
return {
|
|
141
|
-
ide: 'crush',
|
|
142
|
-
path: path.relative(projectDir, launcherPath),
|
|
143
|
-
command: launcherName.replace('.md', ''),
|
|
144
|
-
type: 'custom-agent-launcher',
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
module.exports = { CrushSetup };
|
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
const path = require('node:path');
|
|
2
|
-
const { BaseIdeSetup } = require('./_base-ide');
|
|
3
|
-
const chalk = require('chalk');
|
|
4
|
-
const { AgentCommandGenerator } = require('./shared/agent-command-generator');
|
|
5
|
-
const { WorkflowCommandGenerator } = require('./shared/workflow-command-generator');
|
|
6
|
-
const { TaskToolCommandGenerator } = require('./shared/task-tool-command-generator');
|
|
7
|
-
const { customAgentColonName } = require('./shared/path-utils');
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Cursor IDE setup handler
|
|
11
|
-
*/
|
|
12
|
-
class CursorSetup extends BaseIdeSetup {
|
|
13
|
-
constructor() {
|
|
14
|
-
super('cursor', 'Cursor', true); // preferred IDE
|
|
15
|
-
this.configDir = '.cursor';
|
|
16
|
-
this.rulesDir = 'rules';
|
|
17
|
-
this.commandsDir = 'commands';
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Cleanup old BMAD installation before reinstalling
|
|
22
|
-
* @param {string} projectDir - Project directory
|
|
23
|
-
*/
|
|
24
|
-
async cleanup(projectDir) {
|
|
25
|
-
const fs = require('fs-extra');
|
|
26
|
-
const commandsDir = path.join(projectDir, this.configDir, this.commandsDir);
|
|
27
|
-
|
|
28
|
-
// Remove any bmad* files from the commands directory (cleans up old bmad: and bmad- formats)
|
|
29
|
-
if (await fs.pathExists(commandsDir)) {
|
|
30
|
-
const entries = await fs.readdir(commandsDir);
|
|
31
|
-
for (const entry of entries) {
|
|
32
|
-
if (entry.startsWith('bmad')) {
|
|
33
|
-
await fs.remove(path.join(commandsDir, entry));
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
// Also remove legacy bmad folder if it exists
|
|
38
|
-
const bmadFolder = path.join(commandsDir, 'bmad');
|
|
39
|
-
if (await fs.pathExists(bmadFolder)) {
|
|
40
|
-
await fs.remove(bmadFolder);
|
|
41
|
-
console.log(chalk.dim(` Removed old BMAD commands from ${this.name}`));
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Setup Cursor IDE configuration
|
|
47
|
-
* @param {string} projectDir - Project directory
|
|
48
|
-
* @param {string} bmadDir - BMAD installation directory
|
|
49
|
-
* @param {Object} options - Setup options
|
|
50
|
-
*/
|
|
51
|
-
async setup(projectDir, bmadDir, options = {}) {
|
|
52
|
-
console.log(chalk.cyan(`Setting up ${this.name}...`));
|
|
53
|
-
|
|
54
|
-
// Clean up old BMAD installation first
|
|
55
|
-
await this.cleanup(projectDir);
|
|
56
|
-
|
|
57
|
-
// Create .cursor/commands directory structure
|
|
58
|
-
const cursorDir = path.join(projectDir, this.configDir);
|
|
59
|
-
const commandsDir = path.join(cursorDir, this.commandsDir);
|
|
60
|
-
await this.ensureDir(commandsDir);
|
|
61
|
-
|
|
62
|
-
// Use underscore format: files written directly to commands dir (no bmad subfolder)
|
|
63
|
-
// Creates: .cursor/commands/bmad_bmm_pm.md
|
|
64
|
-
|
|
65
|
-
// Generate agent launchers using AgentCommandGenerator
|
|
66
|
-
// This creates small launcher files that reference the actual agents in _bmad/
|
|
67
|
-
const agentGen = new AgentCommandGenerator(this.bmadFolderName);
|
|
68
|
-
const { artifacts: agentArtifacts, counts: agentCounts } = await agentGen.collectAgentArtifacts(bmadDir, options.selectedModules || []);
|
|
69
|
-
|
|
70
|
-
// Write agent launcher files using flat underscore naming
|
|
71
|
-
// Creates files like: bmad_bmm_pm.md
|
|
72
|
-
const agentCount = await agentGen.writeColonArtifacts(commandsDir, agentArtifacts);
|
|
73
|
-
|
|
74
|
-
// Generate workflow commands from manifest (if it exists)
|
|
75
|
-
const workflowGen = new WorkflowCommandGenerator(this.bmadFolderName);
|
|
76
|
-
const { artifacts: workflowArtifacts } = await workflowGen.collectWorkflowArtifacts(bmadDir);
|
|
77
|
-
|
|
78
|
-
// Write workflow-command artifacts using flat underscore naming
|
|
79
|
-
// Creates files like: bmad_bmm_correct-course.md
|
|
80
|
-
const workflowCommandCount = await workflowGen.writeColonArtifacts(commandsDir, workflowArtifacts);
|
|
81
|
-
|
|
82
|
-
// Generate task and tool commands from manifests (if they exist)
|
|
83
|
-
const taskToolGen = new TaskToolCommandGenerator();
|
|
84
|
-
const taskToolResult = await taskToolGen.generateColonTaskToolCommands(projectDir, bmadDir, commandsDir);
|
|
85
|
-
|
|
86
|
-
console.log(chalk.green(`✓ ${this.name} configured:`));
|
|
87
|
-
console.log(chalk.dim(` - ${agentCount} agents installed`));
|
|
88
|
-
if (workflowCommandCount > 0) {
|
|
89
|
-
console.log(chalk.dim(` - ${workflowCommandCount} workflow commands generated`));
|
|
90
|
-
}
|
|
91
|
-
if (taskToolResult.generated > 0) {
|
|
92
|
-
console.log(
|
|
93
|
-
chalk.dim(
|
|
94
|
-
` - ${taskToolResult.generated} task/tool commands generated (${taskToolResult.tasks} tasks, ${taskToolResult.tools} tools)`,
|
|
95
|
-
),
|
|
96
|
-
);
|
|
97
|
-
}
|
|
98
|
-
console.log(chalk.dim(` - Commands directory: ${path.relative(projectDir, commandsDir)}`));
|
|
99
|
-
|
|
100
|
-
return {
|
|
101
|
-
success: true,
|
|
102
|
-
agents: agentCount,
|
|
103
|
-
tasks: taskToolResult.tasks || 0,
|
|
104
|
-
tools: taskToolResult.tools || 0,
|
|
105
|
-
workflows: workflowCommandCount,
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Install a custom agent launcher for Cursor
|
|
111
|
-
* @param {string} projectDir - Project directory
|
|
112
|
-
* @param {string} agentName - Agent name (e.g., "fred-commit-poet")
|
|
113
|
-
* @param {string} agentPath - Path to compiled agent (relative to project root)
|
|
114
|
-
* @param {Object} metadata - Agent metadata
|
|
115
|
-
* @returns {Object|null} Info about created command
|
|
116
|
-
*/
|
|
117
|
-
async installCustomAgentLauncher(projectDir, agentName, agentPath, metadata) {
|
|
118
|
-
const commandsDir = path.join(projectDir, this.configDir, this.commandsDir);
|
|
119
|
-
|
|
120
|
-
if (!(await this.exists(path.join(projectDir, this.configDir)))) {
|
|
121
|
-
return null; // IDE not configured for this project
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
await this.ensureDir(commandsDir);
|
|
125
|
-
|
|
126
|
-
const launcherContent = `You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
|
|
127
|
-
|
|
128
|
-
<agent-activation CRITICAL="TRUE">
|
|
129
|
-
1. LOAD the FULL agent file from @${agentPath}
|
|
130
|
-
2. READ its entire contents - this contains the complete agent persona, menu, and instructions
|
|
131
|
-
3. FOLLOW every step in the <activation> section precisely
|
|
132
|
-
4. DISPLAY the welcome/greeting as instructed
|
|
133
|
-
5. PRESENT the numbered menu
|
|
134
|
-
6. WAIT for user input before proceeding
|
|
135
|
-
</agent-activation>
|
|
136
|
-
`;
|
|
137
|
-
|
|
138
|
-
// Cursor uses YAML frontmatter matching Claude Code format
|
|
139
|
-
const commandContent = `---
|
|
140
|
-
name: '${agentName}'
|
|
141
|
-
description: '${agentName} agent'
|
|
142
|
-
---
|
|
143
|
-
|
|
144
|
-
${launcherContent}
|
|
145
|
-
`;
|
|
146
|
-
|
|
147
|
-
// Use underscore format: bmad_custom_fred-commit-poet.md
|
|
148
|
-
// Written directly to commands dir (no bmad subfolder)
|
|
149
|
-
const launcherName = customAgentColonName(agentName);
|
|
150
|
-
const launcherPath = path.join(commandsDir, launcherName);
|
|
151
|
-
await this.writeFile(launcherPath, commandContent);
|
|
152
|
-
|
|
153
|
-
return {
|
|
154
|
-
path: launcherPath,
|
|
155
|
-
command: `/${launcherName.replace('.md', '')}`,
|
|
156
|
-
};
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
module.exports = { CursorSetup };
|