installer fixes

This commit is contained in:
Brian Madison 2025-12-03 22:44:13 -06:00
parent aa1cf76f88
commit 0b9290789e
8 changed files with 167 additions and 36 deletions

View File

@ -1,7 +1,7 @@
---
name: create-prd
description: Creates a comprehensive PRDs through collaborative step-by-step discovery between two product managers working as peers.
main_config: `{project-root}/{bmad_folder}/bmm/config.yaml`
main_config: '{project-root}/{bmad_folder}/bmm/config.yaml'
web_bundle: true
---

View File

@ -3,6 +3,7 @@ const fs = require('fs-extra');
const { BaseIdeSetup } = require('./_base-ide');
const chalk = require('chalk');
const { AgentCommandGenerator } = require('./shared/agent-command-generator');
const { WorkflowCommandGenerator } = require('./shared/workflow-command-generator');
/**
* Auggie CLI setup handler
@ -33,10 +34,23 @@ class AuggieSetup extends BaseIdeSetup {
const agentGen = new AgentCommandGenerator(this.bmadFolderName);
const { artifacts: agentArtifacts } = await agentGen.collectAgentArtifacts(bmadDir, options.selectedModules || []);
// Get tasks, tools, and workflows (standalone only)
// Get tasks, tools, and workflows (ALL workflows now generate commands)
const tasks = await this.getTasks(bmadDir, true);
const tools = await this.getTools(bmadDir, true);
const workflows = await this.getWorkflows(bmadDir, true);
// Get ALL workflows using the new workflow command generator
const workflowGenerator = new WorkflowCommandGenerator(this.bmadFolderName);
const { artifacts: workflowArtifacts, counts: workflowCounts } = await workflowGenerator.collectWorkflowArtifacts(bmadDir);
// Convert workflow artifacts to expected format
const workflows = workflowArtifacts
.filter((artifact) => artifact.type === 'workflow-command')
.map((artifact) => ({
module: artifact.module,
name: path.basename(artifact.relativePath, '.md'),
path: artifact.sourcePath,
content: artifact.content,
}));
const bmadCommandsDir = path.join(location, 'bmad');
const agentsDir = path.join(bmadCommandsDir, 'agents');
@ -73,13 +87,11 @@ class AuggieSetup extends BaseIdeSetup {
await this.writeFile(targetPath, commandContent);
}
// Install workflows
// Install workflows (already generated commands)
for (const workflow of workflows) {
const content = await this.readFile(workflow.path);
const commandContent = this.createWorkflowCommand(workflow, content);
// Use the pre-generated workflow command content
const targetPath = path.join(workflowsDir, `${workflow.module}-${workflow.name}.md`);
await this.writeFile(targetPath, commandContent);
await this.writeFile(targetPath, workflow.content);
}
const totalInstalled = agentArtifacts.length + tasks.length + tools.length + workflows.length;

View File

@ -3,6 +3,7 @@ const fs = require('fs-extra');
const { BaseIdeSetup } = require('./_base-ide');
const chalk = require('chalk');
const { AgentCommandGenerator } = require('./shared/agent-command-generator');
const { WorkflowCommandGenerator } = require('./shared/workflow-command-generator');
/**
* Crush IDE setup handler
@ -34,10 +35,23 @@ class CrushSetup extends BaseIdeSetup {
const agentGen = new AgentCommandGenerator(this.bmadFolderName);
const { artifacts: agentArtifacts } = await agentGen.collectAgentArtifacts(bmadDir, options.selectedModules || []);
// Get tasks, tools, and workflows (standalone only)
// Get tasks, tools, and workflows (ALL workflows now generate commands)
const tasks = await this.getTasks(bmadDir, true);
const tools = await this.getTools(bmadDir, true);
const workflows = await this.getWorkflows(bmadDir, true);
// Get ALL workflows using the new workflow command generator
const workflowGenerator = new WorkflowCommandGenerator(this.bmadFolderName);
const { artifacts: workflowArtifacts, counts: workflowCounts } = await workflowGenerator.collectWorkflowArtifacts(bmadDir);
// Convert workflow artifacts to expected format for organizeByModule
const workflows = workflowArtifacts
.filter((artifact) => artifact.type === 'workflow-command')
.map((artifact) => ({
module: artifact.module,
name: path.basename(artifact.relativePath, '.md'),
path: artifact.sourcePath,
content: artifact.content,
}));
// Organize by module
const agentCount = await this.organizeByModule(commandsDir, agentArtifacts, tasks, tools, workflows, projectDir);
@ -113,13 +127,12 @@ class CrushSetup extends BaseIdeSetup {
toolCount++;
}
// Copy module-specific workflows
// Copy module-specific workflow commands (already generated)
const moduleWorkflows = workflows.filter((w) => w.module === module);
for (const workflow of moduleWorkflows) {
const content = await this.readFile(workflow.path);
const commandContent = this.createWorkflowCommand(workflow, content);
// Use the pre-generated workflow command content
const targetPath = path.join(moduleWorkflowsDir, `${workflow.name}.md`);
await this.writeFile(targetPath, commandContent);
await this.writeFile(targetPath, workflow.content);
workflowCount++;
}
}

View File

@ -2,6 +2,7 @@ const path = require('node:path');
const { BaseIdeSetup } = require('./_base-ide');
const chalk = require('chalk');
const { AgentCommandGenerator } = require('./shared/agent-command-generator');
const { WorkflowCommandGenerator } = require('./shared/workflow-command-generator');
/**
* Cursor IDE setup handler
@ -53,10 +54,22 @@ class CursorSetup extends BaseIdeSetup {
// Convert artifacts to agent format for index creation
const agents = agentArtifacts.map((a) => ({ module: a.module, name: a.name }));
// Get tasks, tools, and workflows (standalone only)
// Get tasks, tools, and workflows (ALL workflows now generate commands)
const tasks = await this.getTasks(bmadDir, true);
const tools = await this.getTools(bmadDir, true);
const workflows = await this.getWorkflows(bmadDir, true);
// Get ALL workflows using the new workflow command generator
const workflowGenerator = new WorkflowCommandGenerator(this.bmadFolderName);
const { artifacts: workflowArtifacts, counts: workflowCounts } = await workflowGenerator.collectWorkflowArtifacts(bmadDir);
// Convert artifacts to workflow objects for directory creation
const workflows = workflowArtifacts
.filter((artifact) => artifact.type === 'workflow-command')
.map((artifact) => ({
module: artifact.module,
name: path.basename(artifact.relativePath, '.md'),
path: artifact.sourcePath,
}));
// Create directories for each module
const modules = new Set();
@ -113,18 +126,21 @@ class CursorSetup extends BaseIdeSetup {
toolCount++;
}
// Process and copy workflows
// Process and copy workflow commands (generated, not raw workflows)
let workflowCount = 0;
for (const workflow of workflows) {
const content = await this.readAndProcess(workflow.path, {
module: workflow.module,
name: workflow.name,
});
for (const artifact of workflowArtifacts) {
if (artifact.type === 'workflow-command') {
// Add MDC metadata header to workflow command
const content = this.wrapLauncherWithMDC(artifact.content, {
module: artifact.module,
name: path.basename(artifact.relativePath, '.md'),
});
const targetPath = path.join(bmadRulesDir, workflow.module, 'workflows', `${workflow.name}.mdc`);
const targetPath = path.join(bmadRulesDir, artifact.module, 'workflows', `${path.basename(artifact.relativePath, '.md')}.mdc`);
await this.writeFile(targetPath, content);
workflowCount++;
await this.writeFile(targetPath, content);
workflowCount++;
}
}
// Create BMAD index file (but NOT .cursorrules - user manages that)

View File

@ -4,6 +4,7 @@ const yaml = require('js-yaml');
const { BaseIdeSetup } = require('./_base-ide');
const chalk = require('chalk');
const { AgentCommandGenerator } = require('./shared/agent-command-generator');
const { WorkflowCommandGenerator } = require('./shared/workflow-command-generator');
/**
* Gemini CLI setup handler
@ -68,9 +69,13 @@ class GeminiSetup extends BaseIdeSetup {
const agentGen = new AgentCommandGenerator(this.bmadFolderName);
const { artifacts: agentArtifacts } = await agentGen.collectAgentArtifacts(bmadDir, options.selectedModules || []);
// Get tasks
// Get tasks and workflows (ALL workflows now generate commands)
const tasks = await this.getTasks(bmadDir);
// Get ALL workflows using the new workflow command generator
const workflowGenerator = new WorkflowCommandGenerator(this.bmadFolderName);
const { artifacts: workflowArtifacts, counts: workflowCounts } = await workflowGenerator.collectWorkflowArtifacts(bmadDir);
// Install agents as TOML files with bmad- prefix (flat structure)
let agentCount = 0;
for (const artifact of agentArtifacts) {
@ -98,17 +103,37 @@ class GeminiSetup extends BaseIdeSetup {
console.log(chalk.green(` ✓ Added task: /bmad:tasks:${task.module}:${task.name}`));
}
// Install workflows as TOML files with bmad- prefix (flat structure)
let workflowCount = 0;
for (const artifact of workflowArtifacts) {
if (artifact.type === 'workflow-command') {
// Create TOML wrapper around workflow command content
const tomlContent = await this.createWorkflowToml(artifact);
// Flat structure: bmad-workflow-{module}-{name}.toml
const workflowName = path.basename(artifact.relativePath, '.md');
const tomlPath = path.join(commandsDir, `bmad-workflow-${artifact.module}-${workflowName}.toml`);
await this.writeFile(tomlPath, tomlContent);
workflowCount++;
console.log(chalk.green(` ✓ Added workflow: /bmad:workflows:${artifact.module}:${workflowName}`));
}
}
console.log(chalk.green(`${this.name} configured:`));
console.log(chalk.dim(` - ${agentCount} agents configured`));
console.log(chalk.dim(` - ${taskCount} tasks configured`));
console.log(chalk.dim(` - ${workflowCount} workflows configured`));
console.log(chalk.dim(` - Commands directory: ${path.relative(projectDir, commandsDir)}`));
console.log(chalk.dim(` - Agent activation: /bmad:agents:{agent-name}`));
console.log(chalk.dim(` - Task activation: /bmad:tasks:{task-name}`));
console.log(chalk.dim(` - Workflow activation: /bmad:workflows:{workflow-name}`));
return {
success: true,
agents: agentCount,
tasks: taskCount,
workflows: workflowCount,
};
}
@ -179,6 +204,27 @@ ${contentWithoutFrontmatter}
return tomlContent;
}
/**
* Create workflow TOML content from artifact
*/
async createWorkflowToml(artifact) {
// Extract description from artifact content
const descriptionMatch = artifact.content.match(/description:\s*"([^"]+)"/);
const description = descriptionMatch
? descriptionMatch[1]
: `BMAD ${artifact.module.toUpperCase()} Workflow: ${path.basename(artifact.relativePath, '.md')}`;
// Strip frontmatter from command content
const frontmatterRegex = /^---\s*\n[\s\S]*?\n---\s*\n/;
const contentWithoutFrontmatter = artifact.content.replace(frontmatterRegex, '').trim();
return `description = "${description}"
prompt = """
${contentWithoutFrontmatter}
"""
`;
}
/**
* Cleanup Gemini configuration - surgically remove only BMAD files
*/

