@grec0/memory-bank-mcp 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -3
- package/dist/common/projectKnowledgeService.js +75 -53
- package/dist/index.js +40 -20
- package/dist/tools/analyzeCoverage.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -905,7 +905,7 @@ npm test -- --coverage
|
|
|
905
905
|
1. **Aumenta `minScore`**: Usa 0.8 o 0.9 para resultados más precisos
|
|
906
906
|
2. **Usa filtros**: `filterByFile` o `filterByLanguage`
|
|
907
907
|
3. **Reformula la query**: Sé más específico y descriptivo
|
|
908
|
-
4. **Reindexa**: `memorybank_index_code({
|
|
908
|
+
4. **Reindexa**: `memorybank_index_code({ path: "..." })` (detecta cambios automáticamente por hash)
|
|
909
909
|
|
|
910
910
|
### Error: "projectId is required"
|
|
911
911
|
|
|
@@ -917,15 +917,17 @@ npm test -- --coverage
|
|
|
917
917
|
memorybank_get_stats({})
|
|
918
918
|
```
|
|
919
919
|
|
|
920
|
-
Si `pendingFiles` muestra archivos pendientes:
|
|
920
|
+
Si `pendingFiles` muestra archivos pendientes, reindexa el directorio:
|
|
921
921
|
|
|
922
922
|
```json
|
|
923
923
|
{
|
|
924
924
|
"projectId": "my-project",
|
|
925
|
-
"
|
|
925
|
+
"path": "C:/workspaces/mi-proyecto/src"
|
|
926
926
|
}
|
|
927
927
|
```
|
|
928
928
|
|
|
929
|
+
El sistema detecta cambios por hash automáticamente. Solo usa `forceReindex: true` si necesitas regenerar embeddings aunque no haya cambios.
|
|
930
|
+
|
|
929
931
|
---
|
|
930
932
|
|
|
931
933
|
## 📖 Documentación Adicional
|
|
@@ -362,7 +362,7 @@ ${chunk.content}
|
|
|
362
362
|
return doc;
|
|
363
363
|
}
|
|
364
364
|
/**
|
|
365
|
-
* Generates all project documents
|
|
365
|
+
* Generates all project documents (in parallel for speed)
|
|
366
366
|
*/
|
|
367
367
|
async generateAllDocuments(chunks, force = false) {
|
|
368
368
|
const result = {
|
|
@@ -374,54 +374,65 @@ ${chunk.content}
|
|
|
374
374
|
totalOutputTokens: 0,
|
|
375
375
|
errors: [],
|
|
376
376
|
};
|
|
377
|
-
// Get previous progress if exists
|
|
377
|
+
// Get previous progress if exists (read before parallel generation)
|
|
378
378
|
let previousProgress;
|
|
379
379
|
const progressPath = path.join(this.options.docsPath, "progress.md");
|
|
380
380
|
if (fs.existsSync(progressPath)) {
|
|
381
381
|
previousProgress = fs.readFileSync(progressPath, "utf-8");
|
|
382
382
|
}
|
|
383
|
-
//
|
|
384
|
-
const
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
"
|
|
390
|
-
"
|
|
383
|
+
// Prepare chunks for activeContext (recent only)
|
|
384
|
+
const recentChunks = [...chunks]
|
|
385
|
+
.sort((a, b) => b.timestamp - a.timestamp)
|
|
386
|
+
.slice(0, Math.min(30, chunks.length));
|
|
387
|
+
// All document types to generate
|
|
388
|
+
const docTypes = [
|
|
389
|
+
"techContext",
|
|
390
|
+
"projectBrief",
|
|
391
|
+
"systemPatterns",
|
|
392
|
+
"productContext",
|
|
393
|
+
"activeContext",
|
|
394
|
+
"progress",
|
|
391
395
|
];
|
|
392
|
-
|
|
396
|
+
console.error(`\n🚀 Generating ${docTypes.length} documents in PARALLEL...`);
|
|
397
|
+
// Generate all documents in parallel
|
|
398
|
+
const generationPromises = docTypes.map(async (docType) => {
|
|
393
399
|
try {
|
|
394
|
-
// For activeContext, use only recent chunks
|
|
395
|
-
|
|
396
|
-
if (docType === "activeContext") {
|
|
397
|
-
// Sort by timestamp and take most recent
|
|
398
|
-
docChunks = [...chunks]
|
|
399
|
-
.sort((a, b) => b.timestamp - a.timestamp)
|
|
400
|
-
.slice(0, Math.min(30, chunks.length));
|
|
401
|
-
}
|
|
400
|
+
// For activeContext, use only recent chunks
|
|
401
|
+
const docChunks = docType === "activeContext" ? recentChunks : chunks;
|
|
402
402
|
const existingMetadata = this.metadataCache.get(docType);
|
|
403
403
|
const isNew = !existingMetadata;
|
|
404
404
|
const doc = await this.generateDocument(docType, docChunks, force, docType === "progress" ? previousProgress : undefined);
|
|
405
|
-
|
|
406
|
-
result.totalReasoningTokens += doc.metadata.reasoningTokens;
|
|
407
|
-
result.totalOutputTokens += doc.metadata.outputTokens;
|
|
408
|
-
if (isNew) {
|
|
409
|
-
result.documentsGenerated.push(docType);
|
|
410
|
-
}
|
|
411
|
-
else {
|
|
412
|
-
result.documentsUpdated.push(docType);
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
else {
|
|
416
|
-
result.documentsSkipped.push(docType);
|
|
417
|
-
}
|
|
405
|
+
return { docType, doc, isNew, error: null };
|
|
418
406
|
}
|
|
419
407
|
catch (error) {
|
|
408
|
+
return { docType, doc: null, isNew: false, error: error };
|
|
409
|
+
}
|
|
410
|
+
});
|
|
411
|
+
// Wait for all documents to complete
|
|
412
|
+
const results = await Promise.all(generationPromises);
|
|
413
|
+
// Process results
|
|
414
|
+
for (const { docType, doc, isNew, error } of results) {
|
|
415
|
+
if (error) {
|
|
420
416
|
console.error(`Error generating ${docType}: ${error.message}`);
|
|
421
417
|
result.errors.push(`${docType}: ${error.message}`);
|
|
422
418
|
result.success = false;
|
|
419
|
+
continue;
|
|
420
|
+
}
|
|
421
|
+
if (doc) {
|
|
422
|
+
result.totalReasoningTokens += doc.metadata.reasoningTokens;
|
|
423
|
+
result.totalOutputTokens += doc.metadata.outputTokens;
|
|
424
|
+
if (isNew) {
|
|
425
|
+
result.documentsGenerated.push(docType);
|
|
426
|
+
}
|
|
427
|
+
else {
|
|
428
|
+
result.documentsUpdated.push(docType);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
else {
|
|
432
|
+
result.documentsSkipped.push(docType);
|
|
423
433
|
}
|
|
424
434
|
}
|
|
435
|
+
console.error(`\n✅ Parallel generation complete: ${result.documentsGenerated.length + result.documentsUpdated.length} docs, ${result.totalReasoningTokens} reasoning + ${result.totalOutputTokens} output tokens`);
|
|
425
436
|
return result;
|
|
426
437
|
}
|
|
427
438
|
/**
|
|
@@ -462,42 +473,53 @@ ${chunk.content}
|
|
|
462
473
|
totalOutputTokens: 0,
|
|
463
474
|
errors: [],
|
|
464
475
|
};
|
|
465
|
-
// Get previous progress
|
|
476
|
+
// Get previous progress (read before parallel generation)
|
|
466
477
|
let previousProgress;
|
|
467
478
|
const progressPath = path.join(this.options.docsPath, "progress.md");
|
|
468
479
|
if (fs.existsSync(progressPath)) {
|
|
469
480
|
previousProgress = fs.readFileSync(progressPath, "utf-8");
|
|
470
481
|
}
|
|
471
|
-
|
|
482
|
+
// Prepare recent chunks for activeContext
|
|
483
|
+
const recentChunks = [...chunks]
|
|
484
|
+
.sort((a, b) => b.timestamp - a.timestamp)
|
|
485
|
+
.slice(0, Math.min(30, chunks.length));
|
|
486
|
+
console.error(`\n🚀 Updating ${docsToUpdate.length} documents in PARALLEL...`);
|
|
487
|
+
// Generate docs in parallel
|
|
488
|
+
const updatePromises = docsToUpdate.map(async (docType) => {
|
|
472
489
|
try {
|
|
473
|
-
|
|
474
|
-
if (docType === "activeContext") {
|
|
475
|
-
docChunks = [...chunks]
|
|
476
|
-
.sort((a, b) => b.timestamp - a.timestamp)
|
|
477
|
-
.slice(0, Math.min(30, chunks.length));
|
|
478
|
-
}
|
|
490
|
+
const docChunks = docType === "activeContext" ? recentChunks : chunks;
|
|
479
491
|
const existingMetadata = this.metadataCache.get(docType);
|
|
480
492
|
const isNew = !existingMetadata;
|
|
481
493
|
const doc = await this.generateDocument(docType, docChunks, true, // Force update for changed docs
|
|
482
494
|
docType === "progress" ? previousProgress : undefined);
|
|
483
|
-
|
|
484
|
-
result.totalReasoningTokens += doc.metadata.reasoningTokens;
|
|
485
|
-
result.totalOutputTokens += doc.metadata.outputTokens;
|
|
486
|
-
if (isNew) {
|
|
487
|
-
result.documentsGenerated.push(docType);
|
|
488
|
-
}
|
|
489
|
-
else {
|
|
490
|
-
result.documentsUpdated.push(docType);
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
else {
|
|
494
|
-
result.documentsSkipped.push(docType);
|
|
495
|
-
}
|
|
495
|
+
return { docType, doc, isNew, error: null };
|
|
496
496
|
}
|
|
497
497
|
catch (error) {
|
|
498
|
+
return { docType, doc: null, isNew: false, error: error };
|
|
499
|
+
}
|
|
500
|
+
});
|
|
501
|
+
// Wait for all
|
|
502
|
+
const updateResults = await Promise.all(updatePromises);
|
|
503
|
+
// Process results
|
|
504
|
+
for (const { docType, doc, isNew, error } of updateResults) {
|
|
505
|
+
if (error) {
|
|
498
506
|
console.error(`Error updating ${docType}: ${error.message}`);
|
|
499
507
|
result.errors.push(`${docType}: ${error.message}`);
|
|
500
508
|
result.success = false;
|
|
509
|
+
continue;
|
|
510
|
+
}
|
|
511
|
+
if (doc) {
|
|
512
|
+
result.totalReasoningTokens += doc.metadata.reasoningTokens;
|
|
513
|
+
result.totalOutputTokens += doc.metadata.outputTokens;
|
|
514
|
+
if (isNew) {
|
|
515
|
+
result.documentsGenerated.push(docType);
|
|
516
|
+
}
|
|
517
|
+
else {
|
|
518
|
+
result.documentsUpdated.push(docType);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
else {
|
|
522
|
+
result.documentsSkipped.push(docType);
|
|
501
523
|
}
|
|
502
524
|
}
|
|
503
525
|
// Mark docs we didn't update as skipped
|
package/dist/index.js
CHANGED
|
@@ -38,24 +38,31 @@ const server = new McpServer({
|
|
|
38
38
|
version: VERSION,
|
|
39
39
|
});
|
|
40
40
|
// Tool: Index Code
|
|
41
|
-
server.tool("memorybank_index_code",
|
|
41
|
+
server.tool("memorybank_index_code", `Indexa semánticamente código de un DIRECTORIO para búsquedas semánticas.
|
|
42
|
+
|
|
43
|
+
⚠️ IMPORTANTE:
|
|
44
|
+
- El path debe ser una RUTA ABSOLUTA a un DIRECTORIO (no archivo)
|
|
45
|
+
- Ejemplo correcto: "C:/workspaces/mi-proyecto/src/components"
|
|
46
|
+
- Ejemplo incorrecto: "src/components" (ruta relativa)
|
|
47
|
+
- Ejemplo incorrecto: "C:/workspaces/mi-proyecto/src/file.ts" (archivo, no directorio)
|
|
48
|
+
|
|
49
|
+
Si quieres indexar un archivo específico, usa el directorio que lo contiene.`, {
|
|
42
50
|
projectId: z
|
|
43
51
|
.string()
|
|
44
|
-
.describe("Identificador único del proyecto (OBLIGATORIO). Debe coincidir con el definido en AGENTS.md
|
|
52
|
+
.describe("Identificador único del proyecto (OBLIGATORIO). Debe coincidir con el definido en AGENTS.md"),
|
|
45
53
|
path: z
|
|
46
54
|
.string()
|
|
47
|
-
.
|
|
48
|
-
.describe("Ruta relativa o absoluta del directorio/archivo a indexar (por defecto: raíz del workspace)"),
|
|
55
|
+
.describe("RUTA ABSOLUTA al DIRECTORIO a indexar. Ejemplo: 'C:/workspaces/proyecto/src'. NO usar rutas relativas. NO usar rutas a archivos."),
|
|
49
56
|
recursive: z
|
|
50
57
|
.boolean()
|
|
51
58
|
.optional()
|
|
52
59
|
.default(true)
|
|
53
|
-
.describe("Indexar recursivamente subdirectorios"),
|
|
60
|
+
.describe("Indexar recursivamente subdirectorios (default: true)"),
|
|
54
61
|
forceReindex: z
|
|
55
62
|
.boolean()
|
|
56
63
|
.optional()
|
|
57
64
|
.default(false)
|
|
58
|
-
.describe("
|
|
65
|
+
.describe("RARAMENTE NECESARIO. El sistema detecta cambios por hash automáticamente. Solo usa true si necesitas regenerar embeddings sin cambios en archivos."),
|
|
59
66
|
}, async (args) => {
|
|
60
67
|
const result = await indexCode({
|
|
61
68
|
projectId: args.projectId,
|
|
@@ -107,18 +114,21 @@ server.tool("memorybank_search", "Busca código relevante mediante búsqueda sem
|
|
|
107
114
|
};
|
|
108
115
|
});
|
|
109
116
|
// Tool: Read File
|
|
110
|
-
server.tool("memorybank_read_file",
|
|
117
|
+
server.tool("memorybank_read_file", `Lee el contenido de un archivo específico. Usa para obtener contexto adicional.
|
|
118
|
+
|
|
119
|
+
⚠️ Preferir RUTA ABSOLUTA para evitar errores.
|
|
120
|
+
Ejemplo: "C:/workspaces/proyecto/src/index.ts"`, {
|
|
111
121
|
path: z
|
|
112
122
|
.string()
|
|
113
|
-
.describe("Ruta
|
|
123
|
+
.describe("Ruta al archivo. Preferir ABSOLUTA: 'C:/workspaces/proyecto/src/file.ts'"),
|
|
114
124
|
startLine: z
|
|
115
125
|
.number()
|
|
116
126
|
.optional()
|
|
117
|
-
.describe("Línea inicial
|
|
127
|
+
.describe("Línea inicial (opcional)"),
|
|
118
128
|
endLine: z
|
|
119
129
|
.number()
|
|
120
130
|
.optional()
|
|
121
|
-
.describe("Línea final
|
|
131
|
+
.describe("Línea final (opcional)"),
|
|
122
132
|
}, async (args) => {
|
|
123
133
|
const result = await readFile({
|
|
124
134
|
path: args.path,
|
|
@@ -130,21 +140,24 @@ server.tool("memorybank_read_file", "Lee el contenido de un archivo específico
|
|
|
130
140
|
};
|
|
131
141
|
});
|
|
132
142
|
// Tool: Write File
|
|
133
|
-
server.tool("memorybank_write_file",
|
|
143
|
+
server.tool("memorybank_write_file", `Escribe un archivo y automáticamente lo reindexa en el Memory Bank.
|
|
144
|
+
|
|
145
|
+
⚠️ Preferir RUTA ABSOLUTA para evitar errores.
|
|
146
|
+
Ejemplo path: "C:/workspaces/proyecto/src/nuevo.ts"`, {
|
|
134
147
|
projectId: z
|
|
135
148
|
.string()
|
|
136
|
-
.describe("Identificador del proyecto (OBLIGATORIO)
|
|
149
|
+
.describe("Identificador del proyecto (OBLIGATORIO)"),
|
|
137
150
|
path: z
|
|
138
151
|
.string()
|
|
139
|
-
.describe("Ruta
|
|
152
|
+
.describe("Ruta al archivo. Preferir ABSOLUTA: 'C:/workspaces/proyecto/src/file.ts'"),
|
|
140
153
|
content: z
|
|
141
154
|
.string()
|
|
142
|
-
.describe("Contenido
|
|
155
|
+
.describe("Contenido COMPLETO del archivo"),
|
|
143
156
|
autoReindex: z
|
|
144
157
|
.boolean()
|
|
145
158
|
.optional()
|
|
146
159
|
.default(true)
|
|
147
|
-
.describe("
|
|
160
|
+
.describe("Auto-reindexar después de escribir (default: true)"),
|
|
148
161
|
}, async (args) => {
|
|
149
162
|
const result = await writeFile({
|
|
150
163
|
projectId: args.projectId,
|
|
@@ -164,13 +177,18 @@ server.tool("memorybank_get_stats", "Obtiene estadísticas del Memory Bank: arch
|
|
|
164
177
|
};
|
|
165
178
|
});
|
|
166
179
|
// Tool: Analyze Coverage
|
|
167
|
-
server.tool("memorybank_analyze_coverage",
|
|
180
|
+
server.tool("memorybank_analyze_coverage", `Analiza la cobertura de indexación del proyecto.
|
|
181
|
+
|
|
182
|
+
⚠️ IMPORTANTE:
|
|
183
|
+
- path debe ser RUTA ABSOLUTA al DIRECTORIO raíz del workspace
|
|
184
|
+
- Ejemplo: "C:/workspaces/mi-proyecto" (NO rutas relativas)
|
|
185
|
+
- Puede tardar en workspaces grandes`, {
|
|
168
186
|
projectId: z
|
|
169
187
|
.string()
|
|
170
|
-
.describe("Identificador del proyecto
|
|
188
|
+
.describe("Identificador del proyecto (OBLIGATORIO)"),
|
|
171
189
|
path: z
|
|
172
190
|
.string()
|
|
173
|
-
.describe("
|
|
191
|
+
.describe("RUTA ABSOLUTA al directorio raíz del workspace. Ejemplo: 'C:/workspaces/mi-proyecto'"),
|
|
174
192
|
}, async (args) => {
|
|
175
193
|
try {
|
|
176
194
|
const targetPath = args.path;
|
|
@@ -261,13 +279,15 @@ server.tool(getProjectDocsToolDefinition.name, getProjectDocsToolDefinition.desc
|
|
|
261
279
|
// Context Management Tools (Cline-style)
|
|
262
280
|
// ==========================================
|
|
263
281
|
// Tool: Initialize Memory Bank
|
|
264
|
-
server.tool(initializeMemoryBankToolDefinition.name, initializeMemoryBankToolDefinition.description
|
|
282
|
+
server.tool(initializeMemoryBankToolDefinition.name, initializeMemoryBankToolDefinition.description + `
|
|
283
|
+
|
|
284
|
+
⚠️ projectPath debe ser RUTA ABSOLUTA. Ejemplo: "C:/workspaces/mi-proyecto"`, {
|
|
265
285
|
projectId: z
|
|
266
286
|
.string()
|
|
267
287
|
.describe("Identificador único del proyecto (OBLIGATORIO)"),
|
|
268
288
|
projectPath: z
|
|
269
289
|
.string()
|
|
270
|
-
.describe("
|
|
290
|
+
.describe("RUTA ABSOLUTA al proyecto. Ejemplo: 'C:/workspaces/mi-proyecto'"),
|
|
271
291
|
projectName: z
|
|
272
292
|
.string()
|
|
273
293
|
.optional()
|
|
@@ -177,7 +177,7 @@ function generateRecommendations(stats, tree) {
|
|
|
177
177
|
}
|
|
178
178
|
// Pending reindex
|
|
179
179
|
if (stats.pendingReindexFiles > 0) {
|
|
180
|
-
recommendations.push(`🔄 Hay ${stats.pendingReindexFiles} archivo(s) con cambios pendientes
|
|
180
|
+
recommendations.push(`🔄 Hay ${stats.pendingReindexFiles} archivo(s) con cambios pendientes. Ejecuta memorybank_index_code con el path del directorio - los cambios se detectan automáticamente por hash.`);
|
|
181
181
|
}
|
|
182
182
|
// Language-specific recommendations
|
|
183
183
|
const unindexedLanguages = Object.entries(stats.languageBreakdown)
|