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.

206 lines (205 loc) 7.19 kB
import * as fs from 'fs/promises'; import * as path from 'path'; import logger from '../logger.js'; import { getProjectRoot } from '../tools/code-map-generator/utils/pathUtils.enhanced.js'; const DEFAULT_JOB_TIMEOUT_CONFIG = { defaults: { taskExecution: 300000, llmRequest: 60000, fileOperations: 10000, networkOperations: 20000, databaseOperations: 15000, taskDecomposition: 600000, recursiveTaskDecomposition: 720000, taskRefinement: 180000, agentCommunication: 30000 }, toolTimeouts: {}, retryPolicy: { maxRetries: 3, backoffMultiplier: 2.0, initialDelayMs: 1000, maxDelayMs: 30000, enableExponentialBackoff: true, retryableErrors: ['TIMEOUT', 'NETWORK_ERROR', 'RATE_LIMIT'] }, monitoring: { enableTimeoutLogging: true, logLevel: 'warn', metricsEnabled: true } }; export class JobTimeoutConfigManager { static instance = null; config = null; configPath; initialized = false; constructor() { const projectRoot = getProjectRoot(); this.configPath = path.join(projectRoot, 'job-timeout-config.json'); } static getInstance() { if (!JobTimeoutConfigManager.instance) { JobTimeoutConfigManager.instance = new JobTimeoutConfigManager(); } return JobTimeoutConfigManager.instance; } async initialize() { if (this.initialized) { logger.debug('JobTimeoutConfigManager already initialized'); return; } try { await this.loadConfig(); this.initialized = true; logger.info('JobTimeoutConfigManager initialized successfully'); } catch (error) { logger.error({ error }, 'Failed to initialize JobTimeoutConfigManager'); this.config = DEFAULT_JOB_TIMEOUT_CONFIG; this.initialized = true; } } async loadConfig() { try { const configContent = await fs.readFile(this.configPath, 'utf-8'); const loadedConfig = JSON.parse(configContent); this.config = { ...DEFAULT_JOB_TIMEOUT_CONFIG, ...loadedConfig, defaults: { ...DEFAULT_JOB_TIMEOUT_CONFIG.defaults, ...loadedConfig.defaults }, toolTimeouts: { ...loadedConfig.toolTimeouts }, retryPolicy: { ...DEFAULT_JOB_TIMEOUT_CONFIG.retryPolicy, ...loadedConfig.retryPolicy }, monitoring: { ...DEFAULT_JOB_TIMEOUT_CONFIG.monitoring, ...loadedConfig.monitoring } }; logger.info({ configPath: this.configPath, toolCount: Object.keys(this.config.toolTimeouts).length }, 'Loaded job timeout configuration'); } catch (error) { if (error.code === 'ENOENT') { logger.warn({ configPath: this.configPath }, 'Job timeout config file not found, using defaults'); } else { logger.error({ error, configPath: this.configPath }, 'Error loading job timeout config'); } this.config = DEFAULT_JOB_TIMEOUT_CONFIG; } } getToolTimeoutConfig(toolName) { if (!this.config) { logger.warn('JobTimeoutConfigManager not initialized'); return null; } const toolConfig = this.config.toolTimeouts[toolName]; if (!toolConfig) { logger.debug({ toolName }, 'No specific timeout config for tool, using defaults'); return null; } return toolConfig; } getTimeoutOperation(toolName) { const toolConfig = this.getToolTimeoutConfig(toolName); return toolConfig?.timeoutOperation || 'taskExecution'; } getCustomTimeoutMs(toolName) { const toolConfig = this.getToolTimeoutConfig(toolName); return toolConfig?.customTimeoutMs; } getDefaultTimeout(operation) { if (!this.config) { return DEFAULT_JOB_TIMEOUT_CONFIG.defaults[operation] || 60000; } return this.config.defaults[operation] || 60000; } getRetryPolicy() { if (!this.config) { return DEFAULT_JOB_TIMEOUT_CONFIG.retryPolicy; } return this.config.retryPolicy; } getMonitoringConfig() { if (!this.config) { return DEFAULT_JOB_TIMEOUT_CONFIG.monitoring; } return this.config.monitoring; } isTimeoutLoggingEnabled() { return this.getMonitoringConfig().enableTimeoutLogging; } areMetricsEnabled() { return this.getMonitoringConfig().metricsEnabled; } getConfiguredTools() { if (!this.config) { return []; } return Object.keys(this.config.toolTimeouts); } validateConfig() { const errors = []; if (!this.config) { errors.push('Configuration not loaded'); return { valid: false, errors }; } const requiredDefaults = [ 'taskExecution', 'llmRequest', 'fileOperations', 'networkOperations', 'databaseOperations' ]; for (const op of requiredDefaults) { if (!this.config.defaults[op] || this.config.defaults[op] <= 0) { errors.push(`Invalid or missing default timeout for ${op}`); } } for (const [toolName, toolConfig] of Object.entries(this.config.toolTimeouts)) { if (!toolConfig.timeoutOperation) { errors.push(`Tool ${toolName} missing timeoutOperation`); } if (toolConfig.customTimeoutMs !== undefined && toolConfig.customTimeoutMs !== null && toolConfig.customTimeoutMs <= 0) { errors.push(`Tool ${toolName} has invalid customTimeoutMs`); } } if (this.config.retryPolicy.maxRetries < 0) { errors.push('Invalid maxRetries in retry policy'); } if (this.config.retryPolicy.backoffMultiplier < 1.0) { errors.push('Invalid backoffMultiplier in retry policy'); } return { valid: errors.length === 0, errors }; } async reload() { logger.info('Reloading job timeout configuration'); await this.loadConfig(); } getConfigSummary() { return { initialized: this.initialized, configPath: this.configPath, toolCount: this.config ? Object.keys(this.config.toolTimeouts).length : 0, defaultTimeouts: this.config?.defaults || {}, retryEnabled: (this.config?.retryPolicy?.maxRetries ?? 0) > 0, monitoringEnabled: this.config?.monitoring.metricsEnabled || false }; } } export function getJobTimeoutConfigManager() { return JobTimeoutConfigManager.getInstance(); }