sidecar content goes to custom core config location

This commit is contained in:
Brian Madison
2025-12-06 21:08:57 -06:00
parent ba2c81263b
commit 1697a45376
12 changed files with 377 additions and 30 deletions

View File

@@ -438,9 +438,10 @@ function compileToXml(agentYaml, agentName = '', targetPath = '') {
* @param {Object} answers - Answers from install_config questions (or defaults)
* @param {string} agentName - Optional final agent name (user's custom persona name)
* @param {string} targetPath - Optional target path for agent ID
* @param {Object} options - Additional options including config
* @returns {Object} { xml: string, metadata: Object }
*/
function compileAgent(yamlContent, answers = {}, agentName = '', targetPath = '') {
function compileAgent(yamlContent, answers = {}, agentName = '', targetPath = '', options = {}) {
// Parse YAML
const agentYaml = yaml.parse(yamlContent);
@@ -466,14 +467,22 @@ function compileAgent(yamlContent, answers = {}, agentName = '', targetPath = ''
finalAnswers = { ...defaults, ...answers };
}
// Add agent_sidecar_folder to answers if provided in config
if (options.config && options.config.agent_sidecar_folder) {
finalAnswers.agent_sidecar_folder = options.config.agent_sidecar_folder;
}
// Process templates with answers
const processedYaml = processAgentYaml(agentYaml, finalAnswers);
// Strip install_config from output
const cleanYaml = stripInstallConfig(processedYaml);
// Compile to XML
const xml = compileToXml(cleanYaml, agentName, targetPath);
// Replace {agent_sidecar_folder} in XML content
let xml = compileToXml(cleanYaml, agentName, targetPath);
if (finalAnswers.agent_sidecar_folder) {
xml = xml.replaceAll('{agent_sidecar_folder}', finalAnswers.agent_sidecar_folder);
}
return {
xml,

View File

@@ -93,7 +93,6 @@ function discoverAgents(searchPath) {
name: agentName,
path: fullPath,
yamlFile: agentYamlPath,
hasSidecar: true,
relativePath: agentRelativePath,
});
}
@@ -127,12 +126,15 @@ function loadAgentConfig(yamlPath) {
// These take precedence over defaults
const savedAnswers = agentYaml?.saved_answers || {};
const metadata = agentYaml?.agent?.metadata || {};
return {
yamlContent: content,
agentYaml,
installConfig,
defaults: { ...defaults, ...savedAnswers }, // saved_answers override defaults
metadata: agentYaml?.agent?.metadata || {},
metadata,
hasSidecar: metadata.hasSidecar === true,
};
}
@@ -232,9 +234,10 @@ async function promptInstallQuestions(installConfig, defaults, presetAnswers = {
* @param {Object} agentInfo - Agent discovery info
* @param {Object} answers - User answers for install_config
* @param {string} targetPath - Target installation directory
* @param {Object} options - Additional options including config
* @returns {Object} Installation result
*/
function installAgent(agentInfo, answers, targetPath) {
function installAgent(agentInfo, answers, targetPath, options = {}) {
// Compile the agent
const { xml, metadata, processedYaml } = compileAgent(fs.readFileSync(agentInfo.yamlFile, 'utf8'), answers);
@@ -261,11 +264,27 @@ function installAgent(agentInfo, answers, targetPath) {
sidecarCopied: false,
};
// Copy sidecar files for expert agents
if (agentInfo.hasSidecar && agentInfo.type === 'expert') {
const sidecarFiles = copySidecarFiles(agentInfo.path, agentTargetDir, agentInfo.yamlFile);
// Handle sidecar files for agents with hasSidecar flag
if (agentInfo.hasSidecar === true && agentInfo.type === 'expert') {
// Get agent sidecar folder from config or use default
const agentSidecarFolder = options.config?.agent_sidecar_folder || '{project-root}/.myagent-data';
// Resolve path variables
const resolvedSidecarFolder = agentSidecarFolder
.replaceAll('{project-root}', options.projectRoot || process.cwd())
.replaceAll('{bmad_folder}', options.bmadFolder || '.bmad');
// Create sidecar directory for this agent
const agentSidecarDir = path.join(resolvedSidecarFolder, agentFolderName);
if (!fs.existsSync(agentSidecarDir)) {
fs.mkdirSync(agentSidecarDir, { recursive: true });
}
// Find and copy sidecar folder
const sidecarFiles = copyAgentSidecarFiles(agentInfo.path, agentSidecarDir, agentInfo.yamlFile);
result.sidecarCopied = true;
result.sidecarFiles = sidecarFiles;
result.sidecarDir = agentSidecarDir;
}
return result;
@@ -309,6 +328,50 @@ function copySidecarFiles(sourceDir, targetDir, excludeYaml) {
return copied;
}
/**
* Find and copy agent sidecar folders
* @param {string} sourceDir - Source agent directory
* @param {string} targetSidecarDir - Target sidecar directory for the agent
* @param {string} excludeYaml - The .agent.yaml file to exclude
* @returns {Array} List of copied files
*/
function copyAgentSidecarFiles(sourceDir, targetSidecarDir, excludeYaml) {
const copied = [];
// Find folders with "sidecar" in the name
const entries = fs.readdirSync(sourceDir, { withFileTypes: true });
for (const entry of entries) {
if (entry.isDirectory() && entry.name.toLowerCase().includes('sidecar')) {
const sidecarSourcePath = path.join(sourceDir, entry.name);
// Recursively copy the sidecar folder contents
function copySidecarDir(src, dest) {
if (!fs.existsSync(dest)) {
fs.mkdirSync(dest, { recursive: true });
}
const sidecarEntries = fs.readdirSync(src, { withFileTypes: true });
for (const sidecarEntry of sidecarEntries) {
const srcPath = path.join(src, sidecarEntry.name);
const destPath = path.join(dest, sidecarEntry.name);
if (sidecarEntry.isDirectory()) {
copySidecarDir(srcPath, destPath);
} else {
fs.copyFileSync(srcPath, destPath);
copied.push(destPath);
}
}
}
copySidecarDir(sidecarSourcePath, targetSidecarDir);
}
}
return copied;
}
/**
* Update agent metadata ID to reflect installed location
* @param {string} compiledContent - Compiled XML content
@@ -745,6 +808,7 @@ module.exports = {
promptInstallQuestions,
installAgent,
copySidecarFiles,
copyAgentSidecarFiles,
updateAgentId,
detectBmadProject,
addToManifest,