UNPKG

@andrebuzeli/advanced-memory-markdown-mcp

Version:

Advanced Memory Bank MCP v3.1.5 - Sistema avançado de gerenciamento de memória com isolamento de projetos por IDE, sincronização sob demanda, backup a cada 30min, apenas arquivos .md principais sincronizados, pasta reasoning temporária com limpeza automát

298 lines 12.2 kB
/** * New Memory Manager v2.0 - Gerencia memórias por tópicos em arquivos markdown * * IMPORTANTE - NOME DO PROJETO: * - O projectName DEVE ser exatamente o nome da pasta RAIZ do projeto aberto no IDE * - NÃO é uma subpasta, NÃO é um subprojeto - é a pasta raiz que foi aberta no IDE * - O nome deve ser uma cópia EXATA sem adicionar ou remover nada * * RESPONSABILIDADE - CONHECIMENTO TÉCNICO: * - Documentação técnica e arquitetural * - Decisões de design e implementação * - Conhecimento de domínio e regras de negócio * - Lições aprendidas e best practices * - Configurações e procedimentos * - Base de conhecimento da equipe * * Funcionalidades v2.0: * - Operações individuais e múltiplas em tópicos * - Criação e gerenciamento de tópicos de memória * - Armazenamento em memory.md no MEMORY_BANK_ROOT * - Sistema de tags e importância * - Busca e filtragem de conteúdo * - Sincronização automática com pasta .memory-bank local */ import * as fs from 'fs/promises'; import { SyncManager } from './sync-manager.js'; export class NewMemoryManager { syncManager; constructor() { this.syncManager = new SyncManager(); } /** * Creates a new memory topic */ async create(projectName, topicName, description, content, importance = 5, tags = []) { // Ensure project structure exists await this.syncManager.ensureProjectStructure(projectName); const memoryFile = this.syncManager.getProjectFilePath(projectName, 'memory.md'); const topic = { name: topicName, description, content, created: Date.now(), modified: Date.now(), tags, importance }; await this.addTopicToFile(memoryFile, topic); return topic; } /** * Reads a specific memory topic */ async read(projectName, topicName) { const topics = await this.list(projectName); return topics.find(topic => topic.name === topicName) || null; } /** * Updates a memory topic */ async update(projectName, topicName, updates) { const memoryFile = this.syncManager.getProjectFilePath(projectName, 'memory.md'); const topics = await this.loadTopicsFromFile(memoryFile); const topicIndex = topics.findIndex(topic => topic.name === topicName); if (topicIndex === -1) return null; const updatedTopic = { ...topics[topicIndex], ...updates, modified: Date.now() }; topics[topicIndex] = updatedTopic; await this.saveTopicsToFile(memoryFile, topics); return updatedTopic; } /** * Deletes a memory topic */ async delete(projectName, topicName) { const memoryFile = this.syncManager.getProjectFilePath(projectName, 'memory.md'); const topics = await this.loadTopicsFromFile(memoryFile); const filteredTopics = topics.filter(topic => topic.name !== topicName); if (filteredTopics.length === topics.length) return false; await this.saveTopicsToFile(memoryFile, filteredTopics); return true; } /** * Lists all memory topics for a project */ async list(projectName) { const memoryFile = this.syncManager.getProjectFilePath(projectName, 'memory.md'); return await this.loadTopicsFromFile(memoryFile); } // ========== OPERAÇÕES MÚLTIPLAS v2.0 ========== /** * Creates multiple memory topics at once */ async createMultiple(projectName, topics) { await this.syncManager.ensureProjectStructure(projectName); const memoryFile = this.syncManager.getProjectFilePath(projectName, 'memory.md'); const existingTopics = await this.loadTopicsFromFile(memoryFile); const createdTopics = []; for (const topicData of topics) { const topic = { name: topicData.topicName, description: topicData.description, content: topicData.content, created: Date.now(), modified: Date.now(), tags: topicData.tags || [], importance: topicData.importance || 5 }; existingTopics.push(topic); createdTopics.push(topic); } await this.saveTopicsToFile(memoryFile, existingTopics); return createdTopics; } /** * Reads multiple memory topics at once */ async readMultiple(projectName, topicNames) { const memoryFile = this.syncManager.getProjectFilePath(projectName, 'memory.md'); const topics = await this.loadTopicsFromFile(memoryFile); return topicNames.map(topicName => topics.find(topic => topic.name === topicName) || null); } /** * Updates multiple memory topics at once */ async updateMultiple(projectName, updates) { const memoryFile = this.syncManager.getProjectFilePath(projectName, 'memory.md'); const topics = await this.loadTopicsFromFile(memoryFile); const updatedTopics = []; for (const updateData of updates) { const topicIndex = topics.findIndex(topic => topic.name === updateData.topicName); if (topicIndex !== -1) { const updatedTopic = { ...topics[topicIndex], ...updateData.updates, modified: Date.now() }; topics[topicIndex] = updatedTopic; updatedTopics.push(updatedTopic); } else { updatedTopics.push(null); } } await this.saveTopicsToFile(memoryFile, topics); return updatedTopics; } /** * Deletes multiple memory topics at once */ async deleteMultiple(projectName, topicNames) { const memoryFile = this.syncManager.getProjectFilePath(projectName, 'memory.md'); const topics = await this.loadTopicsFromFile(memoryFile); const results = []; for (const topicName of topicNames) { const initialLength = topics.length; const filteredTopics = topics.filter(topic => topic.name !== topicName); if (filteredTopics.length < initialLength) { results.push(true); // Update the topics array for next iteration topics.splice(0, topics.length, ...filteredTopics); } else { results.push(false); } } await this.saveTopicsToFile(memoryFile, topics); return results; } /** * Adds a topic to the memory.md file */ async addTopicToFile(filePath, topic) { const topics = await this.loadTopicsFromFile(filePath); // Remove existing topic with same name if exists const filteredTopics = topics.filter(t => t.name !== topic.name); filteredTopics.push(topic); await this.saveTopicsToFile(filePath, filteredTopics); } /** * Loads topics from memory.md file */ async loadTopicsFromFile(filePath) { try { const content = await fs.readFile(filePath, 'utf8'); const topics = []; // Parse markdown content to extract topics const lines = content.split('\n'); let currentTopic = null; let inTopicsSection = false; let inContent = false; let contentLines = []; for (const line of lines) { if (line.startsWith('## Tópicos')) { inTopicsSection = true; continue; } if (inTopicsSection && line.startsWith('---')) { // Save last topic if exists if (currentTopic && currentTopic.name) { currentTopic.content = contentLines.join('\n').trim(); topics.push(currentTopic); } break; } if (inTopicsSection && line.startsWith('### ')) { // Save previous topic if exists if (currentTopic && currentTopic.name) { currentTopic.content = contentLines.join('\n').trim(); topics.push(currentTopic); } // Start new topic const topicMatch = line.match(/### (.+) - (.+)/); if (topicMatch && topicMatch[1] && topicMatch[2]) { currentTopic = { name: topicMatch[1], description: topicMatch[2] }; contentLines = []; inContent = false; } } if (currentTopic && inTopicsSection) { if (line.startsWith('**Importância:**')) { currentTopic.importance = parseInt(line.replace('**Importância:**', '').trim()); } else if (line.startsWith('**Tags:**')) { const tagsStr = line.replace('**Tags:**', '').trim(); currentTopic.tags = tagsStr ? tagsStr.split(', ') : []; } else if (line.startsWith('**Criado:**')) { currentTopic.created = parseInt(line.replace('**Criado:**', '').trim()); } else if (line.startsWith('**Modificado:**')) { currentTopic.modified = parseInt(line.replace('**Modificado:**', '').trim()); } else if (line.startsWith('**Conteúdo:**')) { inContent = true; } else if (inContent && !line.startsWith('**') && !line.startsWith('###')) { contentLines.push(line); } } } // Save last topic if exists if (currentTopic && currentTopic.name) { currentTopic.content = contentLines.join('\n').trim(); topics.push(currentTopic); } return topics; } catch { return []; } } /** * Saves topics to memory.md file */ async saveTopicsToFile(filePath, topics) { try { const content = await fs.readFile(filePath, 'utf8'); const lines = content.split('\n'); // Find the topics section const topicsIndex = lines.findIndex(line => line.startsWith('## Tópicos')); const endIndex = lines.findIndex((line, index) => index > topicsIndex && line.startsWith('---')); if (topicsIndex === -1) return; // Build new topics section const newTopicsSection = ['## Tópicos', '']; if (topics.length === 0) { newTopicsSection.push('<!-- Nenhum tópico criado ainda -->', ''); } else { // Sort topics by importance (descending) const sortedTopics = topics.sort((a, b) => b.importance - a.importance); for (const topic of sortedTopics) { newTopicsSection.push(`### ${topic.name} - ${topic.description}`, `**Importância:** ${topic.importance}`, `**Tags:** ${topic.tags.join(', ')}`, `**Criado:** ${topic.created}`, `**Modificado:** ${topic.modified}`, `**Conteúdo:**`, topic.content, ''); } } // Replace the topics section const newLines = [ ...lines.slice(0, topicsIndex), ...newTopicsSection, ...lines.slice(endIndex) ]; await fs.writeFile(filePath, newLines.join('\n'), 'utf8'); } catch (error) { console.error('Error saving topics to file:', error); } } } //# sourceMappingURL=new-memory-manager.js.map