UNPKG

jay-code

Version:

Streamlined AI CLI orchestration engine with mathematical rigor and enterprise-grade reliability

288 lines (251 loc) 7.86 kB
#!/usr/bin/env deno run --allow-read /** * Example Configuration Validator * Validates all example configuration files for correctness */ import { walk } from "https://deno.land/std@0.220.0/fs/mod.ts"; interface ValidationResult { file: string; valid: boolean; errors: string[]; } interface ConfigSchema { [key: string]: { type: string; required?: boolean; properties?: ConfigSchema; }; } const JAY_CODE_CONFIG_SCHEMA: ConfigSchema = { orchestrator: { type: 'object', required: true, properties: { maxConcurrentAgents: { type: 'number' }, taskQueueSize: { type: 'number' }, healthCheckInterval: { type: 'number' }, shutdownTimeout: { type: 'number' }, }, }, terminal: { type: 'object', properties: { type: { type: 'string' }, poolSize: { type: 'number' }, recycleAfter: { type: 'number' }, healthCheckInterval: { type: 'number' }, commandTimeout: { type: 'number' }, }, }, memory: { type: 'object', properties: { backend: { type: 'string' }, cacheSizeMB: { type: 'number' }, syncInterval: { type: 'number' }, conflictResolution: { type: 'string' }, retentionDays: { type: 'number' }, }, }, coordination: { type: 'object', properties: { maxRetries: { type: 'number' }, retryDelay: { type: 'number' }, deadlockDetection: { type: 'boolean' }, resourceTimeout: { type: 'number' }, messageTimeout: { type: 'number' }, }, }, mcp: { type: 'object', properties: { transport: { type: 'string' }, port: { type: 'number' }, tlsEnabled: { type: 'boolean' }, }, }, logging: { type: 'object', properties: { level: { type: 'string' }, format: { type: 'string' }, destination: { type: 'string' }, }, }, }; const WORKFLOW_SCHEMA: ConfigSchema = { name: { type: 'string', required: true }, description: { type: 'string' }, tasks: { type: 'array', required: true, properties: { id: { type: 'string', required: true }, type: { type: 'string', required: true }, description: { type: 'string', required: true }, dependencies: { type: 'array' }, assignTo: { type: 'string' }, priority: { type: 'string' }, timeout: { type: 'number' }, }, }, }; function validateType(value: any, expectedType: string): boolean { switch (expectedType) { case 'string': return typeof value === 'string'; case 'number': return typeof value === 'number'; case 'boolean': return typeof value === 'boolean'; case 'array': return Array.isArray(value); case 'object': return typeof value === 'object' && value !== null && !Array.isArray(value); default: return false; } } function validateObject(obj: any, schema: ConfigSchema, path = ''): string[] { const errors: string[] = []; // Check required fields for (const [key, spec] of Object.entries(schema)) { if (spec.required && !(key in obj)) { errors.push(`${path}${key} is required but missing`); continue; } if (key in obj) { const value = obj[key]; const currentPath = path ? `${path}${key}.` : `${key}.`; if (!validateType(value, spec.type)) { errors.push(`${path}${key} should be of type ${spec.type}, got ${typeof value}`); continue; } // Validate nested objects if (spec.type === 'object' && spec.properties) { errors.push(...validateObject(value, spec.properties, currentPath)); } // Validate array items if (spec.type === 'array' && spec.properties && Array.isArray(value)) { value.forEach((item, index) => { if (typeof item === 'object') { errors.push(...validateObject(item, spec.properties!, `${currentPath}[${index}].`)); } }); } } } return errors; } function validateClaudeFlowConfig(config: any): string[] { return validateObject(config, JAY_CODE_CONFIG_SCHEMA); } function validateWorkflow(workflow: any): string[] { const errors = validateObject(workflow, WORKFLOW_SCHEMA); // Additional workflow-specific validations if (workflow.tasks && Array.isArray(workflow.tasks)) { const taskIds = new Set<string>(); for (const [index, task] of workflow.tasks.entries()) { // Check for duplicate task IDs if (taskIds.has(task.id)) { errors.push(`Duplicate task ID "${task.id}" found at index ${index}`); } else { taskIds.add(task.id); } // Validate dependencies reference existing tasks if (task.dependencies && Array.isArray(task.dependencies)) { for (const dep of task.dependencies) { if (!taskIds.has(dep) && !workflow.tasks.slice(0, index).some((t: any) => t.id === dep)) { errors.push(`Task "${task.id}" depends on non-existent task "${dep}"`); } } } // Validate priority values if (task.priority && !['low', 'medium', 'high', 'critical'].includes(task.priority)) { errors.push(`Task "${task.id}" has invalid priority "${task.priority}"`); } // Validate timeout is positive if (task.timeout && task.timeout <= 0) { errors.push(`Task "${task.id}" has invalid timeout ${task.timeout}`); } } } return errors; } async function validateFile(filePath: string): Promise<ValidationResult> { const result: ValidationResult = { file: filePath, valid: false, errors: [], }; try { const content = await Deno.readTextFile(filePath); const config = JSON.parse(content); // Determine validation type based on file name/content if (filePath.includes('workflow') || config.tasks) { result.errors = validateWorkflow(config); } else if (filePath.includes('config') || config.orchestrator) { result.errors = validateClaudeFlowConfig(config); } else { result.errors.push('Unknown configuration file type'); } result.valid = result.errors.length === 0; } catch (error) { if (error instanceof SyntaxError) { result.errors.push(`Invalid JSON: ${error.message}`); } else { result.errors.push(`Failed to read file: ${error.message}`); } } return result; } async function main(): Promise<void> { console.log('Validating example configurations...\n'); const results: ValidationResult[] = []; // Find all JSON files in examples directory for await (const entry of walk('./examples', { exts: ['.json'] })) { if (entry.isFile) { const result = await validateFile(entry.path); results.push(result); } } // Also check any config files in the root const rootConfigFiles = ['jay-code.config.json', 'config.json']; for (const filename of rootConfigFiles) { try { await Deno.stat(filename); const result = await validateFile(filename); results.push(result); } catch { // File doesn't exist, skip } } if (results.length === 0) { console.log('No configuration files found to validate.'); return; } // Report results let hasErrors = false; for (const result of results) { if (result.valid) { console.log(`✅ ${result.file}: Valid`); } else { console.log(`❌ ${result.file}: Invalid`); for (const error of result.errors) { console.log(` - ${error}`); } hasErrors = true; } } console.log(`\nValidated ${results.length} configuration files.`); if (hasErrors) { console.error('❌ Some configuration files have errors!'); Deno.exit(1); } else { console.log('✅ All configuration files are valid!'); } } if (import.meta.main) { await main(); }