fix: single agent install and team installation support
This commit is contained in:
@@ -78,10 +78,7 @@ class ConfigLoader {
|
||||
// Convert to flat list of file paths
|
||||
const depPaths = [];
|
||||
|
||||
// Add core files
|
||||
const config = await this.load();
|
||||
const coreFiles = config['agent-dependencies']?.['core-files'] || [];
|
||||
depPaths.push(...coreFiles);
|
||||
// Core files and utilities are included automatically by DependencyResolver
|
||||
|
||||
// Add agent file itself is already handled by installer
|
||||
|
||||
@@ -121,6 +118,82 @@ class ConfigLoader {
|
||||
getAgentPath(agentId) {
|
||||
return path.join(this.getBmadCorePath(), 'agents', `${agentId}.md`);
|
||||
}
|
||||
|
||||
async getAvailableTeams() {
|
||||
const teamsDir = path.join(this.getBmadCorePath(), 'agent-teams');
|
||||
|
||||
try {
|
||||
const entries = await fs.readdir(teamsDir, { withFileTypes: true });
|
||||
const teams = [];
|
||||
|
||||
for (const entry of entries) {
|
||||
if (entry.isFile() && entry.name.endsWith('.yml')) {
|
||||
const teamPath = path.join(teamsDir, entry.name);
|
||||
|
||||
try {
|
||||
const teamContent = await fs.readFile(teamPath, 'utf8');
|
||||
const teamConfig = yaml.load(teamContent);
|
||||
|
||||
if (teamConfig.bundle) {
|
||||
teams.push({
|
||||
id: path.basename(entry.name, '.yml'),
|
||||
name: teamConfig.bundle.name || entry.name,
|
||||
description: teamConfig.bundle.description || 'Team configuration',
|
||||
icon: teamConfig.bundle.icon || '📋'
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(`Warning: Could not load team config ${entry.name}: ${error.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return teams;
|
||||
} catch (error) {
|
||||
console.warn(`Warning: Could not scan teams directory: ${error.message}`);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
getTeamPath(teamId) {
|
||||
return path.join(this.getBmadCorePath(), 'agent-teams', `${teamId}.yml`);
|
||||
}
|
||||
|
||||
async getTeamDependencies(teamId) {
|
||||
// Use DependencyResolver to dynamically parse team dependencies
|
||||
const DependencyResolver = require('../../lib/dependency-resolver');
|
||||
const resolver = new DependencyResolver(path.join(__dirname, '..', '..', '..'));
|
||||
|
||||
try {
|
||||
const teamDeps = await resolver.resolveTeamDependencies(teamId);
|
||||
|
||||
// Convert to flat list of file paths
|
||||
const depPaths = [];
|
||||
|
||||
// Add team config file
|
||||
depPaths.push(`.bmad-core/agent-teams/${teamId}.yml`);
|
||||
|
||||
// Add all agents
|
||||
for (const agent of teamDeps.agents) {
|
||||
const filePath = `.bmad-core/agents/${agent.id}.md`;
|
||||
if (!depPaths.includes(filePath)) {
|
||||
depPaths.push(filePath);
|
||||
}
|
||||
}
|
||||
|
||||
// Add all resolved resources
|
||||
for (const resource of teamDeps.resources) {
|
||||
const filePath = `.bmad-core/${resource.type}/${resource.id}.${resource.type === 'workflows' ? 'yml' : 'md'}`;
|
||||
if (!depPaths.includes(filePath)) {
|
||||
depPaths.push(filePath);
|
||||
}
|
||||
}
|
||||
|
||||
return depPaths;
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to resolve team dependencies for ${teamId}: ${error.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new ConfigLoader();
|
||||
@@ -220,11 +220,12 @@ class Installer {
|
||||
const agentPath = configLoader.getAgentPath(config.agent);
|
||||
const destAgentPath = path.join(
|
||||
installDir,
|
||||
".bmad-core",
|
||||
"agents",
|
||||
`${config.agent}.md`
|
||||
);
|
||||
await fileManager.copyFile(agentPath, destAgentPath);
|
||||
files.push(`agents/${config.agent}.md`);
|
||||
files.push(`.bmad-core/agents/${config.agent}.md`);
|
||||
|
||||
// Copy dependencies
|
||||
const dependencies = await configLoader.getAgentDependencies(
|
||||
@@ -240,9 +241,9 @@ class Installer {
|
||||
const copiedFiles = await fileManager.copyGlobPattern(
|
||||
dep.replace(".bmad-core/", ""),
|
||||
sourceBase,
|
||||
installDir
|
||||
path.join(installDir, ".bmad-core")
|
||||
);
|
||||
files.push(...copiedFiles);
|
||||
files.push(...copiedFiles.map(f => `.bmad-core/${f}`));
|
||||
} else {
|
||||
// Handle single files
|
||||
const sourcePath = path.join(
|
||||
@@ -251,14 +252,72 @@ class Installer {
|
||||
);
|
||||
const destPath = path.join(
|
||||
installDir,
|
||||
dep.replace(".bmad-core/", "")
|
||||
dep
|
||||
);
|
||||
|
||||
if (await fileManager.copyFile(sourcePath, destPath)) {
|
||||
files.push(dep.replace(".bmad-core/", ""));
|
||||
files.push(dep);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (config.installType === "team") {
|
||||
// Team installation
|
||||
spinner.text = `Installing ${config.team} team...`;
|
||||
|
||||
// Get team dependencies
|
||||
const teamDependencies = await configLoader.getTeamDependencies(config.team);
|
||||
const sourceBase = configLoader.getBmadCorePath();
|
||||
|
||||
// Install all team dependencies
|
||||
for (const dep of teamDependencies) {
|
||||
spinner.text = `Copying team dependency: ${dep}`;
|
||||
|
||||
if (dep.includes("*")) {
|
||||
// Handle glob patterns
|
||||
const copiedFiles = await fileManager.copyGlobPattern(
|
||||
dep.replace(".bmad-core/", ""),
|
||||
sourceBase,
|
||||
path.join(installDir, ".bmad-core")
|
||||
);
|
||||
files.push(...copiedFiles.map(f => `.bmad-core/${f}`));
|
||||
} else {
|
||||
// Handle single files
|
||||
const sourcePath = path.join(sourceBase, dep.replace(".bmad-core/", ""));
|
||||
const destPath = path.join(installDir, dep);
|
||||
|
||||
if (await fileManager.copyFile(sourcePath, destPath)) {
|
||||
files.push(dep);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (config.installType === "expansion-only") {
|
||||
// Expansion-only installation - create minimal .bmad-core structure
|
||||
spinner.text = "Creating minimal .bmad-core structure for expansion packs...";
|
||||
|
||||
const bmadCoreDestDir = path.join(installDir, ".bmad-core");
|
||||
await fileManager.ensureDirectory(bmadCoreDestDir);
|
||||
|
||||
// Create basic directory structure
|
||||
const dirs = ['agents', 'agent-teams', 'templates', 'tasks', 'checklists', 'workflows', 'data', 'utils', 'schemas'];
|
||||
for (const dir of dirs) {
|
||||
await fileManager.ensureDirectory(path.join(bmadCoreDestDir, dir));
|
||||
}
|
||||
|
||||
// Copy minimal required files (schemas, utils, etc.)
|
||||
const sourceBase = configLoader.getBmadCorePath();
|
||||
const essentialFiles = [
|
||||
'schemas/**/*',
|
||||
'utils/**/*'
|
||||
];
|
||||
|
||||
for (const pattern of essentialFiles) {
|
||||
const copiedFiles = await fileManager.copyGlobPattern(
|
||||
pattern,
|
||||
sourceBase,
|
||||
bmadCoreDestDir
|
||||
);
|
||||
files.push(...copiedFiles.map(f => `.bmad-core/${f}`));
|
||||
}
|
||||
}
|
||||
|
||||
// Install expansion packs if requested
|
||||
@@ -664,6 +723,10 @@ class Installer {
|
||||
return configLoader.getAvailableExpansionPacks();
|
||||
}
|
||||
|
||||
async getAvailableTeams() {
|
||||
return configLoader.getAvailableTeams();
|
||||
}
|
||||
|
||||
async installExpansionPacks(installDir, selectedPacks, spinner) {
|
||||
if (!selectedPacks || selectedPacks.length === 0) {
|
||||
return [];
|
||||
|
||||
Reference in New Issue
Block a user