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.
Files changed (45) hide show
  1. package/CHANGELOG.md +8 -1
  2. package/package.json +1 -1
  3. package/src/bmm/module-help.csv +31 -31
  4. package/src/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-04-review.md +1 -1
  5. package/src/core/module-help.csv +8 -8
  6. package/tools/cli/installers/install-messages.yaml +11 -10
  7. package/tools/cli/installers/lib/core/installer.js +26 -40
  8. package/tools/cli/installers/lib/ide/_config-driven.js +423 -0
  9. package/tools/cli/installers/lib/ide/codex.js +40 -12
  10. package/tools/cli/installers/lib/ide/manager.js +65 -38
  11. package/tools/cli/installers/lib/ide/platform-codes.js +100 -0
  12. package/tools/cli/installers/lib/ide/platform-codes.yaml +241 -0
  13. package/tools/cli/installers/lib/ide/shared/agent-command-generator.js +19 -5
  14. package/tools/cli/installers/lib/ide/shared/bmad-artifacts.js +5 -0
  15. package/tools/cli/installers/lib/ide/shared/path-utils.js +166 -50
  16. package/tools/cli/installers/lib/ide/shared/task-tool-command-generator.js +7 -5
  17. package/tools/cli/installers/lib/ide/shared/workflow-command-generator.js +21 -3
  18. package/tools/cli/installers/lib/ide/templates/combined/antigravity.md +8 -0
  19. package/tools/cli/installers/lib/ide/templates/combined/default-agent.md +15 -0
  20. package/tools/cli/installers/lib/ide/templates/combined/default-workflow-yaml.md +14 -0
  21. package/tools/cli/installers/lib/ide/templates/combined/default-workflow.md +6 -0
  22. package/tools/cli/installers/lib/ide/templates/combined/rovodev.md +9 -0
  23. package/tools/cli/installers/lib/ide/templates/combined/trae.md +9 -0
  24. package/tools/cli/installers/lib/ide/templates/combined/windsurf-workflow.md +10 -0
  25. package/tools/cli/installers/lib/ide/templates/split/gemini/body.md +10 -0
  26. package/tools/cli/installers/lib/ide/templates/split/gemini/header.toml +2 -0
  27. package/tools/cli/installers/lib/ide/templates/split/opencode/body.md +10 -0
  28. package/tools/cli/installers/lib/ide/templates/split/opencode/header.md +4 -0
  29. package/tools/cli/lib/ui.js +19 -75
  30. package/tools/cli/installers/lib/ide/STANDARDIZATION_PLAN.md +0 -208
  31. package/tools/cli/installers/lib/ide/antigravity.js +0 -474
  32. package/tools/cli/installers/lib/ide/auggie.js +0 -244
  33. package/tools/cli/installers/lib/ide/claude-code.js +0 -506
  34. package/tools/cli/installers/lib/ide/cline.js +0 -272
  35. package/tools/cli/installers/lib/ide/crush.js +0 -149
  36. package/tools/cli/installers/lib/ide/cursor.js +0 -160
  37. package/tools/cli/installers/lib/ide/gemini.js +0 -301
  38. package/tools/cli/installers/lib/ide/github-copilot.js +0 -383
  39. package/tools/cli/installers/lib/ide/iflow.js +0 -191
  40. package/tools/cli/installers/lib/ide/opencode.js +0 -257
  41. package/tools/cli/installers/lib/ide/qwen.js +0 -372
  42. package/tools/cli/installers/lib/ide/roo.js +0 -273
  43. package/tools/cli/installers/lib/ide/rovo-dev.js +0 -290
  44. package/tools/cli/installers/lib/ide/trae.js +0 -313
  45. 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 };