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.

300 lines (299 loc) 12.5 kB
import path from 'path'; import { readFile } from 'fs/promises'; import { pathExists } from 'fs-extra'; import logger from '../../../logger.js'; import { getProjectRoot } from '../../code-map-generator/utils/pathUtils.enhanced.js'; import { contextCuratorConfigSchema, validateContextCuratorConfig } from '../types/context-curator.js'; export class ContextCuratorConfigLoader { static instance = null; config = null; llmConfig = null; configLoaded = false; lastLoadTime = 0; cacheTTL = 300000; llmConfigPath; contextCuratorConfigPath; constructor() { const projectRoot = getProjectRoot(); this.llmConfigPath = path.join(projectRoot, 'llm_config.json'); this.contextCuratorConfigPath = path.join(projectRoot, 'context-curator-config.json'); } static getInstance() { if (!ContextCuratorConfigLoader.instance) { ContextCuratorConfigLoader.instance = new ContextCuratorConfigLoader(); } return ContextCuratorConfigLoader.instance; } async loadConfig() { try { const now = Date.now(); if (this.configLoaded && (now - this.lastLoadTime) < this.cacheTTL && this.config) { logger.debug('Using cached Context Curator configuration'); return { success: true, config: this.config, source: 'mixed', warnings: [] }; } logger.info('Loading Context Curator configuration...'); const warnings = []; const llmResult = await this.loadLLMConfig(); if (!llmResult.success) { warnings.push(`LLM config warning: ${llmResult.error}`); } const envConfig = this.loadEnvironmentConfig(); const fileConfig = await this.loadFileConfig(); if (fileConfig.warnings.length > 0) { warnings.push(...fileConfig.warnings); } const mergedConfig = this.mergeConfigurations(envConfig, fileConfig.config); const validatedConfig = validateContextCuratorConfig(mergedConfig); this.config = validatedConfig; this.configLoaded = true; this.lastLoadTime = now; logger.info('Context Curator configuration loaded successfully'); return { success: true, config: validatedConfig, source: this.determineConfigSource(envConfig, fileConfig.config), warnings }; } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; logger.error('Failed to load Context Curator configuration:', errorMessage); const now = Date.now(); const defaultConfig = contextCuratorConfigSchema.parse({}); this.config = defaultConfig; this.configLoaded = true; this.lastLoadTime = now; return { success: false, config: defaultConfig, error: errorMessage, source: 'defaults', warnings: ['Using default configuration due to load failure'] }; } } getConfig() { return this.config; } getLLMModel(operation) { if (!this.llmConfig) { return this.getEnvironmentFallbackModel(); } const prefixedOperation = `context_curator_${operation}`; return this.llmConfig.llm_mapping[prefixedOperation] || this.llmConfig.llm_mapping[operation] || this.llmConfig.llm_mapping['default_generation'] || this.getEnvironmentFallbackModel(); } getEnvironmentFallbackModel() { return process.env.GEMINI_MODEL || process.env.VIBE_DEFAULT_LLM_MODEL || 'google/gemini-2.5-flash-preview-05-20'; } async reloadConfig() { this.configLoaded = false; this.lastLoadTime = 0; return this.loadConfig(); } validateConfiguration() { if (!this.config) { return { valid: false, errors: ['No configuration loaded'] }; } try { validateContextCuratorConfig(this.config); return { valid: true, errors: [] }; } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown validation error'; return { valid: false, errors: [errorMessage] }; } } getConfigSummary() { return { loaded: this.configLoaded, lastLoadTime: new Date(this.lastLoadTime).toISOString(), hasConfig: !!this.config, hasLLMConfig: !!this.llmConfig, cacheAge: Date.now() - this.lastLoadTime, cacheTTL: this.cacheTTL }; } async loadLLMConfig() { try { if (!(await pathExists(this.llmConfigPath))) { return { success: false, error: 'LLM config file not found' }; } const content = await readFile(this.llmConfigPath, 'utf-8'); const llmConfig = JSON.parse(content); if (!llmConfig.llm_mapping || typeof llmConfig.llm_mapping !== 'object') { return { success: false, error: 'Invalid LLM config format' }; } this.llmConfig = llmConfig; logger.debug('LLM configuration loaded successfully'); return { success: true }; } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; logger.warn('Failed to load LLM configuration:', errorMessage); return { success: false, error: errorMessage }; } } loadEnvironmentConfig() { const envConfig = {}; const contentDensity = {}; if (process.env.VIBE_CONTEXT_CURATOR_MAX_CONTENT_LENGTH) { const parsed = parseInt(process.env.VIBE_CONTEXT_CURATOR_MAX_CONTENT_LENGTH, 10); if (!isNaN(parsed)) { contentDensity.maxContentLength = parsed; } } if (process.env.VIBE_CONTEXT_CURATOR_OPTIMIZATION_THRESHOLD) { const parsed = parseInt(process.env.VIBE_CONTEXT_CURATOR_OPTIMIZATION_THRESHOLD, 10); if (!isNaN(parsed)) { contentDensity.optimizationThreshold = parsed; } } if (process.env.VIBE_CONTEXT_CURATOR_PRESERVE_COMMENTS) { contentDensity.preserveComments = process.env.VIBE_CONTEXT_CURATOR_PRESERVE_COMMENTS === 'true'; } if (process.env.VIBE_CONTEXT_CURATOR_PRESERVE_TYPES) { contentDensity.preserveTypes = process.env.VIBE_CONTEXT_CURATOR_PRESERVE_TYPES === 'true'; } if (Object.keys(contentDensity).length > 0) { envConfig.contentDensity = contentDensity; } const relevanceScoring = {}; if (process.env.VIBE_CONTEXT_CURATOR_KEYWORD_WEIGHT) { const parsed = parseFloat(process.env.VIBE_CONTEXT_CURATOR_KEYWORD_WEIGHT); if (!isNaN(parsed)) { relevanceScoring.keywordWeight = parsed; } } if (process.env.VIBE_CONTEXT_CURATOR_SEMANTIC_WEIGHT) { const parsed = parseFloat(process.env.VIBE_CONTEXT_CURATOR_SEMANTIC_WEIGHT); if (!isNaN(parsed)) { relevanceScoring.semanticWeight = parsed; } } if (process.env.VIBE_CONTEXT_CURATOR_STRUCTURAL_WEIGHT) { const parsed = parseFloat(process.env.VIBE_CONTEXT_CURATOR_STRUCTURAL_WEIGHT); if (!isNaN(parsed)) { relevanceScoring.structuralWeight = parsed; } } if (process.env.VIBE_CONTEXT_CURATOR_MIN_RELEVANCE_THRESHOLD) { const parsed = parseFloat(process.env.VIBE_CONTEXT_CURATOR_MIN_RELEVANCE_THRESHOLD); if (!isNaN(parsed)) { relevanceScoring.minRelevanceThreshold = parsed; } } if (Object.keys(relevanceScoring).length > 0) { envConfig.relevanceScoring = relevanceScoring; } const outputFormat = {}; if (process.env.VIBE_CONTEXT_CURATOR_INCLUDE_META_PROMPT) { outputFormat.includeMetaPrompt = process.env.VIBE_CONTEXT_CURATOR_INCLUDE_META_PROMPT === 'true'; } if (process.env.VIBE_CONTEXT_CURATOR_INCLUDE_FILE_CONTENT) { outputFormat.includeFileContent = process.env.VIBE_CONTEXT_CURATOR_INCLUDE_FILE_CONTENT === 'true'; } if (process.env.VIBE_CONTEXT_CURATOR_MAX_TOKENS_PER_FILE) { const parsed = parseInt(process.env.VIBE_CONTEXT_CURATOR_MAX_TOKENS_PER_FILE, 10); if (!isNaN(parsed)) { outputFormat.maxTokensPerFile = parsed; } } if (process.env.VIBE_CONTEXT_CURATOR_XML_VALIDATION) { outputFormat.xmlValidation = process.env.VIBE_CONTEXT_CURATOR_XML_VALIDATION === 'true'; } if (Object.keys(outputFormat).length > 0) { envConfig.outputFormat = outputFormat; } const llmIntegration = {}; if (process.env.VIBE_CONTEXT_CURATOR_MAX_RETRIES) { const parsed = parseInt(process.env.VIBE_CONTEXT_CURATOR_MAX_RETRIES, 10); if (!isNaN(parsed)) { llmIntegration.maxRetries = parsed; } } if (process.env.VIBE_CONTEXT_CURATOR_TIMEOUT_MS) { const parsed = parseInt(process.env.VIBE_CONTEXT_CURATOR_TIMEOUT_MS, 10); if (!isNaN(parsed)) { llmIntegration.timeoutMs = parsed; } } if (process.env.VIBE_CONTEXT_CURATOR_FALLBACK_MODEL) { llmIntegration.fallbackModel = process.env.VIBE_CONTEXT_CURATOR_FALLBACK_MODEL; } if (Object.keys(llmIntegration).length > 0) { envConfig.llmIntegration = llmIntegration; } if (Object.keys(envConfig).length > 0) { logger.debug('Environment configuration loaded'); } return envConfig; } async loadFileConfig() { const warnings = []; try { if (!(await pathExists(this.contextCuratorConfigPath))) { logger.debug('Context Curator config file not found, using defaults'); return { config: {}, warnings }; } const content = await readFile(this.contextCuratorConfigPath, 'utf-8'); const fileConfig = JSON.parse(content); logger.debug('File configuration loaded successfully'); return { config: fileConfig, warnings }; } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; warnings.push(`Failed to load file configuration: ${errorMessage}`); logger.warn('Failed to load file configuration:', errorMessage); return { config: {}, warnings }; } } mergeConfigurations(envConfig, fileConfig) { const merged = {}; if (fileConfig.contentDensity || envConfig.contentDensity) { merged.contentDensity = { ...fileConfig.contentDensity, ...envConfig.contentDensity }; } if (fileConfig.relevanceScoring || envConfig.relevanceScoring) { merged.relevanceScoring = { ...fileConfig.relevanceScoring, ...envConfig.relevanceScoring }; } if (fileConfig.outputFormat || envConfig.outputFormat) { merged.outputFormat = { ...fileConfig.outputFormat, ...envConfig.outputFormat }; } if (fileConfig.llmIntegration || envConfig.llmIntegration) { merged.llmIntegration = { ...fileConfig.llmIntegration, ...envConfig.llmIntegration }; } return merged; } determineConfigSource(envConfig, fileConfig) { const hasEnvConfig = Object.keys(envConfig).length > 0; const hasFileConfig = Object.keys(fileConfig).length > 0; if (hasEnvConfig && hasFileConfig) return 'mixed'; if (hasEnvConfig) return 'environment'; if (hasFileConfig) return 'file'; return 'defaults'; } }