diff --git a/src/utility/agent-components/agent.customize.template.yaml b/src/utility/agent-components/agent.customize.template.yaml index 3fb4785f..b8cc648b 100644 --- a/src/utility/agent-components/agent.customize.template.yaml +++ b/src/utility/agent-components/agent.customize.template.yaml @@ -1,6 +1,5 @@ # Agent Customization # Customize any section below - all are optional -# After editing: npx bmad-method build # Override agent name agent: diff --git a/tools/cli/installers/lib/core/installer.js b/tools/cli/installers/lib/core/installer.js index 77ec343c..b749e0d4 100644 --- a/tools/cli/installers/lib/core/installer.js +++ b/tools/cli/installers/lib/core/installer.js @@ -2798,11 +2798,28 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice: const relativePath = path.relative(bmadDir, fullPath); const fileName = path.basename(fullPath); - // Skip _cfg directory EXCEPT for agent customizations - if ( - (relativePath.startsWith('_cfg/') || relativePath.startsWith('_cfg\\')) && // Allow .customize.yaml files in _cfg/agents/ - !(relativePath.includes('/agents/') && fileName.endsWith('.customize.yaml')) - ) { + // Skip _cfg directory EXCEPT for modified agent customizations + if (relativePath.startsWith('_cfg/') || relativePath.startsWith('_cfg\\')) { + // Special handling for .customize.yaml files - only preserve if modified + if (relativePath.includes('/agents/') && fileName.endsWith('.customize.yaml')) { + // Check if the customization file has been modified from manifest + const manifestPath = path.join(bmadDir, '_cfg', 'manifest.yaml'); + if (await fs.pathExists(manifestPath)) { + const crypto = require('node:crypto'); + const currentContent = await fs.readFile(fullPath, 'utf8'); + const currentHash = crypto.createHash('sha256').update(currentContent).digest('hex'); + + const yaml = require('yaml'); + const manifestContent = await fs.readFile(manifestPath, 'utf8'); + const manifestData = yaml.parse(manifestContent); + const originalHash = manifestData.agentCustomizations?.[relativePath]; + + // Only add to customFiles if hash differs (user modified) + if (originalHash && currentHash !== originalHash) { + customFiles.push(fullPath); + } + } + } continue; } @@ -2814,7 +2831,11 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice: if (!fileInfo) { // File not in manifest = custom file - customFiles.push(fullPath); + // EXCEPT: Agent .md files in module folders are generated files, not custom + // Only treat .md files under _cfg/agents/ as custom + if (!(fileName.endsWith('.md') && relativePath.includes('/agents/') && !relativePath.startsWith('_cfg/'))) { + customFiles.push(fullPath); + } } else if (manifestHasHashes && fileInfo.hash) { // File in manifest with hash - check if it was modified const currentHash = await this.manifest.calculateFileHash(fullPath); diff --git a/tools/cli/installers/lib/modules/manager.js b/tools/cli/installers/lib/modules/manager.js index 73e9b6ab..55cc6039 100644 --- a/tools/cli/installers/lib/modules/manager.js +++ b/tools/cli/installers/lib/modules/manager.js @@ -820,6 +820,32 @@ class ModuleManager { if (await fs.pathExists(genericTemplatePath)) { await this.copyFileWithPlaceholderReplacement(genericTemplatePath, customizePath); console.log(chalk.dim(` Created customize: ${moduleName}-${agentName}.customize.yaml`)); + + // Store original hash for modification detection + const crypto = require('node:crypto'); + const customizeContent = await fs.readFile(customizePath, 'utf8'); + const originalHash = crypto.createHash('sha256').update(customizeContent).digest('hex'); + + // Store in main manifest + const manifestPath = path.join(bmadDir, '_cfg', 'manifest.yaml'); + let manifestData = {}; + if (await fs.pathExists(manifestPath)) { + const manifestContent = await fs.readFile(manifestPath, 'utf8'); + const yaml = require('yaml'); + manifestData = yaml.parse(manifestContent); + } + if (!manifestData.agentCustomizations) { + manifestData.agentCustomizations = {}; + } + manifestData.agentCustomizations[path.relative(bmadDir, customizePath)] = originalHash; + + // Write back to manifest + const yaml = require('yaml'); + const updatedContent = yaml.stringify(manifestData, { + indent: 2, + lineWidth: 0, + }); + await fs.writeFile(manifestPath, updatedContent, 'utf8'); } }