vibe-coder-mcp
Version:
Production-ready MCP server with complete agent integration, multi-transport support, and comprehensive development automation tools for AI-assisted workflows.
240 lines (239 loc) • 10.6 kB
JavaScript
import logger from '../../../logger.js';
import fs from 'fs/promises';
export class ConfigValidator {
static instance;
constructor() { }
static getInstance() {
if (!ConfigValidator.instance) {
ConfigValidator.instance = new ConfigValidator();
}
return ConfigValidator.instance;
}
async validateConfig(config) {
const errors = [];
const warnings = [];
const suggestions = [];
try {
logger.debug('Starting comprehensive configuration validation');
const llmValidation = this.validateLLMConfig(config.llm);
errors.push(...llmValidation.errors);
warnings.push(...llmValidation.warnings);
const mcpValidation = this.validateMCPConfig(config.mcp);
errors.push(...mcpValidation.errors);
warnings.push(...mcpValidation.warnings);
const taskManagerValidation = this.validateTaskManagerConfig(config.taskManager);
errors.push(...taskManagerValidation.errors);
warnings.push(...taskManagerValidation.warnings);
suggestions.push(...taskManagerValidation.suggestions);
const performanceValidation = this.validatePerformanceConfig(config.taskManager.performance);
errors.push(...performanceValidation.errors);
warnings.push(...performanceValidation.warnings);
const crossValidation = this.validateCrossConfigDependencies(config);
errors.push(...crossValidation.errors);
warnings.push(...crossValidation.warnings);
const isValid = errors.length === 0;
if (isValid) {
logger.info('Configuration validation completed successfully');
}
else {
logger.warn({ errors, warnings }, 'Configuration validation found issues');
}
return {
isValid,
errors,
warnings,
suggestions,
validatedConfig: isValid ? config : undefined
};
}
catch (error) {
logger.error({ error }, 'Configuration validation failed');
return {
isValid: false,
errors: [`Configuration validation error: ${error instanceof Error ? error.message : 'Unknown error'}`],
warnings,
suggestions
};
}
}
validateEnvironmentVariables() {
const required = [
'OPENROUTER_API_KEY',
'VIBE_CODER_OUTPUT_DIR'
];
const missing = [];
const invalid = [];
const warnings = [];
for (const envVar of required) {
if (!process.env[envVar]) {
missing.push(envVar);
}
}
if (process.env.VIBE_SECURITY_PERFORMANCE_THRESHOLD) {
const threshold = parseInt(process.env.VIBE_SECURITY_PERFORMANCE_THRESHOLD, 10);
if (isNaN(threshold) || threshold < 10 || threshold > 10000) {
invalid.push('VIBE_SECURITY_PERFORMANCE_THRESHOLD must be a number between 10 and 10000');
}
}
if (process.env.VIBE_TASK_MANAGER_SECURITY_MODE) {
const mode = process.env.VIBE_TASK_MANAGER_SECURITY_MODE;
if (!['strict', 'permissive'].includes(mode)) {
invalid.push('VIBE_TASK_MANAGER_SECURITY_MODE must be either "strict" or "permissive"');
}
}
const deprecated = [
'VIBE_TASK_MANAGER_CONFIG_PATH',
'VIBE_LEGACY_MODE'
];
for (const envVar of deprecated) {
if (process.env[envVar]) {
warnings.push(`Environment variable ${envVar} is deprecated and will be ignored`);
}
}
const isValid = missing.length === 0 && invalid.length === 0;
return {
isValid,
missing,
invalid,
warnings
};
}
async validateSecurityConfig(config) {
const errors = [];
const warnings = [];
const suggestions = [];
try {
try {
await fs.access(config.allowedReadDirectory, fs.constants.R_OK);
}
catch {
errors.push(`Read directory not accessible: ${config.allowedReadDirectory}`);
}
try {
await fs.access(config.allowedWriteDirectory, fs.constants.W_OK);
}
catch {
try {
await fs.mkdir(config.allowedWriteDirectory, { recursive: true });
suggestions.push(`Created write directory: ${config.allowedWriteDirectory}`);
}
catch {
errors.push(`Write directory not accessible and cannot be created: ${config.allowedWriteDirectory}`);
}
}
if (!['strict', 'permissive'].includes(config.securityMode)) {
errors.push(`Invalid security mode: ${config.securityMode}. Must be 'strict' or 'permissive'`);
}
if (config.securityMode === 'permissive') {
warnings.push('Security mode is set to permissive. Consider using strict mode for production');
}
if (config.allowedReadDirectory === '/' || config.allowedWriteDirectory === '/') {
errors.push('Root directory access is not allowed for security reasons');
}
if (config.allowedReadDirectory.includes('..') || config.allowedWriteDirectory.includes('..')) {
errors.push('Directory paths cannot contain ".." for security reasons');
}
}
catch (error) {
errors.push(`Security configuration validation error: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
return {
isValid: errors.length === 0,
errors,
warnings,
suggestions
};
}
validateLLMConfig(config) {
const errors = [];
const warnings = [];
if (!config) {
errors.push('LLM configuration is required');
return { errors, warnings };
}
const llmConfig = config;
if (!llmConfig.apiKey) {
errors.push('LLM API key is required');
}
if (!llmConfig.baseURL) {
warnings.push('LLM base URL not specified, using default');
}
if (llmConfig.timeout && (typeof llmConfig.timeout === 'number' && (llmConfig.timeout < 1000 || llmConfig.timeout > 300000))) {
warnings.push('LLM timeout should be between 1 second and 5 minutes');
}
return { errors, warnings };
}
validateMCPConfig(config) {
const errors = [];
const warnings = [];
if (!config) {
errors.push('MCP configuration is required');
return { errors, warnings };
}
const mcpConfig = config;
if (mcpConfig.transport && typeof mcpConfig.transport === 'string' && !['stdio', 'sse', 'websocket', 'http'].includes(mcpConfig.transport)) {
errors.push(`Invalid MCP transport: ${mcpConfig.transport}`);
}
return { errors, warnings };
}
validateTaskManagerConfig(config) {
const errors = [];
const warnings = [];
const suggestions = [];
if (!config) {
errors.push('Task Manager configuration is required');
return { errors, warnings, suggestions };
}
const taskConfig = config;
if (taskConfig.maxConcurrentTasks && typeof taskConfig.maxConcurrentTasks === 'number' && (taskConfig.maxConcurrentTasks < 1 || taskConfig.maxConcurrentTasks > 100)) {
errors.push('maxConcurrentTasks must be between 1 and 100');
}
const performanceTargets = taskConfig.performanceTargets;
if (performanceTargets?.maxResponseTime && typeof performanceTargets.maxResponseTime === 'number' && performanceTargets.maxResponseTime > 1000) {
warnings.push('Response time target above 1 second may impact user experience');
}
const agentSettings = taskConfig.agentSettings;
if (agentSettings?.maxAgents && typeof agentSettings.maxAgents === 'number' && agentSettings.maxAgents > 50) {
warnings.push('High number of agents may impact performance');
}
const validStrategies = ['round_robin', 'least_loaded', 'capability_based', 'priority_based'];
if (agentSettings?.coordinationStrategy && typeof agentSettings.coordinationStrategy === 'string' && !validStrategies.includes(agentSettings.coordinationStrategy)) {
errors.push(`Invalid coordination strategy: ${agentSettings.coordinationStrategy}`);
}
return { errors, warnings, suggestions };
}
validatePerformanceConfig(config) {
const errors = [];
const warnings = [];
if (!config) {
warnings.push('Performance configuration not specified, using defaults');
return { errors, warnings };
}
const perfConfig = config;
const memoryManagement = perfConfig.memoryManagement;
if (memoryManagement?.maxMemoryPercentage &&
typeof memoryManagement.maxMemoryPercentage === 'number' &&
(memoryManagement.maxMemoryPercentage < 10 || memoryManagement.maxMemoryPercentage > 90)) {
errors.push('Memory percentage must be between 10% and 90%');
}
const caching = perfConfig.caching;
if (caching?.maxCacheSize && typeof caching.maxCacheSize === 'number' && caching.maxCacheSize < 1024 * 1024) {
warnings.push('Cache size below 1MB may not be effective');
}
return { errors, warnings };
}
validateCrossConfigDependencies(config) {
const errors = [];
const warnings = [];
const maxConcurrent = config.taskManager.maxConcurrentTasks;
const responseTarget = config.taskManager.performanceTargets.maxResponseTime;
if (maxConcurrent > 10 && responseTarget < 100) {
warnings.push('High concurrency with low response time target may be difficult to achieve');
}
const maxAgents = config.taskManager.agentSettings.maxAgents;
if (maxAgents > maxConcurrent * 2) {
warnings.push('Number of agents significantly exceeds concurrent tasks, may waste resources');
}
return { errors, warnings };
}
}