we only need one yaml lib

This commit is contained in:
Brian Madison 2025-12-13 18:35:07 +08:00
parent ce42d56fdd
commit 8642553bd7
27 changed files with 130 additions and 96 deletions

View File

@ -31,7 +31,6 @@ npm install -D @seontechnologies/playwright-utils
- `@playwright/test` >= 1.54.1 (required) - `@playwright/test` >= 1.54.1 (required)
- `ajv` >= 8.0.0 (optional - for JSON Schema validation) - `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) - `zod` >= 3.0.0 (optional - for Zod schema validation)
## Available Utilities ## Available Utilities

View File

@ -269,7 +269,7 @@ The validation is integrated into the GitHub Actions workflow:
## Dependencies ## Dependencies
- **zod**: Schema validation library - **zod**: Schema validation library
- **js-yaml**: YAML parsing - **yaml**: YAML parsing
- **glob**: File pattern matching - **glob**: File pattern matching
- **c8**: Code coverage reporting - **c8**: Code coverage reporting

View File

@ -10,7 +10,7 @@
const fs = require('node:fs'); const fs = require('node:fs');
const path = require('node:path'); const path = require('node:path');
const yaml = require('js-yaml'); const yaml = require('yaml');
const { validateAgentFile } = require('../tools/schema/agent.js'); const { validateAgentFile } = require('../tools/schema/agent.js');
const { glob } = require('glob'); const { glob } = require('glob');
@ -182,7 +182,7 @@ function runTest(filePath) {
let agentData; let agentData;
try { try {
agentData = yaml.load(fileContent); agentData = yaml.parse(fileContent);
} catch (parseError) { } catch (parseError) {
// YAML parse error // YAML parse error
if (shouldPass) { if (shouldPass) {

View File

@ -1,6 +1,6 @@
const path = require('node:path'); const path = require('node:path');
const fs = require('fs-extra'); const fs = require('fs-extra');
const yaml = require('js-yaml'); const yaml = require('yaml');
const chalk = require('chalk'); const chalk = require('chalk');
const inquirer = require('inquirer'); const inquirer = require('inquirer');
const { getProjectRoot, getModulePath } = require('../../../lib/project-root'); const { getProjectRoot, getModulePath } = require('../../../lib/project-root');
@ -109,7 +109,7 @@ class ConfigCollector {
if (await fs.pathExists(moduleConfigPath)) { if (await fs.pathExists(moduleConfigPath)) {
try { try {
const content = await fs.readFile(moduleConfigPath, 'utf8'); const content = await fs.readFile(moduleConfigPath, 'utf8');
const moduleConfig = yaml.load(content); const moduleConfig = yaml.parse(content);
if (moduleConfig) { if (moduleConfig) {
this.existingConfig[entry.name] = moduleConfig; this.existingConfig[entry.name] = moduleConfig;
foundAny = true; foundAny = true;
@ -238,7 +238,7 @@ class ConfigCollector {
} }
const configContent = await fs.readFile(configPath, 'utf8'); const configContent = await fs.readFile(configPath, 'utf8');
const moduleConfig = yaml.load(configContent); const moduleConfig = yaml.parse(configContent);
if (!moduleConfig) { if (!moduleConfig) {
return false; return false;
@ -514,7 +514,7 @@ class ConfigCollector {
} }
const configContent = await fs.readFile(configPath, 'utf8'); const configContent = await fs.readFile(configPath, 'utf8');
const moduleConfig = yaml.load(configContent); const moduleConfig = yaml.parse(configContent);
if (!moduleConfig) { if (!moduleConfig) {
return; return;

View File

@ -31,7 +31,7 @@ class CustomModuleCache {
} }
const content = await fs.readFile(this.manifestPath, 'utf8'); const content = await fs.readFile(this.manifestPath, 'utf8');
const yaml = require('js-yaml'); const yaml = require('yaml');
return yaml.parse(content) || {}; return yaml.parse(content) || {};
} }
@ -39,11 +39,10 @@ class CustomModuleCache {
* Update cache manifest * Update cache manifest
*/ */
async updateCacheManifest(manifest) { async updateCacheManifest(manifest) {
const yaml = require('js-yaml'); const yaml = require('yaml');
const content = yaml.dump(manifest, { const content = yaml.stringify(manifest, {
indent: 2, indent: 2,
lineWidth: -1, lineWidth: 0,
noRefs: true,
sortKeys: false, sortKeys: false,
}); });

View File

@ -2,7 +2,7 @@ const fs = require('fs-extra');
const path = require('node:path'); const path = require('node:path');
const glob = require('glob'); const glob = require('glob');
const chalk = require('chalk'); const chalk = require('chalk');
const yaml = require('js-yaml'); const yaml = require('yaml');
/** /**
* Dependency Resolver for BMAD modules * Dependency Resolver for BMAD modules
@ -147,7 +147,7 @@ class DependencyResolver {
// Quote values with backticks to make them valid YAML // Quote values with backticks to make them valid YAML
yamlContent = yamlContent.replaceAll(/: `([^`]+)`/g, ': "$1"'); yamlContent = yamlContent.replaceAll(/: `([^`]+)`/g, ': "$1"');
const frontmatter = yaml.load(yamlContent); const frontmatter = yaml.parse(yamlContent);
if (frontmatter.dependencies) { if (frontmatter.dependencies) {
const deps = Array.isArray(frontmatter.dependencies) ? frontmatter.dependencies : [frontmatter.dependencies]; const deps = Array.isArray(frontmatter.dependencies) ? frontmatter.dependencies : [frontmatter.dependencies];

View File

@ -1,6 +1,6 @@
const path = require('node:path'); const path = require('node:path');
const fs = require('fs-extra'); const fs = require('fs-extra');
const yaml = require('js-yaml'); const yaml = require('yaml');
const { Manifest } = require('./manifest'); const { Manifest } = require('./manifest');
class Detector { class Detector {
@ -237,7 +237,7 @@ class Detector {
return false; return false;
} }
try { try {
const yaml = require('js-yaml'); const yaml = require('yaml');
const manifestContent = await fs.readFile(manifestPath, 'utf8'); const manifestContent = await fs.readFile(manifestPath, 'utf8');
const manifest = yaml.parse(manifestContent); const manifest = yaml.parse(manifestContent);
// V6+ manifest has installation.version // V6+ manifest has installation.version

View File

@ -1,6 +1,6 @@
const path = require('node:path'); const path = require('node:path');
const fs = require('fs-extra'); const fs = require('fs-extra');
const yaml = require('js-yaml'); const yaml = require('yaml');
/** /**
* Manages IDE configuration persistence * Manages IDE configuration persistence
@ -61,10 +61,9 @@ class IdeConfigManager {
configuration: configuration || {}, configuration: configuration || {},
}; };
const yamlContent = yaml.dump(configData, { const yamlContent = yaml.stringify(configData, {
indent: 2, indent: 2,
lineWidth: -1, lineWidth: 0,
noRefs: true,
sortKeys: false, sortKeys: false,
}); });
@ -88,7 +87,7 @@ class IdeConfigManager {
try { try {
const content = await fs.readFile(configPath, 'utf8'); const content = await fs.readFile(configPath, 'utf8');
const config = yaml.load(content); const config = yaml.parse(content);
return config; return config;
} catch (error) { } catch (error) {
console.warn(`Warning: Failed to load IDE config for ${ideName}:`, error.message); console.warn(`Warning: Failed to load IDE config for ${ideName}:`, error.message);

View File

@ -18,6 +18,7 @@ const { CLIUtils } = require('../../../lib/cli-utils');
const { ManifestGenerator } = require('./manifest-generator'); const { ManifestGenerator } = require('./manifest-generator');
const { IdeConfigManager } = require('./ide-config-manager'); const { IdeConfigManager } = require('./ide-config-manager');
const { CustomHandler } = require('../custom/handler'); const { CustomHandler } = require('../custom/handler');
const { filterCustomizationData } = require('../../../lib/agent/compiler');
class Installer { class Installer {
constructor() { constructor() {
@ -1457,7 +1458,7 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
* @param {Object} moduleConfigs - Collected configuration values * @param {Object} moduleConfigs - Collected configuration values
*/ */
async generateModuleConfigs(bmadDir, moduleConfigs) { async generateModuleConfigs(bmadDir, moduleConfigs) {
const yaml = require('js-yaml'); const yaml = require('yaml');
// Extract core config values to share with other modules // Extract core config values to share with other modules
const coreConfig = moduleConfigs.core || {}; 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 // Convert config to YAML
let yamlContent = yaml.dump(finalConfig, { let yamlContent = yaml.stringify(finalConfig, {
indent: 2, indent: 2,
lineWidth: -1, lineWidth: 0,
noRefs: true, minContentWidth: 0,
sortKeys: false,
}); });
// If we have core values, reorganize the YAML to group them with their comment // 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) { if (customizeExists) {
const customizeContent = await fs.readFile(customizePath, 'utf8'); const customizeContent = await fs.readFile(customizePath, 'utf8');
const yaml = require('js-yaml'); const yaml = require('yaml');
const customizeYaml = yaml.parse(customizeContent); const customizeYaml = yaml.parse(customizeContent);
// Detect what fields are customized (similar to rebuildAgentFiles) // 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) { if (customizeExists) {
const customizeContent = await fs.readFile(customizePath, 'utf8'); const customizeContent = await fs.readFile(customizePath, 'utf8');
const yaml = require('js-yaml'); const yaml = require('yaml');
const customizeYaml = yaml.load(customizeContent); const customizeYaml = yaml.parse(customizeContent);
// Detect what fields are customized // Detect what fields are customized
if (customizeYaml) { if (customizeYaml) {
@ -2085,18 +2085,21 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
customizeData = yaml.parse(customizeContent); customizeData = yaml.parse(customizeContent);
} }
// Build agent answers from customize data // Build agent answers from customize data (filter empty values)
const answers = {}; const answers = {};
if (customizeData.persona) { if (customizeData.persona) {
Object.assign(answers, customizeData.persona); Object.assign(answers, filterCustomizationData(customizeData.persona));
} }
if (customizeData.agent?.metadata) { 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; answers.critical_actions = customizeData.critical_actions;
} }
if (customizeData.memories) { if (customizeData.memories && customizeData.memories.length > 0) {
answers.memories = customizeData.memories; answers.memories = customizeData.memories;
} }
@ -2153,8 +2156,8 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
let manifest = null; let manifest = null;
if (await fs.pathExists(manifestPath)) { if (await fs.pathExists(manifestPath)) {
const manifestContent = await fs.readFile(manifestPath, 'utf8'); const manifestContent = await fs.readFile(manifestPath, 'utf8');
const yaml = require('js-yaml'); const yaml = require('yaml');
manifest = yaml.load(manifestContent); manifest = yaml.parse(manifestContent);
installedModules = manifest.modules || []; installedModules = manifest.modules || [];
} }

View File

@ -1,6 +1,6 @@
const path = require('node:path'); const path = require('node:path');
const fs = require('fs-extra'); const fs = require('fs-extra');
const yaml = require('js-yaml'); const yaml = require('yaml');
const crypto = require('node:crypto'); const crypto = require('node:crypto');
const { getSourcePath, getModulePath } = require('../../../lib/project-root'); const { getSourcePath, getModulePath } = require('../../../lib/project-root');
@ -480,10 +480,9 @@ class ManifestGenerator {
ides: this.selectedIdes, ides: this.selectedIdes,
}; };
const yamlStr = yaml.dump(manifest, { const yamlStr = yaml.stringify(manifest, {
indent: 2, indent: 2,
lineWidth: -1, lineWidth: 0,
noRefs: true,
sortKeys: false, sortKeys: false,
}); });

View File

@ -11,7 +11,7 @@ class Manifest {
*/ */
async create(bmadDir, data, installedFiles = []) { async create(bmadDir, data, installedFiles = []) {
const manifestPath = path.join(bmadDir, '_cfg', 'manifest.yaml'); const manifestPath = path.join(bmadDir, '_cfg', 'manifest.yaml');
const yaml = require('js-yaml'); const yaml = require('yaml');
// Ensure _cfg directory exists // Ensure _cfg directory exists
await fs.ensureDir(path.dirname(manifestPath)); await fs.ensureDir(path.dirname(manifestPath));
@ -28,10 +28,9 @@ class Manifest {
}; };
// Write YAML manifest // Write YAML manifest
const yamlContent = yaml.dump(manifestData, { const yamlContent = yaml.stringify(manifestData, {
indent: 2, indent: 2,
lineWidth: -1, lineWidth: 0,
noRefs: true,
sortKeys: false, sortKeys: false,
}); });
@ -48,12 +47,12 @@ class Manifest {
*/ */
async read(bmadDir) { async read(bmadDir) {
const yamlPath = path.join(bmadDir, '_cfg', 'manifest.yaml'); const yamlPath = path.join(bmadDir, '_cfg', 'manifest.yaml');
const yaml = require('js-yaml'); const yaml = require('yaml');
if (await fs.pathExists(yamlPath)) { if (await fs.pathExists(yamlPath)) {
try { try {
const content = await fs.readFile(yamlPath, 'utf8'); 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 // Flatten the structure for compatibility with existing code
return { return {
@ -79,7 +78,7 @@ class Manifest {
* @param {Array} installedFiles - Updated list of installed files * @param {Array} installedFiles - Updated list of installed files
*/ */
async update(bmadDir, updates, installedFiles = null) { async update(bmadDir, updates, installedFiles = null) {
const yaml = require('js-yaml'); const yaml = require('yaml');
const manifest = (await this.read(bmadDir)) || {}; const manifest = (await this.read(bmadDir)) || {};
// Merge updates // Merge updates
@ -101,10 +100,9 @@ class Manifest {
const manifestPath = path.join(bmadDir, '_cfg', 'manifest.yaml'); const manifestPath = path.join(bmadDir, '_cfg', 'manifest.yaml');
await fs.ensureDir(path.dirname(manifestPath)); await fs.ensureDir(path.dirname(manifestPath));
const yamlContent = yaml.dump(manifestData, { const yamlContent = yaml.stringify(manifestData, {
indent: 2, indent: 2,
lineWidth: -1, lineWidth: 0,
noRefs: true,
sortKeys: false, sortKeys: false,
}); });
@ -526,9 +524,9 @@ class Manifest {
try { try {
if (await fs.pathExists(configPath)) { if (await fs.pathExists(configPath)) {
const yaml = require('js-yaml'); const yaml = require('yaml');
const content = await fs.readFile(configPath, 'utf8'); const content = await fs.readFile(configPath, 'utf8');
configs[moduleName] = yaml.load(content); configs[moduleName] = yaml.parse(content);
} }
} catch (error) { } catch (error) {
console.warn(`Could not load config for module ${moduleName}:`, error.message); console.warn(`Could not load config for module ${moduleName}:`, error.message);

View File

@ -1,7 +1,7 @@
const path = require('node:path'); const path = require('node:path');
const fs = require('fs-extra'); const fs = require('fs-extra');
const chalk = require('chalk'); const chalk = require('chalk');
const yaml = require('js-yaml'); const yaml = require('yaml');
const { FileOps } = require('../../../lib/file-ops'); const { FileOps } = require('../../../lib/file-ops');
const { XmlHandler } = require('../../../lib/xml-handler'); const { XmlHandler } = require('../../../lib/xml-handler');

View File

@ -346,7 +346,7 @@ class BaseIdeSetup {
} else if (entry.isFile() && entry.name === 'workflow.yaml') { } else if (entry.isFile() && entry.name === 'workflow.yaml') {
// Read workflow.yaml to get name and standalone property // Read workflow.yaml to get name and standalone property
try { try {
const yaml = require('js-yaml'); const yaml = require('yaml');
const content = await fs.readFile(fullPath, 'utf8'); const content = await fs.readFile(fullPath, 'utf8');
const workflowData = yaml.parse(content); const workflowData = yaml.parse(content);
@ -454,7 +454,7 @@ class BaseIdeSetup {
// Check for standalone: true in YAML frontmatter // Check for standalone: true in YAML frontmatter
const frontmatterMatch = content.match(/^---\s*\n([\s\S]*?)\n---/); const frontmatterMatch = content.match(/^---\s*\n([\s\S]*?)\n---/);
if (frontmatterMatch) { if (frontmatterMatch) {
const yaml = require('js-yaml'); const yaml = require('yaml');
try { try {
const frontmatter = yaml.parse(frontmatterMatch[1]); const frontmatter = yaml.parse(frontmatterMatch[1]);
standalone = frontmatter.standalone === true; standalone = frontmatter.standalone === true;

View File

@ -45,7 +45,7 @@ class AntigravitySetup extends BaseIdeSetup {
const injectionConfigPath = path.join(sourceModulesPath, moduleName, 'sub-modules', 'antigravity', 'injections.yaml'); const injectionConfigPath = path.join(sourceModulesPath, moduleName, 'sub-modules', 'antigravity', 'injections.yaml');
if (await this.exists(injectionConfigPath)) { if (await this.exists(injectionConfigPath)) {
const yaml = require('js-yaml'); const yaml = require('yaml');
try { try {
// Load injection configuration // Load injection configuration

View File

@ -44,7 +44,7 @@ class ClaudeCodeSetup extends BaseIdeSetup {
const injectionConfigPath = path.join(sourceModulesPath, moduleName, 'sub-modules', 'claude-code', 'injections.yaml'); const injectionConfigPath = path.join(sourceModulesPath, moduleName, 'sub-modules', 'claude-code', 'injections.yaml');
if (await this.exists(injectionConfigPath)) { if (await this.exists(injectionConfigPath)) {
const yaml = require('js-yaml'); const yaml = require('yaml');
try { try {
// Load injection configuration // Load injection configuration

View File

@ -1,6 +1,6 @@
const path = require('node:path'); const path = require('node:path');
const fs = require('fs-extra'); const fs = require('fs-extra');
const yaml = require('js-yaml'); const yaml = require('yaml');
const { BaseIdeSetup } = require('./_base-ide'); const { BaseIdeSetup } = require('./_base-ide');
const chalk = require('chalk'); const chalk = require('chalk');
const { AgentCommandGenerator } = require('./shared/agent-command-generator'); const { AgentCommandGenerator } = require('./shared/agent-command-generator');

View File

@ -2,7 +2,7 @@ const path = require('node:path');
const { BaseIdeSetup } = require('./_base-ide'); const { BaseIdeSetup } = require('./_base-ide');
const chalk = require('chalk'); const chalk = require('chalk');
const fs = require('fs-extra'); const fs = require('fs-extra');
const yaml = require('js-yaml'); const yaml = require('yaml');
/** /**
* Kiro CLI setup handler for BMad Method * Kiro CLI setup handler for BMad Method

View File

@ -2,7 +2,7 @@ const path = require('node:path');
const fs = require('fs-extra'); const fs = require('fs-extra');
const os = require('node:os'); const os = require('node:os');
const chalk = require('chalk'); const chalk = require('chalk');
const yaml = require('js-yaml'); const yaml = require('yaml');
const { BaseIdeSetup } = require('./_base-ide'); const { BaseIdeSetup } = require('./_base-ide');
const { WorkflowCommandGenerator } = require('./shared/workflow-command-generator'); const { WorkflowCommandGenerator } = require('./shared/workflow-command-generator');
const { TaskToolCommandGenerator } = require('./shared/task-tool-command-generator'); const { TaskToolCommandGenerator } = require('./shared/task-tool-command-generator');

View File

@ -1,6 +1,6 @@
const path = require('node:path'); const path = require('node:path');
const fs = require('fs-extra'); const fs = require('fs-extra');
const yaml = require('js-yaml'); const yaml = require('yaml');
const { glob } = require('glob'); const { glob } = require('glob');
const { getSourcePath } = require('../../../../lib/project-root'); const { getSourcePath } = require('../../../../lib/project-root');

View File

@ -1,9 +1,10 @@
const path = require('node:path'); const path = require('node:path');
const fs = require('fs-extra'); const fs = require('fs-extra');
const yaml = require('js-yaml'); const yaml = require('yaml');
const chalk = require('chalk'); const chalk = require('chalk');
const { XmlHandler } = require('../../../lib/xml-handler'); const { XmlHandler } = require('../../../lib/xml-handler');
const { getProjectRoot, getSourcePath, getModulePath } = require('../../../lib/project-root'); const { getProjectRoot, getSourcePath, getModulePath } = require('../../../lib/project-root');
const { filterCustomizationData } = require('../../../lib/agent/compiler');
/** /**
* Manages the installation, updating, and removal of BMAD modules. * Manages the installation, updating, and removal of BMAD modules.
@ -12,7 +13,7 @@ const { getProjectRoot, getSourcePath, getModulePath } = require('../../../lib/p
* *
* @class ModuleManager * @class ModuleManager
* @requires fs-extra * @requires fs-extra
* @requires js-yaml * @requires yaml
* @requires chalk * @requires chalk
* @requires XmlHandler * @requires XmlHandler
* *
@ -312,7 +313,7 @@ class ModuleManager {
// Read module config for metadata // Read module config for metadata
try { try {
const configContent = await fs.readFile(configPath, 'utf8'); 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 // Use the code property as the id if available
if (config.code) { if (config.code) {
@ -387,7 +388,7 @@ class ModuleManager {
if (configPath) { if (configPath) {
try { try {
const configContent = await fs.readFile(configPath, 'utf8'); const configContent = await fs.readFile(configPath, 'utf8');
const config = yaml.load(configContent); const config = yaml.parse(configContent);
if (config.code === moduleName) { if (config.code === moduleName) {
return modulePath; return modulePath;
} }
@ -427,14 +428,14 @@ class ModuleManager {
if (await fs.pathExists(rootCustomConfigPath)) { if (await fs.pathExists(rootCustomConfigPath)) {
try { try {
const customContent = await fs.readFile(rootCustomConfigPath, 'utf8'); const customContent = await fs.readFile(rootCustomConfigPath, 'utf8');
customConfig = yaml.load(customContent); customConfig = yaml.parse(customContent);
} catch (error) { } catch (error) {
console.warn(chalk.yellow(`Warning: Failed to read custom.yaml for ${moduleName}:`, error.message)); console.warn(chalk.yellow(`Warning: Failed to read custom.yaml for ${moduleName}:`, error.message));
} }
} else if (await fs.pathExists(moduleInstallerCustomPath)) { } else if (await fs.pathExists(moduleInstallerCustomPath)) {
try { try {
const customContent = await fs.readFile(moduleInstallerCustomPath, 'utf8'); const customContent = await fs.readFile(moduleInstallerCustomPath, 'utf8');
customConfig = yaml.load(customContent); customConfig = yaml.parse(customContent);
} catch (error) { } catch (error) {
console.warn(chalk.yellow(`Warning: Failed to read custom.yaml for ${moduleName}:`, error.message)); 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)) { if (await fs.pathExists(configPath)) {
try { try {
const configContent = await fs.readFile(configPath, 'utf8'); const configContent = await fs.readFile(configPath, 'utf8');
const config = yaml.load(configContent); const config = yaml.parse(configContent);
Object.assign(moduleInfo, config); Object.assign(moduleInfo, config);
} catch (error) { } catch (error) {
console.warn(`Failed to read installed module config:`, error.message); console.warn(`Failed to read installed module config:`, error.message);
@ -700,7 +701,7 @@ class ModuleManager {
try { try {
// First check if web_bundle exists by parsing // First check if web_bundle exists by parsing
const workflowConfig = yaml.load(yamlContent); const workflowConfig = yaml.parse(yamlContent);
if (workflowConfig.web_bundle === undefined) { if (workflowConfig.web_bundle === undefined) {
// No web_bundle section, just write (placeholders already replaced above) // No web_bundle section, just write (placeholders already replaced above)
@ -827,20 +828,23 @@ class ModuleManager {
let answers = {}; let answers = {};
if (await fs.pathExists(customizePath)) { if (await fs.pathExists(customizePath)) {
const customizeContent = await fs.readFile(customizePath, 'utf8'); const customizeContent = await fs.readFile(customizePath, 'utf8');
const customizeData = yaml.load(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) {
Object.assign(answers, customizeData.persona); Object.assign(answers, filterCustomizationData(customizeData.persona));
} }
if (customizeData.agent?.metadata) { 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; answers.critical_actions = customizeData.critical_actions;
} }
if (customizeData.memories) { if (customizeData.memories && customizeData.memories.length > 0) {
answers.memories = customizeData.memories; answers.memories = customizeData.memories;
} }
} }
@ -852,7 +856,7 @@ class ModuleManager {
if (await fs.pathExists(coreConfigPath)) { if (await fs.pathExists(coreConfigPath)) {
const yaml = require('yaml'); const yaml = require('yaml');
const coreConfigContent = await fs.readFile(coreConfigPath, 'utf8'); const coreConfigContent = await fs.readFile(coreConfigPath, 'utf8');
coreConfig = yaml.load(coreConfigContent); coreConfig = yaml.parse(coreConfigContent);
} }
// Check if agent has sidecar // Check if agent has sidecar
@ -1017,7 +1021,7 @@ class ModuleManager {
for (const agentFile of yamlFiles) { for (const agentFile of yamlFiles) {
const agentPath = path.join(sourceAgentsPath, agentFile); 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 // Check if agent has menu items with workflow-install
const menuItems = agentYaml?.agent?.menu || []; const menuItems = agentYaml?.agent?.menu || [];

View File

@ -1,4 +1,4 @@
const yaml = require('js-yaml'); const yaml = require('yaml');
const fs = require('fs-extra'); const fs = require('fs-extra');
/** /**
@ -91,7 +91,7 @@ class AgentAnalyzer {
*/ */
async analyzeAgentFile(filePath) { async analyzeAgentFile(filePath) {
const content = await fs.readFile(filePath, 'utf8'); const content = await fs.readFile(filePath, 'utf8');
const agentYaml = yaml.load(content); const agentYaml = yaml.parse(content);
return this.analyzeAgentObject(agentYaml); return this.analyzeAgentObject(agentYaml);
} }

View File

@ -313,7 +313,11 @@ async function compileAgent(yamlContent, answers = {}, agentName = '', targetPat
// Apply customization merges before template processing // Apply customization merges before template processing
// Handle metadata overrides (like name) // Handle metadata overrides (like name)
if (answers.metadata) { 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 // Remove from answers so it doesn't get processed as template variables
const { metadata, ...templateAnswers } = answers; const { metadata, ...templateAnswers } = answers;
answers = templateAnswers; 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 * Process TTS injection markers in content
* @param {string} content - Content to process * @param {string} content - Content to process
@ -431,4 +465,5 @@ module.exports = {
buildPersonaXml, buildPersonaXml,
buildPromptsXml, buildPromptsXml,
buildMenuXml, buildMenuXml,
filterCustomizationData,
}; };

View File

@ -1,5 +1,5 @@
const fs = require('fs-extra'); const fs = require('fs-extra');
const yaml = require('js-yaml'); const yaml = require('yaml');
const path = require('node:path'); const path = require('node:path');
const packageJson = require('../../../package.json'); const packageJson = require('../../../package.json');
@ -18,7 +18,7 @@ class Config {
} }
const content = await fs.readFile(configPath, 'utf8'); const content = await fs.readFile(configPath, 'utf8');
return yaml.load(content); return yaml.parse(content);
} }
/** /**

View File

@ -1,6 +1,6 @@
const fs = require('fs-extra'); const fs = require('fs-extra');
const path = require('node:path'); const path = require('node:path');
const yaml = require('js-yaml'); const yaml = require('yaml');
const { getProjectRoot } = require('./project-root'); const { getProjectRoot } = require('./project-root');
/** /**
@ -20,7 +20,7 @@ class PlatformCodes {
try { try {
if (fs.existsSync(this.configPath)) { if (fs.existsSync(this.configPath)) {
const content = fs.readFileSync(this.configPath, 'utf8'); const content = fs.readFileSync(this.configPath, 'utf8');
this.config = yaml.load(content); this.config = yaml.parse(content);
} else { } else {
console.warn(`Platform codes config not found at ${this.configPath}`); console.warn(`Platform codes config not found at ${this.configPath}`);
this.config = { platforms: {} }; this.config = { platforms: {} };

View File

@ -1,6 +1,6 @@
const fs = require('node:fs'); const fs = require('node:fs');
const path = require('node:path'); const path = require('node:path');
const yaml = require('js-yaml'); const yaml = require('yaml');
const { execSync } = require('node:child_process'); const { execSync } = require('node:child_process');
// Dynamic import for ES module // Dynamic import for ES module
@ -57,11 +57,10 @@ async function formatYamlContent(content, filename) {
} }
// Parse and re-dump YAML to format it // Parse and re-dump YAML to format it
const parsed = yaml.load(fixedContent); const parsed = yaml.parse(fixedContent);
const formatted = yaml.dump(parsed, { const formatted = yaml.stringify(parsed, {
indent: 2, indent: 2,
lineWidth: -1, // Disable line wrapping lineWidth: 0, // Disable line wrapping
noRefs: true,
sortKeys: false, // Preserve key order sortKeys: false, // Preserve key order
}); });
// Ensure POSIX-compliant final newline // Ensure POSIX-compliant final newline
@ -96,7 +95,6 @@ async function processMarkdownFile(filePath) {
const [fullMatch, yamlContent] = match; const [fullMatch, yamlContent] = match;
const formatted = await formatYamlContent(yamlContent, filePath); const formatted = await formatYamlContent(yamlContent, filePath);
if (formatted !== null) { if (formatted !== null) {
// Remove trailing newline that js-yaml adds
const trimmedFormatted = formatted.replace(/\n$/, ''); const trimmedFormatted = formatted.replace(/\n$/, '');
if (trimmedFormatted !== yamlContent) { if (trimmedFormatted !== yamlContent) {

View File

@ -1,4 +1,4 @@
const yaml = require('js-yaml'); const yaml = require('yaml');
const fs = require('fs-extra'); const fs = require('fs-extra');
const path = require('node:path'); const path = require('node:path');
const crypto = require('node:crypto'); const crypto = require('node:crypto');
@ -64,13 +64,13 @@ class YamlXmlBuilder {
async loadAndMergeAgent(agentYamlPath, customizeYamlPath = null) { async loadAndMergeAgent(agentYamlPath, customizeYamlPath = null) {
// Load base agent // Load base agent
const agentContent = await fs.readFile(agentYamlPath, 'utf8'); const agentContent = await fs.readFile(agentYamlPath, 'utf8');
const agentYaml = yaml.load(agentContent); const agentYaml = yaml.parse(agentContent);
// Load customization if exists // Load customization if exists
let merged = agentYaml; let merged = agentYaml;
if (customizeYamlPath && (await fs.pathExists(customizeYamlPath))) { if (customizeYamlPath && (await fs.pathExists(customizeYamlPath))) {
const customizeContent = await fs.readFile(customizeYamlPath, 'utf8'); const customizeContent = await fs.readFile(customizeYamlPath, 'utf8');
const customizeYaml = yaml.load(customizeContent); const customizeYaml = yaml.parse(customizeContent);
if (customizeYaml) { if (customizeYaml) {
// Special handling: persona fields are merged, but only non-empty values override // Special handling: persona fields are merged, but only non-empty values override

View File

@ -12,7 +12,7 @@
*/ */
const { glob } = require('glob'); const { glob } = require('glob');
const yaml = require('js-yaml'); const yaml = require('yaml');
const fs = require('node:fs'); const fs = require('node:fs');
const path = require('node:path'); const path = require('node:path');
const { validateAgentFile } = require('./schema/agent.js'); const { validateAgentFile } = require('./schema/agent.js');
@ -49,7 +49,7 @@ async function main(customProjectRoot) {
try { try {
const fileContent = fs.readFileSync(filePath, 'utf8'); 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 // Convert absolute path to relative src/ path for module detection
const srcRelativePath = relativePath.startsWith('src/') ? relativePath : path.relative(project_root, filePath).replaceAll('\\', '/'); const srcRelativePath = relativePath.startsWith('src/') ? relativePath : path.relative(project_root, filePath).replaceAll('\\', '/');