UNPKG

mega-minds

Version:

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

293 lines (223 loc) 9.41 kB
// lib/memory/MemoryManager.js const fs = require('fs-extra'); const path = require('path'); class MemoryManager { constructor(projectPath) { this.projectPath = projectPath; this.memoryPath = path.join(projectPath, '.mega-minds'); this.claudeFile = path.join(projectPath, '.claude', 'claude.md'); this.sessionsPath = path.join(this.memoryPath, 'sessions'); this.memoryFilesPath = path.join(this.memoryPath, 'memory'); } async initialize() { // Ensure all memory directories exist await fs.ensureDir(this.memoryPath); await fs.ensureDir(this.sessionsPath); await fs.ensureDir(this.memoryFilesPath); await fs.ensureDir(path.join(this.memoryPath, 'agents')); // Initialize memory files if they don't exist await this.initializeMemoryFiles(); } async initializeMemoryFiles() { const projectName = path.basename(this.projectPath); // Architecture memory const architectureFile = path.join(this.memoryFilesPath, 'architecture.md'); if (!await fs.pathExists(architectureFile)) { await fs.writeFile(architectureFile, this.generateArchitectureMemory(projectName)); } // Recent work memory const recentWorkFile = path.join(this.memoryFilesPath, 'recent-work.md'); if (!await fs.pathExists(recentWorkFile)) { await fs.writeFile(recentWorkFile, this.generateRecentWorkMemory()); } // Active context const activeContextFile = path.join(this.memoryPath, 'agents', 'active-context.md'); if (!await fs.pathExists(activeContextFile)) { await fs.writeFile(activeContextFile, this.generateActiveContextMemory()); } } generateClaudeMemoryFile(projectName) { return `# ${projectName} - AI Development Team Memory @import .mega-minds/memory/architecture.md @import .mega-minds/memory/recent-work.md @import .mega-minds/agents/active-context.md ## Memory Management Commands **For Claude Code - Use these commands when needed:** - \`mega-minds compress-context\` - When approaching token limits - \`mega-minds save-session "description"\` - Save current development session - \`mega-minds load-session\` - Load previous session state - \`mega-minds agent-status\` - See what agents are working on - \`mega-minds update-memory "what happened"\` - Update project memory ## Project Overview **Project**: ${projectName} **Type**: [Web Application/API/Mobile App/etc.] **Tech Stack**: [To be determined by technical architecture agent] ## Development Guidelines - **Quality First**: All code must pass quality gates before proceeding - **Documentation**: Document all decisions and architecture changes - **Testing**: Comprehensive test coverage for all features - **Security**: Follow security best practices throughout development ## Current Development Status **Active Sprint**: Project initialization **Next Milestone**: [To be determined] --- *This file is managed by mega-minds AI development team* *Context is automatically optimized and compressed as needed*`; } generateArchitectureMemory(projectName) { return `# Architecture Memory - ${projectName} ## Technology Decisions *Track all major technology and architecture decisions here* ### Decision Log | Date | Decision | Rationale | Decided By | |------|----------|-----------|------------| | ${new Date().toISOString().split('T')[0]} | Project initialized with mega-minds | AI development team setup | Project Setup | ## System Architecture *This section will be updated as architecture is defined* ### Core Components - [ ] Frontend application - [ ] Backend API - [ ] Database layer - [ ] Authentication system ### Technology Stack **Frontend**: [To be decided] **Backend**: [To be decided] **Database**: [To be decided] **Authentication**: [To be decided] ## API Design *API endpoints and contracts will be documented here* ## Database Schema *Database design and relationships will be documented here* ## Security Architecture *Security policies and implementations will be documented here* --- *This file maintains core architectural decisions and never gets compressed*`; } generateRecentWorkMemory() { return `# Recent Work Memory ## Current Session **Started**: ${new Date().toISOString()} **Focus**: Project initialization and setup ## Completed Tasks *Recently completed development tasks* ### Today - ✅ Project initialized with mega-minds AI development team - ✅ Memory management system activated ## In Progress *Current development work* ### Active Tasks - 🔄 Awaiting first development request ## Upcoming Work *Planned development tasks* ### Next Tasks - [ ] Define project requirements - [ ] Choose technology stack - [ ] Set up development environment ## Notes *Important notes and reminders from recent work* --- *This file tracks recent development activity and gets compressed when old*`; } generateActiveContextMemory() { return `# Active Agent Context ## Currently Active Agents *No agents currently active* ## Agent States \`\`\`json { "lastUpdated": "${new Date().toISOString()}", "activeAgents": {}, "queuedTasks": [], "blockers": [] } \`\`\` ## Current Handoffs *No active handoffs* ## Pending Decisions *No pending decisions* --- *This file tracks real-time agent activity and coordination*`; } async saveSession(sessionData) { const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); const sessionFile = path.join(this.sessionsPath, `session-${timestamp}.json`); const session = { timestamp: new Date().toISOString(), description: sessionData.description || 'Development session', work: sessionData.work || {}, agentStates: sessionData.agentStates || {}, decisions: sessionData.decisions || [], nextSteps: sessionData.nextSteps || [] }; await fs.writeFile(sessionFile, JSON.stringify(session, null, 2)); // Update recent work memory await this.updateRecentWorkMemory(session); console.log(`💾 Session saved: ${sessionFile}`); return sessionFile; } async loadLatestSession() { const sessions = await this.listSessions(); if (sessions.length === 0) { return null; } const latestSession = sessions[sessions.length - 1]; const sessionData = await fs.readJSON(latestSession); console.log(`📂 Loaded session from: ${path.basename(latestSession)}`); return sessionData; } async listSessions() { if (!await fs.pathExists(this.sessionsPath)) { return []; } const files = await fs.readdir(this.sessionsPath); return files .filter(file => file.startsWith('session-') && file.endsWith('.json')) .map(file => path.join(this.sessionsPath, file)) .sort(); } async updateRecentWorkMemory(session) { const recentWorkFile = path.join(this.memoryFilesPath, 'recent-work.md'); let content = `# Recent Work Memory ## Latest Session: ${session.description} **Completed**: ${session.timestamp} ### Work Completed ${session.work.completed ? session.work.completed.map(item => `- ✅ ${item}`).join('\n') : '- No completed work recorded'} ### Decisions Made ${session.decisions.length ? session.decisions.map(decision => `- 📋 ${decision}`).join('\n') : '- No decisions recorded'} ### Next Steps ${session.nextSteps.length ? session.nextSteps.map(step => `- 🔄 ${step}`).join('\n') : '- No next steps defined'} ## Agent Activity ${Object.keys(session.agentStates).length ? Object.entries(session.agentStates).map(([agent, state]) => `- **${agent}**: ${state.status || 'unknown status'}` ).join('\n') : '- No agent activity recorded'} --- *Updated: ${new Date().toISOString()}*`; await fs.writeFile(recentWorkFile, content); } async updateArchitectureDecision(decision) { const architectureFile = path.join(this.memoryFilesPath, 'architecture.md'); let content = await fs.readFile(architectureFile, 'utf8'); const date = new Date().toISOString().split('T')[0]; const newRow = `| ${date} | ${decision.title} | ${decision.rationale} | ${decision.decidedBy} |`; // Insert the new decision into the decision log table content = content.replace( /(\| Date \| Decision \| Rationale \| Decided By \|\n\|------|----------|-----------|------------\|)/, `$1\n${newRow}` ); await fs.writeFile(architectureFile, content); console.log(`📐 Architecture decision recorded: ${decision.title}`); } async getMemoryStats() { const sessions = await this.listSessions(); const memoryFiles = await fs.readdir(this.memoryFilesPath); return { totalSessions: sessions.length, memoryFiles: memoryFiles.length, lastSession: sessions.length > 0 ? path.basename(sessions[sessions.length - 1]) : null, projectAge: sessions.length > 0 ? Math.floor((Date.now() - fs.statSync(sessions[0]).birthtime) / (1000 * 60 * 60 * 24)) : 0 }; } } module.exports = MemoryManager;