View File

@ -3,6 +3,7 @@ const fs = require('fs-extra');
const { BaseIdeSetup } = require('./_base-ide');
const chalk = require('chalk');
const { AgentCommandGenerator } = require('./shared/agent-command-generator');
const { WorkflowCommandGenerator } = require('./shared/workflow-command-generator');
/**
* iFlow CLI setup handler
@ -29,9 +30,11 @@ class IFlowSetup extends BaseIdeSetup {
const commandsDir = path.join(iflowDir, this.commandsDir, 'bmad');
const agentsDir = path.join(commandsDir, 'agents');
const tasksDir = path.join(commandsDir, 'tasks');
const workflowsDir = path.join(commandsDir, 'workflows');
await this.ensureDir(agentsDir);
await this.ensureDir(tasksDir);
await this.ensureDir(workflowsDir);
// Generate agent launchers
const agentGen = new AgentCommandGenerator(this.bmadFolderName);
@ -47,9 +50,13 @@ class IFlowSetup extends BaseIdeSetup {
agentCount++;
}
// Get tasks
// Get tasks and workflows (ALL workflows now generate commands)
const tasks = await this.getTasks(bmadDir);
// Get ALL workflows using the new workflow command generator
const workflowGenerator = new WorkflowCommandGenerator(this.bmadFolderName);
const { artifacts: workflowArtifacts, counts: workflowCounts } = await workflowGenerator.collectWorkflowArtifacts(bmadDir);
// Setup tasks as commands
let taskCount = 0;
for (const task of tasks) {
@ -61,15 +68,27 @@ class IFlowSetup extends BaseIdeSetup {
taskCount++;
}
// Setup workflows as commands (already generated)
let workflowCount = 0;
for (const artifact of workflowArtifacts) {
if (artifact.type === 'workflow-command') {
const targetPath = path.join(workflowsDir, `${artifact.module}-${path.basename(artifact.relativePath, '.md')}.md`);
await this.writeFile(targetPath, artifact.content);
workflowCount++;
}
}
console.log(chalk.green(`${this.name} configured:`));
console.log(chalk.dim(` - ${agentCount} agent commands created`));
console.log(chalk.dim(` - ${taskCount} task commands created`));
console.log(chalk.dim(` - ${workflowCount} workflow commands created`));
console.log(chalk.dim(` - Commands directory: ${path.relative(projectDir, commandsDir)}`));
return {
success: true,
agents: agentCount,
tasks: taskCount,
workflows: workflowCount,
};
}

View File

@ -156,16 +156,41 @@ class KiroCliSetup extends BaseIdeSetup {
return;
}
// Extract agent name from ID path (e.g., "{bmad_folder}/bmm/agents/analyst.md" -> "analyst")
const idPath = agentData.agent.metadata.id;
const basename = path.basename(idPath, '.md');
const agentName = basename.startsWith('bmad-') ? basename : `bmad-${basename}`;
// Extract module from file path
const normalizedPath = path.normalize(agentFile);
const pathParts = normalizedPath.split(path.sep);
const basename = path.basename(agentFile, '.agent.yaml');
// Find the module name from path
let moduleName = 'unknown';
if (pathParts.includes('src')) {
const srcIndex = pathParts.indexOf('src');
if (srcIndex + 3 < pathParts.length) {
const folderAfterSrc = pathParts[srcIndex + 1];
// Handle both src/core/agents and src/modules/[module]/agents patterns
if (folderAfterSrc === 'core') {
moduleName = 'core';
} else if (folderAfterSrc === 'modules') {
moduleName = pathParts[srcIndex + 2]; // The actual module name
}
}
}
// Extract the agent name from the ID path in YAML if available
let agentBaseName = basename;
if (agentData.agent && agentData.agent.metadata && agentData.agent.metadata.id) {
const idPath = agentData.agent.metadata.id;
agentBaseName = path.basename(idPath, '.md');
}
const agentName = `bmad-${moduleName}-${agentBaseName}`;
const sanitizedAgentName = this.sanitizeAgentName(agentName);
// Create JSON definition
await this.createAgentDefinitionFromYaml(agentsDir, agentName, agentData);
await this.createAgentDefinitionFromYaml(agentsDir, sanitizedAgentName, agentData);
// Create prompt file
await this.createAgentPromptFromYaml(agentsDir, agentName, agentData, projectDir);
await this.createAgentPromptFromYaml(agentsDir, sanitizedAgentName, agentData, projectDir);
}
/**

View File

@ -47,7 +47,7 @@ class OpenCodeSetup extends BaseIdeSetup {
agentCount++;
}
// Install workflow commands with flat naming: bmad-workflow-{module}-{name}.md
// Install workflow commands with flat naming: bmad-{module}-{workflow-name}
const workflowGenerator = new WorkflowCommandGenerator(this.bmadFolderName);
const { artifacts: workflowArtifacts, counts: workflowCounts } = await workflowGenerator.collectWorkflowArtifacts(bmadDir);
@ -55,10 +55,10 @@ class OpenCodeSetup extends BaseIdeSetup {
for (const artifact of workflowArtifacts) {
if (artifact.type === 'workflow-command') {
const commandContent = artifact.content;
// Flat structure: bmad-workflow-{module}-{name}.md
// Flat structure: bmad-{module}-{workflow-name}.md
// artifact.relativePath is like: bmm/workflows/plan-project.md
const workflowName = path.basename(artifact.relativePath, '.md');
const targetPath = path.join(commandsBaseDir, `bmad-workflow-${artifact.module}-${workflowName}.md`);
const targetPath = path.join(commandsBaseDir, `bmad-${artifact.module}-${workflowName}.md`);
await this.writeFile(targetPath, commandContent);
workflowCommandCount++;
}