BMAD-METHOD/tools/cli/installers/lib/ide/claude-code.js

123 lines
3.6 KiB
JavaScript

const path = require('node:path');
const { BaseIdeSetup } = require('./_base-ide');
const chalk = require('chalk');
/**
* Claude Code IDE setup handler for WDS
*/
class ClaudeCodeSetup extends BaseIdeSetup {
constructor() {
super('claude-code', 'Claude Code', true); // preferred IDE
this.configDir = '.claude/skills';
}
/**
* Setup Claude Code IDE configuration
* @param {string} projectDir - Project directory
* @param {string} wdsDir - WDS installation directory
* @param {Object} options - Setup options
*/
async setup(projectDir, wdsDir, options = {}) {
// Get all WDS agents
const agents = await this.getAgents(wdsDir);
if (agents.length === 0) {
throw new Error('No agents found in WDS installation');
}
// Create launcher file for each agent in .claude/skills/{slug}/SKILL.md
const skillsDir = path.join(projectDir, this.configDir);
let agentCount = 0;
for (const agent of agents) {
// Create launcher content that references the compiled agent
const launcher = this.formatAgentLauncher(agent.name, agent.path);
// Add Claude Code-specific YAML frontmatter
const content = this.processContent(launcher, agent.metadata);
// Write launcher file as .claude/skills/{slug}/SKILL.md
const agentDir = path.join(skillsDir, agent.slug);
await this.ensureDir(agentDir);
const filePath = path.join(agentDir, 'SKILL.md');
await this.writeFile(filePath, content);
agentCount++;
}
if (options.logger) {
options.logger.log(chalk.dim(` - ${agentCount} agent(s) configured for Claude Code`));
}
return {
success: true,
agents: agentCount,
};
}
/**
* Process content with Claude Code-specific YAML frontmatter
* @param {string} content - Launcher content
* @param {Object} metadata - Agent metadata
* @returns {string} Processed content with Claude Code YAML frontmatter
*/
processContent(content, metadata = {}) {
// Strip any existing frontmatter from launcher
const frontmatterRegex = /^---\s*\n[\s\S]*?\n---\s*\n/;
const contentWithoutFrontmatter = content.replace(frontmatterRegex, '');
const name = metadata.name || 'WDS Agent';
const description = metadata.description || 'Agent';
// Create Claude Code YAML metadata header
const yamlHeader = `---
name: ${name}
description: ${description}
---
`;
return yamlHeader + contentWithoutFrontmatter;
}
/**
* Cleanup Claude Code WDS configuration
* @param {string} projectDir - Project directory
*/
async cleanup(projectDir) {
// Remove per-agent skill directories
const agents = ['saga', 'freya'];
for (const slug of agents) {
const skillPath = path.join(projectDir, this.configDir, slug);
if (await this.exists(skillPath)) {
await this.remove(skillPath);
}
}
// Also clean up legacy .claude/skills/wds/ if present
const legacyPath = path.join(projectDir, '.claude/skills/wds');
if (await this.exists(legacyPath)) {
await this.remove(legacyPath);
console.log(chalk.dim(`Removed legacy Claude Code WDS configuration`));
}
}
/**
* Detect if Claude Code is configured in project
* @param {string} projectDir - Project directory
* @returns {boolean}
*/
async detect(projectDir) {
return await this.exists(path.join(projectDir, '.claude'));
}
/**
* Remove directory helper
* @param {string} dirPath - Directory to remove
*/
async remove(dirPath) {
const fs = require('fs-extra');
await fs.remove(dirPath);
}
}
module.exports = { ClaudeCodeSetup };