mirror of
https://github.com/bmad-code-org/BMAD-METHOD.git
synced 2026-01-30 04:32:02 +00:00
Fix github-copilot installer to use UnifiedInstaller for prompts
- Add .github/prompts directory alongside .github/agents - Use UnifiedInstaller with TemplateType.COPILOT for prompts/workflows/tasks/tools - Fix typo: bmd-custom- -> bmad- prefix for agents - Update cleanup to handle both directories - Format fixes for auggie.js and windsurf.js
This commit is contained in:
@@ -28,12 +28,17 @@ class AuggieSetup extends BaseIdeSetup {
|
||||
const targetDir = path.join(projectDir, '.augment', 'commands');
|
||||
|
||||
// Install using UnifiedInstaller
|
||||
const counts = await this.installer.install(projectDir, bmadDir, {
|
||||
const counts = await this.installer.install(
|
||||
projectDir,
|
||||
bmadDir,
|
||||
{
|
||||
targetDir,
|
||||
namingStyle: NamingStyle.FLAT_COLON,
|
||||
templateType: TemplateType.AUGMENT,
|
||||
includeNestedStructure: false,
|
||||
}, options.selectedModules || []);
|
||||
},
|
||||
options.selectedModules || [],
|
||||
);
|
||||
|
||||
console.log(chalk.green(`✓ ${this.name} configured:`));
|
||||
console.log(chalk.dim(` - ${counts.agents} agents installed`));
|
||||
|
||||
@@ -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 { UnifiedInstaller, NamingStyle, TemplateType } = require('./shared/unified-installer');
|
||||
const prompts = require('../../../lib/prompts');
|
||||
|
||||
/**
|
||||
@@ -13,6 +14,7 @@ class GitHubCopilotSetup extends BaseIdeSetup {
|
||||
super('github-copilot', 'GitHub Copilot', true); // preferred IDE
|
||||
this.configDir = '.github';
|
||||
this.agentsDir = 'agents';
|
||||
this.promptsDir = 'prompts';
|
||||
this.vscodeDir = '.vscode';
|
||||
}
|
||||
|
||||
@@ -94,41 +96,63 @@ class GitHubCopilotSetup extends BaseIdeSetup {
|
||||
const config = options.preCollectedConfig || {};
|
||||
await this.configureVsCodeSettings(projectDir, { ...options, ...config });
|
||||
|
||||
// Create .github/agents directory
|
||||
// Create .github/agents and .github/prompts directories
|
||||
const githubDir = path.join(projectDir, this.configDir);
|
||||
const agentsDir = path.join(githubDir, this.agentsDir);
|
||||
const promptsDir = path.join(githubDir, this.promptsDir);
|
||||
await this.ensureDir(agentsDir);
|
||||
await this.ensureDir(promptsDir);
|
||||
|
||||
// Clean up any existing BMAD files before reinstalling
|
||||
await this.cleanup(projectDir);
|
||||
|
||||
// Generate agent launchers
|
||||
// 1. Generate agent launchers (custom .agent.md format - not using UnifiedInstaller)
|
||||
const agentGen = new AgentCommandGenerator(this.bmadFolderName);
|
||||
const { artifacts: agentArtifacts } = await agentGen.collectAgentArtifacts(bmadDir, options.selectedModules || []);
|
||||
|
||||
// Create agent files with bmd- prefix
|
||||
// Create agent files with bmad- prefix
|
||||
let agentCount = 0;
|
||||
for (const artifact of agentArtifacts) {
|
||||
const content = artifact.content;
|
||||
const agentContent = await this.createAgentContent({ module: artifact.module, name: artifact.name }, content);
|
||||
|
||||
// Use bmd- prefix: bmd-custom-{module}-{name}.agent.md
|
||||
const targetPath = path.join(agentsDir, `bmd-custom-${artifact.module}-${artifact.name}.agent.md`);
|
||||
// Use bmad- prefix: bmad-{module}-{name}.agent.md
|
||||
const targetPath = path.join(agentsDir, `bmad-${artifact.module}-${artifact.name}.agent.md`);
|
||||
await this.writeFile(targetPath, agentContent);
|
||||
agentCount++;
|
||||
|
||||
console.log(chalk.green(` ✓ Created agent: bmd-custom-${artifact.module}-${artifact.name}`));
|
||||
console.log(chalk.green(` ✓ Created agent: bmad-${artifact.module}-${artifact.name}`));
|
||||
}
|
||||
|
||||
// 2. Install prompts using UnifiedInstaller
|
||||
const installer = new UnifiedInstaller(this.bmadFolderName);
|
||||
const promptCounts = await installer.install(
|
||||
projectDir,
|
||||
bmadDir,
|
||||
{
|
||||
targetDir: promptsDir,
|
||||
namingStyle: NamingStyle.FLAT_DASH,
|
||||
templateType: TemplateType.COPILOT,
|
||||
},
|
||||
options.selectedModules || [],
|
||||
);
|
||||
|
||||
console.log(chalk.green(`✓ ${this.name} configured:`));
|
||||
console.log(chalk.dim(` - ${agentCount} agents created`));
|
||||
console.log(
|
||||
chalk.dim(
|
||||
` - ${promptCounts.agents} prompts, ${promptCounts.workflows} workflows, ${promptCounts.tasks + promptCounts.tools} tasks/tools`,
|
||||
),
|
||||
);
|
||||
console.log(chalk.dim(` - Agents directory: ${path.relative(projectDir, agentsDir)}`));
|
||||
console.log(chalk.dim(` - Prompts directory: ${path.relative(projectDir, promptsDir)}`));
|
||||
console.log(chalk.dim(` - VS Code settings configured`));
|
||||
console.log(chalk.dim('\n Agents available in VS Code Chat view'));
|
||||
console.log(chalk.dim('\n Agents and prompts available in VS Code Chat view'));
|
||||
|
||||
return {
|
||||
success: true,
|
||||
agents: agentCount,
|
||||
prompts: promptCounts.total,
|
||||
settings: true,
|
||||
};
|
||||
}
|
||||
@@ -286,14 +310,15 @@ ${cleanContent}
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up new agents directory
|
||||
// Clean up agents directory
|
||||
const agentsDir = path.join(projectDir, this.configDir, this.agentsDir);
|
||||
if (await fs.pathExists(agentsDir)) {
|
||||
const files = await fs.readdir(agentsDir);
|
||||
let removed = 0;
|
||||
|
||||
for (const file of files) {
|
||||
if (file.startsWith('bmd-') && file.endsWith('.agent.md')) {
|
||||
// Remove old bmd-* files (typo fix) and current bmad-* files
|
||||
if ((file.startsWith('bmd-') || file.startsWith('bmad-')) && file.endsWith('.agent.md')) {
|
||||
await fs.remove(path.join(agentsDir, file));
|
||||
removed++;
|
||||
}
|
||||
@@ -303,6 +328,24 @@ ${cleanContent}
|
||||
console.log(chalk.dim(` Cleaned up ${removed} existing BMAD agents`));
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up prompts directory
|
||||
const promptsDir = path.join(projectDir, this.configDir, this.promptsDir);
|
||||
if (await fs.pathExists(promptsDir)) {
|
||||
const files = await fs.readdir(promptsDir);
|
||||
let removed = 0;
|
||||
|
||||
for (const file of files) {
|
||||
if (file.startsWith('bmad-') && file.endsWith('.md')) {
|
||||
await fs.remove(path.join(promptsDir, file));
|
||||
removed++;
|
||||
}
|
||||
}
|
||||
|
||||
if (removed > 0) {
|
||||
console.log(chalk.dim(` Cleaned up ${removed} existing BMAD prompts`));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -370,12 +413,12 @@ tools: ${JSON.stringify(copilotTools)}
|
||||
${launcherContent}
|
||||
`;
|
||||
|
||||
const agentFilePath = path.join(agentsDir, `bmd-custom-${agentName}.agent.md`);
|
||||
const agentFilePath = path.join(agentsDir, `bmad-${agentName}.agent.md`);
|
||||
await this.writeFile(agentFilePath, agentContent);
|
||||
|
||||
return {
|
||||
path: agentFilePath,
|
||||
command: `bmd-custom-${agentName}`,
|
||||
command: `bmad-${agentName}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ const TemplateType = {
|
||||
WINDSURF: 'windsurf', // YAML with auto_execution_mode
|
||||
AUGMENT: 'augment', // YAML frontmatter
|
||||
GEMINI: 'gemini', // TOML frontmatter with description/prompt
|
||||
COPILOT: 'copilot', // YAML with tools array for GitHub Copilot
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -98,7 +99,15 @@ class UnifiedInstaller {
|
||||
// 1. Install Agents
|
||||
const agentGen = new AgentCommandGenerator(this.bmadFolderName);
|
||||
const { artifacts: agentArtifacts } = await agentGen.collectAgentArtifacts(bmadDir, selectedModules);
|
||||
counts.agents = await this.writeArtifacts(agentArtifacts, targetDir, namingStyle, templateType, fileExtension, customTemplateFn, 'agent');
|
||||
counts.agents = await this.writeArtifacts(
|
||||
agentArtifacts,
|
||||
targetDir,
|
||||
namingStyle,
|
||||
templateType,
|
||||
fileExtension,
|
||||
customTemplateFn,
|
||||
'agent',
|
||||
);
|
||||
|
||||
// 2. Install Workflows (filter out README artifacts)
|
||||
const workflowGen = new WorkflowCommandGenerator(this.bmadFolderName);
|
||||
@@ -170,7 +179,9 @@ class UnifiedInstaller {
|
||||
* @returns {Promise<number>} Number of artifacts written
|
||||
*/
|
||||
async writeArtifacts(artifacts, targetDir, namingStyle, templateType, fileExtension, customTemplateFn, artifactType) {
|
||||
console.log(`[DEBUG] writeArtifacts: artifactType=${artifactType}, count=${artifacts.length}, targetDir=${targetDir}, fileExtension=${fileExtension}`);
|
||||
console.log(
|
||||
`[DEBUG] writeArtifacts: artifactType=${artifactType}, count=${artifacts.length}, targetDir=${targetDir}, fileExtension=${fileExtension}`,
|
||||
);
|
||||
let written = 0;
|
||||
|
||||
for (const artifact of artifacts) {
|
||||
@@ -238,6 +249,11 @@ class UnifiedInstaller {
|
||||
return this.addGeminiFrontmatter(artifact, content);
|
||||
}
|
||||
|
||||
case TemplateType.COPILOT: {
|
||||
// Add Copilot frontmatter with tools array
|
||||
return this.addCopilotFrontmatter(artifact, content);
|
||||
}
|
||||
|
||||
default: {
|
||||
return content;
|
||||
}
|
||||
@@ -305,7 +321,7 @@ description: ${name}
|
||||
}
|
||||
|
||||
// Escape any triple quotes in content
|
||||
const escapedContent = contentWithoutFrontmatter.replace(/"""/g, '\\"\\"\\"');
|
||||
const escapedContent = contentWithoutFrontmatter.replaceAll('"""', String.raw`\"\"\"`);
|
||||
|
||||
return `description = "${description}"
|
||||
prompt = """
|
||||
@@ -314,6 +330,44 @@ ${escapedContent}
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add GitHub Copilot frontmatter with tools array
|
||||
*/
|
||||
addCopilotFrontmatter(artifact, content) {
|
||||
// Remove existing frontmatter if present
|
||||
const frontmatterRegex = /^---\s*\n[\s\S]*?\n---\s*\n/;
|
||||
const contentWithoutFrontmatter = content.replace(frontmatterRegex, '');
|
||||
|
||||
// GitHub Copilot tools array (as specified)
|
||||
const tools = [
|
||||
'changes',
|
||||
'edit',
|
||||
'fetch',
|
||||
'githubRepo',
|
||||
'problems',
|
||||
'runCommands',
|
||||
'runTasks',
|
||||
'runTests',
|
||||
'search',
|
||||
'runSubagent',
|
||||
'testFailure',
|
||||
'todos',
|
||||
'usages',
|
||||
];
|
||||
|
||||
const name = artifact.name || artifact.displayName || 'prompt';
|
||||
const description = `Activates the ${name} ${artifact.type || 'workflow'}.`;
|
||||
|
||||
const frontmatter = `---
|
||||
description: "${description}"
|
||||
tools: ${JSON.stringify(tools)}
|
||||
---
|
||||
|
||||
`;
|
||||
|
||||
return frontmatter + contentWithoutFrontmatter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get tasks from manifest CSV
|
||||
*/
|
||||
|
||||
@@ -39,12 +39,17 @@ class WindsurfSetup extends BaseIdeSetup {
|
||||
await this.cleanup(projectDir);
|
||||
|
||||
// Use UnifiedInstaller with Windsurf-specific configuration
|
||||
const counts = await this.unifiedInstaller.install(projectDir, bmadDir, {
|
||||
const counts = await this.unifiedInstaller.install(
|
||||
projectDir,
|
||||
bmadDir,
|
||||
{
|
||||
targetDir: workflowsDir,
|
||||
namingStyle: NamingStyle.FLAT_DASH,
|
||||
templateType: TemplateType.WINDSURF,
|
||||
customTemplateFn: this.windsurfTemplate.bind(this),
|
||||
}, options.selectedModules || []);
|
||||
},
|
||||
options.selectedModules || [],
|
||||
);
|
||||
|
||||
// Post-process tasks and tools to add Windsurf auto_execution_mode
|
||||
// UnifiedInstaller handles agents/workflows correctly, but tasks/tools
|
||||
@@ -129,7 +134,7 @@ ${contentWithoutFrontmatter}`;
|
||||
const parts = entry.name.replace('bmad-', '').replace('.md', '').split('-');
|
||||
if (parts.length < 2) continue;
|
||||
|
||||
const type = parts[parts.length - 2]; // second to last part should be 'task' or 'tool'
|
||||
const type = parts.at(-2); // second to last part should be 'task' or 'tool'
|
||||
|
||||
if (type === 'task' || type === 'tool') {
|
||||
// Check if auto_execution_mode is already present
|
||||
|
||||
Reference in New Issue
Block a user