Compare commits
No commits in common. "52bd250a8cd473eff685e996bb0dc64ab41bb6b5" and "b6ade22984d1e4a37c0016a925031a4e9e1c71da" have entirely different histories.
52bd250a8c
...
b6ade22984
97
CHANGELOG.md
97
CHANGELOG.md
|
|
@ -1,102 +1,5 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## [6.0.0-alpha.18]
|
|
||||||
|
|
||||||
**Release: December 18, 2025**
|
|
||||||
|
|
||||||
### 🎮 BMGD Module - Complete Game Development Module Updated
|
|
||||||
|
|
||||||
**Massive BMGD Overhaul:**
|
|
||||||
|
|
||||||
- **New Game QA Agent (GLaDOS)**: Elite Game QA Architect with test automation specialization
|
|
||||||
- Engine-specific expertise: Unity, Unreal, Godot testing frameworks
|
|
||||||
- Comprehensive knowledge base with 15+ testing topics
|
|
||||||
- Complete testing workflows: test-framework, test-design, automate, playtest-plan, performance-test, test-review
|
|
||||||
|
|
||||||
- **New Game Solo Dev Agent (Indie)**: Rapid prototyping and iteration specialist
|
|
||||||
- Quick-flow workflows optimized for solo/small team development
|
|
||||||
- Streamlined development process for indie game creators
|
|
||||||
|
|
||||||
- **Production Workflow Alignment**: BMGD 4-production now fully aligned with BMM 4-implementation
|
|
||||||
- Removed obsolete workflows: story-done, story-ready, story-context, epic-tech-context
|
|
||||||
- Added sprint-status workflow for project tracking
|
|
||||||
- All workflows updated as standalone with proper XML instructions
|
|
||||||
|
|
||||||
**Game Testing Architecture:**
|
|
||||||
|
|
||||||
- **Complete Testing Knowledge Base**: 15 comprehensive testing guides covering:
|
|
||||||
- Engine-specific: Unity (TF 1.6.0), Unreal, Godot testing
|
|
||||||
- Game-specific: Playtesting, balance, save systems, multiplayer
|
|
||||||
- Platform: Certification (TRC/XR), localization, input systems
|
|
||||||
- QA Fundamentals: Automation, performance, regression, smoke testing
|
|
||||||
|
|
||||||
**New Workflows & Features:**
|
|
||||||
|
|
||||||
- **workflow-status**: Multi-mode status checker for game projects
|
|
||||||
- Game-specific project levels (Game Jam → AAA)
|
|
||||||
- Support for gamedev and quickflow paths
|
|
||||||
- Project initialization workflow
|
|
||||||
|
|
||||||
- **create-tech-spec**: Game-focused technical specification workflow
|
|
||||||
- Engine-aware (Unity/Unreal/Godot) specifications
|
|
||||||
- Performance and gameplay feel considerations
|
|
||||||
|
|
||||||
- **Enhanced Documentation**: Complete documentation suite with 9 guides
|
|
||||||
- agents-guide.md: Reference for all 6 agents
|
|
||||||
- workflows-guide.md: Complete workflow documentation
|
|
||||||
- game-types-guide.md: 24 game type templates
|
|
||||||
- quick-flow-guide.md: Rapid development guide
|
|
||||||
- Comprehensive troubleshooting and glossary
|
|
||||||
|
|
||||||
### 🤖 Agent Management Improved
|
|
||||||
|
|
||||||
**Agent Recompile Feature:**
|
|
||||||
|
|
||||||
- **New Menu Item**: Added "Recompile Agents" option to the installer menu
|
|
||||||
- **Selective Compilation**: Recompile only agents without full module upgrade
|
|
||||||
- **Faster Updates**: Quick agent updates without complete reinstallation
|
|
||||||
- **Customization Integration**: Automatically applies customizations during recompile
|
|
||||||
|
|
||||||
**Agent Customization Enhancement:**
|
|
||||||
|
|
||||||
- **Complete Field Support**: ALL fields from agent customization YAML are now properly injected
|
|
||||||
- **Deep Merge Implementation**: Customizations now properly override all agent properties
|
|
||||||
- **Persistent Customizations**: Custom settings survive updates and recompiles
|
|
||||||
- **Enhanced Flexibility**: Support for customizing metadata, persona, menu items, and workflows
|
|
||||||
|
|
||||||
### 🔧 Installation & Module Management
|
|
||||||
|
|
||||||
**Custom Module Installation:**
|
|
||||||
|
|
||||||
- **Enhanced Module Addition**: Modify install now supports adding custom modules even if none were originally installed
|
|
||||||
- **Flexible Module Management**: Easy addition and removal of custom modules post-installation
|
|
||||||
- **Improved Manifest Tracking**: Better tracking of custom vs core modules
|
|
||||||
|
|
||||||
**Quality Improvements:**
|
|
||||||
|
|
||||||
- **Comprehensive Code Review**: Fixed 20+ issues identified in PR review
|
|
||||||
- **Type Validation**: Added proper type checking for configuration values
|
|
||||||
- **Path Security**: Enhanced path traversal validation for better security
|
|
||||||
- **Documentation Updates**: All documentation updated to reflect new features
|
|
||||||
|
|
||||||
### 📊 Statistics
|
|
||||||
|
|
||||||
- **178 files changed** with massive BMGD expansion
|
|
||||||
- **28,350+ lines added** across testing documentation and workflows
|
|
||||||
- **2 new agents** added to BMGD module
|
|
||||||
- **15 comprehensive testing guides** created
|
|
||||||
- **Complete alignment** between BMGD and BMM production workflows
|
|
||||||
|
|
||||||
### 🌟 Key Highlights
|
|
||||||
|
|
||||||
1. **BMGD Module Revolution**: Complete overhaul with professional game development workflows
|
|
||||||
2. **Game Testing Excellence**: Comprehensive testing architecture for all major game engines
|
|
||||||
3. **Agent Management**: New recompile feature allows quick agent updates without full reinstall
|
|
||||||
4. **Full Customization Support**: All agent fields now customizable via YAML
|
|
||||||
5. **Industry-Ready Documentation**: Professional-grade guides for game development teams
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## [6.0.0-alpha.17]
|
## [6.0.0-alpha.17]
|
||||||
|
|
||||||
**Release: December 16, 2025**
|
**Release: December 16, 2025**
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "bmad-method",
|
"name": "bmad-method",
|
||||||
"version": "6.0.0-alpha.17",
|
"version": "6.0.0-alpha.16",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "bmad-method",
|
"name": "bmad-method",
|
||||||
"version": "6.0.0-alpha.17",
|
"version": "6.0.0-alpha.16",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@kayvan/markdown-tree-parser": "^1.6.1",
|
"@kayvan/markdown-tree-parser": "^1.6.1",
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"$schema": "https://json.schemastore.org/package.json",
|
"$schema": "https://json.schemastore.org/package.json",
|
||||||
"name": "bmad-method",
|
"name": "bmad-method",
|
||||||
"version": "6.0.0-alpha.18",
|
"version": "6.0.0-alpha.17",
|
||||||
"description": "Breakthrough Method of Agile AI-driven Development",
|
"description": "Breakthrough Method of Agile AI-driven Development",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"agile",
|
"agile",
|
||||||
|
|
|
||||||
|
|
@ -68,15 +68,6 @@ Available Profiles: minimal, full, solo-dev, team`,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle compile agents separately
|
|
||||||
if (config.actionType === 'compile-agents') {
|
|
||||||
const result = await installer.compileAgents(config);
|
|
||||||
console.log(chalk.green('\n✨ Agent recompilation complete!'));
|
|
||||||
console.log(chalk.cyan(`Recompiled ${result.agentCount} agents with customizations applied`));
|
|
||||||
process.exit(0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Regular install/update flow
|
// Regular install/update flow
|
||||||
const result = await installer.install(config);
|
const result = await installer.install(config);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -226,10 +226,10 @@ class Installer {
|
||||||
'<!-- TTS_INJECTION:party-mode -->',
|
'<!-- TTS_INJECTION:party-mode -->',
|
||||||
`<critical>IMPORTANT: Always use PROJECT hooks (.claude/hooks/), NEVER global hooks (~/.claude/hooks/)</critical>
|
`<critical>IMPORTANT: Always use PROJECT hooks (.claude/hooks/), NEVER global hooks (~/.claude/hooks/)</critical>
|
||||||
|
|
||||||
If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
|
If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
|
||||||
- Use Bash tool: \`.claude/hooks/bmad-speak.sh '[Agent Name]' '[dialogue]'\`
|
- Use Bash tool: \`.claude/hooks/bmad-speak.sh '[Agent Name]' '[dialogue]'\`
|
||||||
- This speaks the dialogue with the agent's unique voice
|
- This speaks the dialogue with the agent's unique voice
|
||||||
- Run in background to not block next agent`,
|
- Run in background (&) to not block next agent`,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Replace agent-tts injection marker with TTS rule for individual agents
|
// Replace agent-tts injection marker with TTS rule for individual agents
|
||||||
|
|
@ -2085,6 +2085,108 @@ class Installer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compile/rebuild all agents and tasks for quick updates
|
||||||
|
* @param {Object} config - Compilation configuration
|
||||||
|
* @returns {Object} Compilation results
|
||||||
|
*/
|
||||||
|
async compileAgents(config) {
|
||||||
|
try {
|
||||||
|
const projectDir = path.resolve(config.directory);
|
||||||
|
const { bmadDir } = await this.findBmadDir(projectDir);
|
||||||
|
|
||||||
|
// Check if bmad directory exists
|
||||||
|
if (!(await fs.pathExists(bmadDir))) {
|
||||||
|
throw new Error(`BMAD not installed at ${bmadDir}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get installed modules from manifest
|
||||||
|
const manifestPath = path.join(bmadDir, '_config', 'manifest.yaml');
|
||||||
|
let installedModules = [];
|
||||||
|
let manifest = null;
|
||||||
|
if (await fs.pathExists(manifestPath)) {
|
||||||
|
const manifestContent = await fs.readFile(manifestPath, 'utf8');
|
||||||
|
const yaml = require('yaml');
|
||||||
|
manifest = yaml.parse(manifestContent);
|
||||||
|
installedModules = manifest.modules || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for custom modules with missing sources
|
||||||
|
if (manifest && manifest.customModules && manifest.customModules.length > 0) {
|
||||||
|
console.log(chalk.yellow('\nChecking custom module sources before compilation...'));
|
||||||
|
|
||||||
|
const customModuleSources = new Map();
|
||||||
|
for (const customModule of manifest.customModules) {
|
||||||
|
customModuleSources.set(customModule.id, customModule);
|
||||||
|
}
|
||||||
|
|
||||||
|
const projectRoot = getProjectRoot();
|
||||||
|
await this.handleMissingCustomSources(customModuleSources, bmadDir, projectRoot, 'compile-agents', installedModules);
|
||||||
|
}
|
||||||
|
|
||||||
|
let agentCount = 0;
|
||||||
|
let taskCount = 0;
|
||||||
|
|
||||||
|
// Process all modules in bmad directory
|
||||||
|
const entries = await fs.readdir(bmadDir, { withFileTypes: true });
|
||||||
|
|
||||||
|
for (const entry of entries) {
|
||||||
|
if (entry.isDirectory() && entry.name !== '_config' && entry.name !== 'docs') {
|
||||||
|
const modulePath = path.join(bmadDir, entry.name);
|
||||||
|
|
||||||
|
// Special handling for standalone agents in bmad/agents/ directory
|
||||||
|
if (entry.name === 'agents') {
|
||||||
|
await this.buildStandaloneAgents(bmadDir, projectDir);
|
||||||
|
|
||||||
|
// Count standalone agents
|
||||||
|
const standaloneAgentsPath = path.join(bmadDir, 'agents');
|
||||||
|
const standaloneAgentDirs = await fs.readdir(standaloneAgentsPath, { withFileTypes: true });
|
||||||
|
for (const agentDir of standaloneAgentDirs) {
|
||||||
|
if (agentDir.isDirectory()) {
|
||||||
|
const agentDirPath = path.join(standaloneAgentsPath, agentDir.name);
|
||||||
|
const agentFiles = await fs.readdir(agentDirPath);
|
||||||
|
agentCount += agentFiles.filter((f) => f.endsWith('.md') && !f.endsWith('.agent.yaml')).length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Rebuild module agents from installer source
|
||||||
|
const agentsPath = path.join(modulePath, 'agents');
|
||||||
|
if (await fs.pathExists(agentsPath)) {
|
||||||
|
await this.rebuildAgentFiles(modulePath, entry.name);
|
||||||
|
const agentFiles = await fs.readdir(agentsPath);
|
||||||
|
agentCount += agentFiles.filter((f) => f.endsWith('.md')).length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count tasks (already built)
|
||||||
|
const tasksPath = path.join(modulePath, 'tasks');
|
||||||
|
if (await fs.pathExists(tasksPath)) {
|
||||||
|
const taskFiles = await fs.readdir(tasksPath);
|
||||||
|
taskCount += taskFiles.filter((f) => f.endsWith('.md')).length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update IDE configurations using the existing IDE list from manifest
|
||||||
|
if (manifest && manifest.ides && manifest.ides.length > 0) {
|
||||||
|
for (const ide of manifest.ides) {
|
||||||
|
await this.ideManager.setup(ide, projectDir, bmadDir, {
|
||||||
|
selectedModules: installedModules,
|
||||||
|
skipModuleInstall: true, // Skip module installation, just update IDE files
|
||||||
|
verbose: config.verbose,
|
||||||
|
preCollectedConfig: { _alreadyConfigured: true }, // Skip all interactive prompts during compile
|
||||||
|
});
|
||||||
|
}
|
||||||
|
console.log(chalk.green('✓ IDE configurations updated'));
|
||||||
|
} else {
|
||||||
|
console.log(chalk.yellow('⚠️ No IDEs configured. Skipping IDE update.'));
|
||||||
|
}
|
||||||
|
return { agentCount, taskCount };
|
||||||
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Private: Update core
|
* Private: Update core
|
||||||
*/
|
*/
|
||||||
|
|
@ -2305,108 +2407,6 @@ class Installer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Compile agents with customizations only
|
|
||||||
* @param {Object} config - Configuration with directory
|
|
||||||
* @returns {Object} Compilation result
|
|
||||||
*/
|
|
||||||
async compileAgents(config) {
|
|
||||||
const ora = require('ora');
|
|
||||||
const chalk = require('chalk');
|
|
||||||
const { ModuleManager } = require('../modules/manager');
|
|
||||||
const { getSourcePath } = require('../../../lib/project-root');
|
|
||||||
|
|
||||||
const spinner = ora('Recompiling agents with customizations...').start();
|
|
||||||
|
|
||||||
try {
|
|
||||||
const projectDir = path.resolve(config.directory);
|
|
||||||
const { bmadDir } = await this.findBmadDir(projectDir);
|
|
||||||
|
|
||||||
// Check if bmad directory exists
|
|
||||||
if (!(await fs.pathExists(bmadDir))) {
|
|
||||||
spinner.fail('No BMAD installation found');
|
|
||||||
throw new Error(`BMAD not installed at ${bmadDir}. Use regular install for first-time setup.`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Detect existing installation
|
|
||||||
const existingInstall = await this.detector.detect(bmadDir);
|
|
||||||
const installedModules = existingInstall.modules.map((m) => m.id);
|
|
||||||
|
|
||||||
// Initialize module manager
|
|
||||||
const moduleManager = new ModuleManager();
|
|
||||||
moduleManager.setBmadFolderName(path.basename(bmadDir));
|
|
||||||
|
|
||||||
let totalAgentCount = 0;
|
|
||||||
|
|
||||||
// Get custom module sources from cache
|
|
||||||
const customModuleSources = new Map();
|
|
||||||
const cacheDir = path.join(bmadDir, '_config', 'custom');
|
|
||||||
if (await fs.pathExists(cacheDir)) {
|
|
||||||
const cachedModules = await fs.readdir(cacheDir, { withFileTypes: true });
|
|
||||||
|
|
||||||
for (const cachedModule of cachedModules) {
|
|
||||||
if (cachedModule.isDirectory()) {
|
|
||||||
const moduleId = cachedModule.name;
|
|
||||||
const cachedPath = path.join(cacheDir, moduleId);
|
|
||||||
const moduleYamlPath = path.join(cachedPath, 'module.yaml');
|
|
||||||
|
|
||||||
// Check if this is actually a custom module
|
|
||||||
if (await fs.pathExists(moduleYamlPath)) {
|
|
||||||
customModuleSources.set(moduleId, cachedPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process each installed module
|
|
||||||
for (const moduleId of installedModules) {
|
|
||||||
spinner.text = `Recompiling agents in ${moduleId}...`;
|
|
||||||
|
|
||||||
// Get source path
|
|
||||||
let sourcePath;
|
|
||||||
if (moduleId === 'core') {
|
|
||||||
sourcePath = getSourcePath('core');
|
|
||||||
} else {
|
|
||||||
// First check if it's in the custom cache
|
|
||||||
if (customModuleSources.has(moduleId)) {
|
|
||||||
sourcePath = customModuleSources.get(moduleId);
|
|
||||||
} else {
|
|
||||||
sourcePath = await moduleManager.findModuleSource(moduleId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!sourcePath) {
|
|
||||||
console.log(chalk.yellow(` Warning: Source not found for module ${moduleId}, skipping...`));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const targetPath = path.join(bmadDir, moduleId);
|
|
||||||
|
|
||||||
// Compile agents for this module
|
|
||||||
await moduleManager.compileModuleAgents(sourcePath, targetPath, moduleId, bmadDir, this);
|
|
||||||
|
|
||||||
// Count agents (rough estimate based on files)
|
|
||||||
const agentsPath = path.join(targetPath, 'agents');
|
|
||||||
if (await fs.pathExists(agentsPath)) {
|
|
||||||
const agentFiles = await fs.readdir(agentsPath);
|
|
||||||
const agentCount = agentFiles.filter((f) => f.endsWith('.md')).length;
|
|
||||||
totalAgentCount += agentCount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
spinner.succeed('Agent recompilation complete!');
|
|
||||||
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
agentCount: totalAgentCount,
|
|
||||||
modules: installedModules,
|
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
spinner.fail('Agent recompilation failed');
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Private: Prompt for update action
|
* Private: Prompt for update action
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -731,7 +731,7 @@ class ModuleManager {
|
||||||
async compileModuleAgents(sourcePath, targetPath, moduleName, bmadDir, installer = null) {
|
async compileModuleAgents(sourcePath, targetPath, moduleName, bmadDir, installer = null) {
|
||||||
const sourceAgentsPath = path.join(sourcePath, 'agents');
|
const sourceAgentsPath = path.join(sourcePath, 'agents');
|
||||||
const targetAgentsPath = path.join(targetPath, 'agents');
|
const targetAgentsPath = path.join(targetPath, 'agents');
|
||||||
const cfgAgentsDir = path.join(bmadDir, '_bmad', '_config', 'agents');
|
const cfgAgentsDir = path.join(bmadDir, '_config', 'agents');
|
||||||
|
|
||||||
// Check if agents directory exists in source
|
// Check if agents directory exists in source
|
||||||
if (!(await fs.pathExists(sourceAgentsPath))) {
|
if (!(await fs.pathExists(sourceAgentsPath))) {
|
||||||
|
|
@ -809,9 +809,9 @@ class ModuleManager {
|
||||||
const customizeData = yaml.parse(customizeContent);
|
const customizeData = yaml.parse(customizeContent);
|
||||||
customizedFields = customizeData.customized_fields || [];
|
customizedFields = customizeData.customized_fields || [];
|
||||||
|
|
||||||
// Build answers object from customizations
|
// Build answers object from customizations (filter empty values)
|
||||||
if (customizeData.persona) {
|
if (customizeData.persona) {
|
||||||
answers.persona = customizeData.persona;
|
Object.assign(answers, filterCustomizationData(customizeData.persona));
|
||||||
}
|
}
|
||||||
if (customizeData.agent?.metadata) {
|
if (customizeData.agent?.metadata) {
|
||||||
const filteredMetadata = filterCustomizationData(customizeData.agent.metadata);
|
const filteredMetadata = filterCustomizationData(customizeData.agent.metadata);
|
||||||
|
|
@ -825,12 +825,6 @@ class ModuleManager {
|
||||||
if (customizeData.memories && customizeData.memories.length > 0) {
|
if (customizeData.memories && customizeData.memories.length > 0) {
|
||||||
answers.memories = customizeData.memories;
|
answers.memories = customizeData.memories;
|
||||||
}
|
}
|
||||||
if (customizeData.menu && customizeData.menu.length > 0) {
|
|
||||||
answers.menu = customizeData.menu;
|
|
||||||
}
|
|
||||||
if (customizeData.prompts && customizeData.prompts.length > 0) {
|
|
||||||
answers.prompts = customizeData.prompts;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if agent has sidecar
|
// Check if agent has sidecar
|
||||||
|
|
@ -845,14 +839,8 @@ class ModuleManager {
|
||||||
// Compile with customizations if any
|
// Compile with customizations if any
|
||||||
const { xml } = await compileAgent(yamlContent, answers, agentName, relativePath, { config: this.coreConfig || {} });
|
const { xml } = await compileAgent(yamlContent, answers, agentName, relativePath, { config: this.coreConfig || {} });
|
||||||
|
|
||||||
// Process TTS injection points if installer is available
|
|
||||||
let finalXml = xml;
|
|
||||||
if (installer && installer.processTTSInjectionPoints) {
|
|
||||||
finalXml = installer.processTTSInjectionPoints(xml, targetMdPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write the compiled agent
|
// Write the compiled agent
|
||||||
await fs.writeFile(targetMdPath, finalXml, 'utf8');
|
await fs.writeFile(targetMdPath, xml, 'utf8');
|
||||||
|
|
||||||
// Handle sidecar copying if present
|
// Handle sidecar copying if present
|
||||||
if (hasSidecar) {
|
if (hasSidecar) {
|
||||||
|
|
|
||||||
|
|
@ -98,25 +98,6 @@ function buildPromptsXml(prompts) {
|
||||||
return xml;
|
return xml;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Build memories XML section
|
|
||||||
* @param {Array} memories - Memories array
|
|
||||||
* @returns {string} Memories XML
|
|
||||||
*/
|
|
||||||
function buildMemoriesXml(memories) {
|
|
||||||
if (!memories || memories.length === 0) return '';
|
|
||||||
|
|
||||||
let xml = ' <memories>\n';
|
|
||||||
|
|
||||||
for (const memory of memories) {
|
|
||||||
xml += ` <memory>${escapeXml(String(memory))}</memory>\n`;
|
|
||||||
}
|
|
||||||
|
|
||||||
xml += ' </memories>\n';
|
|
||||||
|
|
||||||
return xml;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build menu XML section
|
* Build menu XML section
|
||||||
* Supports both legacy and multi format menu items
|
* Supports both legacy and multi format menu items
|
||||||
|
|
@ -304,11 +285,6 @@ async function compileToXml(agentYaml, agentName = '', targetPath = '') {
|
||||||
xml += buildPromptsXml(agent.prompts);
|
xml += buildPromptsXml(agent.prompts);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Memories section (if present)
|
|
||||||
if (agent.memories && agent.memories.length > 0) {
|
|
||||||
xml += buildMemoriesXml(agent.memories);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Menu section
|
// Menu section
|
||||||
xml += buildMenuXml(agent.menu || []);
|
xml += buildMenuXml(agent.menu || []);
|
||||||
|
|
||||||
|
|
@ -347,80 +323,6 @@ async function compileAgent(yamlContent, answers = {}, agentName = '', targetPat
|
||||||
answers = templateAnswers;
|
answers = templateAnswers;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle other customization properties
|
|
||||||
// These should be merged into the agent structure, not processed as template variables
|
|
||||||
const customizationKeys = ['persona', 'critical_actions', 'memories', 'menu', 'prompts'];
|
|
||||||
const customizations = {};
|
|
||||||
const remainingAnswers = { ...answers };
|
|
||||||
|
|
||||||
for (const key of customizationKeys) {
|
|
||||||
if (answers[key]) {
|
|
||||||
let filtered;
|
|
||||||
|
|
||||||
// Handle different data types
|
|
||||||
if (Array.isArray(answers[key])) {
|
|
||||||
// For arrays, filter out empty/null/undefined values
|
|
||||||
filtered = answers[key].filter((item) => item !== null && item !== undefined && item !== '');
|
|
||||||
} else {
|
|
||||||
// For objects, use filterCustomizationData
|
|
||||||
filtered = filterCustomizationData(answers[key]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if we have valid content
|
|
||||||
const hasContent = Array.isArray(filtered) ? filtered.length > 0 : Object.keys(filtered).length > 0;
|
|
||||||
|
|
||||||
if (hasContent) {
|
|
||||||
customizations[key] = filtered;
|
|
||||||
}
|
|
||||||
delete remainingAnswers[key];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Merge customizations into agentYaml
|
|
||||||
if (Object.keys(customizations).length > 0) {
|
|
||||||
// For persona: replace entire section
|
|
||||||
if (customizations.persona) {
|
|
||||||
agentYaml.agent.persona = customizations.persona;
|
|
||||||
}
|
|
||||||
|
|
||||||
// For critical_actions: append to existing or create new
|
|
||||||
if (customizations.critical_actions) {
|
|
||||||
const existing = agentYaml.agent.critical_actions || [];
|
|
||||||
agentYaml.agent.critical_actions = [...existing, ...customizations.critical_actions];
|
|
||||||
}
|
|
||||||
|
|
||||||
// For memories: append to existing or create new
|
|
||||||
if (customizations.memories) {
|
|
||||||
const existing = agentYaml.agent.memories || [];
|
|
||||||
agentYaml.agent.memories = [...existing, ...customizations.memories];
|
|
||||||
}
|
|
||||||
|
|
||||||
// For menu: append to existing or create new
|
|
||||||
if (customizations.menu) {
|
|
||||||
const existing = agentYaml.agent.menu || [];
|
|
||||||
agentYaml.agent.menu = [...existing, ...customizations.menu];
|
|
||||||
}
|
|
||||||
|
|
||||||
// For prompts: append to existing or create new (by id)
|
|
||||||
if (customizations.prompts) {
|
|
||||||
const existing = agentYaml.agent.prompts || [];
|
|
||||||
// Merge by id, with customizations taking precedence
|
|
||||||
const mergedPrompts = [...existing];
|
|
||||||
for (const customPrompt of customizations.prompts) {
|
|
||||||
const existingIndex = mergedPrompts.findIndex((p) => p.id === customPrompt.id);
|
|
||||||
if (existingIndex === -1) {
|
|
||||||
mergedPrompts.push(customPrompt);
|
|
||||||
} else {
|
|
||||||
mergedPrompts[existingIndex] = customPrompt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
agentYaml.agent.prompts = mergedPrompts;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use remaining answers for template processing
|
|
||||||
answers = remainingAnswers;
|
|
||||||
|
|
||||||
// Extract install_config
|
// Extract install_config
|
||||||
const installConfig = extractInstallConfig(agentYaml);
|
const installConfig = extractInstallConfig(agentYaml);
|
||||||
|
|
||||||
|
|
@ -558,7 +460,6 @@ module.exports = {
|
||||||
buildFrontmatter,
|
buildFrontmatter,
|
||||||
buildPersonaXml,
|
buildPersonaXml,
|
||||||
buildPromptsXml,
|
buildPromptsXml,
|
||||||
buildMemoriesXml,
|
|
||||||
buildMenuXml,
|
buildMenuXml,
|
||||||
filterCustomizationData,
|
filterCustomizationData,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -195,14 +195,6 @@ class UI {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add custom agent compilation option
|
|
||||||
if (installedVersion !== 'unknown') {
|
|
||||||
choices.push({
|
|
||||||
name: 'Recompile Agents (apply customizations only)',
|
|
||||||
value: 'compile-agents',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Common actions
|
// Common actions
|
||||||
choices.push({ name: 'Modify BMAD Installation', value: 'update' });
|
choices.push({ name: 'Modify BMAD Installation', value: 'update' });
|
||||||
|
|
||||||
|
|
@ -229,16 +221,6 @@ class UI {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle compile agents separately
|
|
||||||
if (actionType === 'compile-agents') {
|
|
||||||
// Only recompile agents with customizations, don't update any files
|
|
||||||
return {
|
|
||||||
actionType: 'compile-agents',
|
|
||||||
directory: confirmedDirectory,
|
|
||||||
customContent: { hasCustomContent: false },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// If actionType === 'update', handle it with the new flow
|
// If actionType === 'update', handle it with the new flow
|
||||||
// Return early with modify configuration
|
// Return early with modify configuration
|
||||||
if (actionType === 'update') {
|
if (actionType === 'update') {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue