@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
JavaScript
/**
* 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