bmad-method 4.27.6 → 4.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/bmad-core/agents/bmad-master.md +2 -4
- package/bmad-core/agents/bmad-orchestrator.md +0 -3
- package/bmad-core/core-config.yaml +1 -5
- package/bmad-core/data/bmad-kb.md +2 -2
- package/bmad-core/tasks/correct-course.md +9 -12
- package/bmad-core/tasks/create-brownfield-story.md +10 -61
- package/bmad-core/tasks/create-deep-research-prompt.md +5 -17
- package/bmad-core/tasks/create-next-story.md +3 -4
- package/bmad-core/tasks/document-project.md +37 -13
- package/bmad-core/tasks/facilitate-brainstorming-session.md +1 -1
- package/bmad-core/tasks/generate-ai-frontend-prompt.md +1 -1
- package/bmad-core/tasks/kb-mode-interaction.md +8 -3
- package/bmad-core/tasks/review-story.md +3 -3
- package/bmad-core/tasks/shard-doc.md +5 -9
- package/common/tasks/create-doc.md +4 -0
- package/dist/agents/analyst.txt +43 -31
- package/dist/agents/architect.txt +42 -30
- package/dist/agents/bmad-master.txt +61 -602
- package/dist/agents/bmad-orchestrator.txt +7 -548
- package/dist/agents/pm.txt +19 -38
- package/dist/agents/po.txt +14 -21
- package/dist/agents/qa.txt +3 -3
- package/dist/agents/sm.txt +11 -15
- package/dist/agents/ux-expert.txt +6 -18
- package/dist/expansion-packs/bmad-2d-phaser-game-dev/agents/game-designer.txt +5 -17
- package/dist/expansion-packs/bmad-2d-phaser-game-dev/teams/phaser-2d-nodejs-game-team.txt +50 -579
- package/dist/expansion-packs/bmad-creator-tools/agents/bmad-the-creator.txt +5 -17
- package/dist/teams/team-all.txt +70 -607
- package/dist/teams/team-fullstack.txt +65 -601
- package/dist/teams/team-ide-minimal.txt +26 -575
- package/dist/teams/team-no-ui.txt +64 -600
- package/docs/agentic-tools/claude-code-guide.md +1 -1
- package/docs/agentic-tools/gemini-cli-guide.md +6 -7
- package/docs/bmad-workflow-guide.md +1 -0
- package/expansion-packs/bmad-2d-phaser-game-dev/config.yaml +1 -0
- package/expansion-packs/bmad-creator-tools/config.yaml +1 -0
- package/expansion-packs/bmad-infrastructure-devops/config.yaml +1 -0
- package/package.json +1 -1
- package/tools/installer/config/install.config.yaml +7 -6
- package/tools/installer/lib/ide-setup.js +406 -49
- package/tools/installer/package.json +1 -1
- package/tools/upgraders/v3-to-v4-upgrader.js +1 -1
- package/bmad-core/tasks/create-workflow-plan.md +0 -289
- package/bmad-core/tasks/doc-migration-task.md +0 -143
- package/bmad-core/tasks/update-workflow-plan.md +0 -248
|
@@ -7,7 +7,7 @@ For the complete workflow, see the [BMad Workflow Guide](../bmad-workflow-guide.
|
|
|
7
7
|
When running `npx bmad-method install`, select **Claude Code** as your IDE. This creates:
|
|
8
8
|
|
|
9
9
|
- `.bmad-core/` folder with all agents
|
|
10
|
-
- `.claude/commands
|
|
10
|
+
- `.claude/commands/BMad` folder with agent command files (`.md`)
|
|
11
11
|
|
|
12
12
|
## Using BMad Agents in Claude Code
|
|
13
13
|
|
|
@@ -6,23 +6,22 @@ For the complete workflow, see the [BMad Workflow Guide](../bmad-workflow-guide.
|
|
|
6
6
|
|
|
7
7
|
When running `npx bmad-method install`, select **Gemini CLI** as your IDE. This creates:
|
|
8
8
|
|
|
9
|
-
- `.gemini/
|
|
10
|
-
- `.gemini/settings.json` configured to load all agents automatically
|
|
9
|
+
- `.gemini/bmad-method/` directory with all agent context in GEMINI.md file
|
|
11
10
|
|
|
12
11
|
## Using BMad Agents with Gemini CLI
|
|
13
12
|
|
|
14
13
|
Simply mention the agent in your prompt:
|
|
15
14
|
|
|
16
|
-
- "As
|
|
17
|
-
- "Acting as
|
|
18
|
-
- "
|
|
15
|
+
- "As \*dev, implement the login feature"
|
|
16
|
+
- "Acting as \*architect, review this system design"
|
|
17
|
+
- "\*sm, create the next story for our project"
|
|
19
18
|
|
|
20
19
|
The Gemini CLI automatically loads the appropriate agent context.
|
|
21
20
|
|
|
22
21
|
## Gemini CLI-Specific Features
|
|
23
22
|
|
|
24
|
-
- **Context files**: All agents loaded as context in `.gemini/
|
|
25
|
-
- **Automatic loading**:
|
|
23
|
+
- **Context files**: All agents loaded as context in `.gemini/bmad-method/GEMINI.md`
|
|
24
|
+
- **Automatic loading**: GEMINI.md ensures agents are always available
|
|
26
25
|
- **Natural language**: No special syntax needed, just mention the agent
|
|
27
26
|
|
|
28
27
|
## Tips for Gemini CLI Users
|
|
@@ -111,6 +111,7 @@ Follow the SM → Dev cycle for systematic story development:
|
|
|
111
111
|
|
|
112
112
|
- **Claude Code**: `/agent-name` (e.g., `/bmad-master`)
|
|
113
113
|
- **Cursor**: `@agent-name` (e.g., `@bmad-master`)
|
|
114
|
+
- **Gemini CLI**: `*agent-name` (e.g., `*bmad-master`)
|
|
114
115
|
- **Windsurf**: `@agent-name` (e.g., `@bmad-master`)
|
|
115
116
|
- **Trae**: `@agent-name` (e.g., `@bmad-master`)
|
|
116
117
|
- **Roo Code**: Select mode from mode selector (e.g., `bmad-bmad-master`)
|
package/package.json
CHANGED
|
@@ -21,7 +21,7 @@ ide-configurations:
|
|
|
21
21
|
# 3. The agent will adopt that persona for the conversation
|
|
22
22
|
claude-code:
|
|
23
23
|
name: Claude Code
|
|
24
|
-
rule-dir: .claude/commands/
|
|
24
|
+
rule-dir: .claude/commands/BMad/
|
|
25
25
|
format: multi-file
|
|
26
26
|
command-suffix: .md
|
|
27
27
|
instructions: |
|
|
@@ -68,13 +68,14 @@ ide-configurations:
|
|
|
68
68
|
# 4. Rules are stored in .clinerules/ directory in your project
|
|
69
69
|
gemini:
|
|
70
70
|
name: Gemini CLI
|
|
71
|
-
rule-dir: .gemini/
|
|
72
|
-
format:
|
|
71
|
+
rule-dir: .gemini/bmad-method/
|
|
72
|
+
format: single-file
|
|
73
|
+
command-suffix: .md
|
|
73
74
|
instructions: |
|
|
74
75
|
# To use BMad agents with the Gemini CLI:
|
|
75
|
-
# 1. The installer creates a .gemini/ directory in your project.
|
|
76
|
-
# 2. It
|
|
77
|
-
# 3. Simply mention the agent in your prompt (e.g., "As
|
|
76
|
+
# 1. The installer creates a .gemini/bmad-method/ directory in your project.
|
|
77
|
+
# 2. It concatenates all agent files into a single GEMINI.md file.
|
|
78
|
+
# 3. Simply mention the agent in your prompt (e.g., "As *dev, ...").
|
|
78
79
|
# 4. The Gemini CLI will automatically have the context for that agent.
|
|
79
80
|
github-copilot:
|
|
80
81
|
name: Github Copilot
|
|
@@ -131,19 +131,64 @@ class IdeSetup {
|
|
|
131
131
|
}
|
|
132
132
|
|
|
133
133
|
async setupClaudeCode(installDir, selectedAgent) {
|
|
134
|
-
|
|
135
|
-
const
|
|
134
|
+
// Setup bmad-core commands
|
|
135
|
+
const coreSlashPrefix = await this.getCoreSlashPrefix(installDir);
|
|
136
|
+
const coreAgents = selectedAgent ? [selectedAgent] : await this.getCoreAgentIds(installDir);
|
|
137
|
+
const coreTasks = await this.getCoreTaskIds(installDir);
|
|
138
|
+
await this.setupClaudeCodeForPackage(installDir, "core", coreSlashPrefix, coreAgents, coreTasks, ".bmad-core");
|
|
139
|
+
|
|
140
|
+
// Setup expansion pack commands
|
|
141
|
+
const expansionPacks = await this.getInstalledExpansionPacks(installDir);
|
|
142
|
+
for (const packInfo of expansionPacks) {
|
|
143
|
+
const packSlashPrefix = await this.getExpansionPackSlashPrefix(packInfo.path);
|
|
144
|
+
const packAgents = await this.getExpansionPackAgents(packInfo.path);
|
|
145
|
+
const packTasks = await this.getExpansionPackTasks(packInfo.path);
|
|
146
|
+
|
|
147
|
+
if (packAgents.length > 0 || packTasks.length > 0) {
|
|
148
|
+
// Use the actual directory name where the expansion pack is installed
|
|
149
|
+
const rootPath = path.relative(installDir, packInfo.path);
|
|
150
|
+
await this.setupClaudeCodeForPackage(installDir, packInfo.name, packSlashPrefix, packAgents, packTasks, rootPath);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
136
153
|
|
|
137
|
-
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
138
156
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
157
|
+
async setupClaudeCodeForPackage(installDir, packageName, slashPrefix, agentIds, taskIds, rootPath) {
|
|
158
|
+
const commandsBaseDir = path.join(installDir, ".claude", "commands", slashPrefix);
|
|
159
|
+
const agentsDir = path.join(commandsBaseDir, "agents");
|
|
160
|
+
const tasksDir = path.join(commandsBaseDir, "tasks");
|
|
161
|
+
|
|
162
|
+
// Ensure directories exist
|
|
163
|
+
await fileManager.ensureDirectory(agentsDir);
|
|
164
|
+
await fileManager.ensureDirectory(tasksDir);
|
|
165
|
+
|
|
166
|
+
// Setup agents
|
|
167
|
+
for (const agentId of agentIds) {
|
|
168
|
+
// Find the agent file - for expansion packs, prefer the expansion pack version
|
|
169
|
+
let agentPath;
|
|
170
|
+
if (packageName !== "core") {
|
|
171
|
+
// For expansion packs, first try to find the agent in the expansion pack directory
|
|
172
|
+
const expansionPackPath = path.join(installDir, rootPath, "agents", `${agentId}.md`);
|
|
173
|
+
if (await fileManager.pathExists(expansionPackPath)) {
|
|
174
|
+
agentPath = expansionPackPath;
|
|
175
|
+
} else {
|
|
176
|
+
// Fall back to core if not found in expansion pack
|
|
177
|
+
agentPath = await this.findAgentPath(agentId, installDir);
|
|
178
|
+
}
|
|
179
|
+
} else {
|
|
180
|
+
// For core, use the normal search
|
|
181
|
+
agentPath = await this.findAgentPath(agentId, installDir);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const commandPath = path.join(agentsDir, `${agentId}.md`);
|
|
143
185
|
|
|
144
186
|
if (agentPath) {
|
|
145
187
|
// Create command file with agent content
|
|
146
|
-
|
|
188
|
+
let agentContent = await fileManager.readFile(agentPath);
|
|
189
|
+
|
|
190
|
+
// Replace {root} placeholder with the appropriate root path for this context
|
|
191
|
+
agentContent = agentContent.replace(/{root}/g, rootPath);
|
|
147
192
|
|
|
148
193
|
// Add command header
|
|
149
194
|
let commandContent = `# /${agentId} Command\n\n`;
|
|
@@ -151,13 +196,50 @@ class IdeSetup {
|
|
|
151
196
|
commandContent += agentContent;
|
|
152
197
|
|
|
153
198
|
await fileManager.writeFile(commandPath, commandContent);
|
|
154
|
-
console.log(chalk.green(`✓ Created command: /${agentId}`));
|
|
199
|
+
console.log(chalk.green(`✓ Created agent command: /${agentId}`));
|
|
155
200
|
}
|
|
156
201
|
}
|
|
157
202
|
|
|
158
|
-
|
|
203
|
+
// Setup tasks
|
|
204
|
+
for (const taskId of taskIds) {
|
|
205
|
+
// Find the task file - for expansion packs, prefer the expansion pack version
|
|
206
|
+
let taskPath;
|
|
207
|
+
if (packageName !== "core") {
|
|
208
|
+
// For expansion packs, first try to find the task in the expansion pack directory
|
|
209
|
+
const expansionPackPath = path.join(installDir, rootPath, "tasks", `${taskId}.md`);
|
|
210
|
+
if (await fileManager.pathExists(expansionPackPath)) {
|
|
211
|
+
taskPath = expansionPackPath;
|
|
212
|
+
} else {
|
|
213
|
+
// Fall back to core if not found in expansion pack
|
|
214
|
+
taskPath = await this.findTaskPath(taskId, installDir);
|
|
215
|
+
}
|
|
216
|
+
} else {
|
|
217
|
+
// For core, use the normal search
|
|
218
|
+
taskPath = await this.findTaskPath(taskId, installDir);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const commandPath = path.join(tasksDir, `${taskId}.md`);
|
|
159
222
|
|
|
160
|
-
|
|
223
|
+
if (taskPath) {
|
|
224
|
+
// Create command file with task content
|
|
225
|
+
let taskContent = await fileManager.readFile(taskPath);
|
|
226
|
+
|
|
227
|
+
// Replace {root} placeholder with the appropriate root path for this context
|
|
228
|
+
taskContent = taskContent.replace(/{root}/g, rootPath);
|
|
229
|
+
|
|
230
|
+
// Add command header
|
|
231
|
+
let commandContent = `# /${taskId} Task\n\n`;
|
|
232
|
+
commandContent += `When this command is used, execute the following task:\n\n`;
|
|
233
|
+
commandContent += taskContent;
|
|
234
|
+
|
|
235
|
+
await fileManager.writeFile(commandPath, commandContent);
|
|
236
|
+
console.log(chalk.green(`✓ Created task command: /${taskId}`));
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
console.log(chalk.green(`\n✓ Created Claude Code commands for ${packageName} in ${commandsBaseDir}`));
|
|
241
|
+
console.log(chalk.dim(` - Agents in: ${agentsDir}`));
|
|
242
|
+
console.log(chalk.dim(` - Tasks in: ${tasksDir}`));
|
|
161
243
|
}
|
|
162
244
|
|
|
163
245
|
async setupWindsurf(installDir, selectedAgent) {
|
|
@@ -311,6 +393,49 @@ class IdeSetup {
|
|
|
311
393
|
return [...new Set(allAgentIds)];
|
|
312
394
|
}
|
|
313
395
|
|
|
396
|
+
async getCoreAgentIds(installDir) {
|
|
397
|
+
const allAgentIds = [];
|
|
398
|
+
|
|
399
|
+
// Check core agents in .bmad-core or root only
|
|
400
|
+
let agentsDir = path.join(installDir, ".bmad-core", "agents");
|
|
401
|
+
if (!(await fileManager.pathExists(agentsDir))) {
|
|
402
|
+
agentsDir = path.join(installDir, "bmad-core", "agents");
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
if (await fileManager.pathExists(agentsDir)) {
|
|
406
|
+
const glob = require("glob");
|
|
407
|
+
const agentFiles = glob.sync("*.md", { cwd: agentsDir });
|
|
408
|
+
allAgentIds.push(...agentFiles.map((file) => path.basename(file, ".md")));
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
return [...new Set(allAgentIds)];
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
async getCoreTaskIds(installDir) {
|
|
415
|
+
const allTaskIds = [];
|
|
416
|
+
|
|
417
|
+
// Check core tasks in .bmad-core or root only
|
|
418
|
+
let tasksDir = path.join(installDir, ".bmad-core", "tasks");
|
|
419
|
+
if (!(await fileManager.pathExists(tasksDir))) {
|
|
420
|
+
tasksDir = path.join(installDir, "bmad-core", "tasks");
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
if (await fileManager.pathExists(tasksDir)) {
|
|
424
|
+
const glob = require("glob");
|
|
425
|
+
const taskFiles = glob.sync("*.md", { cwd: tasksDir });
|
|
426
|
+
allTaskIds.push(...taskFiles.map((file) => path.basename(file, ".md")));
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// Check common tasks
|
|
430
|
+
const commonTasksDir = path.join(installDir, "common", "tasks");
|
|
431
|
+
if (await fileManager.pathExists(commonTasksDir)) {
|
|
432
|
+
const commonTaskFiles = glob.sync("*.md", { cwd: commonTasksDir });
|
|
433
|
+
allTaskIds.push(...commonTaskFiles.map((file) => path.basename(file, ".md")));
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
return [...new Set(allTaskIds)];
|
|
437
|
+
}
|
|
438
|
+
|
|
314
439
|
async getAgentTitle(agentId, installDir) {
|
|
315
440
|
// Try to find the agent file in various locations
|
|
316
441
|
const possiblePaths = [
|
|
@@ -350,6 +475,194 @@ class IdeSetup {
|
|
|
350
475
|
).join(' ');
|
|
351
476
|
}
|
|
352
477
|
|
|
478
|
+
async getAllTaskIds(installDir) {
|
|
479
|
+
const glob = require("glob");
|
|
480
|
+
const allTaskIds = [];
|
|
481
|
+
|
|
482
|
+
// Check core tasks in .bmad-core or root
|
|
483
|
+
let tasksDir = path.join(installDir, ".bmad-core", "tasks");
|
|
484
|
+
if (!(await fileManager.pathExists(tasksDir))) {
|
|
485
|
+
tasksDir = path.join(installDir, "bmad-core", "tasks");
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
if (await fileManager.pathExists(tasksDir)) {
|
|
489
|
+
const taskFiles = glob.sync("*.md", { cwd: tasksDir });
|
|
490
|
+
allTaskIds.push(...taskFiles.map((file) => path.basename(file, ".md")));
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// Check common tasks
|
|
494
|
+
const commonTasksDir = path.join(installDir, "common", "tasks");
|
|
495
|
+
if (await fileManager.pathExists(commonTasksDir)) {
|
|
496
|
+
const commonTaskFiles = glob.sync("*.md", { cwd: commonTasksDir });
|
|
497
|
+
allTaskIds.push(...commonTaskFiles.map((file) => path.basename(file, ".md")));
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
// Also check for expansion pack tasks in dot folders
|
|
501
|
+
const expansionDirs = glob.sync(".*/tasks", { cwd: installDir });
|
|
502
|
+
for (const expDir of expansionDirs) {
|
|
503
|
+
const fullExpDir = path.join(installDir, expDir);
|
|
504
|
+
const expTaskFiles = glob.sync("*.md", { cwd: fullExpDir });
|
|
505
|
+
allTaskIds.push(...expTaskFiles.map((file) => path.basename(file, ".md")));
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// Check expansion-packs folder tasks
|
|
509
|
+
const expansionPacksDir = path.join(installDir, "expansion-packs");
|
|
510
|
+
if (await fileManager.pathExists(expansionPacksDir)) {
|
|
511
|
+
const expPackDirs = glob.sync("*/tasks", { cwd: expansionPacksDir });
|
|
512
|
+
for (const expDir of expPackDirs) {
|
|
513
|
+
const fullExpDir = path.join(expansionPacksDir, expDir);
|
|
514
|
+
const expTaskFiles = glob.sync("*.md", { cwd: fullExpDir });
|
|
515
|
+
allTaskIds.push(...expTaskFiles.map((file) => path.basename(file, ".md")));
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// Remove duplicates
|
|
520
|
+
return [...new Set(allTaskIds)];
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
async findTaskPath(taskId, installDir) {
|
|
524
|
+
// Try to find the task file in various locations
|
|
525
|
+
const possiblePaths = [
|
|
526
|
+
path.join(installDir, ".bmad-core", "tasks", `${taskId}.md`),
|
|
527
|
+
path.join(installDir, "bmad-core", "tasks", `${taskId}.md`),
|
|
528
|
+
path.join(installDir, "common", "tasks", `${taskId}.md`)
|
|
529
|
+
];
|
|
530
|
+
|
|
531
|
+
// Also check expansion pack directories
|
|
532
|
+
const glob = require("glob");
|
|
533
|
+
|
|
534
|
+
// Check dot folder expansion packs
|
|
535
|
+
const expansionDirs = glob.sync(".*/tasks", { cwd: installDir });
|
|
536
|
+
for (const expDir of expansionDirs) {
|
|
537
|
+
possiblePaths.push(path.join(installDir, expDir, `${taskId}.md`));
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
// Check expansion-packs folder
|
|
541
|
+
const expansionPacksDir = path.join(installDir, "expansion-packs");
|
|
542
|
+
if (await fileManager.pathExists(expansionPacksDir)) {
|
|
543
|
+
const expPackDirs = glob.sync("*/tasks", { cwd: expansionPacksDir });
|
|
544
|
+
for (const expDir of expPackDirs) {
|
|
545
|
+
possiblePaths.push(path.join(expansionPacksDir, expDir, `${taskId}.md`));
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
for (const taskPath of possiblePaths) {
|
|
550
|
+
if (await fileManager.pathExists(taskPath)) {
|
|
551
|
+
return taskPath;
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
return null;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
async getCoreSlashPrefix(installDir) {
|
|
559
|
+
try {
|
|
560
|
+
const coreConfigPath = path.join(installDir, ".bmad-core", "core-config.yaml");
|
|
561
|
+
if (!(await fileManager.pathExists(coreConfigPath))) {
|
|
562
|
+
// Try bmad-core directory
|
|
563
|
+
const altConfigPath = path.join(installDir, "bmad-core", "core-config.yaml");
|
|
564
|
+
if (await fileManager.pathExists(altConfigPath)) {
|
|
565
|
+
const configContent = await fileManager.readFile(altConfigPath);
|
|
566
|
+
const config = yaml.load(configContent);
|
|
567
|
+
return config.slashPrefix || "BMad";
|
|
568
|
+
}
|
|
569
|
+
return "BMad"; // fallback
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
const configContent = await fileManager.readFile(coreConfigPath);
|
|
573
|
+
const config = yaml.load(configContent);
|
|
574
|
+
return config.slashPrefix || "BMad";
|
|
575
|
+
} catch (error) {
|
|
576
|
+
console.warn(`Failed to read core slashPrefix, using default 'BMad': ${error.message}`);
|
|
577
|
+
return "BMad";
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
async getInstalledExpansionPacks(installDir) {
|
|
582
|
+
const expansionPacks = [];
|
|
583
|
+
|
|
584
|
+
// Check for dot-prefixed expansion packs in install directory
|
|
585
|
+
const glob = require("glob");
|
|
586
|
+
const dotExpansions = glob.sync(".bmad-*", { cwd: installDir });
|
|
587
|
+
|
|
588
|
+
for (const dotExpansion of dotExpansions) {
|
|
589
|
+
if (dotExpansion !== ".bmad-core") {
|
|
590
|
+
const packPath = path.join(installDir, dotExpansion);
|
|
591
|
+
const packName = dotExpansion.substring(1); // remove the dot
|
|
592
|
+
expansionPacks.push({
|
|
593
|
+
name: packName,
|
|
594
|
+
path: packPath
|
|
595
|
+
});
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
// Check for expansion-packs directory style
|
|
600
|
+
const expansionPacksDir = path.join(installDir, "expansion-packs");
|
|
601
|
+
if (await fileManager.pathExists(expansionPacksDir)) {
|
|
602
|
+
const packDirs = glob.sync("*", { cwd: expansionPacksDir });
|
|
603
|
+
|
|
604
|
+
for (const packDir of packDirs) {
|
|
605
|
+
const packPath = path.join(expansionPacksDir, packDir);
|
|
606
|
+
if ((await fileManager.pathExists(packPath)) &&
|
|
607
|
+
(await fileManager.pathExists(path.join(packPath, "config.yaml")))) {
|
|
608
|
+
expansionPacks.push({
|
|
609
|
+
name: packDir,
|
|
610
|
+
path: packPath
|
|
611
|
+
});
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
return expansionPacks;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
async getExpansionPackSlashPrefix(packPath) {
|
|
620
|
+
try {
|
|
621
|
+
const configPath = path.join(packPath, "config.yaml");
|
|
622
|
+
if (await fileManager.pathExists(configPath)) {
|
|
623
|
+
const configContent = await fileManager.readFile(configPath);
|
|
624
|
+
const config = yaml.load(configContent);
|
|
625
|
+
return config.slashPrefix || path.basename(packPath);
|
|
626
|
+
}
|
|
627
|
+
} catch (error) {
|
|
628
|
+
console.warn(`Failed to read expansion pack slashPrefix from ${packPath}: ${error.message}`);
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
return path.basename(packPath); // fallback to directory name
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
async getExpansionPackAgents(packPath) {
|
|
635
|
+
const agentsDir = path.join(packPath, "agents");
|
|
636
|
+
if (!(await fileManager.pathExists(agentsDir))) {
|
|
637
|
+
return [];
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
try {
|
|
641
|
+
const glob = require("glob");
|
|
642
|
+
const agentFiles = glob.sync("*.md", { cwd: agentsDir });
|
|
643
|
+
return agentFiles.map(file => path.basename(file, ".md"));
|
|
644
|
+
} catch (error) {
|
|
645
|
+
console.warn(`Failed to read expansion pack agents from ${packPath}: ${error.message}`);
|
|
646
|
+
return [];
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
async getExpansionPackTasks(packPath) {
|
|
651
|
+
const tasksDir = path.join(packPath, "tasks");
|
|
652
|
+
if (!(await fileManager.pathExists(tasksDir))) {
|
|
653
|
+
return [];
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
try {
|
|
657
|
+
const glob = require("glob");
|
|
658
|
+
const taskFiles = glob.sync("*.md", { cwd: tasksDir });
|
|
659
|
+
return taskFiles.map(file => path.basename(file, ".md"));
|
|
660
|
+
} catch (error) {
|
|
661
|
+
console.warn(`Failed to read expansion pack tasks from ${packPath}: ${error.message}`);
|
|
662
|
+
return [];
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
|
|
353
666
|
async setupRoo(installDir, selectedAgent) {
|
|
354
667
|
const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
|
|
355
668
|
|
|
@@ -509,15 +822,56 @@ class IdeSetup {
|
|
|
509
822
|
return true;
|
|
510
823
|
}
|
|
511
824
|
|
|
512
|
-
async setupGeminiCli(installDir
|
|
825
|
+
async setupGeminiCli(installDir) {
|
|
513
826
|
await initializeModules();
|
|
514
827
|
const geminiDir = path.join(installDir, ".gemini");
|
|
515
|
-
const
|
|
516
|
-
await fileManager.ensureDirectory(
|
|
828
|
+
const bmadMethodDir = path.join(geminiDir, "bmad-method");
|
|
829
|
+
await fileManager.ensureDirectory(bmadMethodDir);
|
|
830
|
+
|
|
831
|
+
// Update logic for existing settings.json
|
|
832
|
+
const settingsPath = path.join(geminiDir, "settings.json");
|
|
833
|
+
if (await fileManager.pathExists(settingsPath)) {
|
|
834
|
+
try {
|
|
835
|
+
const settingsContent = await fileManager.readFile(settingsPath);
|
|
836
|
+
const settings = JSON.parse(settingsContent);
|
|
837
|
+
let updated = false;
|
|
838
|
+
|
|
839
|
+
// Handle contextFileName property
|
|
840
|
+
if (settings.contextFileName && Array.isArray(settings.contextFileName)) {
|
|
841
|
+
const originalLength = settings.contextFileName.length;
|
|
842
|
+
settings.contextFileName = settings.contextFileName.filter(
|
|
843
|
+
(fileName) => !fileName.startsWith("agents/")
|
|
844
|
+
);
|
|
845
|
+
if (settings.contextFileName.length !== originalLength) {
|
|
846
|
+
updated = true;
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
if (updated) {
|
|
851
|
+
await fileManager.writeFile(
|
|
852
|
+
settingsPath,
|
|
853
|
+
JSON.stringify(settings, null, 2)
|
|
854
|
+
);
|
|
855
|
+
console.log(chalk.green("✓ Updated .gemini/settings.json - removed agent file references"));
|
|
856
|
+
}
|
|
857
|
+
} catch (error) {
|
|
858
|
+
console.warn(
|
|
859
|
+
chalk.yellow("Could not update .gemini/settings.json"),
|
|
860
|
+
error
|
|
861
|
+
);
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
// Remove old agents directory
|
|
866
|
+
const agentsDir = path.join(geminiDir, "agents");
|
|
867
|
+
if (await fileManager.pathExists(agentsDir)) {
|
|
868
|
+
await fileManager.removeDirectory(agentsDir);
|
|
869
|
+
console.log(chalk.green("✓ Removed old .gemini/agents directory"));
|
|
870
|
+
}
|
|
517
871
|
|
|
518
872
|
// Get all available agents
|
|
519
873
|
const agents = await this.getAllAgentIds(installDir);
|
|
520
|
-
|
|
874
|
+
let concatenatedContent = "";
|
|
521
875
|
|
|
522
876
|
for (const agentId of agents) {
|
|
523
877
|
// Find the source agent file
|
|
@@ -525,43 +879,46 @@ class IdeSetup {
|
|
|
525
879
|
|
|
526
880
|
if (agentPath) {
|
|
527
881
|
const agentContent = await fileManager.readFile(agentPath);
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
await
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
882
|
+
|
|
883
|
+
// Create properly formatted agent rule content (similar to trae)
|
|
884
|
+
let agentRuleContent = `# ${agentId.toUpperCase()} Agent Rule\n\n`;
|
|
885
|
+
agentRuleContent += `This rule is triggered when the user types \`*${agentId}\` and activates the ${await this.getAgentTitle(
|
|
886
|
+
agentId,
|
|
887
|
+
installDir
|
|
888
|
+
)} agent persona.\n\n`;
|
|
889
|
+
agentRuleContent += "## Agent Activation\n\n";
|
|
890
|
+
agentRuleContent +=
|
|
891
|
+
"CRITICAL: Read the full YAML, start activation to alter your state of being, follow startup section instructions, stay in this being until told to exit this mode:\n\n";
|
|
892
|
+
agentRuleContent += "```yaml\n";
|
|
893
|
+
// Extract just the YAML content from the agent file
|
|
894
|
+
const yamlContent = extractYamlFromAgent(agentContent);
|
|
895
|
+
if (yamlContent) {
|
|
896
|
+
agentRuleContent += yamlContent;
|
|
897
|
+
}
|
|
898
|
+
else {
|
|
899
|
+
// If no YAML found, include the whole content minus the header
|
|
900
|
+
agentRuleContent += agentContent.replace(/^#.*$/m, "").trim();
|
|
901
|
+
}
|
|
902
|
+
agentRuleContent += "\n```\n\n";
|
|
903
|
+
agentRuleContent += "## File Reference\n\n";
|
|
904
|
+
const relativePath = path.relative(installDir, agentPath).replace(/\\/g, '/');
|
|
905
|
+
agentRuleContent += `The complete agent definition is available in [${relativePath}](${relativePath}).\n\n`;
|
|
906
|
+
agentRuleContent += "## Usage\n\n";
|
|
907
|
+
agentRuleContent += `When the user types \`*${agentId}\`, activate this ${await this.getAgentTitle(
|
|
908
|
+
agentId,
|
|
909
|
+
installDir
|
|
910
|
+
)} persona and follow all instructions defined in the YAML configuration above.\n`;
|
|
911
|
+
|
|
912
|
+
// Add to concatenated content with separator
|
|
913
|
+
concatenatedContent += agentRuleContent + "\n\n---\n\n";
|
|
914
|
+
console.log(chalk.green(`✓ Added context for @${agentId}`));
|
|
557
915
|
}
|
|
558
916
|
}
|
|
559
917
|
|
|
560
|
-
//
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
console.log(chalk.green(`✓ Configured .gemini/settings.json to load all agent context files.`));
|
|
918
|
+
// Write the concatenated content to GEMINI.md
|
|
919
|
+
const geminiMdPath = path.join(bmadMethodDir, "GEMINI.md");
|
|
920
|
+
await fileManager.writeFile(geminiMdPath, concatenatedContent);
|
|
921
|
+
console.log(chalk.green(`\n✓ Created GEMINI.md in ${bmadMethodDir}`));
|
|
565
922
|
|
|
566
923
|
return true;
|
|
567
924
|
}
|
|
@@ -558,7 +558,7 @@ class V3ToV4Upgrader {
|
|
|
558
558
|
try {
|
|
559
559
|
const ideMessages = {
|
|
560
560
|
cursor: "Rules created in .cursor/rules/",
|
|
561
|
-
"claude-code": "Commands created in .claude/commands/",
|
|
561
|
+
"claude-code": "Commands created in .claude/commands/BMad/",
|
|
562
562
|
windsurf: "Rules created in .windsurf/rules/",
|
|
563
563
|
trae: "Rules created in.trae/rules/",
|
|
564
564
|
roo: "Custom modes created in .roomodes",
|