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.

224 lines (223 loc) 7.49 kB
import fs from 'fs/promises'; import path from 'path'; import os from 'os'; import chalk from 'chalk'; import logger from '../../logger.js'; const DEFAULT_CONFIG = { display: { enableMarkdown: true, enableColors: true, enableEmoji: false, maxLineWidth: 80, theme: 'default' }, session: { autoSave: true, autoSaveInterval: 1, sessionDirectory: path.join(os.homedir(), '.vibe', 'sessions'), maxSessionHistory: 1000, preserveContext: true }, history: { maxSize: 1000, persistent: true, historyFile: path.join(os.homedir(), '.vibe', 'history.json') }, commands: { aliasEnabled: true, aliases: { 'q': '/quit', 'h': '/help', 'c': '/clear', 's': '/save', 't': '/tools' }, customCommands: {} }, performance: { requestTimeout: 60000, maxConcurrentRequests: 3, cacheResponses: true, cacheSize: 50 }, developer: { debugMode: false, showTimings: false, showTokenUsage: false, verboseErrors: false }, tools: { defaultTimeout: 300000, preferredRouting: 'semantic', enabledTools: [], disabledTools: [] } }; export class ConfigurationManager { config; configPath; configDir; hasChanges = false; constructor() { this.configDir = path.join(os.homedir(), '.vibe'); this.configPath = path.join(this.configDir, 'config.json'); this.config = { ...DEFAULT_CONFIG }; } async initialize() { try { await this.ensureConfigDirectory(); await this.loadConfig(); logger.info('Configuration loaded successfully'); } catch (error) { logger.warn({ err: error }, 'Failed to load configuration, using defaults'); } } async ensureConfigDirectory() { try { await fs.mkdir(this.configDir, { recursive: true }); } catch (error) { logger.error({ err: error }, 'Failed to create config directory'); throw error; } } async loadConfig() { try { const data = await fs.readFile(this.configPath, 'utf-8'); const userConfig = JSON.parse(data); this.config = this.mergeConfig(DEFAULT_CONFIG, userConfig); } catch { await this.saveConfig(); } } mergeConfig(defaults, user) { const merged = { ...defaults }; for (const key in user) { const k = key; if (user[k] !== undefined) { if (typeof user[k] === 'object' && !Array.isArray(user[k])) { merged[k] = { ...defaults[k], ...user[k] }; } else { merged[k] = user[k]; } } } return merged; } async saveConfig() { try { const data = JSON.stringify(this.config, null, 2); await fs.writeFile(this.configPath, data, 'utf-8'); this.hasChanges = false; logger.info('Configuration saved successfully'); } catch (error) { logger.error({ err: error }, 'Failed to save configuration'); throw error; } } get(section, property) { if (property !== undefined) { return this.config[section][property]; } return this.config[section]; } set(section, propertyOrValue, value) { if (value !== undefined) { const prop = propertyOrValue; this.config[section][prop] = value; } else { this.config[section] = propertyOrValue; } this.hasChanges = true; } getAll() { return { ...this.config }; } async reset() { this.config = { ...DEFAULT_CONFIG }; await this.saveConfig(); } hasUnsavedChanges() { return this.hasChanges; } async autoSave() { if (this.hasChanges && this.config.session.autoSave) { await this.saveConfig(); } } async loadFrom(configPath) { try { const data = await fs.readFile(configPath, 'utf-8'); const userConfig = JSON.parse(data); this.config = this.mergeConfig(DEFAULT_CONFIG, userConfig); this.hasChanges = true; logger.info({ path: configPath }, 'Configuration loaded from custom path'); } catch (error) { logger.error({ err: error, path: configPath }, 'Failed to load configuration from path'); throw error; } } async exportTo(exportPath) { try { const data = JSON.stringify(this.config, null, 2); await fs.writeFile(exportPath, data, 'utf-8'); logger.info({ path: exportPath }, 'Configuration exported'); } catch (error) { logger.error({ err: error, path: exportPath }, 'Failed to export configuration'); throw error; } } printConfig() { const lines = []; lines.push(chalk.yellow.bold('Current Configuration:')); lines.push(chalk.gray('─'.repeat(50))); for (const [section, values] of Object.entries(this.config)) { lines.push(chalk.cyan(`\n${section}:`)); for (const [key, value] of Object.entries(values)) { const formattedValue = typeof value === 'object' ? JSON.stringify(value, null, 2).split('\n').join('\n ') : value; lines.push(` ${chalk.green(key)}: ${formattedValue}`); } } lines.push(chalk.gray('\n─'.repeat(50))); lines.push(chalk.gray(`Config file: ${this.configPath}`)); return lines.join('\n'); } validate() { const errors = []; if (this.config.display.maxLineWidth < 40 || this.config.display.maxLineWidth > 200) { errors.push('maxLineWidth must be between 40 and 200'); } if (this.config.session.autoSaveInterval < 0.5 || this.config.session.autoSaveInterval > 60) { errors.push('autoSaveInterval must be between 0.5 and 60 minutes'); } if (this.config.session.maxSessionHistory < 100 || this.config.session.maxSessionHistory > 10000) { errors.push('maxSessionHistory must be between 100 and 10000'); } if (this.config.history.maxSize < 100 || this.config.history.maxSize > 10000) { errors.push('history.maxSize must be between 100 and 10000'); } if (this.config.performance.requestTimeout < 5000 || this.config.performance.requestTimeout > 600000) { errors.push('requestTimeout must be between 5000ms and 600000ms'); } if (this.config.performance.maxConcurrentRequests < 1 || this.config.performance.maxConcurrentRequests > 10) { errors.push('maxConcurrentRequests must be between 1 and 10'); } if (this.config.performance.cacheSize < 10 || this.config.performance.cacheSize > 1000) { errors.push('cacheSize must be between 10MB and 1000MB'); } return { valid: errors.length === 0, errors }; } } export const configManager = new ConfigurationManager();