mirror of
https://github.com/bmadcode/BMAD-METHOD.git
synced 2025-12-29 16:14:59 +00:00
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.
This commit is contained in:
@@ -1,70 +1,17 @@
|
||||
const path = require('node:path');
|
||||
const os = require('node:os');
|
||||
const { BaseIdeSetup } = require('./_base-ide');
|
||||
const chalk = require('chalk');
|
||||
const inquirer = require('inquirer');
|
||||
|
||||
/**
|
||||
* Auggie CLI setup handler
|
||||
* Allows flexible installation of agents to multiple locations
|
||||
* Installs to project directory (.augment/commands)
|
||||
*/
|
||||
class AuggieSetup extends BaseIdeSetup {
|
||||
constructor() {
|
||||
super('auggie', 'Auggie CLI');
|
||||
this.defaultLocations = [
|
||||
{ name: 'Project Directory (.augment/commands)', value: '.augment/commands', checked: true },
|
||||
{ name: 'User Home (~/.augment/commands)', value: path.join(os.homedir(), '.augment', 'commands') },
|
||||
{ name: 'Custom Location', value: 'custom' },
|
||||
];
|
||||
this.detectionPaths = ['.augment'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect configuration choices before installation
|
||||
* @param {Object} options - Configuration options
|
||||
* @returns {Object} Collected configuration
|
||||
*/
|
||||
async collectConfiguration(options = {}) {
|
||||
const response = await inquirer.prompt([
|
||||
{
|
||||
type: 'checkbox',
|
||||
name: 'locations',
|
||||
message: 'Select Auggie CLI installation locations:',
|
||||
choices: this.defaultLocations,
|
||||
validate: (answers) => {
|
||||
if (answers.length === 0) {
|
||||
return 'Please select at least one location';
|
||||
}
|
||||
return true;
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
const locations = [];
|
||||
for (const loc of response.locations) {
|
||||
if (loc === 'custom') {
|
||||
const custom = await inquirer.prompt([
|
||||
{
|
||||
type: 'input',
|
||||
name: 'path',
|
||||
message: 'Enter custom path for Auggie commands:',
|
||||
validate: (input) => {
|
||||
if (!input.trim()) {
|
||||
return 'Path cannot be empty';
|
||||
}
|
||||
return true;
|
||||
},
|
||||
},
|
||||
]);
|
||||
locations.push(custom.path);
|
||||
} else {
|
||||
locations.push(loc);
|
||||
}
|
||||
}
|
||||
|
||||
return { auggieLocations: locations };
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup Auggie CLI configuration
|
||||
* @param {string} projectDir - Project directory
|
||||
@@ -74,14 +21,8 @@ class AuggieSetup extends BaseIdeSetup {
|
||||
async setup(projectDir, bmadDir, options = {}) {
|
||||
console.log(chalk.cyan(`Setting up ${this.name}...`));
|
||||
|
||||
// Use pre-collected configuration if available
|
||||
const config = options.preCollectedConfig || {};
|
||||
const locations = await this.getInstallLocations(projectDir, { ...options, auggieLocations: config.auggieLocations });
|
||||
|
||||
if (locations.length === 0) {
|
||||
console.log(chalk.yellow('No locations selected. Skipping Auggie CLI setup.'));
|
||||
return { success: false, reason: 'no-locations' };
|
||||
}
|
||||
// Always use project directory
|
||||
const location = path.join(projectDir, '.augment', 'commands');
|
||||
|
||||
// Clean up old BMAD installation first
|
||||
await this.cleanup(projectDir);
|
||||
@@ -92,151 +33,93 @@ class AuggieSetup extends BaseIdeSetup {
|
||||
const tools = await this.getTools(bmadDir, true);
|
||||
const workflows = await this.getWorkflows(bmadDir, true);
|
||||
|
||||
let totalInstalled = 0;
|
||||
const bmadCommandsDir = path.join(location, 'bmad');
|
||||
const agentsDir = path.join(bmadCommandsDir, 'agents');
|
||||
const tasksDir = path.join(bmadCommandsDir, 'tasks');
|
||||
const toolsDir = path.join(bmadCommandsDir, 'tools');
|
||||
const workflowsDir = path.join(bmadCommandsDir, 'workflows');
|
||||
|
||||
// Install to each selected location
|
||||
for (const location of locations) {
|
||||
console.log(chalk.dim(`\n Installing to: ${location}`));
|
||||
await this.ensureDir(agentsDir);
|
||||
await this.ensureDir(tasksDir);
|
||||
await this.ensureDir(toolsDir);
|
||||
await this.ensureDir(workflowsDir);
|
||||
|
||||
const bmadCommandsDir = path.join(location, 'bmad');
|
||||
const agentsDir = path.join(bmadCommandsDir, 'agents');
|
||||
const tasksDir = path.join(bmadCommandsDir, 'tasks');
|
||||
const toolsDir = path.join(bmadCommandsDir, 'tools');
|
||||
const workflowsDir = path.join(bmadCommandsDir, 'workflows');
|
||||
// Install agents
|
||||
for (const agent of agents) {
|
||||
const content = await this.readFile(agent.path);
|
||||
const commandContent = await this.createAgentCommand(agent, content);
|
||||
|
||||
await this.ensureDir(agentsDir);
|
||||
await this.ensureDir(tasksDir);
|
||||
await this.ensureDir(toolsDir);
|
||||
await this.ensureDir(workflowsDir);
|
||||
|
||||
// Install agents
|
||||
for (const agent of agents) {
|
||||
const content = await this.readFile(agent.path);
|
||||
const commandContent = this.createAgentCommand(agent, content);
|
||||
|
||||
const targetPath = path.join(agentsDir, `${agent.module}-${agent.name}.md`);
|
||||
await this.writeFile(targetPath, commandContent);
|
||||
totalInstalled++;
|
||||
}
|
||||
|
||||
// Install tasks
|
||||
for (const task of tasks) {
|
||||
const content = await this.readFile(task.path);
|
||||
const commandContent = this.createTaskCommand(task, content);
|
||||
|
||||
const targetPath = path.join(tasksDir, `${task.module}-${task.name}.md`);
|
||||
await this.writeFile(targetPath, commandContent);
|
||||
totalInstalled++;
|
||||
}
|
||||
|
||||
// Install tools
|
||||
for (const tool of tools) {
|
||||
const content = await this.readFile(tool.path);
|
||||
const commandContent = this.createToolCommand(tool, content);
|
||||
|
||||
const targetPath = path.join(toolsDir, `${tool.module}-${tool.name}.md`);
|
||||
await this.writeFile(targetPath, commandContent);
|
||||
totalInstalled++;
|
||||
}
|
||||
|
||||
// Install workflows
|
||||
for (const workflow of workflows) {
|
||||
const content = await this.readFile(workflow.path);
|
||||
const commandContent = this.createWorkflowCommand(workflow, content);
|
||||
|
||||
const targetPath = path.join(workflowsDir, `${workflow.module}-${workflow.name}.md`);
|
||||
await this.writeFile(targetPath, commandContent);
|
||||
totalInstalled++;
|
||||
}
|
||||
|
||||
console.log(
|
||||
chalk.green(` ✓ Installed ${agents.length} agents, ${tasks.length} tasks, ${tools.length} tools, ${workflows.length} workflows`),
|
||||
);
|
||||
const targetPath = path.join(agentsDir, `${agent.module}-${agent.name}.md`);
|
||||
await this.writeFile(targetPath, commandContent);
|
||||
}
|
||||
|
||||
console.log(chalk.green(`\n✓ ${this.name} configured:`));
|
||||
console.log(chalk.dim(` - ${totalInstalled} total commands installed`));
|
||||
console.log(chalk.dim(` - ${locations.length} location(s) configured`));
|
||||
// Install tasks
|
||||
for (const task of tasks) {
|
||||
const content = await this.readFile(task.path);
|
||||
const commandContent = this.createTaskCommand(task, content);
|
||||
|
||||
const targetPath = path.join(tasksDir, `${task.module}-${task.name}.md`);
|
||||
await this.writeFile(targetPath, commandContent);
|
||||
}
|
||||
|
||||
// Install tools
|
||||
for (const tool of tools) {
|
||||
const content = await this.readFile(tool.path);
|
||||
const commandContent = this.createToolCommand(tool, content);
|
||||
|
||||
const targetPath = path.join(toolsDir, `${tool.module}-${tool.name}.md`);
|
||||
await this.writeFile(targetPath, commandContent);
|
||||
}
|
||||
|
||||
// Install workflows
|
||||
for (const workflow of workflows) {
|
||||
const content = await this.readFile(workflow.path);
|
||||
const commandContent = this.createWorkflowCommand(workflow, content);
|
||||
|
||||
const targetPath = path.join(workflowsDir, `${workflow.module}-${workflow.name}.md`);
|
||||
await this.writeFile(targetPath, commandContent);
|
||||
}
|
||||
|
||||
const totalInstalled = agents.length + tasks.length + tools.length + workflows.length;
|
||||
|
||||
console.log(chalk.green(`✓ ${this.name} configured:`));
|
||||
console.log(chalk.dim(` - ${agents.length} agents installed`));
|
||||
console.log(chalk.dim(` - ${tasks.length} tasks installed`));
|
||||
console.log(chalk.dim(` - ${tools.length} tools installed`));
|
||||
console.log(chalk.dim(` - ${workflows.length} workflows installed`));
|
||||
console.log(chalk.dim(` - Location: ${path.relative(projectDir, location)}`));
|
||||
console.log(chalk.yellow(`\n 💡 Tip: Add 'model: gpt-4o' to command frontmatter to specify AI model`));
|
||||
|
||||
return {
|
||||
success: true,
|
||||
commands: totalInstalled,
|
||||
locations: locations.length,
|
||||
agents: agents.length,
|
||||
tasks: tasks.length,
|
||||
tools: tools.length,
|
||||
workflows: workflows.length,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get installation locations from user
|
||||
*/
|
||||
async getInstallLocations(projectDir, options) {
|
||||
if (options.auggieLocations) {
|
||||
// Process the pre-collected locations to resolve relative paths
|
||||
const processedLocations = [];
|
||||
for (const loc of options.auggieLocations) {
|
||||
if (loc === '.augment/commands') {
|
||||
// Relative to project directory
|
||||
processedLocations.push(path.join(projectDir, loc));
|
||||
} else {
|
||||
processedLocations.push(loc);
|
||||
}
|
||||
}
|
||||
return processedLocations;
|
||||
}
|
||||
|
||||
const response = await inquirer.prompt([
|
||||
{
|
||||
type: 'checkbox',
|
||||
name: 'locations',
|
||||
message: 'Select Auggie CLI installation locations:',
|
||||
choices: this.defaultLocations,
|
||||
validate: (answers) => {
|
||||
if (answers.length === 0) {
|
||||
return 'Please select at least one location';
|
||||
}
|
||||
return true;
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
const locations = [];
|
||||
for (const loc of response.locations) {
|
||||
if (loc === 'custom') {
|
||||
const custom = await inquirer.prompt([
|
||||
{
|
||||
type: 'input',
|
||||
name: 'path',
|
||||
message: 'Enter custom path for Auggie commands:',
|
||||
validate: (input) => {
|
||||
if (!input.trim()) {
|
||||
return 'Path cannot be empty';
|
||||
}
|
||||
return true;
|
||||
},
|
||||
},
|
||||
]);
|
||||
locations.push(custom.path);
|
||||
} else if (loc.startsWith('.augment')) {
|
||||
// Relative to project directory
|
||||
locations.push(path.join(projectDir, loc));
|
||||
} else {
|
||||
locations.push(loc);
|
||||
}
|
||||
}
|
||||
|
||||
return locations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create agent command content
|
||||
*/
|
||||
createAgentCommand(agent, content) {
|
||||
async createAgentCommand(agent, content) {
|
||||
const titleMatch = content.match(/title="([^"]+)"/);
|
||||
const title = titleMatch ? titleMatch[1] : this.formatTitle(agent.name);
|
||||
|
||||
return `# ${title} Agent
|
||||
// Extract description from agent if available
|
||||
const whenToUseMatch = content.match(/whenToUse="([^"]+)"/);
|
||||
const description = whenToUseMatch ? whenToUseMatch[1] : `Activate the ${title} agent`;
|
||||
|
||||
## Activation
|
||||
Type \`@${agent.name}\` to activate this agent.
|
||||
// Get the activation header from central template
|
||||
const activationHeader = await this.getAgentCommandHeader();
|
||||
|
||||
return `---
|
||||
description: "${description}"
|
||||
---
|
||||
|
||||
# ${title} Agent
|
||||
|
||||
${activationHeader}
|
||||
|
||||
${content}
|
||||
|
||||
@@ -252,10 +135,11 @@ BMAD ${agent.module.toUpperCase()} module
|
||||
const nameMatch = content.match(/name="([^"]+)"/);
|
||||
const taskName = nameMatch ? nameMatch[1] : this.formatTitle(task.name);
|
||||
|
||||
return `# ${taskName} Task
|
||||
return `---
|
||||
description: "Execute the ${taskName} task"
|
||||
---
|
||||
|
||||
## Activation
|
||||
Type \`@task-${task.name}\` to execute this task.
|
||||
# ${taskName} Task
|
||||
|
||||
${content}
|
||||
|
||||
@@ -271,10 +155,11 @@ BMAD ${task.module.toUpperCase()} module
|
||||
const nameMatch = content.match(/name="([^"]+)"/);
|
||||
const toolName = nameMatch ? nameMatch[1] : this.formatTitle(tool.name);
|
||||
|
||||
return `# ${toolName} Tool
|
||||
return `---
|
||||
description: "Use the ${toolName} tool"
|
||||
---
|
||||
|
||||
## Activation
|
||||
Type \`@tool-${tool.name}\` to execute this tool.
|
||||
# ${toolName} Tool
|
||||
|
||||
${content}
|
||||
|
||||
@@ -287,13 +172,13 @@ BMAD ${tool.module.toUpperCase()} module
|
||||
* Create workflow command content
|
||||
*/
|
||||
createWorkflowCommand(workflow, content) {
|
||||
return `# ${workflow.name} Workflow
|
||||
const description = workflow.description || `Execute the ${workflow.name} workflow`;
|
||||
|
||||
## Description
|
||||
${workflow.description || 'No description provided'}
|
||||
return `---
|
||||
description: "${description}"
|
||||
---
|
||||
|
||||
## Activation
|
||||
Type \`@workflow-${workflow.name}\` to execute this workflow.
|
||||
# ${workflow.name} Workflow
|
||||
|
||||
${content}
|
||||
|
||||
@@ -308,16 +193,13 @@ BMAD ${workflow.module.toUpperCase()} module
|
||||
async cleanup(projectDir) {
|
||||
const fs = require('fs-extra');
|
||||
|
||||
// Check common locations - bmad folder structure
|
||||
const locations = [path.join(os.homedir(), '.augment', 'commands'), path.join(projectDir, '.augment', 'commands')];
|
||||
// Only clean up project directory
|
||||
const location = path.join(projectDir, '.augment', 'commands');
|
||||
const bmadDir = path.join(location, 'bmad');
|
||||
|
||||
for (const location of locations) {
|
||||
const bmadDir = path.join(location, 'bmad');
|
||||
|
||||
if (await fs.pathExists(bmadDir)) {
|
||||
await fs.remove(bmadDir);
|
||||
console.log(chalk.dim(` Removed old BMAD commands from ${location}`));
|
||||
}
|
||||
if (await fs.pathExists(bmadDir)) {
|
||||
await fs.remove(bmadDir);
|
||||
console.log(chalk.dim(` Removed old BMAD commands`));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user