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.

244 lines (243 loc) 9.26 kB
import { MemoryManager } from '../../code-map-generator/cache/memoryManager.js'; import { AppError } from '../../../utils/errors.js'; import logger from '../../../logger.js'; export class TaskManagerMemoryManager { static instance = null; memoryManager; config; monitoringInterval = null; memoryStats = []; alerts = new Map(); cleanupCallbacks = new Map(); constructor(config) { this.config = config; this.memoryManager = new MemoryManager({ maxMemoryPercentage: config.maxMemoryPercentage, monitorInterval: config.monitorInterval, autoManage: config.autoManage, pruneThreshold: config.pruneThreshold, prunePercentage: config.prunePercentage }); if (config.enabled) { this.startMonitoring(); } logger.info({ config }, 'Task Manager Memory Manager initialized'); } static getInstance(config) { if (!TaskManagerMemoryManager.instance) { if (!config) { throw new AppError('Memory manager configuration required for first initialization'); } TaskManagerMemoryManager.instance = new TaskManagerMemoryManager(config); } return TaskManagerMemoryManager.instance; } startMonitoring() { if (this.monitoringInterval) { return; } this.monitoringInterval = setInterval(() => { this.collectMemoryStats(); this.checkMemoryThresholds(); }, this.config.monitorInterval); logger.debug('Memory monitoring started'); } stopMonitoring() { if (this.monitoringInterval) { clearInterval(this.monitoringInterval); this.monitoringInterval = null; logger.debug('Memory monitoring stopped'); } } collectMemoryStats() { try { const memoryUsage = process.memoryUsage(); let memStats; try { memStats = this.memoryManager?.getMemoryStats?.(); } catch (error) { logger.debug({ err: error }, 'Failed to get memory stats from memory manager, using fallback'); memStats = null; } const stats = { totalMemoryUsage: memoryUsage.heapUsed + memoryUsage.external, heapUsed: memoryUsage.heapUsed, heapTotal: memoryUsage.heapTotal, external: memoryUsage.external, arrayBuffers: memoryUsage.arrayBuffers || 0, rss: memoryUsage.rss, percentageUsed: memStats?.raw?.memoryUsagePercentage || 0, cacheMemoryUsage: this.estimateCacheMemoryUsage(), taskStorageMemoryUsage: this.estimateTaskStorageMemoryUsage(), agentMemoryUsage: this.estimateAgentMemoryUsage(), timestamp: new Date() }; this.memoryStats.push(stats); if (this.memoryStats.length > 100) { this.memoryStats = this.memoryStats.slice(-100); } logger.debug({ heapUsed: `${Math.round(stats.heapUsed / 1024 / 1024)} MB`, percentageUsed: `${(stats.percentageUsed * 100).toFixed(1)}%`, cacheMemory: `${Math.round(stats.cacheMemoryUsage / 1024 / 1024)} MB` }, 'Memory stats collected'); } catch (error) { logger.error({ err: error }, 'Failed to collect memory stats'); } } checkMemoryThresholds() { const currentStats = this.memoryStats[this.memoryStats.length - 1]; if (!currentStats) return; const warningThreshold = this.config.pruneThreshold * 0.8; const criticalThreshold = this.config.pruneThreshold; if (currentStats.percentageUsed >= criticalThreshold) { this.generateAlert('critical', criticalThreshold, currentStats.percentageUsed, 'Critical memory usage detected - automatic cleanup triggered'); this.performAggressiveCleanup(); } else if (currentStats.percentageUsed >= warningThreshold) { this.generateAlert('warning', warningThreshold, currentStats.percentageUsed, 'High memory usage detected - consider manual cleanup'); } } generateAlert(type, threshold, currentUsage, message) { const alertId = `${type}_${Date.now()}`; const alert = { id: alertId, type, threshold, currentUsage, message, timestamp: new Date(), resolved: false }; this.alerts.set(alertId, alert); logger[type === 'critical' ? 'error' : 'warn']({ alertId, threshold: `${(threshold * 100).toFixed(1)}%`, currentUsage: `${(currentUsage * 100).toFixed(1)}%`, message }, `Memory ${type} alert`); } async performAggressiveCleanup() { const startTime = Date.now(); let totalMemoryFreed = 0; let totalItemsRemoved = 0; try { logger.info('Starting aggressive memory cleanup'); for (const [name, callback] of this.cleanupCallbacks) { try { const result = await callback(); if (result.success) { totalMemoryFreed += result.memoryFreed; totalItemsRemoved += result.itemsRemoved; logger.debug({ name, result }, 'Cleanup callback executed'); } } catch (error) { logger.error({ err: error, name }, 'Cleanup callback failed'); } } if (global.gc) { global.gc(); logger.debug('Forced garbage collection'); } try { this.memoryManager?.pruneCaches?.(); } catch (error) { logger.debug({ err: error }, 'Failed to prune memory manager caches'); } const duration = Date.now() - startTime; const result = { success: true, memoryFreed: totalMemoryFreed, itemsRemoved: totalItemsRemoved, duration }; logger.info({ memoryFreed: `${Math.round(totalMemoryFreed / 1024 / 1024)} MB`, itemsRemoved: totalItemsRemoved, duration: `${duration}ms` }, 'Aggressive memory cleanup completed'); return result; } catch (error) { const duration = Date.now() - startTime; logger.error({ err: error, duration }, 'Aggressive memory cleanup failed'); return { success: false, memoryFreed: totalMemoryFreed, itemsRemoved: totalItemsRemoved, duration, error: error instanceof Error ? error.message : String(error) }; } } registerCleanupCallback(name, callback) { this.cleanupCallbacks.set(name, callback); logger.debug({ name }, 'Cleanup callback registered'); } unregisterCleanupCallback(name) { this.cleanupCallbacks.delete(name); logger.debug({ name }, 'Cleanup callback unregistered'); } getCurrentMemoryStats() { return this.memoryStats.length > 0 ? this.memoryStats[this.memoryStats.length - 1] : null; } getMemoryStatsHistory(limit) { const stats = [...this.memoryStats]; return limit ? stats.slice(-limit) : stats; } getActiveAlerts() { return Array.from(this.alerts.values()).filter(alert => !alert.resolved); } resolveAlert(alertId) { const alert = this.alerts.get(alertId); if (alert) { alert.resolved = true; logger.debug({ alertId }, 'Memory alert resolved'); return true; } return false; } estimateCacheMemoryUsage() { return 0; } estimateTaskStorageMemoryUsage() { return 0; } estimateAgentMemoryUsage() { return 0; } getMemoryUsageSummary() { const current = this.getCurrentMemoryStats(); const peak = this.memoryStats.reduce((max, stats) => stats.totalMemoryUsage > max.totalMemoryUsage ? stats : max, this.memoryStats[0] || current); const average = this.memoryStats.length > 0 ? this.memoryStats.reduce((sum, stats) => sum + stats.totalMemoryUsage, 0) / this.memoryStats.length : 0; return { current, peak, average, alertCount: this.getActiveAlerts().length, cleanupCallbacksCount: this.cleanupCallbacks.size }; } shutdown() { this.stopMonitoring(); this.cleanupCallbacks.clear(); this.alerts.clear(); this.memoryStats = []; logger.info('Task Manager Memory Manager shutdown'); } } export function getTaskManagerMemoryManager() { try { return TaskManagerMemoryManager.getInstance(); } catch { return null; } }