UNPKG

cmte

Version:

Design by Committee™ except it's just you and LLMs

103 lines (93 loc) 3.13 kB
import yaml from 'js-yaml'; import { readFile, fileExists } from "../utils/fs.js"; import { logger } from "../utils/logger.js"; /** * Validates the configuration object * @param config Configuration object * @throws Error if validation fails */ function validateConfig(config) { // Check required top-level properties const requiredProps = ['project', 'directives', 'services', 'ai', 'process']; for (const prop of requiredProps) { if (!config[prop]) { throw new Error(`Missing required configuration property: ${prop}`); } } // Check project configuration if (!config.project.name) { throw new Error('Project name is required'); } if (!config.project.outputDirectory) { throw new Error('Project output directory is required'); } // Check directives if (!Array.isArray(config.directives) || config.directives.length === 0) { throw new Error('At least one directive type must be defined'); } // Check services if (!Array.isArray(config.services) || config.services.length === 0) { throw new Error('At least one service must be defined'); } // Check AI configuration if (!config.ai.provider) { throw new Error('AI provider is required'); } if (!config.ai.defaultModel) { throw new Error('Default AI model is required'); } // Check process flows if (!Array.isArray(config.process.flows) || config.process.flows.length === 0) { throw new Error('At least one process flow must be defined'); } // Validate each flow has phases for (const flow of config.process.flows) { if (!flow.name) { throw new Error('All flows must have a name'); } if (!Array.isArray(flow.phases) || flow.phases.length === 0) { throw new Error(`Flow "${flow.name}" must have at least one phase`); } } logger.debug('Configuration validation passed'); } /** * Loads and validates the configuration from a YAML file * @param configPath Path to the configuration file * @returns Validated configuration object */ export async function loadConfig(configPath) { logger.info(`Loading configuration from ${configPath}`); // Check if the file exists if (!(await fileExists(configPath))) { throw new Error(`Configuration file not found: ${configPath}`); } try { // Read the YAML file const yamlContent = await readFile(configPath); // Parse YAML const config = yaml.load(yamlContent); // Validate the configuration validateConfig(config); logger.info('Configuration loaded successfully'); return config; } catch (error) { if (error instanceof yaml.YAMLException) { logger.error('Invalid YAML format', { error }); throw new Error(`Invalid YAML format in ${configPath}: ${error.message}`); } else if (error instanceof Error) { logger.error('Failed to load configuration', { error }); throw error; } else { // For any other unknown error types logger.error('Unknown error loading configuration', { error }); throw new Error(`Unknown error loading configuration: ${String(error)}`); } } }