@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 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({ forceReindex: true })`
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
- "forceReindex": true
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
- // Define generation order (some docs may depend on others conceptually)
384
- const docOrder = [
385
- "techContext", // Foundation - understand the tech stack first
386
- "projectBrief", // High-level overview
387
- "systemPatterns", // Architecture
388
- "productContext", // Business/user perspective
389
- "activeContext", // Current state
390
- "progress", // Progress tracking (last, uses previous data)
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
- for (const docType of docOrder) {
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 (by timestamp)
395
- let docChunks = chunks;
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
- if (doc) {
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
- for (const docType of docsToUpdate) {
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
- let docChunks = chunks;
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
- if (doc) {
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", "Indexa semánticamente código de un directorio o archivo específico para permitir búsquedas semánticas. El projectId es OBLIGATORIO y debe coincidir con el definido en AGENTS.md", {
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 del proyecto"),
52
+ .describe("Identificador único del proyecto (OBLIGATORIO). Debe coincidir con el definido en AGENTS.md"),
45
53
  path: z
46
54
  .string()
47
- .optional()
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("Forzar reindexación completa aunque no haya cambios"),
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", "Lee el contenido de un archivo específico del workspace. Usa esta herramienta para obtener contexto adicional cuando los fragmentos de búsqueda no son suficientes", {
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 relativa o absoluta del archivo a leer"),
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 para leer un rango específico (opcional)"),
127
+ .describe("Línea inicial (opcional)"),
118
128
  endLine: z
119
129
  .number()
120
130
  .optional()
121
- .describe("Línea final para leer un rango específico (opcional)"),
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", "Escribe o modifica un archivo y automáticamente lo reindexa en el Memory Bank para mantener la consistencia. El projectId es OBLIGATORIO para la reindexación correcta", {
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). Necesario para la auto-reindexación correcta"),
149
+ .describe("Identificador del proyecto (OBLIGATORIO)"),
137
150
  path: z
138
151
  .string()
139
- .describe("Ruta relativa o absoluta del archivo a escribir"),
152
+ .describe("Ruta al archivo. Preferir ABSOLUTA: 'C:/workspaces/proyecto/src/file.ts'"),
140
153
  content: z
141
154
  .string()
142
- .describe("Contenido completo del archivo a escribir"),
155
+ .describe("Contenido COMPLETO del archivo"),
143
156
  autoReindex: z
144
157
  .boolean()
145
158
  .optional()
146
159
  .default(true)
147
- .describe("Reindexar automáticamente el archivo después de escribirlo"),
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", "Analiza la cobertura de indexación del proyecto. Muestra qué carpetas/archivos están indexados, cuáles no, y cuáles tienen cambios pendientes. OBLIGATORIO: projectId y path (ruta absoluta del workspace). NOTA: Puede tardar en workspaces grandes", {
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 a analizar (OBLIGATORIO)"),
188
+ .describe("Identificador del proyecto (OBLIGATORIO)"),
171
189
  path: z
172
190
  .string()
173
- .describe("Ruta absoluta del workspace a analizar (OBLIGATORIO). Ejemplo: 'C:/workspaces/mi-proyecto'"),
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("Ruta absoluta del proyecto"),
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 de reindexación. Ejecuta memorybank_index_code({ forceReindex: true })`);
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)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grec0/memory-bank-mcp",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "MCP server for semantic code indexing with Memory Bank - AI-powered codebase understanding",
5
5
  "license": "MIT",
6
6
  "author": "@grec0",