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
JavaScript
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;
}
}