mirror of
https://github.com/bmadcode/BMAD-METHOD.git
synced 2025-12-29 16:14:59 +00:00
fix: Prevent duplicate manifest entries and update GitHub Copilot tool names
- Deduplicate module lists in manifest generator using Set to prevent duplicate entries in installed manifests - Update GitHub Copilot tool names to match official VS Code documentation (November 2025) - Clean up legacy bmad/, bmd/, and web-bundles directories
This commit is contained in:
@@ -34,8 +34,9 @@ class ManifestGenerator {
|
||||
|
||||
// Store modules list (all modules including preserved ones)
|
||||
const preservedModules = options.preservedModules || [];
|
||||
this.modules = ['core', ...selectedModules, ...preservedModules];
|
||||
this.updatedModules = ['core', ...selectedModules]; // Only these get rescanned
|
||||
// Deduplicate modules list to prevent duplicates
|
||||
this.modules = [...new Set(['core', ...selectedModules, ...preservedModules])];
|
||||
this.updatedModules = [...new Set(['core', ...selectedModules])]; // Only these get rescanned
|
||||
this.preservedModules = preservedModules; // These stay as-is in CSVs
|
||||
this.bmadDir = bmadDir;
|
||||
this.allInstalledFiles = installedFiles;
|
||||
@@ -91,15 +92,8 @@ class ManifestGenerator {
|
||||
async collectWorkflows(selectedModules) {
|
||||
this.workflows = [];
|
||||
|
||||
// Get core workflows from installed bmad directory
|
||||
const corePath = path.join(this.bmadDir, 'core');
|
||||
if (await fs.pathExists(corePath)) {
|
||||
const coreWorkflows = await this.getWorkflowsFromPath(corePath, 'core');
|
||||
this.workflows.push(...coreWorkflows);
|
||||
}
|
||||
|
||||
// Get module workflows from installed bmad directory
|
||||
for (const moduleName of selectedModules) {
|
||||
// Use updatedModules which already includes deduplicated 'core' + selectedModules
|
||||
for (const moduleName of this.updatedModules) {
|
||||
const modulePath = path.join(this.bmadDir, moduleName);
|
||||
|
||||
if (await fs.pathExists(modulePath)) {
|
||||
@@ -186,15 +180,8 @@ class ManifestGenerator {
|
||||
async collectAgents(selectedModules) {
|
||||
this.agents = [];
|
||||
|
||||
// Get core agents from installed bmad directory
|
||||
const coreAgentsPath = path.join(this.bmadDir, 'core', 'agents');
|
||||
if (await fs.pathExists(coreAgentsPath)) {
|
||||
const coreAgents = await this.getAgentsFromDir(coreAgentsPath, 'core');
|
||||
this.agents.push(...coreAgents);
|
||||
}
|
||||
|
||||
// Get module agents from installed bmad directory
|
||||
for (const moduleName of selectedModules) {
|
||||
// Use updatedModules which already includes deduplicated 'core' + selectedModules
|
||||
for (const moduleName of this.updatedModules) {
|
||||
const agentsPath = path.join(this.bmadDir, moduleName, 'agents');
|
||||
|
||||
if (await fs.pathExists(agentsPath)) {
|
||||
@@ -300,15 +287,8 @@ class ManifestGenerator {
|
||||
async collectTasks(selectedModules) {
|
||||
this.tasks = [];
|
||||
|
||||
// Get core tasks from installed bmad directory
|
||||
const coreTasksPath = path.join(this.bmadDir, 'core', 'tasks');
|
||||
if (await fs.pathExists(coreTasksPath)) {
|
||||
const coreTasks = await this.getTasksFromDir(coreTasksPath, 'core');
|
||||
this.tasks.push(...coreTasks);
|
||||
}
|
||||
|
||||
// Get module tasks from installed bmad directory
|
||||
for (const moduleName of selectedModules) {
|
||||
// Use updatedModules which already includes deduplicated 'core' + selectedModules
|
||||
for (const moduleName of this.updatedModules) {
|
||||
const tasksPath = path.join(this.bmadDir, moduleName, 'tasks');
|
||||
|
||||
if (await fs.pathExists(tasksPath)) {
|
||||
@@ -376,15 +356,8 @@ class ManifestGenerator {
|
||||
async collectTools(selectedModules) {
|
||||
this.tools = [];
|
||||
|
||||
// Get core tools from installed bmad directory
|
||||
const coreToolsPath = path.join(this.bmadDir, 'core', 'tools');
|
||||
if (await fs.pathExists(coreToolsPath)) {
|
||||
const coreTools = await this.getToolsFromDir(coreToolsPath, 'core');
|
||||
this.tools.push(...coreTools);
|
||||
}
|
||||
|
||||
// Get module tools from installed bmad directory
|
||||
for (const moduleName of selectedModules) {
|
||||
// Use updatedModules which already includes deduplicated 'core' + selectedModules
|
||||
for (const moduleName of this.updatedModules) {
|
||||
const toolsPath = path.join(this.bmadDir, moduleName, 'tools');
|
||||
|
||||
if (await fs.pathExists(toolsPath)) {
|
||||
@@ -564,26 +537,14 @@ class ManifestGenerator {
|
||||
async writeWorkflowManifest(cfgDir) {
|
||||
const csvPath = path.join(cfgDir, 'workflow-manifest.csv');
|
||||
|
||||
// Define expected columns and defaults for schema upgrade
|
||||
const expectedColumns = ['name', 'description', 'module', 'path', 'standalone'];
|
||||
const defaultValues = { standalone: 'false' };
|
||||
|
||||
// Get preserved rows from existing CSV (module is column 2, 0-indexed)
|
||||
const preservedRows = await this.getPreservedCsvRows(csvPath, 2, expectedColumns, defaultValues);
|
||||
|
||||
// Create CSV header with standalone column
|
||||
let csv = 'name,description,module,path,standalone\n';
|
||||
|
||||
// Add new rows for updated modules
|
||||
// Add all workflows
|
||||
for (const workflow of this.workflows) {
|
||||
csv += `"${workflow.name}","${workflow.description}","${workflow.module}","${workflow.path}","${workflow.standalone}"\n`;
|
||||
}
|
||||
|
||||
// Add preserved rows for modules we didn't update
|
||||
for (const row of preservedRows) {
|
||||
csv += row + '\n';
|
||||
}
|
||||
|
||||
await fs.writeFile(csvPath, csv);
|
||||
return csvPath;
|
||||
}
|
||||
@@ -595,36 +556,14 @@ class ManifestGenerator {
|
||||
async writeAgentManifest(cfgDir) {
|
||||
const csvPath = path.join(cfgDir, 'agent-manifest.csv');
|
||||
|
||||
// Define expected columns (no schema changes for agents currently)
|
||||
const expectedColumns = [
|
||||
'name',
|
||||
'displayName',
|
||||
'title',
|
||||
'icon',
|
||||
'role',
|
||||
'identity',
|
||||
'communicationStyle',
|
||||
'principles',
|
||||
'module',
|
||||
'path',
|
||||
];
|
||||
|
||||
// Get preserved rows from existing CSV (module is column 8, 0-indexed)
|
||||
const preservedRows = await this.getPreservedCsvRows(csvPath, 8, expectedColumns);
|
||||
|
||||
// Create CSV header with persona fields
|
||||
let csv = 'name,displayName,title,icon,role,identity,communicationStyle,principles,module,path\n';
|
||||
|
||||
// Add new rows for updated modules
|
||||
// Add all agents
|
||||
for (const agent of this.agents) {
|
||||
csv += `"${agent.name}","${agent.displayName}","${agent.title}","${agent.icon}","${agent.role}","${agent.identity}","${agent.communicationStyle}","${agent.principles}","${agent.module}","${agent.path}"\n`;
|
||||
}
|
||||
|
||||
// Add preserved rows for modules we didn't update
|
||||
for (const row of preservedRows) {
|
||||
csv += row + '\n';
|
||||
}
|
||||
|
||||
await fs.writeFile(csvPath, csv);
|
||||
return csvPath;
|
||||
}
|
||||
@@ -636,26 +575,14 @@ class ManifestGenerator {
|
||||
async writeTaskManifest(cfgDir) {
|
||||
const csvPath = path.join(cfgDir, 'task-manifest.csv');
|
||||
|
||||
// Define expected columns and defaults for schema upgrade
|
||||
const expectedColumns = ['name', 'displayName', 'description', 'module', 'path', 'standalone'];
|
||||
const defaultValues = { standalone: 'false' };
|
||||
|
||||
// Get preserved rows from existing CSV (module is column 3, 0-indexed)
|
||||
const preservedRows = await this.getPreservedCsvRows(csvPath, 3, expectedColumns, defaultValues);
|
||||
|
||||
// Create CSV header with standalone column
|
||||
let csv = 'name,displayName,description,module,path,standalone\n';
|
||||
|
||||
// Add new rows for updated modules
|
||||
// Add all tasks
|
||||
for (const task of this.tasks) {
|
||||
csv += `"${task.name}","${task.displayName}","${task.description}","${task.module}","${task.path}","${task.standalone}"\n`;
|
||||
}
|
||||
|
||||
// Add preserved rows for modules we didn't update
|
||||
for (const row of preservedRows) {
|
||||
csv += row + '\n';
|
||||
}
|
||||
|
||||
await fs.writeFile(csvPath, csv);
|
||||
return csvPath;
|
||||
}
|
||||
@@ -667,26 +594,14 @@ class ManifestGenerator {
|
||||
async writeToolManifest(cfgDir) {
|
||||
const csvPath = path.join(cfgDir, 'tool-manifest.csv');
|
||||
|
||||
// Define expected columns and defaults for schema upgrade
|
||||
const expectedColumns = ['name', 'displayName', 'description', 'module', 'path', 'standalone'];
|
||||
const defaultValues = { standalone: 'false' };
|
||||
|
||||
// Get preserved rows from existing CSV (module is column 3, 0-indexed)
|
||||
const preservedRows = await this.getPreservedCsvRows(csvPath, 3, expectedColumns, defaultValues);
|
||||
|
||||
// Create CSV header with standalone column
|
||||
let csv = 'name,displayName,description,module,path,standalone\n';
|
||||
|
||||
// Add new rows for updated modules
|
||||
// Add all tools
|
||||
for (const tool of this.tools) {
|
||||
csv += `"${tool.name}","${tool.displayName}","${tool.description}","${tool.module}","${tool.path}","${tool.standalone}"\n`;
|
||||
}
|
||||
|
||||
// Add preserved rows for modules we didn't update
|
||||
for (const row of preservedRows) {
|
||||
csv += row + '\n';
|
||||
}
|
||||
|
||||
await fs.writeFile(csvPath, csv);
|
||||
return csvPath;
|
||||
}
|
||||
@@ -714,9 +629,6 @@ class ManifestGenerator {
|
||||
async writeFilesManifest(cfgDir) {
|
||||
const csvPath = path.join(cfgDir, 'files-manifest.csv');
|
||||
|
||||
// Get preserved rows from existing CSV (module is column 2, 0-indexed)
|
||||
const preservedRows = await this.getPreservedCsvRows(csvPath, 2);
|
||||
|
||||
// Create CSV header with hash column
|
||||
let csv = 'type,name,module,path,hash\n';
|
||||
|
||||
@@ -763,16 +675,11 @@ class ManifestGenerator {
|
||||
return a.name.localeCompare(b.name);
|
||||
});
|
||||
|
||||
// Add rows for updated modules
|
||||
// Add all files
|
||||
for (const file of allFiles) {
|
||||
csv += `"${file.type}","${file.name}","${file.module}","${file.path}","${file.hash}"\n`;
|
||||
}
|
||||
|
||||
// Add preserved rows for modules we didn't update
|
||||
for (const row of preservedRows) {
|
||||
csv += row + '\n';
|
||||
}
|
||||
|
||||
await fs.writeFile(csvPath, csv);
|
||||
return csvPath;
|
||||
}
|
||||
|
||||
@@ -214,24 +214,31 @@ class GitHubCopilotSetup extends BaseIdeSetup {
|
||||
const whenToUseMatch = content.match(/whenToUse="([^"]+)"/);
|
||||
const description = whenToUseMatch ? whenToUseMatch[1] : `Activates the ${title} agent persona.`;
|
||||
|
||||
// Available GitHub Copilot tools
|
||||
// Available GitHub Copilot tools (November 2025 - Official VS Code Documentation)
|
||||
// Reference: https://code.visualstudio.com/docs/copilot/reference/copilot-vscode-features#_chat-tools
|
||||
const tools = [
|
||||
'changes',
|
||||
'codebase',
|
||||
'fetch',
|
||||
'findTestFiles',
|
||||
'githubRepo',
|
||||
'problems',
|
||||
'usages',
|
||||
'editFiles',
|
||||
'runCommands',
|
||||
'runTasks',
|
||||
'runTests',
|
||||
'search',
|
||||
'searchResults',
|
||||
'terminalLastCommand',
|
||||
'terminalSelection',
|
||||
'testFailure',
|
||||
'changes', // List of source control changes
|
||||
'codebase', // Perform code search in workspace
|
||||
'createDirectory', // Create new directory in workspace
|
||||
'createFile', // Create new file in workspace
|
||||
'editFiles', // Apply edits to files in workspace
|
||||
'fetch', // Fetch content from web page
|
||||
'fileSearch', // Search files using glob patterns
|
||||
'githubRepo', // Perform code search in GitHub repo
|
||||
'listDirectory', // List files in a directory
|
||||
'problems', // Add workspace issues from Problems panel
|
||||
'readFile', // Read content of a file in workspace
|
||||
'runInTerminal', // Run shell command in integrated terminal
|
||||
'runTask', // Run existing task in workspace
|
||||
'runTests', // Run unit tests in workspace
|
||||
'runVscodeCommand', // Run VS Code command
|
||||
'search', // Enable file searching in workspace
|
||||
'searchResults', // Get search results from Search view
|
||||
'terminalLastCommand', // Get last terminal command and output
|
||||
'terminalSelection', // Get current terminal selection
|
||||
'testFailure', // Get unit test failure information
|
||||
'textSearch', // Find text in files
|
||||
'usages', // Find references and navigate definitions
|
||||
];
|
||||
|
||||
let chatmodeContent = `---
|
||||
|
||||
Reference in New Issue
Block a user