UNPKG

mega-minds

Version:

Enhanced multi-agent workflow system for Claude Code projects with automated handoff management and Claude Code hooks integration

454 lines (397 loc) 13.5 kB
/** * MCP Server Integration for Mega-Minds Variable-Driven Agent System * Phase 3: Advanced Integration Implementation * * Provides real-time context integration with Claude Code SDK via MCP protocol */ const path = require('path'); const { ContextualVariableEngine } = require('./variable-engine'); const { AgentSectionManager } = require('./section-manager'); const { PerformanceMonitor } = require('./performance-monitor'); class MegaMindsProtocolServer { constructor(projectPath, config = {}) { this.projectPath = projectPath; this.config = { refreshInterval: config.refreshInterval || 30000, // 30 seconds maxCacheSize: config.maxCacheSize || 100, enableStreamingUpdates: config.enableStreamingUpdates || true, ...config }; this.variableEngine = new ContextualVariableEngine(projectPath, config); // Use mega-minds package templates directory, not project directory const megaMindsTemplatesPath = path.join(__dirname, '..', 'templates'); this.sectionManager = new AgentSectionManager(megaMindsTemplatesPath, this.variableEngine); this.performanceMonitor = new PerformanceMonitor(); this.activeConnections = new Map(); this.contextCache = new Map(); } /** * Get comprehensive agent context from Claude Code SDK * @param {string} sessionId - Current Claude Code session ID * @returns {Object} Complete session context for variable generation */ async getAgentContext(sessionId) { try { // Start performance timing this.performanceMonitor.startTiming(); // Check cache first const cacheKey = `context_${sessionId}`; if (this.contextCache.has(cacheKey)) { const cached = this.contextCache.get(cacheKey); if (!this.isCacheExpired(cached)) { this.performanceMonitor.recordMetric('cache-hit'); return cached.context; } } // Gather real-time context from Claude Code SDK const context = { session: { id: sessionId, startTime: new Date().toISOString(), environment: process.env.NODE_ENV || 'development' }, // Memory status from Claude Code memory: await this.getMemoryStatus(sessionId), // Active agents tracking activeAgents: await this.getActiveAgents(sessionId), // Project context project: await this.getProjectContext(sessionId), // Performance metrics performance: this.performanceMonitor.getCurrentMetrics(), // System health system: await this.getSystemHealth() }; // Cache the context this.cacheContext(cacheKey, context); // Record performance const duration = this.performanceMonitor.endTiming('context-generation'); context.performance.contextGenerationTime = duration; return context; } catch (error) { console.error('MCP Context Generation Error:', error); return this.getFallbackContext(sessionId); } } /** * Invoke agent with dynamic section loading * @param {string} agentName - Target agent name * @param {Object} context - Session context * @param {string} sectionType - Section type to load ('coordination', 'expertise', 'boundaries', 'full') * @returns {Object} Agent configuration with injected variables */ async invokeAgent(agentName, context, sectionType = 'full') { try { this.performanceMonitor.startTiming(); // Generate context-aware variables const variables = await this.variableEngine.generateVariables( agentName, sectionType, context ); // Load agent sections with variable injection const sections = await this.sectionManager.loadAgentSection( agentName, sectionType, context ); // Create optimized claude.md for this agent const optimizedClaude = this.sectionManager.renderClaudeTemplate(variables); const agentConfig = { name: agentName, sections: sections, variables: variables, claudeConfig: optimizedClaude, metadata: { generatedAt: new Date().toISOString(), sectionType: sectionType, contextId: context.session.id, optimizationScore: variables['{{OPTIMIZATION_SCORE}}'] } }; // Record performance const duration = this.performanceMonitor.endTiming('agent-invocation'); agentConfig.metadata.invocationTime = duration; // Update agent tracking await this.recordAgentActivation(agentName, context.session.id); return agentConfig; } catch (error) { console.error('MCP Agent Invocation Error:', error); throw new Error(`Failed to invoke agent ${agentName}: ${error.message}`); } } /** * Enable real-time streaming updates for active sessions * @param {string} sessionId - Session to stream updates to * @param {Function} callback - Callback for updates */ enableStreamingUpdates(sessionId, callback) { if (!this.config.enableStreamingUpdates) { console.warn('Streaming updates disabled in configuration'); return; } const streamId = `stream_${sessionId}_${Date.now()}`; const updateInterval = setInterval(async () => { try { const freshContext = await this.getAgentContext(sessionId); const hasChanges = this.detectContextChanges(sessionId, freshContext); if (hasChanges) { callback({ type: 'context-update', sessionId: sessionId, context: freshContext, timestamp: new Date().toISOString() }); } } catch (error) { console.error('Streaming update error:', error); callback({ type: 'error', sessionId: sessionId, error: error.message, timestamp: new Date().toISOString() }); } }, this.config.refreshInterval); this.activeConnections.set(streamId, { sessionId: sessionId, interval: updateInterval, callback: callback, startedAt: new Date() }); return streamId; } /** * Disable streaming updates for a session * @param {string} streamId - Stream identifier to stop */ disableStreamingUpdates(streamId) { const connection = this.activeConnections.get(streamId); if (connection) { clearInterval(connection.interval); this.activeConnections.delete(streamId); } } /** * Get current memory status from Claude Code * @param {string} sessionId - Session ID * @returns {Object} Memory status information */ async getMemoryStatus(sessionId) { // Placeholder for Claude Code SDK integration // This would interface with actual Claude Code memory APIs return { current: Math.floor(Math.random() * 3000), // MB limit: 3500, // MB pressure: 'normal', // normal|warning|critical efficiency: 85 + Math.floor(Math.random() * 10) // 85-95% }; } /** * Get active agents for session * @param {string} sessionId - Session ID * @returns {Object} Active agent information */ async getActiveAgents(sessionId) { // Placeholder for Claude Code SDK integration return { active: ['project-orchestrator-agent'], count: 1, limit: 2, coordinationSuccess: 95 + Math.floor(Math.random() * 5) // 95-99% }; } /** * Get project context from Claude Code * @param {string} sessionId - Session ID * @returns {Object} Project context information */ async getProjectContext(sessionId) { const packageJson = await this.readPackageJson(); return { name: packageJson?.name || 'mega-minds', version: packageJson?.version || '2.1.0', techStack: this.detectTechStack(), mission: 'AI-powered development team coordination system', phase: 'Variable-Driven Integration' }; } /** * Get system health metrics * @returns {Object} System health information */ async getSystemHealth() { const cpuUsage = process.cpuUsage(); const memoryUsage = process.memoryUsage(); return { status: 'healthy', cpu: { user: cpuUsage.user, system: cpuUsage.system }, memory: { rss: Math.round(memoryUsage.rss / 1024 / 1024), // MB heapUsed: Math.round(memoryUsage.heapUsed / 1024 / 1024), // MB heapTotal: Math.round(memoryUsage.heapTotal / 1024 / 1024) // MB }, uptime: process.uptime() }; } /** * Detect technology stack from project files * @returns {Array} Technology stack array */ detectTechStack() { const fs = require('fs'); const path = require('path'); const techStack = []; try { // Check for common config files const configFiles = [ { file: 'package.json', tech: 'Node.js' }, { file: 'requirements.txt', tech: 'Python' }, { file: 'Cargo.toml', tech: 'Rust' }, { file: 'go.mod', tech: 'Go' }, { file: 'composer.json', tech: 'PHP' } ]; configFiles.forEach(({ file, tech }) => { if (fs.existsSync(path.join(this.projectPath, file))) { techStack.push(tech); } }); // Default if nothing detected if (techStack.length === 0) { techStack.push('JavaScript', 'AI Development'); } } catch (error) { console.error('Tech stack detection error:', error); techStack.push('Unknown'); } return techStack; } /** * Read package.json if it exists * @returns {Object|null} Package.json contents or null */ async readPackageJson() { const fs = require('fs').promises; const path = require('path'); try { const packagePath = path.join(this.projectPath, 'package.json'); const content = await fs.readFile(packagePath, 'utf8'); return JSON.parse(content); } catch (error) { return null; } } /** * Cache context with expiration * @param {string} key - Cache key * @param {Object} context - Context to cache */ cacheContext(key, context) { this.contextCache.set(key, { context: context, timestamp: Date.now() }); // Cleanup old entries if (this.contextCache.size > this.config.maxCacheSize) { const oldestKey = this.contextCache.keys().next().value; this.contextCache.delete(oldestKey); } } /** * Check if cached context is expired * @param {Object} cached - Cached entry * @returns {boolean} True if expired */ isCacheExpired(cached) { return (Date.now() - cached.timestamp) > this.config.refreshInterval; } /** * Get fallback context when main context fails * @param {string} sessionId - Session ID * @returns {Object} Minimal fallback context */ getFallbackContext(sessionId) { return { session: { id: sessionId, startTime: new Date().toISOString(), environment: 'fallback' }, memory: { current: 1000, limit: 3500, pressure: 'unknown', efficiency: 50 }, activeAgents: { active: [], count: 0, limit: 2, coordinationSuccess: 50 }, project: { name: 'mega-minds', version: '2.1.0', techStack: ['JavaScript'], mission: 'AI Development System', phase: 'Fallback Mode' }, performance: this.performanceMonitor.getCurrentMetrics(), system: { status: 'degraded', memory: { rss: 1000, heapUsed: 500, heapTotal: 1000 }, uptime: 0 } }; } /** * Detect context changes for streaming updates * @param {string} sessionId - Session ID * @param {Object} newContext - New context to compare * @returns {boolean} True if changes detected */ detectContextChanges(sessionId, newContext) { const lastContextKey = `last_${sessionId}`; const lastContext = this.contextCache.get(lastContextKey); if (!lastContext) { this.contextCache.set(lastContextKey, { context: newContext, timestamp: Date.now() }); return true; } // Check for significant changes const changes = [ newContext.memory.pressure !== lastContext.context.memory.pressure, newContext.activeAgents.count !== lastContext.context.activeAgents.count, newContext.system.status !== lastContext.context.system.status ]; const hasChanges = changes.some(change => change); if (hasChanges) { this.contextCache.set(lastContextKey, { context: newContext, timestamp: Date.now() }); } return hasChanges; } /** * Record agent activation for tracking * @param {string} agentName - Agent name * @param {string} sessionId - Session ID */ async recordAgentActivation(agentName, sessionId) { // Placeholder for agent tracking system console.log(`Agent activated: ${agentName} in session ${sessionId}`); } /** * Cleanup resources and close connections */ cleanup() { // Stop all streaming connections for (const [streamId, connection] of this.activeConnections) { clearInterval(connection.interval); } this.activeConnections.clear(); // Clear caches this.contextCache.clear(); console.log('MCP Server Integration cleaned up'); } } module.exports = { MegaMindsProtocolServer };