diff --git a/src/modules/bmm/testarch/knowledge/overview.md b/src/modules/bmm/testarch/knowledge/overview.md index 5fbb9801..8155d55f 100644 --- a/src/modules/bmm/testarch/knowledge/overview.md +++ b/src/modules/bmm/testarch/knowledge/overview.md @@ -31,7 +31,6 @@ npm install -D @seontechnologies/playwright-utils - `@playwright/test` >= 1.54.1 (required) - `ajv` >= 8.0.0 (optional - for JSON Schema validation) -- `js-yaml` >= 4.0.0 (optional - for YAML schema support) - `zod` >= 3.0.0 (optional - for Zod schema validation) ## Available Utilities diff --git a/test/README.md b/test/README.md index 6253bd7e..da2f2962 100644 --- a/test/README.md +++ b/test/README.md @@ -269,7 +269,7 @@ The validation is integrated into the GitHub Actions workflow: ## Dependencies - **zod**: Schema validation library -- **js-yaml**: YAML parsing +- **yaml**: YAML parsing - **glob**: File pattern matching - **c8**: Code coverage reporting diff --git a/test/test-agent-schema.js b/test/test-agent-schema.js index 51cd65bb..ecb3b673 100644 --- a/test/test-agent-schema.js +++ b/test/test-agent-schema.js @@ -10,7 +10,7 @@ const fs = require('node:fs'); const path = require('node:path'); -const yaml = require('js-yaml'); +const yaml = require('yaml'); const { validateAgentFile } = require('../tools/schema/agent.js'); const { glob } = require('glob'); @@ -182,7 +182,7 @@ function runTest(filePath) { let agentData; try { - agentData = yaml.load(fileContent); + agentData = yaml.parse(fileContent); } catch (parseError) { // YAML parse error if (shouldPass) { diff --git a/tools/cli/installers/lib/core/config-collector.js b/tools/cli/installers/lib/core/config-collector.js index 8f0c9885..d82e345f 100644 --- a/tools/cli/installers/lib/core/config-collector.js +++ b/tools/cli/installers/lib/core/config-collector.js @@ -1,6 +1,6 @@ const path = require('node:path'); const fs = require('fs-extra'); -const yaml = require('js-yaml'); +const yaml = require('yaml'); const chalk = require('chalk'); const inquirer = require('inquirer'); const { getProjectRoot, getModulePath } = require('../../../lib/project-root'); @@ -109,7 +109,7 @@ class ConfigCollector { if (await fs.pathExists(moduleConfigPath)) { try { const content = await fs.readFile(moduleConfigPath, 'utf8'); - const moduleConfig = yaml.load(content); + const moduleConfig = yaml.parse(content); if (moduleConfig) { this.existingConfig[entry.name] = moduleConfig; foundAny = true; @@ -238,7 +238,7 @@ class ConfigCollector { } const configContent = await fs.readFile(configPath, 'utf8'); - const moduleConfig = yaml.load(configContent); + const moduleConfig = yaml.parse(configContent); if (!moduleConfig) { return false; @@ -514,7 +514,7 @@ class ConfigCollector { } const configContent = await fs.readFile(configPath, 'utf8'); - const moduleConfig = yaml.load(configContent); + const moduleConfig = yaml.parse(configContent); if (!moduleConfig) { return; diff --git a/tools/cli/installers/lib/core/custom-module-cache.js b/tools/cli/installers/lib/core/custom-module-cache.js index 0261efc7..a3945039 100644 --- a/tools/cli/installers/lib/core/custom-module-cache.js +++ b/tools/cli/installers/lib/core/custom-module-cache.js @@ -31,7 +31,7 @@ class CustomModuleCache { } const content = await fs.readFile(this.manifestPath, 'utf8'); - const yaml = require('js-yaml'); + const yaml = require('yaml'); return yaml.parse(content) || {}; } @@ -39,11 +39,10 @@ class CustomModuleCache { * Update cache manifest */ async updateCacheManifest(manifest) { - const yaml = require('js-yaml'); - const content = yaml.dump(manifest, { + const yaml = require('yaml'); + const content = yaml.stringify(manifest, { indent: 2, - lineWidth: -1, - noRefs: true, + lineWidth: 0, sortKeys: false, }); diff --git a/tools/cli/installers/lib/core/dependency-resolver.js b/tools/cli/installers/lib/core/dependency-resolver.js index c53aec58..7ed4716f 100644 --- a/tools/cli/installers/lib/core/dependency-resolver.js +++ b/tools/cli/installers/lib/core/dependency-resolver.js @@ -2,7 +2,7 @@ const fs = require('fs-extra'); const path = require('node:path'); const glob = require('glob'); const chalk = require('chalk'); -const yaml = require('js-yaml'); +const yaml = require('yaml'); /** * Dependency Resolver for BMAD modules @@ -147,7 +147,7 @@ class DependencyResolver { // Quote values with backticks to make them valid YAML yamlContent = yamlContent.replaceAll(/: `([^`]+)`/g, ': "$1"'); - const frontmatter = yaml.load(yamlContent); + const frontmatter = yaml.parse(yamlContent); if (frontmatter.dependencies) { const deps = Array.isArray(frontmatter.dependencies) ? frontmatter.dependencies : [frontmatter.dependencies]; diff --git a/tools/cli/installers/lib/core/detector.js b/tools/cli/installers/lib/core/detector.js index 251b60f5..f87034e0 100644 --- a/tools/cli/installers/lib/core/detector.js +++ b/tools/cli/installers/lib/core/detector.js @@ -1,6 +1,6 @@ const path = require('node:path'); const fs = require('fs-extra'); -const yaml = require('js-yaml'); +const yaml = require('yaml'); const { Manifest } = require('./manifest'); class Detector { @@ -237,7 +237,7 @@ class Detector { return false; } try { - const yaml = require('js-yaml'); + const yaml = require('yaml'); const manifestContent = await fs.readFile(manifestPath, 'utf8'); const manifest = yaml.parse(manifestContent); // V6+ manifest has installation.version diff --git a/tools/cli/installers/lib/core/ide-config-manager.js b/tools/cli/installers/lib/core/ide-config-manager.js index 8b09a8c2..91ca2b79 100644 --- a/tools/cli/installers/lib/core/ide-config-manager.js +++ b/tools/cli/installers/lib/core/ide-config-manager.js @@ -1,6 +1,6 @@ const path = require('node:path'); const fs = require('fs-extra'); -const yaml = require('js-yaml'); +const yaml = require('yaml'); /** * Manages IDE configuration persistence @@ -61,10 +61,9 @@ class IdeConfigManager { configuration: configuration || {}, }; - const yamlContent = yaml.dump(configData, { + const yamlContent = yaml.stringify(configData, { indent: 2, - lineWidth: -1, - noRefs: true, + lineWidth: 0, sortKeys: false, }); @@ -88,7 +87,7 @@ class IdeConfigManager { try { const content = await fs.readFile(configPath, 'utf8'); - const config = yaml.load(content); + const config = yaml.parse(content); return config; } catch (error) { console.warn(`Warning: Failed to load IDE config for ${ideName}:`, error.message); diff --git a/tools/cli/installers/lib/core/installer.js b/tools/cli/installers/lib/core/installer.js index 4a70e1ed..77ec343c 100644 --- a/tools/cli/installers/lib/core/installer.js +++ b/tools/cli/installers/lib/core/installer.js @@ -18,6 +18,7 @@ const { CLIUtils } = require('../../../lib/cli-utils'); const { ManifestGenerator } = require('./manifest-generator'); const { IdeConfigManager } = require('./ide-config-manager'); const { CustomHandler } = require('../custom/handler'); +const { filterCustomizationData } = require('../../../lib/agent/compiler'); class Installer { constructor() { @@ -1457,7 +1458,7 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice: * @param {Object} moduleConfigs - Collected configuration values */ async generateModuleConfigs(bmadDir, moduleConfigs) { - const yaml = require('js-yaml'); + const yaml = require('yaml'); // Extract core config values to share with other modules const coreConfig = moduleConfigs.core || {}; @@ -1504,11 +1505,10 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice: } // Convert config to YAML - let yamlContent = yaml.dump(finalConfig, { + let yamlContent = yaml.stringify(finalConfig, { indent: 2, - lineWidth: -1, - noRefs: true, - sortKeys: false, + lineWidth: 0, + minContentWidth: 0, }); // If we have core values, reorganize the YAML to group them with their comment @@ -1949,7 +1949,7 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice: if (customizeExists) { const customizeContent = await fs.readFile(customizePath, 'utf8'); - const yaml = require('js-yaml'); + const yaml = require('yaml'); const customizeYaml = yaml.parse(customizeContent); // Detect what fields are customized (similar to rebuildAgentFiles) @@ -2040,8 +2040,8 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice: if (customizeExists) { const customizeContent = await fs.readFile(customizePath, 'utf8'); - const yaml = require('js-yaml'); - const customizeYaml = yaml.load(customizeContent); + const yaml = require('yaml'); + const customizeYaml = yaml.parse(customizeContent); // Detect what fields are customized if (customizeYaml) { @@ -2085,18 +2085,21 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice: customizeData = yaml.parse(customizeContent); } - // Build agent answers from customize data + // Build agent answers from customize data (filter empty values) const answers = {}; if (customizeData.persona) { - Object.assign(answers, customizeData.persona); + Object.assign(answers, filterCustomizationData(customizeData.persona)); } if (customizeData.agent?.metadata) { - Object.assign(answers, { metadata: customizeData.agent.metadata }); + const filteredMetadata = filterCustomizationData(customizeData.agent.metadata); + if (Object.keys(filteredMetadata).length > 0) { + Object.assign(answers, { metadata: filteredMetadata }); + } } - if (customizeData.critical_actions) { + if (customizeData.critical_actions && customizeData.critical_actions.length > 0) { answers.critical_actions = customizeData.critical_actions; } - if (customizeData.memories) { + if (customizeData.memories && customizeData.memories.length > 0) { answers.memories = customizeData.memories; } @@ -2153,8 +2156,8 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice: let manifest = null; if (await fs.pathExists(manifestPath)) { const manifestContent = await fs.readFile(manifestPath, 'utf8'); - const yaml = require('js-yaml'); - manifest = yaml.load(manifestContent); + const yaml = require('yaml'); + manifest = yaml.parse(manifestContent); installedModules = manifest.modules || []; } diff --git a/tools/cli/installers/lib/core/manifest-generator.js b/tools/cli/installers/lib/core/manifest-generator.js index 9532cad7..b25581cf 100644 --- a/tools/cli/installers/lib/core/manifest-generator.js +++ b/tools/cli/installers/lib/core/manifest-generator.js @@ -1,6 +1,6 @@ const path = require('node:path'); const fs = require('fs-extra'); -const yaml = require('js-yaml'); +const yaml = require('yaml'); const crypto = require('node:crypto'); const { getSourcePath, getModulePath } = require('../../../lib/project-root'); @@ -480,10 +480,9 @@ class ManifestGenerator { ides: this.selectedIdes, }; - const yamlStr = yaml.dump(manifest, { + const yamlStr = yaml.stringify(manifest, { indent: 2, - lineWidth: -1, - noRefs: true, + lineWidth: 0, sortKeys: false, }); diff --git a/tools/cli/installers/lib/core/manifest.js b/tools/cli/installers/lib/core/manifest.js index ce12304f..743b2564 100644 --- a/tools/cli/installers/lib/core/manifest.js +++ b/tools/cli/installers/lib/core/manifest.js @@ -11,7 +11,7 @@ class Manifest { */ async create(bmadDir, data, installedFiles = []) { const manifestPath = path.join(bmadDir, '_cfg', 'manifest.yaml'); - const yaml = require('js-yaml'); + const yaml = require('yaml'); // Ensure _cfg directory exists await fs.ensureDir(path.dirname(manifestPath)); @@ -28,10 +28,9 @@ class Manifest { }; // Write YAML manifest - const yamlContent = yaml.dump(manifestData, { + const yamlContent = yaml.stringify(manifestData, { indent: 2, - lineWidth: -1, - noRefs: true, + lineWidth: 0, sortKeys: false, }); @@ -48,12 +47,12 @@ class Manifest { */ async read(bmadDir) { const yamlPath = path.join(bmadDir, '_cfg', 'manifest.yaml'); - const yaml = require('js-yaml'); + const yaml = require('yaml'); if (await fs.pathExists(yamlPath)) { try { const content = await fs.readFile(yamlPath, 'utf8'); - const manifestData = yaml.load(content); + const manifestData = yaml.parse(content); // Flatten the structure for compatibility with existing code return { @@ -79,7 +78,7 @@ class Manifest { * @param {Array} installedFiles - Updated list of installed files */ async update(bmadDir, updates, installedFiles = null) { - const yaml = require('js-yaml'); + const yaml = require('yaml'); const manifest = (await this.read(bmadDir)) || {}; // Merge updates @@ -101,10 +100,9 @@ class Manifest { const manifestPath = path.join(bmadDir, '_cfg', 'manifest.yaml'); await fs.ensureDir(path.dirname(manifestPath)); - const yamlContent = yaml.dump(manifestData, { + const yamlContent = yaml.stringify(manifestData, { indent: 2, - lineWidth: -1, - noRefs: true, + lineWidth: 0, sortKeys: false, }); @@ -526,9 +524,9 @@ class Manifest { try { if (await fs.pathExists(configPath)) { - const yaml = require('js-yaml'); + const yaml = require('yaml'); const content = await fs.readFile(configPath, 'utf8'); - configs[moduleName] = yaml.load(content); + configs[moduleName] = yaml.parse(content); } } catch (error) { console.warn(`Could not load config for module ${moduleName}:`, error.message); diff --git a/tools/cli/installers/lib/custom/handler.js b/tools/cli/installers/lib/custom/handler.js index 94dad5e3..6289aa57 100644 --- a/tools/cli/installers/lib/custom/handler.js +++ b/tools/cli/installers/lib/custom/handler.js @@ -1,7 +1,7 @@ const path = require('node:path'); const fs = require('fs-extra'); const chalk = require('chalk'); -const yaml = require('js-yaml'); +const yaml = require('yaml'); const { FileOps } = require('../../../lib/file-ops'); const { XmlHandler } = require('../../../lib/xml-handler'); diff --git a/tools/cli/installers/lib/ide/_base-ide.js b/tools/cli/installers/lib/ide/_base-ide.js index 0451e73e..f870194c 100644 --- a/tools/cli/installers/lib/ide/_base-ide.js +++ b/tools/cli/installers/lib/ide/_base-ide.js @@ -346,7 +346,7 @@ class BaseIdeSetup { } else if (entry.isFile() && entry.name === 'workflow.yaml') { // Read workflow.yaml to get name and standalone property try { - const yaml = require('js-yaml'); + const yaml = require('yaml'); const content = await fs.readFile(fullPath, 'utf8'); const workflowData = yaml.parse(content); @@ -454,7 +454,7 @@ class BaseIdeSetup { // Check for standalone: true in YAML frontmatter const frontmatterMatch = content.match(/^---\s*\n([\s\S]*?)\n---/); if (frontmatterMatch) { - const yaml = require('js-yaml'); + const yaml = require('yaml'); try { const frontmatter = yaml.parse(frontmatterMatch[1]); standalone = frontmatter.standalone === true; diff --git a/tools/cli/installers/lib/ide/antigravity.js b/tools/cli/installers/lib/ide/antigravity.js index e4f024e6..b921b4de 100644 --- a/tools/cli/installers/lib/ide/antigravity.js +++ b/tools/cli/installers/lib/ide/antigravity.js @@ -45,7 +45,7 @@ class AntigravitySetup extends BaseIdeSetup { const injectionConfigPath = path.join(sourceModulesPath, moduleName, 'sub-modules', 'antigravity', 'injections.yaml'); if (await this.exists(injectionConfigPath)) { - const yaml = require('js-yaml'); + const yaml = require('yaml'); try { // Load injection configuration diff --git a/tools/cli/installers/lib/ide/claude-code.js b/tools/cli/installers/lib/ide/claude-code.js index 06ff1d86..56131e44 100644 --- a/tools/cli/installers/lib/ide/claude-code.js +++ b/tools/cli/installers/lib/ide/claude-code.js @@ -44,7 +44,7 @@ class ClaudeCodeSetup extends BaseIdeSetup { const injectionConfigPath = path.join(sourceModulesPath, moduleName, 'sub-modules', 'claude-code', 'injections.yaml'); if (await this.exists(injectionConfigPath)) { - const yaml = require('js-yaml'); + const yaml = require('yaml'); try { // Load injection configuration diff --git a/tools/cli/installers/lib/ide/gemini.js b/tools/cli/installers/lib/ide/gemini.js index c2e6191e..82746abf 100644 --- a/tools/cli/installers/lib/ide/gemini.js +++ b/tools/cli/installers/lib/ide/gemini.js @@ -1,6 +1,6 @@ const path = require('node:path'); const fs = require('fs-extra'); -const yaml = require('js-yaml'); +const yaml = require('yaml'); const { BaseIdeSetup } = require('./_base-ide'); const chalk = require('chalk'); const { AgentCommandGenerator } = require('./shared/agent-command-generator'); diff --git a/tools/cli/installers/lib/ide/kiro-cli.js b/tools/cli/installers/lib/ide/kiro-cli.js index 1263a803..47f2a29d 100644 --- a/tools/cli/installers/lib/ide/kiro-cli.js +++ b/tools/cli/installers/lib/ide/kiro-cli.js @@ -2,7 +2,7 @@ const path = require('node:path'); const { BaseIdeSetup } = require('./_base-ide'); const chalk = require('chalk'); const fs = require('fs-extra'); -const yaml = require('js-yaml'); +const yaml = require('yaml'); /** * Kiro CLI setup handler for BMad Method diff --git a/tools/cli/installers/lib/ide/opencode.js b/tools/cli/installers/lib/ide/opencode.js index 2296a40a..cf5e8eec 100644 --- a/tools/cli/installers/lib/ide/opencode.js +++ b/tools/cli/installers/lib/ide/opencode.js @@ -2,7 +2,7 @@ const path = require('node:path'); const fs = require('fs-extra'); const os = require('node:os'); const chalk = require('chalk'); -const yaml = require('js-yaml'); +const yaml = require('yaml'); const { BaseIdeSetup } = require('./_base-ide'); const { WorkflowCommandGenerator } = require('./shared/workflow-command-generator'); const { TaskToolCommandGenerator } = require('./shared/task-tool-command-generator'); diff --git a/tools/cli/installers/lib/ide/shared/module-injections.js b/tools/cli/installers/lib/ide/shared/module-injections.js index 9a4448b0..6e38ee10 100644 --- a/tools/cli/installers/lib/ide/shared/module-injections.js +++ b/tools/cli/installers/lib/ide/shared/module-injections.js @@ -1,6 +1,6 @@ const path = require('node:path'); const fs = require('fs-extra'); -const yaml = require('js-yaml'); +const yaml = require('yaml'); const { glob } = require('glob'); const { getSourcePath } = require('../../../../lib/project-root'); diff --git a/tools/cli/installers/lib/modules/manager.js b/tools/cli/installers/lib/modules/manager.js index a5b790de..73e9b6ab 100644 --- a/tools/cli/installers/lib/modules/manager.js +++ b/tools/cli/installers/lib/modules/manager.js @@ -1,9 +1,10 @@ const path = require('node:path'); const fs = require('fs-extra'); -const yaml = require('js-yaml'); +const yaml = require('yaml'); const chalk = require('chalk'); const { XmlHandler } = require('../../../lib/xml-handler'); const { getProjectRoot, getSourcePath, getModulePath } = require('../../../lib/project-root'); +const { filterCustomizationData } = require('../../../lib/agent/compiler'); /** * Manages the installation, updating, and removal of BMAD modules. @@ -12,7 +13,7 @@ const { getProjectRoot, getSourcePath, getModulePath } = require('../../../lib/p * * @class ModuleManager * @requires fs-extra - * @requires js-yaml + * @requires yaml * @requires chalk * @requires XmlHandler * @@ -312,7 +313,7 @@ class ModuleManager { // Read module config for metadata try { const configContent = await fs.readFile(configPath, 'utf8'); - const config = yaml.load(configContent); + const config = yaml.parse(configContent); // Use the code property as the id if available if (config.code) { @@ -387,7 +388,7 @@ class ModuleManager { if (configPath) { try { const configContent = await fs.readFile(configPath, 'utf8'); - const config = yaml.load(configContent); + const config = yaml.parse(configContent); if (config.code === moduleName) { return modulePath; } @@ -427,14 +428,14 @@ class ModuleManager { if (await fs.pathExists(rootCustomConfigPath)) { try { const customContent = await fs.readFile(rootCustomConfigPath, 'utf8'); - customConfig = yaml.load(customContent); + customConfig = yaml.parse(customContent); } catch (error) { console.warn(chalk.yellow(`Warning: Failed to read custom.yaml for ${moduleName}:`, error.message)); } } else if (await fs.pathExists(moduleInstallerCustomPath)) { try { const customContent = await fs.readFile(moduleInstallerCustomPath, 'utf8'); - customConfig = yaml.load(customContent); + customConfig = yaml.parse(customContent); } catch (error) { console.warn(chalk.yellow(`Warning: Failed to read custom.yaml for ${moduleName}:`, error.message)); } @@ -569,7 +570,7 @@ class ModuleManager { if (await fs.pathExists(configPath)) { try { const configContent = await fs.readFile(configPath, 'utf8'); - const config = yaml.load(configContent); + const config = yaml.parse(configContent); Object.assign(moduleInfo, config); } catch (error) { console.warn(`Failed to read installed module config:`, error.message); @@ -700,7 +701,7 @@ class ModuleManager { try { // First check if web_bundle exists by parsing - const workflowConfig = yaml.load(yamlContent); + const workflowConfig = yaml.parse(yamlContent); if (workflowConfig.web_bundle === undefined) { // No web_bundle section, just write (placeholders already replaced above) @@ -827,20 +828,23 @@ class ModuleManager { let answers = {}; if (await fs.pathExists(customizePath)) { const customizeContent = await fs.readFile(customizePath, 'utf8'); - const customizeData = yaml.load(customizeContent); + const customizeData = yaml.parse(customizeContent); customizedFields = customizeData.customized_fields || []; - // Build answers object from customizations + // Build answers object from customizations (filter empty values) if (customizeData.persona) { - Object.assign(answers, customizeData.persona); + Object.assign(answers, filterCustomizationData(customizeData.persona)); } if (customizeData.agent?.metadata) { - Object.assign(answers, { metadata: customizeData.agent.metadata }); + const filteredMetadata = filterCustomizationData(customizeData.agent.metadata); + if (Object.keys(filteredMetadata).length > 0) { + Object.assign(answers, { metadata: filteredMetadata }); + } } - if (customizeData.critical_actions) { + if (customizeData.critical_actions && customizeData.critical_actions.length > 0) { answers.critical_actions = customizeData.critical_actions; } - if (customizeData.memories) { + if (customizeData.memories && customizeData.memories.length > 0) { answers.memories = customizeData.memories; } } @@ -852,7 +856,7 @@ class ModuleManager { if (await fs.pathExists(coreConfigPath)) { const yaml = require('yaml'); const coreConfigContent = await fs.readFile(coreConfigPath, 'utf8'); - coreConfig = yaml.load(coreConfigContent); + coreConfig = yaml.parse(coreConfigContent); } // Check if agent has sidecar @@ -1017,7 +1021,7 @@ class ModuleManager { for (const agentFile of yamlFiles) { const agentPath = path.join(sourceAgentsPath, agentFile); - const agentYaml = yaml.load(await fs.readFile(agentPath, 'utf8')); + const agentYaml = yaml.parse(await fs.readFile(agentPath, 'utf8')); // Check if agent has menu items with workflow-install const menuItems = agentYaml?.agent?.menu || []; diff --git a/tools/cli/lib/agent-analyzer.js b/tools/cli/lib/agent-analyzer.js index e10ab85b..ae834a09 100644 --- a/tools/cli/lib/agent-analyzer.js +++ b/tools/cli/lib/agent-analyzer.js @@ -1,4 +1,4 @@ -const yaml = require('js-yaml'); +const yaml = require('yaml'); const fs = require('fs-extra'); /** @@ -91,7 +91,7 @@ class AgentAnalyzer { */ async analyzeAgentFile(filePath) { const content = await fs.readFile(filePath, 'utf8'); - const agentYaml = yaml.load(content); + const agentYaml = yaml.parse(content); return this.analyzeAgentObject(agentYaml); } diff --git a/tools/cli/lib/agent/compiler.js b/tools/cli/lib/agent/compiler.js index 42a66418..71aa326c 100644 --- a/tools/cli/lib/agent/compiler.js +++ b/tools/cli/lib/agent/compiler.js @@ -313,7 +313,11 @@ async function compileAgent(yamlContent, answers = {}, agentName = '', targetPat // Apply customization merges before template processing // Handle metadata overrides (like name) if (answers.metadata) { - agentYaml.agent.metadata = { ...agentYaml.agent.metadata, ...answers.metadata }; + // Filter out empty values from metadata + const filteredMetadata = filterCustomizationData(answers.metadata); + if (Object.keys(filteredMetadata).length > 0) { + agentYaml.agent.metadata = { ...agentYaml.agent.metadata, ...filteredMetadata }; + } // Remove from answers so it doesn't get processed as template variables const { metadata, ...templateAnswers } = answers; answers = templateAnswers; @@ -353,6 +357,36 @@ async function compileAgent(yamlContent, answers = {}, agentName = '', targetPat }; } +/** + * Filter customization data to remove empty/null values + * @param {Object} data - Raw customization data + * @returns {Object} Filtered customization data + */ +function filterCustomizationData(data) { + const filtered = {}; + + for (const [key, value] of Object.entries(data)) { + if (value === null || value === undefined || value === '') { + continue; // Skip null/undefined/empty values + } + + if (Array.isArray(value)) { + if (value.length > 0) { + filtered[key] = value; + } + } else if (typeof value === 'object') { + const nested = filterCustomizationData(value); + if (Object.keys(nested).length > 0) { + filtered[key] = nested; + } + } else { + filtered[key] = value; + } + } + + return filtered; +} + /** * Process TTS injection markers in content * @param {string} content - Content to process @@ -431,4 +465,5 @@ module.exports = { buildPersonaXml, buildPromptsXml, buildMenuXml, + filterCustomizationData, }; diff --git a/tools/cli/lib/config.js b/tools/cli/lib/config.js index 1f7c2ad8..a7825030 100644 --- a/tools/cli/lib/config.js +++ b/tools/cli/lib/config.js @@ -1,5 +1,5 @@ const fs = require('fs-extra'); -const yaml = require('js-yaml'); +const yaml = require('yaml'); const path = require('node:path'); const packageJson = require('../../../package.json'); @@ -18,7 +18,7 @@ class Config { } const content = await fs.readFile(configPath, 'utf8'); - return yaml.load(content); + return yaml.parse(content); } /** diff --git a/tools/cli/lib/platform-codes.js b/tools/cli/lib/platform-codes.js index d539503a..bdf0e48c 100644 --- a/tools/cli/lib/platform-codes.js +++ b/tools/cli/lib/platform-codes.js @@ -1,6 +1,6 @@ const fs = require('fs-extra'); const path = require('node:path'); -const yaml = require('js-yaml'); +const yaml = require('yaml'); const { getProjectRoot } = require('./project-root'); /** @@ -20,7 +20,7 @@ class PlatformCodes { try { if (fs.existsSync(this.configPath)) { const content = fs.readFileSync(this.configPath, 'utf8'); - this.config = yaml.load(content); + this.config = yaml.parse(content); } else { console.warn(`Platform codes config not found at ${this.configPath}`); this.config = { platforms: {} }; diff --git a/tools/cli/lib/yaml-format.js b/tools/cli/lib/yaml-format.js index 66dbe3d9..3c38b921 100755 --- a/tools/cli/lib/yaml-format.js +++ b/tools/cli/lib/yaml-format.js @@ -1,6 +1,6 @@ const fs = require('node:fs'); const path = require('node:path'); -const yaml = require('js-yaml'); +const yaml = require('yaml'); const { execSync } = require('node:child_process'); // Dynamic import for ES module @@ -57,11 +57,10 @@ async function formatYamlContent(content, filename) { } // Parse and re-dump YAML to format it - const parsed = yaml.load(fixedContent); - const formatted = yaml.dump(parsed, { + const parsed = yaml.parse(fixedContent); + const formatted = yaml.stringify(parsed, { indent: 2, - lineWidth: -1, // Disable line wrapping - noRefs: true, + lineWidth: 0, // Disable line wrapping sortKeys: false, // Preserve key order }); // Ensure POSIX-compliant final newline @@ -96,7 +95,6 @@ async function processMarkdownFile(filePath) { const [fullMatch, yamlContent] = match; const formatted = await formatYamlContent(yamlContent, filePath); if (formatted !== null) { - // Remove trailing newline that js-yaml adds const trimmedFormatted = formatted.replace(/\n$/, ''); if (trimmedFormatted !== yamlContent) { diff --git a/tools/cli/lib/yaml-xml-builder.js b/tools/cli/lib/yaml-xml-builder.js index 6f5db1a5..b8b2de58 100644 --- a/tools/cli/lib/yaml-xml-builder.js +++ b/tools/cli/lib/yaml-xml-builder.js @@ -1,4 +1,4 @@ -const yaml = require('js-yaml'); +const yaml = require('yaml'); const fs = require('fs-extra'); const path = require('node:path'); const crypto = require('node:crypto'); @@ -64,13 +64,13 @@ class YamlXmlBuilder { async loadAndMergeAgent(agentYamlPath, customizeYamlPath = null) { // Load base agent const agentContent = await fs.readFile(agentYamlPath, 'utf8'); - const agentYaml = yaml.load(agentContent); + const agentYaml = yaml.parse(agentContent); // Load customization if exists let merged = agentYaml; if (customizeYamlPath && (await fs.pathExists(customizeYamlPath))) { const customizeContent = await fs.readFile(customizeYamlPath, 'utf8'); - const customizeYaml = yaml.load(customizeContent); + const customizeYaml = yaml.parse(customizeContent); if (customizeYaml) { // Special handling: persona fields are merged, but only non-empty values override diff --git a/tools/validate-agent-schema.js b/tools/validate-agent-schema.js index 54140139..b351f8ec 100644 --- a/tools/validate-agent-schema.js +++ b/tools/validate-agent-schema.js @@ -12,7 +12,7 @@ */ const { glob } = require('glob'); -const yaml = require('js-yaml'); +const yaml = require('yaml'); const fs = require('node:fs'); const path = require('node:path'); const { validateAgentFile } = require('./schema/agent.js'); @@ -49,7 +49,7 @@ async function main(customProjectRoot) { try { const fileContent = fs.readFileSync(filePath, 'utf8'); - const agentData = yaml.load(fileContent); + const agentData = yaml.parse(fileContent); // Convert absolute path to relative src/ path for module detection const srcRelativePath = relativePath.startsWith('src/') ? relativePath : path.relative(project_root, filePath).replaceAll('\\', '/');