2025-10-26 19:38:38 -05:00
|
|
|
const path = require('node:path');
|
|
|
|
|
const fs = require('fs-extra');
|
|
|
|
|
const csv = require('csv-parse/sync');
|
|
|
|
|
const chalk = require('chalk');
|
|
|
|
|
|
|
|
|
|
/**
|
Major Enhancements:
- Installation path is now fully configurable, allowing users to specify custom installation directories during setup
- Default installation location changed to .bmad (hidden directory) for cleaner project root organization
Web Bundle Improvements:
- All web bundles (single agent and team) now include party mode support for multi-agent collaboration!
- Advanced elicitation capabilities integrated into standalone agents
- All bundles enhanced with party mode agent manifests
- Added default-party.csv files to bmm, bmgd, and cis module teams
- The default party file is what will be used with single agent bundles. teams can customize for different party configurations before web bundling through a setting in the team yaml file
- New web bundle outputs for all agents (analyst, architect, dev, pm, sm, tea, tech-writer, ux-designer, game-*, creative-squad)
Phase 4 Workflow Updates (In Progress):
- Initiated shift to separate phase 4 implementation artifacts from documentation
- Phase 4 implementation artifacts (stories, code review, sprint plan, context files) will move to dedicated location outside docs folder
- Installer questions and configuration added for artifact path selection
- Updated workflow.yaml files for code-review, sprint-planning, story-context, epic-tech-context, and retrospective workflows to support this, but still might require some udpates
Additional Changes:
- New agent and action command header models for standardization
- Enhanced web-bundle-activation-steps fragment
- Updated web-bundler.js to support new structure
- VS Code settings updated for new .bmad directory
- Party mode instructions and workflow enhanced for better orchestration
IDE Installer Updates:
- Show version number of installer in cli
- improved Installer UX
- Gemini TOML Improved to have clear loading instructions with @ commands
- All tools agent launcher mds improved to use a central file template critical indication isntead of hardcoding in 2 different locations.
2025-11-09 17:39:05 -06:00
|
|
|
* Generates command files for standalone tasks and tools
|
2025-10-26 19:38:38 -05:00
|
|
|
*/
|
|
|
|
|
class TaskToolCommandGenerator {
|
|
|
|
|
/**
|
|
|
|
|
* Generate task and tool commands from manifest CSVs
|
|
|
|
|
* @param {string} projectDir - Project directory
|
|
|
|
|
* @param {string} bmadDir - BMAD installation directory
|
|
|
|
|
* @param {string} baseCommandsDir - Optional base commands directory (defaults to .claude/commands/bmad)
|
|
|
|
|
*/
|
|
|
|
|
async generateTaskToolCommands(projectDir, bmadDir, baseCommandsDir = null) {
|
|
|
|
|
const tasks = await this.loadTaskManifest(bmadDir);
|
|
|
|
|
const tools = await this.loadToolManifest(bmadDir);
|
|
|
|
|
|
|
|
|
|
// Filter to only standalone items
|
|
|
|
|
const standaloneTasks = tasks ? tasks.filter((t) => t.standalone === 'true' || t.standalone === true) : [];
|
|
|
|
|
const standaloneTools = tools ? tools.filter((t) => t.standalone === 'true' || t.standalone === true) : [];
|
|
|
|
|
|
|
|
|
|
// Base commands directory - use provided or default to Claude Code structure
|
|
|
|
|
const commandsDir = baseCommandsDir || path.join(projectDir, '.claude', 'commands', 'bmad');
|
|
|
|
|
|
|
|
|
|
let generatedCount = 0;
|
|
|
|
|
|
|
|
|
|
// Generate command files for tasks
|
|
|
|
|
for (const task of standaloneTasks) {
|
|
|
|
|
const moduleTasksDir = path.join(commandsDir, task.module, 'tasks');
|
|
|
|
|
await fs.ensureDir(moduleTasksDir);
|
|
|
|
|
|
|
|
|
|
const commandContent = this.generateCommandContent(task, 'task');
|
|
|
|
|
const commandPath = path.join(moduleTasksDir, `${task.name}.md`);
|
|
|
|
|
|
|
|
|
|
await fs.writeFile(commandPath, commandContent);
|
|
|
|
|
generatedCount++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Generate command files for tools
|
|
|
|
|
for (const tool of standaloneTools) {
|
|
|
|
|
const moduleToolsDir = path.join(commandsDir, tool.module, 'tools');
|
|
|
|
|
await fs.ensureDir(moduleToolsDir);
|
|
|
|
|
|
|
|
|
|
const commandContent = this.generateCommandContent(tool, 'tool');
|
|
|
|
|
const commandPath = path.join(moduleToolsDir, `${tool.name}.md`);
|
|
|
|
|
|
|
|
|
|
await fs.writeFile(commandPath, commandContent);
|
|
|
|
|
generatedCount++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
generated: generatedCount,
|
|
|
|
|
tasks: standaloneTasks.length,
|
|
|
|
|
tools: standaloneTools.length,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Generate command content for a task or tool
|
|
|
|
|
*/
|
|
|
|
|
generateCommandContent(item, type) {
|
|
|
|
|
const description = item.description || `Execute ${item.displayName || item.name}`;
|
|
|
|
|
|
|
|
|
|
// Convert path to use {project-root} placeholder
|
|
|
|
|
let itemPath = item.path;
|
|
|
|
|
if (itemPath.startsWith('bmad/')) {
|
|
|
|
|
itemPath = `{project-root}/${itemPath}`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return `---
|
|
|
|
|
description: '${description.replaceAll("'", "''")}'
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
# ${item.displayName || item.name}
|
|
|
|
|
|
|
|
|
|
LOAD and execute the ${type} at: ${itemPath}
|
|
|
|
|
|
|
|
|
|
Follow all instructions in the ${type} file exactly as written.
|
|
|
|
|
`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Load task manifest CSV
|
|
|
|
|
*/
|
|
|
|
|
async loadTaskManifest(bmadDir) {
|
2025-12-13 19:41:09 +08:00
|
|
|
const manifestPath = path.join(bmadDir, '_config', 'task-manifest.csv');
|
2025-10-26 19:38:38 -05:00
|
|
|
|
|
|
|
|
if (!(await fs.pathExists(manifestPath))) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const csvContent = await fs.readFile(manifestPath, 'utf8');
|
|
|
|
|
return csv.parse(csvContent, {
|
|
|
|
|
columns: true,
|
|
|
|
|
skip_empty_lines: true,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Load tool manifest CSV
|
|
|
|
|
*/
|
|
|
|
|
async loadToolManifest(bmadDir) {
|
2025-12-13 19:41:09 +08:00
|
|
|
const manifestPath = path.join(bmadDir, '_config', 'tool-manifest.csv');
|
2025-10-26 19:38:38 -05:00
|
|
|
|
|
|
|
|
if (!(await fs.pathExists(manifestPath))) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const csvContent = await fs.readFile(manifestPath, 'utf8');
|
|
|
|
|
return csv.parse(csvContent, {
|
|
|
|
|
columns: true,
|
|
|
|
|
skip_empty_lines: true,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
module.exports = { TaskToolCommandGenerator };
|