UNPKG

ai-debug-local-mcp

Version:

🎯 ENHANCED AI GUIDANCE v4.1.2: Dramatically improved tool descriptions help AI users choose the right tools instead of 'close enough' options. Ultra-fast keyboard automation (10x speed), universal recording, multi-ecosystem debugging support, and compreh

222 lines • 7.64 kB
// Session Resource Management System // Provides session-level resource tracking and cleanup import { ResourceManager } from './resource-manager.js'; /** * SessionResourceManager - Manages resources at the session level * * Provides a higher-level interface for resource management that * coordinates with the global ResourceManager */ export class SessionResourceManager { sessions = new Map(); resourceManager; cleanupCallbacks = []; constructor(resourceManager) { this.resourceManager = resourceManager || new ResourceManager(); } /** * Create a new session */ async createSession(sessionId) { if (this.sessions.has(sessionId)) { throw new Error(`Session ${sessionId} already exists`); } const session = { sessionId, createdAt: new Date(), lastUsed: new Date(), resources: [], status: 'active' }; this.sessions.set(sessionId, session); return session; } /** * Get session by ID */ getSession(sessionId) { return this.sessions.get(sessionId); } /** * Attach resource to session */ async attachResource(sessionId, resourceType, resource) { const session = this.sessions.get(sessionId); if (!session) { throw new Error(`Session ${sessionId} not found`); } if (session.status !== 'active') { throw new Error(`Session ${sessionId} is not active (status: ${session.status})`); } // Track in global resource manager this.resourceManager.trackResource(resourceType, sessionId, resource); // Track in session const trackedResource = { sessionId, resourceType, resource, addedAt: new Date(), lastUsed: new Date() }; session.resources.push(trackedResource); session.lastUsed = new Date(); } /** * Get all resources for a session */ getSessionResources(sessionId) { const session = this.sessions.get(sessionId); return session ? [...session.resources] : []; } /** * Update session last used time */ touchSession(sessionId) { const session = this.sessions.get(sessionId); if (session) { session.lastUsed = new Date(); } } /** * Cleanup session and all its resources */ async cleanupSession(sessionId) { const session = this.sessions.get(sessionId); if (!session) { return; // Already cleaned up } // Mark as cleaning to prevent new resources session.status = 'cleaning'; try { // Cleanup all resources const cleanupPromises = session.resources.map(async (resource) => { try { if (resource.resourceType === 'page' && resource.resource.close) { await resource.resource.close(); } else if (resource.resourceType === 'browser' && resource.resource.close) { await resource.resource.close(); } else if (resource.resourceType === 'context' && resource.resource.close) { await resource.resource.close(); } } catch (error) { console.warn(`Failed to cleanup ${resource.resourceType} resource:`, error); } }); await Promise.allSettled(cleanupPromises); // Run registered cleanup callbacks for (const callback of this.cleanupCallbacks) { try { await callback(sessionId); } catch (error) { console.warn(`Cleanup callback failed for session ${sessionId}:`, error); } } // Cleanup in global resource manager await this.resourceManager.cleanupSession(sessionId); // Mark as closed and remove from tracking session.status = 'closed'; this.sessions.delete(sessionId); } catch (error) { console.error(`Error cleaning up session ${sessionId}:`, error); // Force remove even if cleanup failed this.sessions.delete(sessionId); } } /** * Cleanup all sessions */ async cleanupAll() { const sessionIds = Array.from(this.sessions.keys()); const cleanupPromises = sessionIds.map(sessionId => this.cleanupSession(sessionId).catch(error => console.error(`Failed to cleanup session ${sessionId}:`, error))); await Promise.allSettled(cleanupPromises); } /** * Find and cleanup stale sessions */ async cleanupStaleSessions(maxAgeMinutes = 120) { const now = Date.now(); const maxAge = maxAgeMinutes * 60 * 1000; let cleanedCount = 0; const staleSessionIds = []; for (const [sessionId, session] of this.sessions.entries()) { if ((now - session.lastUsed.getTime()) > maxAge) { staleSessionIds.push(sessionId); } } // Cleanup stale sessions for (const sessionId of staleSessionIds) { await this.cleanupSession(sessionId); cleanedCount++; } return cleanedCount; } /** * Get session statistics */ getSessionStats() { const activeSessions = Array.from(this.sessions.values()).filter(s => s.status === 'active'); const totalResources = activeSessions.reduce((sum, session) => sum + session.resources.length, 0); const resourcesByType = {}; // Count resources by type activeSessions.forEach(session => { session.resources.forEach(resource => { resourcesByType[resource.resourceType] = (resourcesByType[resource.resourceType] || 0) + 1; }); }); // Calculate session ages const now = Date.now(); const sessionAges = activeSessions.map(session => Math.floor((now - session.createdAt.getTime()) / 1000 / 60) // age in minutes ); return { totalSessions: this.sessions.size, activeSessions: activeSessions.length, totalResources, resourcesByType, averageResourcesPerSession: activeSessions.length > 0 ? totalResources / activeSessions.length : 0, sessionAges }; } /** * Check if session exists and is active */ isSessionActive(sessionId) { const session = this.sessions.get(sessionId); return session ? session.status === 'active' : false; } /** * Get all active session IDs */ getActiveSessionIds() { return Array.from(this.sessions.entries()) .filter(([_, session]) => session.status === 'active') .map(([sessionId]) => sessionId); } /** * Register cleanup callback */ registerCleanupCallback(callback) { this.cleanupCallbacks.push(callback); } /** * Get the underlying ResourceManager */ getResourceManager() { return this.resourceManager; } /** * Clear all sessions (for testing) */ clear() { this.sessions.clear(); } } /** * Global session resource manager instance */ export const globalSessionResourceManager = new SessionResourceManager(); //# sourceMappingURL=session-resource-manager.js.map