189 lines
8.1 KiB
JavaScript
189 lines
8.1 KiB
JavaScript
const path = require('path');
|
|
const fileManager = require('./file-manager');
|
|
const configLoader = require('./config-loader');
|
|
const chalk = require('chalk');
|
|
|
|
class IdeSetup {
|
|
async setup(ide, installDir, selectedAgent = null) {
|
|
const ideConfig = await configLoader.getIdeConfiguration(ide);
|
|
|
|
if (!ideConfig) {
|
|
console.log(chalk.yellow(`\nNo configuration available for ${ide}`));
|
|
return false;
|
|
}
|
|
|
|
switch (ide) {
|
|
case 'cursor':
|
|
return this.setupCursor(installDir, selectedAgent);
|
|
case 'claude-code':
|
|
return this.setupClaudeCode(installDir, selectedAgent);
|
|
case 'windsurf':
|
|
return this.setupWindsurf(installDir, selectedAgent);
|
|
default:
|
|
console.log(chalk.yellow(`\nIDE ${ide} not yet supported`));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
async setupCursor(installDir, selectedAgent) {
|
|
const cursorRulesDir = path.join(installDir, '.cursor', 'rules');
|
|
const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
|
|
|
|
await fileManager.ensureDirectory(cursorRulesDir);
|
|
|
|
for (const agentId of agents) {
|
|
// Check if bmad-core is a subdirectory (full install) or if agents are in root (single agent install)
|
|
let agentPath = path.join(installDir, 'bmad-core', 'agents', `${agentId}.md`);
|
|
if (!await fileManager.pathExists(agentPath)) {
|
|
agentPath = path.join(installDir, 'agents', `${agentId}.md`);
|
|
}
|
|
|
|
if (await fileManager.pathExists(agentPath)) {
|
|
const agentContent = await fileManager.readFile(agentPath);
|
|
const mdcPath = path.join(cursorRulesDir, `${agentId}.mdc`);
|
|
|
|
// Create MDC content with proper format
|
|
let mdcContent = '\n---\n';
|
|
mdcContent += 'description: \n';
|
|
mdcContent += 'globs: []\n';
|
|
mdcContent += 'alwaysApply: false\n';
|
|
mdcContent += '---\n\n';
|
|
mdcContent += `# ${agentId.toUpperCase()} Agent Rule\n\n`;
|
|
mdcContent += `This rule is triggered when the user types \`@${agentId}\` and activates the ${this.getAgentTitle(agentId)} agent persona.\n\n`;
|
|
mdcContent += '## Agent Activation\n\n';
|
|
mdcContent += 'CRITICAL: Read the full YML, start activation to alter your state of being, follow startup section instructions, stay in this being until told to exit this mode:\n\n';
|
|
mdcContent += '```yml\n';
|
|
// Extract just the YAML content from the agent file
|
|
const yamlMatch = agentContent.match(/```ya?ml\n([\s\S]*?)```/);
|
|
if (yamlMatch) {
|
|
mdcContent += yamlMatch[1].trim();
|
|
} else {
|
|
// If no YAML found, include the whole content minus the header
|
|
mdcContent += agentContent.replace(/^#.*$/m, '').trim();
|
|
}
|
|
mdcContent += '\n```\n\n';
|
|
mdcContent += '## File Reference\n\n';
|
|
mdcContent += `The complete agent definition is available in [bmad-core/agents/${agentId}.md](mdc:bmad-core/agents/${agentId}.md).\n\n`;
|
|
mdcContent += '## Usage\n\n';
|
|
mdcContent += `When the user types \`@${agentId}\`, activate this ${this.getAgentTitle(agentId)} persona and follow all instructions defined in the YML configuration above.\n`;
|
|
|
|
await fileManager.writeFile(mdcPath, mdcContent);
|
|
console.log(chalk.green(`✓ Created rule: ${agentId}.mdc`));
|
|
}
|
|
}
|
|
|
|
console.log(chalk.green(`\n✓ Created Cursor rules in ${cursorRulesDir}`));
|
|
|
|
return true;
|
|
}
|
|
|
|
async setupClaudeCode(installDir, selectedAgent) {
|
|
const commandsDir = path.join(installDir, '.claude', 'commands');
|
|
const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
|
|
|
|
await fileManager.ensureDirectory(commandsDir);
|
|
|
|
for (const agentId of agents) {
|
|
// Check if bmad-core is a subdirectory (full install) or if agents are in root (single agent install)
|
|
let agentPath = path.join(installDir, 'bmad-core', 'agents', `${agentId}.md`);
|
|
if (!await fileManager.pathExists(agentPath)) {
|
|
agentPath = path.join(installDir, 'agents', `${agentId}.md`);
|
|
}
|
|
const commandPath = path.join(commandsDir, `${agentId}.md`);
|
|
|
|
if (await fileManager.pathExists(agentPath)) {
|
|
// Create command file with agent content
|
|
const agentContent = await fileManager.readFile(agentPath);
|
|
|
|
// Add command header
|
|
let commandContent = `# /${agentId} Command\n\n`;
|
|
commandContent += `When this command is used, adopt the following agent persona:\n\n`;
|
|
commandContent += agentContent;
|
|
|
|
await fileManager.writeFile(commandPath, commandContent);
|
|
console.log(chalk.green(`✓ Created command: /${agentId}`));
|
|
}
|
|
}
|
|
|
|
console.log(chalk.green(`\n✓ Created Claude Code commands in ${commandsDir}`));
|
|
|
|
return true;
|
|
}
|
|
|
|
async setupWindsurf(installDir, selectedAgent) {
|
|
const windsurfRulesDir = path.join(installDir, '.windsurf', 'rules');
|
|
const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
|
|
|
|
await fileManager.ensureDirectory(windsurfRulesDir);
|
|
|
|
for (const agentId of agents) {
|
|
// Check if bmad-core is a subdirectory (full install) or if agents are in root (single agent install)
|
|
let agentPath = path.join(installDir, 'bmad-core', 'agents', `${agentId}.md`);
|
|
if (!await fileManager.pathExists(agentPath)) {
|
|
agentPath = path.join(installDir, 'agents', `${agentId}.md`);
|
|
}
|
|
|
|
if (await fileManager.pathExists(agentPath)) {
|
|
const agentContent = await fileManager.readFile(agentPath);
|
|
const mdPath = path.join(windsurfRulesDir, `${agentId}.md`);
|
|
|
|
// Create MD content (similar to Cursor but without frontmatter)
|
|
let mdContent = `# ${agentId.toUpperCase()} Agent Rule\n\n`;
|
|
mdContent += `This rule is triggered when the user types \`@${agentId}\` and activates the ${this.getAgentTitle(agentId)} agent persona.\n\n`;
|
|
mdContent += '## Agent Activation\n\n';
|
|
mdContent += 'CRITICAL: Read the full YML, start activation to alter your state of being, follow startup section instructions, stay in this being until told to exit this mode:\n\n';
|
|
mdContent += '```yml\n';
|
|
// Extract just the YAML content from the agent file
|
|
const yamlMatch = agentContent.match(/```ya?ml\n([\s\S]*?)```/);
|
|
if (yamlMatch) {
|
|
mdContent += yamlMatch[1].trim();
|
|
} else {
|
|
// If no YAML found, include the whole content minus the header
|
|
mdContent += agentContent.replace(/^#.*$/m, '').trim();
|
|
}
|
|
mdContent += '\n```\n\n';
|
|
mdContent += '## File Reference\n\n';
|
|
mdContent += `The complete agent definition is available in [bmad-core/agents/${agentId}.md](bmad-core/agents/${agentId}.md).\n\n`;
|
|
mdContent += '## Usage\n\n';
|
|
mdContent += `When the user types \`@${agentId}\`, activate this ${this.getAgentTitle(agentId)} persona and follow all instructions defined in the YML configuration above.\n`;
|
|
|
|
await fileManager.writeFile(mdPath, mdContent);
|
|
console.log(chalk.green(`✓ Created rule: ${agentId}.md`));
|
|
}
|
|
}
|
|
|
|
console.log(chalk.green(`\n✓ Created Windsurf rules in ${windsurfRulesDir}`));
|
|
|
|
return true;
|
|
}
|
|
|
|
async getAllAgentIds(installDir) {
|
|
// Check if bmad-core is a subdirectory (full install) or if agents are in root (single agent install)
|
|
let agentsDir = path.join(installDir, 'bmad-core', 'agents');
|
|
if (!await fileManager.pathExists(agentsDir)) {
|
|
agentsDir = path.join(installDir, 'agents');
|
|
}
|
|
|
|
const glob = require('glob');
|
|
const agentFiles = glob.sync('*.md', { cwd: agentsDir });
|
|
return agentFiles.map(file => path.basename(file, '.md'));
|
|
}
|
|
|
|
getAgentTitle(agentId) {
|
|
const agentTitles = {
|
|
'analyst': 'Business Analyst',
|
|
'architect': 'Solution Architect',
|
|
'bmad-master': 'BMAD Master',
|
|
'bmad-orchestrator': 'BMAD Orchestrator',
|
|
'dev': 'Developer',
|
|
'pm': 'Product Manager',
|
|
'po': 'Product Owner',
|
|
'qa': 'QA Specialist',
|
|
'sm': 'Scrum Master',
|
|
'ux-expert': 'UX Expert'
|
|
};
|
|
return agentTitles[agentId] || agentId;
|
|
}
|
|
}
|
|
|
|
module.exports = new IdeSetup(); |