UNPKG

vibe-coder-mcp

Version:

Production-ready MCP server with complete agent integration, multi-transport support, and comprehensive development automation tools for AI-assisted workflows.

148 lines (147 loc) 5.73 kB
import { z } from 'zod'; import fs from 'fs-extra'; import path from 'path'; export class ConfigValidator { static instance = null; envSchema = z.object({ OPENROUTER_API_KEY: z.string().min(1, 'API key is required'), OPENROUTER_BASE_URL: z.string().url().optional().default('https://openrouter.ai/api/v1'), VIBE_TASK_MANAGER_READ_DIR: z.string().optional(), VIBE_CODER_OUTPUT_DIR: z.string().optional(), VIBE_TASK_MANAGER_SECURITY_MODE: z.enum(['strict', 'permissive']).optional().default('strict'), CODE_MAP_ALLOWED_DIR: z.string().optional(), GEMINI_MODEL: z.string().optional().default('google/gemini-2.5-flash-preview-05-20'), PERPLEXITY_MODEL: z.string().optional().default('perplexity/sonar') }); llmConfigSchema = z.object({ llm_mapping: z.record(z.string()).refine((mapping) => mapping['default_generation'] !== undefined, { message: 'default_generation mapping is required' }) }); static getInstance() { if (!ConfigValidator.instance) { ConfigValidator.instance = new ConfigValidator(); } return ConfigValidator.instance; } async validateEnvFile(envPath) { const result = { valid: true, errors: [], warnings: [], suggestions: [] }; try { const envContent = await fs.readFile(envPath, 'utf-8'); const envVars = {}; envContent.split('\n').forEach(line => { const trimmed = line.trim(); if (trimmed && !trimmed.startsWith('#')) { const [key, ...valueParts] = trimmed.split('='); if (key) { envVars[key.trim()] = valueParts.join('=').trim(); } } }); const parseResult = this.envSchema.safeParse(envVars); if (!parseResult.success) { result.valid = false; parseResult.error.errors.forEach(err => { result.errors.push(`${err.path.join('.')}: ${err.message}`); if (err.path[0] === 'OPENROUTER_API_KEY') { result.suggestions.push('Get your API key at https://openrouter.ai/'); } }); } if (!envVars.VIBE_CODER_OUTPUT_DIR) { result.warnings.push('VIBE_CODER_OUTPUT_DIR not set, using ./VibeCoderOutput'); } } catch (error) { result.valid = false; result.errors.push(`Failed to read env file: ${error}`); } return result; } async validateLLMConfig(config) { const result = { valid: true, errors: [], warnings: [], suggestions: [] }; const parseResult = this.llmConfigSchema.safeParse(config); if (!parseResult.success) { result.valid = false; parseResult.error.errors.forEach(err => { result.errors.push(err.message); }); result.suggestions.push('Ensure llm_config.json has a default_generation mapping'); } else { const recommended = [ 'task_decomposition', 'intent_recognition', 'research_query' ]; const mappings = parseResult.data.llm_mapping; recommended.forEach(key => { if (!mappings[key]) { result.warnings.push(`Missing recommended mapping: ${key}`); result.suggestions.push(`Add ${key} mapping for better performance`); } }); } return result; } async detectMissingConfigs() { const missing = []; const requiredConfigs = [ { file: '.env', required: true, description: 'Environment variables including API key', defaultPath: path.join(process.cwd(), '.env') }, { file: 'llm_config.json', required: true, description: 'LLM model mappings for different operations', defaultPath: path.join(process.cwd(), 'llm_config.json') }, { file: 'mcp-config.json', required: false, description: 'MCP tool configurations', defaultPath: path.join(process.cwd(), 'mcp-config.json') } ]; for (const config of requiredConfigs) { const exists = await fs.pathExists(config.defaultPath); if (!exists) { missing.push(config); } } return missing; } suggestFixes(issues) { const fixes = []; issues.forEach(issue => { if (issue.suggestedFix) { fixes.push(issue.suggestedFix); } else { switch (issue.field) { case 'OPENROUTER_API_KEY': fixes.push('1. Visit https://openrouter.ai/ to get an API key'); fixes.push('2. Add OPENROUTER_API_KEY=your_key to .env file'); break; case 'llm_mapping.default_generation': fixes.push('Add "default_generation": "google/gemini-2.5-flash-preview-05-20" to llm_config.json'); break; default: fixes.push(`Check ${issue.field} configuration`); } } }); return [...new Set(fixes)]; } }