bmad-method 4.27.5 → 4.28.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/analyst.md +3 -4
- package/bmad-core/agents/architect.md +3 -4
- package/bmad-core/agents/bmad-master.md +9 -31
- package/bmad-core/agents/bmad-orchestrator.md +3 -8
- package/bmad-core/agents/dev.md +3 -4
- package/bmad-core/agents/pm.md +3 -4
- package/bmad-core/agents/po.md +3 -4
- package/bmad-core/agents/qa.md +3 -4
- package/bmad-core/agents/sm.md +3 -4
- package/bmad-core/agents/ux-expert.md +3 -4
- package/bmad-core/tasks/create-next-story.md +0 -1
- package/bmad-core/tasks/validate-next-story.md +1 -1
- package/bmad-core/workflows/brownfield-fullstack.yaml +1 -1
- package/bmad-core/workflows/brownfield-service.yaml +1 -1
- package/bmad-core/workflows/brownfield-ui.yaml +1 -1
- package/bmad-core/workflows/greenfield-fullstack.yaml +1 -1
- package/bmad-core/workflows/greenfield-ui.yaml +1 -1
- package/dist/agents/analyst.txt +3 -3
- package/dist/agents/bmad-master.txt +7 -324
- package/dist/agents/bmad-orchestrator.txt +3 -229
- package/dist/agents/dev.txt +1 -1
- package/dist/agents/po.txt +1 -1
- package/dist/agents/sm.txt +0 -1
- package/dist/expansion-packs/bmad-2d-phaser-game-dev/teams/phaser-2d-nodejs-game-team.txt +0 -226
- package/dist/teams/team-all.txt +9 -236
- package/dist/teams/team-fullstack.txt +9 -235
- package/dist/teams/team-ide-minimal.txt +4 -231
- package/dist/teams/team-no-ui.txt +5 -231
- 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/agents/game-designer.md +2 -3
- package/expansion-packs/bmad-2d-phaser-game-dev/agents/game-developer.md +2 -3
- package/expansion-packs/bmad-2d-phaser-game-dev/agents/game-sm.md +2 -3
- package/expansion-packs/bmad-creator-tools/agents/bmad-the-creator.md +2 -3
- package/expansion-packs/bmad-infrastructure-devops/agents/infra-devops-platform.md +2 -3
- package/package.json +1 -1
- package/tools/installer/config/install.config.yaml +7 -6
- package/tools/installer/lib/file-manager.js +77 -2
- package/tools/installer/lib/ide-setup.js +82 -38
- package/tools/installer/lib/installer.js +54 -25
- package/tools/installer/package.json +1 -1
- package/tools/upgraders/v3-to-v4-upgrader.js +1 -1
- package/bmad-core/utils/plan-management.md +0 -219
|
@@ -131,7 +131,7 @@ class IdeSetup {
|
|
|
131
131
|
}
|
|
132
132
|
|
|
133
133
|
async setupClaudeCode(installDir, selectedAgent) {
|
|
134
|
-
const commandsDir = path.join(installDir, ".claude", "commands");
|
|
134
|
+
const commandsDir = path.join(installDir, ".claude", "commands", "BMad");
|
|
135
135
|
const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
|
|
136
136
|
|
|
137
137
|
await fileManager.ensureDirectory(commandsDir);
|
|
@@ -512,12 +512,53 @@ class IdeSetup {
|
|
|
512
512
|
async setupGeminiCli(installDir, selectedAgent) {
|
|
513
513
|
await initializeModules();
|
|
514
514
|
const geminiDir = path.join(installDir, ".gemini");
|
|
515
|
-
const
|
|
516
|
-
await fileManager.ensureDirectory(
|
|
515
|
+
const bmadMethodDir = path.join(geminiDir, "bmad-method");
|
|
516
|
+
await fileManager.ensureDirectory(bmadMethodDir);
|
|
517
|
+
|
|
518
|
+
// Update logic for existing settings.json
|
|
519
|
+
const settingsPath = path.join(geminiDir, "settings.json");
|
|
520
|
+
if (await fileManager.pathExists(settingsPath)) {
|
|
521
|
+
try {
|
|
522
|
+
const settingsContent = await fileManager.readFile(settingsPath);
|
|
523
|
+
const settings = JSON.parse(settingsContent);
|
|
524
|
+
let updated = false;
|
|
525
|
+
|
|
526
|
+
// Handle contextFileName property
|
|
527
|
+
if (settings.contextFileName && Array.isArray(settings.contextFileName)) {
|
|
528
|
+
const originalLength = settings.contextFileName.length;
|
|
529
|
+
settings.contextFileName = settings.contextFileName.filter(
|
|
530
|
+
(fileName) => !fileName.startsWith("agents/")
|
|
531
|
+
);
|
|
532
|
+
if (settings.contextFileName.length !== originalLength) {
|
|
533
|
+
updated = true;
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
if (updated) {
|
|
538
|
+
await fileManager.writeFile(
|
|
539
|
+
settingsPath,
|
|
540
|
+
JSON.stringify(settings, null, 2)
|
|
541
|
+
);
|
|
542
|
+
console.log(chalk.green("✓ Updated .gemini/settings.json - removed agent file references"));
|
|
543
|
+
}
|
|
544
|
+
} catch (error) {
|
|
545
|
+
console.warn(
|
|
546
|
+
chalk.yellow("Could not update .gemini/settings.json"),
|
|
547
|
+
error
|
|
548
|
+
);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// Remove old agents directory
|
|
553
|
+
const agentsDir = path.join(geminiDir, "agents");
|
|
554
|
+
if (await fileManager.pathExists(agentsDir)) {
|
|
555
|
+
await fileManager.removeDirectory(agentsDir);
|
|
556
|
+
console.log(chalk.green("✓ Removed old .gemini/agents directory"));
|
|
557
|
+
}
|
|
517
558
|
|
|
518
559
|
// Get all available agents
|
|
519
560
|
const agents = await this.getAllAgentIds(installDir);
|
|
520
|
-
|
|
561
|
+
let concatenatedContent = "";
|
|
521
562
|
|
|
522
563
|
for (const agentId of agents) {
|
|
523
564
|
// Find the source agent file
|
|
@@ -525,43 +566,46 @@ class IdeSetup {
|
|
|
525
566
|
|
|
526
567
|
if (agentPath) {
|
|
527
568
|
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
|
-
|
|
569
|
+
|
|
570
|
+
// Create properly formatted agent rule content (similar to trae)
|
|
571
|
+
let agentRuleContent = `# ${agentId.toUpperCase()} Agent Rule\n\n`;
|
|
572
|
+
agentRuleContent += `This rule is triggered when the user types \`*${agentId}\` and activates the ${await this.getAgentTitle(
|
|
573
|
+
agentId,
|
|
574
|
+
installDir
|
|
575
|
+
)} agent persona.\n\n`;
|
|
576
|
+
agentRuleContent += "## Agent Activation\n\n";
|
|
577
|
+
agentRuleContent +=
|
|
578
|
+
"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";
|
|
579
|
+
agentRuleContent += "```yaml\n";
|
|
580
|
+
// Extract just the YAML content from the agent file
|
|
581
|
+
const yamlContent = extractYamlFromAgent(agentContent);
|
|
582
|
+
if (yamlContent) {
|
|
583
|
+
agentRuleContent += yamlContent;
|
|
584
|
+
}
|
|
585
|
+
else {
|
|
586
|
+
// If no YAML found, include the whole content minus the header
|
|
587
|
+
agentRuleContent += agentContent.replace(/^#.*$/m, "").trim();
|
|
588
|
+
}
|
|
589
|
+
agentRuleContent += "\n```\n\n";
|
|
590
|
+
agentRuleContent += "## File Reference\n\n";
|
|
591
|
+
const relativePath = path.relative(installDir, agentPath).replace(/\\/g, '/');
|
|
592
|
+
agentRuleContent += `The complete agent definition is available in [${relativePath}](${relativePath}).\n\n`;
|
|
593
|
+
agentRuleContent += "## Usage\n\n";
|
|
594
|
+
agentRuleContent += `When the user types \`*${agentId}\`, activate this ${await this.getAgentTitle(
|
|
595
|
+
agentId,
|
|
596
|
+
installDir
|
|
597
|
+
)} persona and follow all instructions defined in the YAML configuration above.\n`;
|
|
598
|
+
|
|
599
|
+
// Add to concatenated content with separator
|
|
600
|
+
concatenatedContent += agentRuleContent + "\n\n---\n\n";
|
|
601
|
+
console.log(chalk.green(`✓ Added context for @${agentId}`));
|
|
557
602
|
}
|
|
558
603
|
}
|
|
559
604
|
|
|
560
|
-
//
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
console.log(chalk.green(`✓ Configured .gemini/settings.json to load all agent context files.`));
|
|
605
|
+
// Write the concatenated content to GEMINI.md
|
|
606
|
+
const geminiMdPath = path.join(bmadMethodDir, "GEMINI.md");
|
|
607
|
+
await fileManager.writeFile(geminiMdPath, concatenatedContent);
|
|
608
|
+
console.log(chalk.green(`\n✓ Created GEMINI.md in ${bmadMethodDir}`));
|
|
565
609
|
|
|
566
610
|
return true;
|
|
567
611
|
}
|
|
@@ -244,7 +244,7 @@ class Installer {
|
|
|
244
244
|
spinner.text = "Copying complete .bmad-core folder...";
|
|
245
245
|
const sourceDir = configLoader.getBmadCorePath();
|
|
246
246
|
const bmadCoreDestDir = path.join(installDir, ".bmad-core");
|
|
247
|
-
await fileManager.
|
|
247
|
+
await fileManager.copyDirectoryWithRootReplacement(sourceDir, bmadCoreDestDir, ".bmad-core");
|
|
248
248
|
|
|
249
249
|
// Copy common/ items to .bmad-core
|
|
250
250
|
spinner.text = "Copying common utilities...";
|
|
@@ -263,7 +263,7 @@ class Installer {
|
|
|
263
263
|
// Single agent installation
|
|
264
264
|
spinner.text = `Installing ${config.agent} agent...`;
|
|
265
265
|
|
|
266
|
-
// Copy agent file
|
|
266
|
+
// Copy agent file with {root} replacement
|
|
267
267
|
const agentPath = configLoader.getAgentPath(config.agent);
|
|
268
268
|
const destAgentPath = path.join(
|
|
269
269
|
installDir,
|
|
@@ -271,7 +271,7 @@ class Installer {
|
|
|
271
271
|
"agents",
|
|
272
272
|
`${config.agent}.md`
|
|
273
273
|
);
|
|
274
|
-
await fileManager.
|
|
274
|
+
await fileManager.copyFileWithRootReplacement(agentPath, destAgentPath, ".bmad-core");
|
|
275
275
|
files.push(`.bmad-core/agents/${config.agent}.md`);
|
|
276
276
|
|
|
277
277
|
// Copy dependencies
|
|
@@ -284,15 +284,16 @@ class Installer {
|
|
|
284
284
|
spinner.text = `Copying dependency: ${dep}`;
|
|
285
285
|
|
|
286
286
|
if (dep.includes("*")) {
|
|
287
|
-
// Handle glob patterns
|
|
287
|
+
// Handle glob patterns with {root} replacement
|
|
288
288
|
const copiedFiles = await fileManager.copyGlobPattern(
|
|
289
289
|
dep.replace(".bmad-core/", ""),
|
|
290
290
|
sourceBase,
|
|
291
|
-
path.join(installDir, ".bmad-core")
|
|
291
|
+
path.join(installDir, ".bmad-core"),
|
|
292
|
+
".bmad-core"
|
|
292
293
|
);
|
|
293
294
|
files.push(...copiedFiles.map(f => `.bmad-core/${f}`));
|
|
294
295
|
} else {
|
|
295
|
-
// Handle single files
|
|
296
|
+
// Handle single files with {root} replacement if needed
|
|
296
297
|
const sourcePath = path.join(
|
|
297
298
|
sourceBase,
|
|
298
299
|
dep.replace(".bmad-core/", "")
|
|
@@ -302,7 +303,16 @@ class Installer {
|
|
|
302
303
|
dep
|
|
303
304
|
);
|
|
304
305
|
|
|
305
|
-
|
|
306
|
+
const needsRootReplacement = dep.endsWith('.md') || dep.endsWith('.yaml') || dep.endsWith('.yml');
|
|
307
|
+
let success = false;
|
|
308
|
+
|
|
309
|
+
if (needsRootReplacement) {
|
|
310
|
+
success = await fileManager.copyFileWithRootReplacement(sourcePath, destPath, ".bmad-core");
|
|
311
|
+
} else {
|
|
312
|
+
success = await fileManager.copyFile(sourcePath, destPath);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
if (success) {
|
|
306
316
|
files.push(dep);
|
|
307
317
|
}
|
|
308
318
|
}
|
|
@@ -325,19 +335,29 @@ class Installer {
|
|
|
325
335
|
spinner.text = `Copying team dependency: ${dep}`;
|
|
326
336
|
|
|
327
337
|
if (dep.includes("*")) {
|
|
328
|
-
// Handle glob patterns
|
|
338
|
+
// Handle glob patterns with {root} replacement
|
|
329
339
|
const copiedFiles = await fileManager.copyGlobPattern(
|
|
330
340
|
dep.replace(".bmad-core/", ""),
|
|
331
341
|
sourceBase,
|
|
332
|
-
path.join(installDir, ".bmad-core")
|
|
342
|
+
path.join(installDir, ".bmad-core"),
|
|
343
|
+
".bmad-core"
|
|
333
344
|
);
|
|
334
345
|
files.push(...copiedFiles.map(f => `.bmad-core/${f}`));
|
|
335
346
|
} else {
|
|
336
|
-
// Handle single files
|
|
347
|
+
// Handle single files with {root} replacement if needed
|
|
337
348
|
const sourcePath = path.join(sourceBase, dep.replace(".bmad-core/", ""));
|
|
338
349
|
const destPath = path.join(installDir, dep);
|
|
339
350
|
|
|
340
|
-
|
|
351
|
+
const needsRootReplacement = dep.endsWith('.md') || dep.endsWith('.yaml') || dep.endsWith('.yml');
|
|
352
|
+
let success = false;
|
|
353
|
+
|
|
354
|
+
if (needsRootReplacement) {
|
|
355
|
+
success = await fileManager.copyFileWithRootReplacement(sourcePath, destPath, ".bmad-core");
|
|
356
|
+
} else {
|
|
357
|
+
success = await fileManager.copyFile(sourcePath, destPath);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
if (success) {
|
|
341
361
|
files.push(dep);
|
|
342
362
|
}
|
|
343
363
|
}
|
|
@@ -1172,32 +1192,41 @@ class Installer {
|
|
|
1172
1192
|
nodir: true
|
|
1173
1193
|
});
|
|
1174
1194
|
|
|
1175
|
-
// Copy each file to the expansion pack's dot folder
|
|
1195
|
+
// Copy each file to the expansion pack's dot folder with {root} replacement
|
|
1176
1196
|
for (const file of files) {
|
|
1177
1197
|
const sourcePath = path.join(sourceFolder, file);
|
|
1178
1198
|
const destPath = path.join(expansionDotFolder, folder, file);
|
|
1179
1199
|
|
|
1180
|
-
|
|
1200
|
+
const needsRootReplacement = file.endsWith('.md') || file.endsWith('.yaml') || file.endsWith('.yml');
|
|
1201
|
+
let success = false;
|
|
1202
|
+
|
|
1203
|
+
if (needsRootReplacement) {
|
|
1204
|
+
success = await fileManager.copyFileWithRootReplacement(sourcePath, destPath, `.${packId}`);
|
|
1205
|
+
} else {
|
|
1206
|
+
success = await fileManager.copyFile(sourcePath, destPath);
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
if (success) {
|
|
1181
1210
|
installedFiles.push(path.join(`.${packId}`, folder, file));
|
|
1182
1211
|
}
|
|
1183
1212
|
}
|
|
1184
1213
|
}
|
|
1185
1214
|
}
|
|
1186
1215
|
|
|
1187
|
-
// Copy config.yaml
|
|
1216
|
+
// Copy config.yaml with {root} replacement
|
|
1188
1217
|
const configPath = path.join(expansionPackDir, 'config.yaml');
|
|
1189
1218
|
if (await fileManager.pathExists(configPath)) {
|
|
1190
1219
|
const configDestPath = path.join(expansionDotFolder, 'config.yaml');
|
|
1191
|
-
if (await fileManager.
|
|
1220
|
+
if (await fileManager.copyFileWithRootReplacement(configPath, configDestPath, `.${packId}`)) {
|
|
1192
1221
|
installedFiles.push(path.join(`.${packId}`, 'config.yaml'));
|
|
1193
1222
|
}
|
|
1194
1223
|
}
|
|
1195
1224
|
|
|
1196
|
-
// Copy README if it exists
|
|
1225
|
+
// Copy README if it exists with {root} replacement
|
|
1197
1226
|
const readmePath = path.join(expansionPackDir, 'README.md');
|
|
1198
1227
|
if (await fileManager.pathExists(readmePath)) {
|
|
1199
1228
|
const readmeDestPath = path.join(expansionDotFolder, 'README.md');
|
|
1200
|
-
if (await fileManager.
|
|
1229
|
+
if (await fileManager.copyFileWithRootReplacement(readmePath, readmeDestPath, `.${packId}`)) {
|
|
1201
1230
|
installedFiles.push(path.join(`.${packId}`, 'README.md'));
|
|
1202
1231
|
}
|
|
1203
1232
|
}
|
|
@@ -1258,7 +1287,7 @@ class Installer {
|
|
|
1258
1287
|
const yamlContent = extractYamlFromAgent(agentContent);
|
|
1259
1288
|
if (yamlContent) {
|
|
1260
1289
|
try {
|
|
1261
|
-
const agentConfig = yaml.
|
|
1290
|
+
const agentConfig = yaml.load(yamlContent);
|
|
1262
1291
|
const dependencies = agentConfig.dependencies || {};
|
|
1263
1292
|
|
|
1264
1293
|
// Check for core dependencies (those that don't exist in the expansion pack)
|
|
@@ -1277,9 +1306,9 @@ class Installer {
|
|
|
1277
1306
|
if (await fileManager.pathExists(coreDepPath)) {
|
|
1278
1307
|
spinner.text = `Copying core dependency ${dep} for ${packId}...`;
|
|
1279
1308
|
|
|
1280
|
-
// Copy from core to expansion pack dot folder
|
|
1309
|
+
// Copy from core to expansion pack dot folder with {root} replacement
|
|
1281
1310
|
const destPath = path.join(expansionDotFolder, depType, depFileName);
|
|
1282
|
-
await fileManager.
|
|
1311
|
+
await fileManager.copyFileWithRootReplacement(coreDepPath, destPath, `.${packId}`);
|
|
1283
1312
|
|
|
1284
1313
|
console.log(chalk.dim(` Added core dependency: ${depType}/${depFileName}`));
|
|
1285
1314
|
} else {
|
|
@@ -1321,7 +1350,7 @@ class Installer {
|
|
|
1321
1350
|
const teamContent = await fs.readFile(teamPath, 'utf8');
|
|
1322
1351
|
|
|
1323
1352
|
try {
|
|
1324
|
-
const teamConfig = yaml.
|
|
1353
|
+
const teamConfig = yaml.load(teamContent);
|
|
1325
1354
|
const agents = teamConfig.agents || [];
|
|
1326
1355
|
|
|
1327
1356
|
// Add bmad-orchestrator if not present (required for all teams)
|
|
@@ -1338,9 +1367,9 @@ class Installer {
|
|
|
1338
1367
|
if (await fileManager.pathExists(coreAgentPath)) {
|
|
1339
1368
|
spinner.text = `Copying core agent ${agentId} for ${packId}...`;
|
|
1340
1369
|
|
|
1341
|
-
// Copy agent file
|
|
1370
|
+
// Copy agent file with {root} replacement
|
|
1342
1371
|
const destPath = path.join(expansionDotFolder, 'agents', `${agentId}.md`);
|
|
1343
|
-
await fileManager.
|
|
1372
|
+
await fileManager.copyFileWithRootReplacement(coreAgentPath, destPath, `.${packId}`);
|
|
1344
1373
|
existingAgents.add(agentId);
|
|
1345
1374
|
|
|
1346
1375
|
console.log(chalk.dim(` Added core agent: ${agentId}`));
|
|
@@ -1352,7 +1381,7 @@ class Installer {
|
|
|
1352
1381
|
if (yamlContent) {
|
|
1353
1382
|
try {
|
|
1354
1383
|
|
|
1355
|
-
const agentConfig = yaml.
|
|
1384
|
+
const agentConfig = yaml.load(yamlContent);
|
|
1356
1385
|
const dependencies = agentConfig.dependencies || {};
|
|
1357
1386
|
|
|
1358
1387
|
// Copy all dependencies for this agent
|
|
@@ -1370,7 +1399,7 @@ class Installer {
|
|
|
1370
1399
|
|
|
1371
1400
|
if (await fileManager.pathExists(coreDepPath)) {
|
|
1372
1401
|
const destDepPath = path.join(expansionDotFolder, depType, depFileName);
|
|
1373
|
-
await fileManager.
|
|
1402
|
+
await fileManager.copyFileWithRootReplacement(coreDepPath, destDepPath, `.${packId}`);
|
|
1374
1403
|
console.log(chalk.dim(` Added agent dependency: ${depType}/${depFileName}`));
|
|
1375
1404
|
} else {
|
|
1376
1405
|
// Try common folder
|
|
@@ -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",
|
|
@@ -1,219 +0,0 @@
|
|
|
1
|
-
# Plan Management Utility
|
|
2
|
-
|
|
3
|
-
## Purpose
|
|
4
|
-
|
|
5
|
-
Provides utilities for agents and tasks to interact with workflow plans, check progress, update status, and ensure workflow steps are executed in the appropriate sequence.
|
|
6
|
-
|
|
7
|
-
## Core Functions
|
|
8
|
-
|
|
9
|
-
### 1. Check Plan Existence
|
|
10
|
-
|
|
11
|
-
Check for workflow plan:
|
|
12
|
-
|
|
13
|
-
1. Look for docs/workflow-plan.md (default location)
|
|
14
|
-
2. Return plan status to user (exists/not exists) - if not exists then HALT.
|
|
15
|
-
|
|
16
|
-
### 2. Parse Plan Status
|
|
17
|
-
|
|
18
|
-
[[LLM: Extract current progress from the plan document]]
|
|
19
|
-
|
|
20
|
-
**Plan Parsing Logic:**
|
|
21
|
-
|
|
22
|
-
1. **Identify Step Structure**:
|
|
23
|
-
- Look for checkbox lines: `- [ ]` or `- [x]`
|
|
24
|
-
- Extract step IDs from comments: `<!-- step-id: X.Y -->`
|
|
25
|
-
- Identify agent assignments: `<!-- agent: pm -->`
|
|
26
|
-
|
|
27
|
-
2. **Determine Current State**:
|
|
28
|
-
- Last completed step (highest numbered `[x]`)
|
|
29
|
-
- Next expected step (first `[ ]` after completed steps)
|
|
30
|
-
- Overall progress percentage
|
|
31
|
-
|
|
32
|
-
3. **Extract Metadata**:
|
|
33
|
-
- Workflow type from plan header
|
|
34
|
-
- Decision points and their status
|
|
35
|
-
- Any deviation notes
|
|
36
|
-
|
|
37
|
-
### 3. Sequence Validation
|
|
38
|
-
|
|
39
|
-
[[LLM: Check if requested action aligns with plan sequence]]
|
|
40
|
-
|
|
41
|
-
**Validation Rules:**
|
|
42
|
-
|
|
43
|
-
1. **Strict Mode** (enforceSequence: true):
|
|
44
|
-
- Must complete steps in exact order
|
|
45
|
-
- Warn and block if out of sequence
|
|
46
|
-
- Require explicit override justification
|
|
47
|
-
|
|
48
|
-
2. **Flexible Mode** (enforceSequence: false):
|
|
49
|
-
- Warn about sequence deviation
|
|
50
|
-
- Allow with confirmation
|
|
51
|
-
- Log deviation reason
|
|
52
|
-
|
|
53
|
-
**Warning Templates:**
|
|
54
|
-
|
|
55
|
-
```text
|
|
56
|
-
SEQUENCE WARNING:
|
|
57
|
-
The workflow plan shows you should complete "{expected_step}" next.
|
|
58
|
-
You're attempting to: "{requested_action}"
|
|
59
|
-
|
|
60
|
-
In strict mode: Block and require plan update
|
|
61
|
-
In flexible mode: Allow with confirmation
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
### 4. Plan Update Operations
|
|
65
|
-
|
|
66
|
-
[[LLM: Provide consistent way to update plan progress]]
|
|
67
|
-
|
|
68
|
-
**Update Actions:**
|
|
69
|
-
|
|
70
|
-
1. **Mark Step Complete**:
|
|
71
|
-
- Change `- [ ]` to `- [x]`
|
|
72
|
-
- Add completion timestamp comment
|
|
73
|
-
- Update any status metadata
|
|
74
|
-
|
|
75
|
-
2. **Add Deviation Note**:
|
|
76
|
-
- Insert note explaining why sequence changed
|
|
77
|
-
- Reference the deviation in plan
|
|
78
|
-
|
|
79
|
-
3. **Update Current Step Pointer**:
|
|
80
|
-
- Add/move `<!-- current-step -->` marker
|
|
81
|
-
- Update last-modified timestamp
|
|
82
|
-
|
|
83
|
-
### 5. Integration Instructions
|
|
84
|
-
|
|
85
|
-
[[LLM: How agents and tasks should use this utility]]
|
|
86
|
-
|
|
87
|
-
**For Agents (startup sequence)**:
|
|
88
|
-
|
|
89
|
-
```text
|
|
90
|
-
1. Check if plan exists using this utility
|
|
91
|
-
2. If exists:
|
|
92
|
-
- Parse current status
|
|
93
|
-
- Show user: "Active workflow plan detected. Current step: {X}"
|
|
94
|
-
- Suggest: "Next recommended action: {next_step}"
|
|
95
|
-
3. Continue with normal startup
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
**For Tasks (pre-execution)**:
|
|
99
|
-
|
|
100
|
-
```text
|
|
101
|
-
1. Check if plan exists
|
|
102
|
-
2. If exists:
|
|
103
|
-
- Verify this task aligns with plan
|
|
104
|
-
- If not aligned:
|
|
105
|
-
- In strict mode: Show warning and stop
|
|
106
|
-
- In flexible mode: Show warning and ask for confirmation
|
|
107
|
-
3. After task completion:
|
|
108
|
-
- Update plan if task was a planned step
|
|
109
|
-
- Add note if task was unplanned
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
### 6. Plan Status Report Format
|
|
113
|
-
|
|
114
|
-
[[LLM: Standard format for showing plan status]]
|
|
115
|
-
|
|
116
|
-
```text
|
|
117
|
-
📋 Workflow Plan Status
|
|
118
|
-
━━━━━━━━━━━━━━━━━━━━
|
|
119
|
-
Workflow: {workflow_name}
|
|
120
|
-
Progress: {X}% complete ({completed}/{total} steps)
|
|
121
|
-
|
|
122
|
-
✅ Completed:
|
|
123
|
-
- {completed_step_1}
|
|
124
|
-
- {completed_step_2}
|
|
125
|
-
|
|
126
|
-
🔄 Current Step:
|
|
127
|
-
- {current_step_description}
|
|
128
|
-
|
|
129
|
-
📌 Upcoming:
|
|
130
|
-
- {next_step_1}
|
|
131
|
-
- {next_step_2}
|
|
132
|
-
|
|
133
|
-
⚠️ Notes:
|
|
134
|
-
- {any_deviations_or_notes}
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
### 7. Decision Point Handling
|
|
138
|
-
|
|
139
|
-
[[LLM: Special handling for workflow decision points]]
|
|
140
|
-
|
|
141
|
-
When encountering a decision point in the plan:
|
|
142
|
-
|
|
143
|
-
1. **Identify Decision Marker**: `<!-- decision: {decision_id} -->`
|
|
144
|
-
2. **Check Decision Status**: Made/Pending
|
|
145
|
-
3. **If Pending**:
|
|
146
|
-
- Block progress until decision made
|
|
147
|
-
- Show options to user
|
|
148
|
-
- Record decision when made
|
|
149
|
-
4. **If Made**:
|
|
150
|
-
- Verify current path aligns with decision
|
|
151
|
-
- Warn if attempting alternate path
|
|
152
|
-
|
|
153
|
-
### 8. Plan Abandonment
|
|
154
|
-
|
|
155
|
-
[[LLM: Graceful handling when user wants to stop following plan]]
|
|
156
|
-
|
|
157
|
-
If user wants to abandon plan:
|
|
158
|
-
|
|
159
|
-
1. Confirm abandonment intent
|
|
160
|
-
2. Add abandonment note to plan
|
|
161
|
-
3. Mark plan as "Abandoned" in header
|
|
162
|
-
4. Stop plan checking for remainder of session
|
|
163
|
-
5. Suggest creating new plan if needed
|
|
164
|
-
|
|
165
|
-
## Usage Examples
|
|
166
|
-
|
|
167
|
-
### Example 1: Agent Startup Check
|
|
168
|
-
|
|
169
|
-
```text
|
|
170
|
-
BMad Master starting...
|
|
171
|
-
|
|
172
|
-
[Check for plan]
|
|
173
|
-
Found active workflow plan: brownfield-fullstack
|
|
174
|
-
Progress: 40% complete (4/10 steps)
|
|
175
|
-
Current step: Create PRD (pm agent)
|
|
176
|
-
|
|
177
|
-
Suggestion: Based on your plan, you should work with the PM agent next.
|
|
178
|
-
Use *agent pm to switch, or *plan-status to see full progress.
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
### Example 2: Task Sequence Warning
|
|
182
|
-
|
|
183
|
-
```text
|
|
184
|
-
User: *task create-next-story
|
|
185
|
-
|
|
186
|
-
[Plan check triggered]
|
|
187
|
-
⚠️ SEQUENCE WARNING:
|
|
188
|
-
Your workflow plan indicates the PRD hasn't been created yet.
|
|
189
|
-
Creating stories before the PRD may lead to incomplete requirements.
|
|
190
|
-
|
|
191
|
-
Would you like to:
|
|
192
|
-
1. Continue anyway (will note deviation in plan)
|
|
193
|
-
2. Switch to creating PRD first (*agent pm)
|
|
194
|
-
3. View plan status (*plan-status)
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
### Example 3: Automatic Plan Update
|
|
198
|
-
|
|
199
|
-
```text
|
|
200
|
-
[After completing create-doc task for PRD]
|
|
201
|
-
|
|
202
|
-
✅ Plan Updated: Marked "Create PRD" as complete
|
|
203
|
-
📍 Next step: Create Architecture Document (architect agent)
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
## Implementation Notes
|
|
207
|
-
|
|
208
|
-
- This utility should be lightweight and fast
|
|
209
|
-
- Plan parsing should be resilient to format variations
|
|
210
|
-
- Always preserve user agency - warnings not blocks (unless strict mode)
|
|
211
|
-
- Plan updates should be atomic to prevent corruption
|
|
212
|
-
- Consider plan versioning for rollback capability
|
|
213
|
-
|
|
214
|
-
## Error Handling
|
|
215
|
-
|
|
216
|
-
- Missing plan: Return null, don't error
|
|
217
|
-
- Malformed plan: Warn but continue, treat as no plan
|
|
218
|
-
- Update failures: Log but don't block task completion
|
|
219
|
-
- Parse errors: Fallback to basic text search
|