@grec0/memory-bank-mcp 0.0.4 → 0.0.6
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 +178 -30
- package/dist/common/indexManager.js +53 -9
- package/dist/index.js +32 -9
- package/dist/tools/analyzeCoverage.js +4 -1
- package/dist/tools/indexCode.js +4 -1
- package/dist/tools/searchMemory.js +2 -0
- package/dist/tools/writeFile.js +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -153,18 +153,25 @@ Edita tu archivo de configuración de Claude Desktop:
|
|
|
153
153
|
|
|
154
154
|
## 📚 Herramientas Disponibles
|
|
155
155
|
|
|
156
|
+
> **⚠️ IMPORTANTE**: Todas las herramientas requieren `projectId` obligatorio. Este ID debe coincidir con el definido en tu archivo `AGENTS.md`.
|
|
157
|
+
|
|
156
158
|
### `memorybank_index_code`
|
|
157
159
|
|
|
158
160
|
Indexa código semánticamente para permitir búsquedas.
|
|
159
161
|
|
|
160
162
|
**Parámetros:**
|
|
163
|
+
- `projectId` **(REQUERIDO)**: Identificador único del proyecto
|
|
161
164
|
- `path` (opcional): Ruta relativa o absoluta (default: raíz del workspace)
|
|
162
165
|
- `recursive` (opcional): Indexar subdirectorios (default: true)
|
|
163
166
|
- `forceReindex` (opcional): Forzar reindexación completa (default: false)
|
|
164
167
|
|
|
165
168
|
**Ejemplo:**
|
|
166
|
-
```
|
|
167
|
-
|
|
169
|
+
```json
|
|
170
|
+
{
|
|
171
|
+
"projectId": "my-project",
|
|
172
|
+
"path": "src/auth",
|
|
173
|
+
"recursive": true
|
|
174
|
+
}
|
|
168
175
|
```
|
|
169
176
|
|
|
170
177
|
### `memorybank_search`
|
|
@@ -172,6 +179,7 @@ memorybank_index_code({ path: "src/auth", recursive: true })
|
|
|
172
179
|
Busca código por similitud semántica.
|
|
173
180
|
|
|
174
181
|
**Parámetros:**
|
|
182
|
+
- `projectId` **(REQUERIDO)**: Identificador del proyecto donde buscar
|
|
175
183
|
- `query` (requerido): Consulta en lenguaje natural
|
|
176
184
|
- `topK` (opcional): Número de resultados (default: 10)
|
|
177
185
|
- `minScore` (opcional): Score mínimo 0-1 (default: 0.4)
|
|
@@ -179,12 +187,13 @@ Busca código por similitud semántica.
|
|
|
179
187
|
- `filterByLanguage` (opcional): Filtrar por lenguaje
|
|
180
188
|
|
|
181
189
|
**Ejemplo:**
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
190
|
+
```json
|
|
191
|
+
{
|
|
192
|
+
"projectId": "my-project",
|
|
193
|
+
"query": "función que autentica usuarios con JWT",
|
|
194
|
+
"topK": 5,
|
|
195
|
+
"minScore": 0.8
|
|
196
|
+
}
|
|
188
197
|
```
|
|
189
198
|
|
|
190
199
|
### `memorybank_read_file`
|
|
@@ -206,16 +215,18 @@ memorybank_read_file({ path: "src/auth/service.ts", startLine: 50, endLine: 100
|
|
|
206
215
|
Escribe un archivo y lo reindexa automáticamente.
|
|
207
216
|
|
|
208
217
|
**Parámetros:**
|
|
218
|
+
- `projectId` **(REQUERIDO)**: Identificador del proyecto para reindexación
|
|
209
219
|
- `path` (requerido): Ruta del archivo
|
|
210
220
|
- `content` (requerido): Contenido del archivo
|
|
211
221
|
- `autoReindex` (opcional): Auto-reindexar (default: true)
|
|
212
222
|
|
|
213
223
|
**Ejemplo:**
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
}
|
|
224
|
+
```json
|
|
225
|
+
{
|
|
226
|
+
"projectId": "my-project",
|
|
227
|
+
"path": "src/utils/validator.ts",
|
|
228
|
+
"content": "export function validateEmail(email: string) { ... }"
|
|
229
|
+
}
|
|
219
230
|
```
|
|
220
231
|
|
|
221
232
|
### `memorybank_get_stats`
|
|
@@ -231,9 +242,15 @@ memorybank_get_stats({})
|
|
|
231
242
|
|
|
232
243
|
Analiza la cobertura de indexación del proyecto.
|
|
233
244
|
|
|
245
|
+
**Parámetros:**
|
|
246
|
+
- `projectId` **(REQUERIDO)**: Identificador del proyecto a analizar
|
|
247
|
+
- `path` (opcional): Ruta específica a analizar
|
|
248
|
+
|
|
234
249
|
**Ejemplo:**
|
|
235
|
-
```
|
|
236
|
-
|
|
250
|
+
```json
|
|
251
|
+
{
|
|
252
|
+
"projectId": "my-project"
|
|
253
|
+
}
|
|
237
254
|
```
|
|
238
255
|
|
|
239
256
|
### `memorybank_generate_project_docs` 🆕
|
|
@@ -241,12 +258,15 @@ memorybank_analyze_coverage({})
|
|
|
241
258
|
Genera documentación estructurada del proyecto usando IA con razonamiento (gpt-5-mini).
|
|
242
259
|
|
|
243
260
|
**Parámetros:**
|
|
244
|
-
- `projectId` (
|
|
261
|
+
- `projectId` **(REQUERIDO)**: Identificador del proyecto
|
|
245
262
|
- `force` (opcional): Forzar regeneración (default: false)
|
|
246
263
|
|
|
247
264
|
**Ejemplo:**
|
|
248
|
-
```
|
|
249
|
-
|
|
265
|
+
```json
|
|
266
|
+
{
|
|
267
|
+
"projectId": "my-project",
|
|
268
|
+
"force": true
|
|
269
|
+
}
|
|
250
270
|
```
|
|
251
271
|
|
|
252
272
|
Genera 6 documentos markdown:
|
|
@@ -262,16 +282,119 @@ Genera 6 documentos markdown:
|
|
|
262
282
|
Lee la documentación del proyecto generada por IA.
|
|
263
283
|
|
|
264
284
|
**Parámetros:**
|
|
285
|
+
- `projectId` **(REQUERIDO)**: Identificador del proyecto
|
|
265
286
|
- `document` (opcional): Documento específico o "all"/"summary" (default: "summary")
|
|
266
287
|
- `format` (opcional): "full" o "summary" (default: "full")
|
|
267
288
|
|
|
268
289
|
**Ejemplo:**
|
|
269
|
-
```
|
|
290
|
+
```json
|
|
270
291
|
// Obtener resumen de todos los docs
|
|
271
|
-
|
|
292
|
+
{
|
|
293
|
+
"projectId": "my-project",
|
|
294
|
+
"document": "summary"
|
|
295
|
+
}
|
|
272
296
|
|
|
273
297
|
// Obtener documento específico
|
|
274
|
-
|
|
298
|
+
{
|
|
299
|
+
"projectId": "my-project",
|
|
300
|
+
"document": "systemPatterns"
|
|
301
|
+
}
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
## 📋 Plantillas de Instrucciones para Agentes
|
|
305
|
+
|
|
306
|
+
Memory Bank incluye plantillas de instrucciones en dos formatos:
|
|
307
|
+
- **AGENTS.md** - Estándar [agents.md](https://agents.md/) (compatible con múltiples agentes)
|
|
308
|
+
- **VSCode/Copilot** - Formato `.github/copilot-instructions.md` para VS Code
|
|
309
|
+
|
|
310
|
+
### Instalación - Formato AGENTS.md
|
|
311
|
+
|
|
312
|
+
Copia la plantilla que prefieras a la raíz de tu proyecto:
|
|
313
|
+
|
|
314
|
+
```bash
|
|
315
|
+
# Elegir una plantilla
|
|
316
|
+
cp node_modules/@grec0/memory-bank-mcp/templates/AGENTS.basic.md ./AGENTS.md
|
|
317
|
+
|
|
318
|
+
# Editar los placeholders
|
|
319
|
+
# Reemplaza {{PROJECT_ID}} con tu ID de proyecto
|
|
320
|
+
# Reemplaza {{WORKSPACE_PATH}} con la ruta del workspace
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### Instalación - Formato VS Code
|
|
324
|
+
|
|
325
|
+
Para VS Code con GitHub Copilot, usa el formato `copilot-instructions.md`:
|
|
326
|
+
|
|
327
|
+
```bash
|
|
328
|
+
# Crear carpeta .github si no existe
|
|
329
|
+
mkdir -p .github
|
|
330
|
+
|
|
331
|
+
# Elegir una plantilla
|
|
332
|
+
cp node_modules/@grec0/memory-bank-mcp/templates/vscode/copilot-instructions.basic.md ./.github/copilot-instructions.md
|
|
333
|
+
|
|
334
|
+
# Habilitar en VS Code settings.json:
|
|
335
|
+
# "github.copilot.chat.codeGeneration.useInstructionFiles": true
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
También puedes usar el archivo `.instructions.md` con aplicación condicional:
|
|
339
|
+
|
|
340
|
+
```bash
|
|
341
|
+
# Crear carpeta de instrucciones
|
|
342
|
+
mkdir -p .github/instructions
|
|
343
|
+
|
|
344
|
+
# Copiar instrucciones base
|
|
345
|
+
cp node_modules/@grec0/memory-bank-mcp/templates/vscode/memory-bank.instructions.md ./.github/instructions/
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
### 1. Basic Mode (`AGENTS.basic.md`)
|
|
349
|
+
|
|
350
|
+
**Para proyectos donde quieres control total.**
|
|
351
|
+
|
|
352
|
+
- ✅ El agente SIEMPRE consulta el Memory Bank antes de actuar
|
|
353
|
+
- ✅ Solo indexa cuando el usuario lo solicita explícitamente
|
|
354
|
+
- ✅ Pide permiso antes de modificar código
|
|
355
|
+
- ✅ Sugiere reindexar después de cambios
|
|
356
|
+
|
|
357
|
+
**Ideal para**: Proyectos críticos, revisión de código, onboarding.
|
|
358
|
+
|
|
359
|
+
### 2. Auto-Index Mode (`AGENTS.auto-index.md`)
|
|
360
|
+
|
|
361
|
+
**Para desarrollo activo con sincronización automática.**
|
|
362
|
+
|
|
363
|
+
- ✅ El agente consulta el Memory Bank automáticamente
|
|
364
|
+
- ✅ Reindexa CADA archivo después de modificarlo
|
|
365
|
+
- ✅ Mantiene el Memory Bank siempre actualizado
|
|
366
|
+
- ✅ Puede leer/escribir archivos directamente
|
|
367
|
+
|
|
368
|
+
**Ideal para**: Desarrollo activo, iteración rápida, equipos.
|
|
369
|
+
|
|
370
|
+
### 3. Sandboxed Mode (`AGENTS.sandboxed.md`)
|
|
371
|
+
|
|
372
|
+
**Para entornos sin acceso directo al sistema de archivos.**
|
|
373
|
+
|
|
374
|
+
- ✅ NO tiene acceso directo a archivos
|
|
375
|
+
- ✅ DEBE usar `memorybank_read_file` para leer
|
|
376
|
+
- ✅ DEBE usar `memorybank_write_file` para escribir
|
|
377
|
+
- ✅ Auto-reindexa automáticamente en cada escritura
|
|
378
|
+
|
|
379
|
+
**Ideal para**: Entornos restringidos, desarrollo remoto, seguridad.
|
|
380
|
+
|
|
381
|
+
### Ejemplo de `AGENTS.md` Configurado
|
|
382
|
+
|
|
383
|
+
```markdown
|
|
384
|
+
# AGENTS.md
|
|
385
|
+
|
|
386
|
+
## Project Configuration
|
|
387
|
+
- **Project ID**: `my-awesome-app`
|
|
388
|
+
- **Workspace**: `/home/user/projects/my-awesome-app`
|
|
389
|
+
|
|
390
|
+
## Memory Bank Instructions
|
|
391
|
+
|
|
392
|
+
### CRITICAL: Always Consult Before Acting
|
|
393
|
+
Before any action, call `memorybank_search` with projectId="my-awesome-app"
|
|
394
|
+
|
|
395
|
+
### Auto-Indexing Policy
|
|
396
|
+
AFTER every file modification:
|
|
397
|
+
memorybank_index_code({ projectId: "my-awesome-app", path: "<modified_file>" })
|
|
275
398
|
```
|
|
276
399
|
|
|
277
400
|
## 🎯 Casos de Uso
|
|
@@ -279,13 +402,13 @@ memorybank_get_project_docs({ document: "systemPatterns" })
|
|
|
279
402
|
### 1. Primera Indexación
|
|
280
403
|
|
|
281
404
|
```
|
|
282
|
-
Usuario: Hola, quiero que me ayudes con mi proyecto
|
|
405
|
+
Usuario: Hola, quiero que me ayudes con mi proyecto. El projectId es "my-app"
|
|
283
406
|
Claude: [ejecuta memorybank_get_stats]
|
|
284
407
|
Veo que no hay código indexado aún.
|
|
285
408
|
¿Deseas que indexe el proyecto para poder ayudarte mejor?
|
|
286
409
|
|
|
287
410
|
Usuario: Sí
|
|
288
|
-
Claude: [ejecuta memorybank_index_code({})]
|
|
411
|
+
Claude: [ejecuta memorybank_index_code({ projectId: "my-app" })]
|
|
289
412
|
He indexado 145 archivos (1,234 chunks) en 45 segundos.
|
|
290
413
|
¿En qué puedo ayudarte?
|
|
291
414
|
```
|
|
@@ -294,7 +417,7 @@ Claude: [ejecuta memorybank_index_code({})]
|
|
|
294
417
|
|
|
295
418
|
```
|
|
296
419
|
Usuario: ¿Cómo funciona la autenticación en este proyecto?
|
|
297
|
-
Claude: [ejecuta memorybank_search({ query: "autenticación login usuarios" })]
|
|
420
|
+
Claude: [ejecuta memorybank_search({ projectId: "my-app", query: "autenticación login usuarios" })]
|
|
298
421
|
|
|
299
422
|
La autenticación se implementa en src/auth/authService.ts (líneas 23-87):
|
|
300
423
|
|
|
@@ -308,11 +431,11 @@ Claude: [ejecuta memorybank_search({ query: "autenticación login usuarios" })]
|
|
|
308
431
|
|
|
309
432
|
```
|
|
310
433
|
Usuario: Añade validación de email al formulario de registro
|
|
311
|
-
Claude: [busca formulario de registro]
|
|
312
|
-
[busca validadores existentes]
|
|
434
|
+
Claude: [busca formulario de registro con projectId]
|
|
435
|
+
[busca validadores existentes con projectId]
|
|
313
436
|
[lee archivo actual]
|
|
314
437
|
[genera código respetando estilo del proyecto]
|
|
315
|
-
[escribe archivo con memorybank_write_file]
|
|
438
|
+
[escribe archivo con memorybank_write_file({ projectId: "my-app", ... })]
|
|
316
439
|
|
|
317
440
|
He añadido la validación de email en src/forms/RegisterForm.tsx línea 45.
|
|
318
441
|
Usa el validador existente de emailValidator.ts para mantener consistencia.
|
|
@@ -440,16 +563,32 @@ El sistema maneja automáticamente rate limits con exponential backoff, pero si
|
|
|
440
563
|
|
|
441
564
|
### Índice desactualizado
|
|
442
565
|
|
|
443
|
-
```
|
|
566
|
+
```json
|
|
444
567
|
memorybank_get_stats({})
|
|
445
568
|
```
|
|
446
569
|
|
|
447
570
|
Si `pendingFiles` muestra archivos pendientes:
|
|
448
571
|
|
|
572
|
+
```json
|
|
573
|
+
{
|
|
574
|
+
"projectId": "my-project",
|
|
575
|
+
"forceReindex": true
|
|
576
|
+
}
|
|
449
577
|
```
|
|
450
|
-
|
|
578
|
+
|
|
579
|
+
### Error: "projectId is required"
|
|
580
|
+
|
|
581
|
+
**Solución**: Todas las herramientas requieren `projectId`. Asegúrate de incluirlo en cada llamada:
|
|
582
|
+
|
|
583
|
+
```json
|
|
584
|
+
{
|
|
585
|
+
"projectId": "my-project",
|
|
586
|
+
"query": "..."
|
|
587
|
+
}
|
|
451
588
|
```
|
|
452
589
|
|
|
590
|
+
Tip: Define el `projectId` en tu archivo `AGENTS.md` para que el agente lo use consistentemente.
|
|
591
|
+
|
|
453
592
|
## 🤝 Contribución
|
|
454
593
|
|
|
455
594
|
¡Contribuciones son bienvenidas!
|
|
@@ -462,7 +601,16 @@ memorybank_index_code({ forceReindex: true })
|
|
|
462
601
|
|
|
463
602
|
## 📖 Documentación Adicional
|
|
464
603
|
|
|
465
|
-
- [
|
|
604
|
+
- [templates/](templates/): Plantillas de instrucciones para agentes
|
|
605
|
+
- **Formato AGENTS.md** (estándar multi-agente):
|
|
606
|
+
- `AGENTS.basic.md`: Modo básico (indexación manual)
|
|
607
|
+
- `AGENTS.auto-index.md`: Modo auto-indexación
|
|
608
|
+
- `AGENTS.sandboxed.md`: Modo sin acceso directo a archivos
|
|
609
|
+
- **Formato VS Code** (`templates/vscode/`):
|
|
610
|
+
- `copilot-instructions.basic.md`: Modo básico para Copilot
|
|
611
|
+
- `copilot-instructions.auto-index.md`: Modo auto-indexación para Copilot
|
|
612
|
+
- `copilot-instructions.sandboxed.md`: Modo sandboxed para Copilot
|
|
613
|
+
- `memory-bank.instructions.md`: Instrucciones con aplicación condicional
|
|
466
614
|
- [wiki/Developer-Guide.md](wiki/Developer-Guide.md): Guía para desarrolladores
|
|
467
615
|
- [wiki/API-Reference.md](wiki/API-Reference.md): Referencia completa de API
|
|
468
616
|
|
|
@@ -6,6 +6,12 @@ import * as fs from "fs";
|
|
|
6
6
|
import * as path from "path";
|
|
7
7
|
import { scanFiles, scanSingleFile } from "./fileScanner.js";
|
|
8
8
|
import { chunkCode } from "./chunker.js";
|
|
9
|
+
/**
|
|
10
|
+
* Normalizes a path to use forward slashes for consistent cross-platform behavior
|
|
11
|
+
*/
|
|
12
|
+
function normalizePath(filePath) {
|
|
13
|
+
return filePath.split(path.sep).join('/');
|
|
14
|
+
}
|
|
9
15
|
/**
|
|
10
16
|
* Index manager coordinating the entire indexing pipeline
|
|
11
17
|
*/
|
|
@@ -43,9 +49,16 @@ export class IndexManager {
|
|
|
43
49
|
*/
|
|
44
50
|
loadMetadata() {
|
|
45
51
|
try {
|
|
52
|
+
console.error(`Loading metadata from: ${this.metadataPath}`);
|
|
46
53
|
if (fs.existsSync(this.metadataPath)) {
|
|
47
54
|
const data = fs.readFileSync(this.metadataPath, "utf-8");
|
|
48
|
-
|
|
55
|
+
const metadata = JSON.parse(data);
|
|
56
|
+
const fileCount = Object.keys(metadata.files || {}).length;
|
|
57
|
+
console.error(`Loaded metadata: ${fileCount} files tracked`);
|
|
58
|
+
return metadata;
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
console.error(`Metadata file not found: ${this.metadataPath}`);
|
|
49
62
|
}
|
|
50
63
|
}
|
|
51
64
|
catch (error) {
|
|
@@ -66,7 +79,9 @@ export class IndexManager {
|
|
|
66
79
|
if (!fs.existsSync(dir)) {
|
|
67
80
|
fs.mkdirSync(dir, { recursive: true });
|
|
68
81
|
}
|
|
82
|
+
const fileCount = Object.keys(this.metadata.files).length;
|
|
69
83
|
fs.writeFileSync(this.metadataPath, JSON.stringify(this.metadata, null, 2));
|
|
84
|
+
console.error(` Saved metadata: ${fileCount} files tracked → ${this.metadataPath}`);
|
|
70
85
|
}
|
|
71
86
|
catch (error) {
|
|
72
87
|
console.error(`Warning: Could not save index metadata: ${error}`);
|
|
@@ -79,11 +94,21 @@ export class IndexManager {
|
|
|
79
94
|
if (forceReindex) {
|
|
80
95
|
return true;
|
|
81
96
|
}
|
|
82
|
-
|
|
97
|
+
// Use normalized path for consistent lookup
|
|
98
|
+
const normalizedPath = normalizePath(file.path);
|
|
99
|
+
const fileInfo = this.metadata.files[normalizedPath];
|
|
83
100
|
if (!fileInfo) {
|
|
101
|
+
// Debug: show first few new files
|
|
102
|
+
const trackedCount = Object.keys(this.metadata.files).length;
|
|
103
|
+
if (trackedCount === 0) {
|
|
104
|
+
console.error(` New file (no metadata): ${normalizedPath}`);
|
|
105
|
+
}
|
|
84
106
|
return true; // New file
|
|
85
107
|
}
|
|
86
108
|
if (fileInfo.hash !== file.hash) {
|
|
109
|
+
console.error(` Changed file: ${normalizedPath}`);
|
|
110
|
+
console.error(` Stored hash: ${fileInfo.hash.substring(0, 16)}...`);
|
|
111
|
+
console.error(` Current hash: ${file.hash.substring(0, 16)}...`);
|
|
87
112
|
return true; // File changed
|
|
88
113
|
}
|
|
89
114
|
return false;
|
|
@@ -128,11 +153,12 @@ export class IndexManager {
|
|
|
128
153
|
// Prepare chunk records for storage (using snake_case for LanceDB)
|
|
129
154
|
// Note: All fields must have non-undefined values for LanceDB Arrow conversion
|
|
130
155
|
const timestamp = Date.now();
|
|
131
|
-
|
|
156
|
+
const normalizedFilePath = normalizePath(file.path);
|
|
157
|
+
console.error(` Storing chunks with project_id: '${projectId}', file: '${normalizedFilePath}'`);
|
|
132
158
|
const chunkRecords = chunks.map((chunk, i) => ({
|
|
133
159
|
id: chunk.id,
|
|
134
160
|
vector: embeddings[i].vector,
|
|
135
|
-
file_path:
|
|
161
|
+
file_path: normalizedFilePath, // Use normalized path for consistency
|
|
136
162
|
content: chunk.content,
|
|
137
163
|
start_line: chunk.startLine,
|
|
138
164
|
end_line: chunk.endLine,
|
|
@@ -144,13 +170,13 @@ export class IndexManager {
|
|
|
144
170
|
context: chunk.context || "", // Ensure non-undefined for LanceDB
|
|
145
171
|
project_id: projectId,
|
|
146
172
|
}));
|
|
147
|
-
// Delete old chunks for this file
|
|
148
|
-
await this.vectorStore.deleteChunksByFile(
|
|
173
|
+
// Delete old chunks for this file using normalized path
|
|
174
|
+
await this.vectorStore.deleteChunksByFile(normalizedFilePath);
|
|
149
175
|
// Insert new chunks
|
|
150
176
|
await this.vectorStore.insertChunks(chunkRecords);
|
|
151
177
|
console.error(` Stored ${chunkRecords.length} chunks in vector store`);
|
|
152
|
-
// Update metadata
|
|
153
|
-
this.metadata.files[
|
|
178
|
+
// Update metadata with normalized path for consistent lookups
|
|
179
|
+
this.metadata.files[normalizedFilePath] = {
|
|
154
180
|
hash: file.hash,
|
|
155
181
|
lastIndexed: timestamp,
|
|
156
182
|
chunkCount: chunks.length,
|
|
@@ -191,19 +217,36 @@ export class IndexManager {
|
|
|
191
217
|
const shouldAutoUpdateDocs = options.autoUpdateDocs !== undefined
|
|
192
218
|
? options.autoUpdateDocs
|
|
193
219
|
: this.autoUpdateDocs;
|
|
220
|
+
// Use workspaceRoot for consistent path normalization, fallback to rootPath
|
|
221
|
+
const workspaceRoot = options.workspaceRoot || options.rootPath;
|
|
194
222
|
console.error(`\n=== Starting indexing process ===`);
|
|
195
223
|
console.error(`Root path: ${options.rootPath}`);
|
|
224
|
+
console.error(`Workspace root: ${workspaceRoot}`);
|
|
196
225
|
console.error(`Project ID: ${projectId}`);
|
|
197
226
|
console.error(`Force reindex: ${options.forceReindex || false}`);
|
|
198
227
|
console.error(`Auto-update docs: ${shouldAutoUpdateDocs}`);
|
|
199
228
|
// Initialize vector store
|
|
200
229
|
await this.vectorStore.initialize();
|
|
201
|
-
// Scan files
|
|
230
|
+
// Scan files - always use workspaceRoot for consistent relative paths
|
|
202
231
|
console.error(`\nScanning files...`);
|
|
203
232
|
const files = scanFiles({
|
|
204
233
|
rootPath: options.rootPath,
|
|
205
234
|
recursive: options.recursive !== undefined ? options.recursive : true,
|
|
206
235
|
});
|
|
236
|
+
// Normalize paths to be relative to workspaceRoot, not rootPath
|
|
237
|
+
// This ensures consistent paths in metadata regardless of which subfolder was indexed
|
|
238
|
+
if (workspaceRoot !== options.rootPath) {
|
|
239
|
+
const rootPathResolved = path.resolve(options.rootPath);
|
|
240
|
+
const workspaceRootResolved = path.resolve(workspaceRoot);
|
|
241
|
+
for (const file of files) {
|
|
242
|
+
// Convert path from relative-to-rootPath to relative-to-workspaceRoot
|
|
243
|
+
const absolutePath = path.join(rootPathResolved, file.path);
|
|
244
|
+
file.path = path.relative(workspaceRootResolved, absolutePath);
|
|
245
|
+
// Use forward slashes for consistency
|
|
246
|
+
file.path = file.path.split(path.sep).join('/');
|
|
247
|
+
}
|
|
248
|
+
console.error(` Normalized ${files.length} file paths to workspace root`);
|
|
249
|
+
}
|
|
207
250
|
if (files.length === 0) {
|
|
208
251
|
console.error("No files found to index");
|
|
209
252
|
return {
|
|
@@ -351,6 +394,7 @@ export class IndexManager {
|
|
|
351
394
|
const queryVector = await this.embeddingService.generateQueryEmbedding(query);
|
|
352
395
|
// Search vector store
|
|
353
396
|
const results = await this.vectorStore.search(queryVector, {
|
|
397
|
+
filterByProject: options.projectId,
|
|
354
398
|
topK: options.topK || 10,
|
|
355
399
|
minScore: options.minScore || 0.0,
|
|
356
400
|
filterByFile: options.filterByFile,
|
package/dist/index.js
CHANGED
|
@@ -33,7 +33,10 @@ const server = new McpServer({
|
|
|
33
33
|
version: VERSION,
|
|
34
34
|
});
|
|
35
35
|
// Tool: Index Code
|
|
36
|
-
server.tool("memorybank_index_code", "Indexa semánticamente código de un directorio o archivo específico para permitir búsquedas semánticas", {
|
|
36
|
+
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", {
|
|
37
|
+
projectId: z
|
|
38
|
+
.string()
|
|
39
|
+
.describe("Identificador único del proyecto (OBLIGATORIO). Debe coincidir con el definido en AGENTS.md del proyecto"),
|
|
37
40
|
path: z
|
|
38
41
|
.string()
|
|
39
42
|
.optional()
|
|
@@ -50,6 +53,7 @@ server.tool("memorybank_index_code", "Indexa semánticamente código de un direc
|
|
|
50
53
|
.describe("Forzar reindexación completa aunque no haya cambios"),
|
|
51
54
|
}, async (args) => {
|
|
52
55
|
const result = await indexCode({
|
|
56
|
+
projectId: args.projectId,
|
|
53
57
|
path: args.path,
|
|
54
58
|
recursive: args.recursive,
|
|
55
59
|
forceReindex: args.forceReindex,
|
|
@@ -59,7 +63,10 @@ server.tool("memorybank_index_code", "Indexa semánticamente código de un direc
|
|
|
59
63
|
};
|
|
60
64
|
});
|
|
61
65
|
// Tool: Search Memory Bank
|
|
62
|
-
server.tool("memorybank_search", "Busca código relevante mediante búsqueda semántica vectorial. Usa esta herramienta SIEMPRE que necesites información sobre el código", {
|
|
66
|
+
server.tool("memorybank_search", "Busca código relevante mediante búsqueda semántica vectorial. Usa esta herramienta SIEMPRE que necesites información sobre el código. El projectId es OBLIGATORIO", {
|
|
67
|
+
projectId: z
|
|
68
|
+
.string()
|
|
69
|
+
.describe("Identificador del proyecto donde buscar (OBLIGATORIO). Debe coincidir con el usado al indexar"),
|
|
63
70
|
query: z
|
|
64
71
|
.string()
|
|
65
72
|
.describe("Consulta semántica: describe qué estás buscando en lenguaje natural (ej: 'función de autenticación', '¿cómo se validan los emails?')"),
|
|
@@ -83,6 +90,7 @@ server.tool("memorybank_search", "Busca código relevante mediante búsqueda sem
|
|
|
83
90
|
.describe("Filtrar resultados por lenguaje de programación (ej: 'typescript', 'python')"),
|
|
84
91
|
}, async (args) => {
|
|
85
92
|
const result = await searchMemory({
|
|
93
|
+
projectId: args.projectId,
|
|
86
94
|
query: args.query,
|
|
87
95
|
topK: args.topK,
|
|
88
96
|
minScore: args.minScore,
|
|
@@ -117,7 +125,10 @@ server.tool("memorybank_read_file", "Lee el contenido de un archivo específico
|
|
|
117
125
|
};
|
|
118
126
|
});
|
|
119
127
|
// Tool: Write File
|
|
120
|
-
server.tool("memorybank_write_file", "Escribe o modifica un archivo y automáticamente lo reindexa en el Memory Bank para mantener la consistencia", {
|
|
128
|
+
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", {
|
|
129
|
+
projectId: z
|
|
130
|
+
.string()
|
|
131
|
+
.describe("Identificador del proyecto (OBLIGATORIO). Necesario para la auto-reindexación correcta"),
|
|
121
132
|
path: z
|
|
122
133
|
.string()
|
|
123
134
|
.describe("Ruta relativa o absoluta del archivo a escribir"),
|
|
@@ -131,6 +142,7 @@ server.tool("memorybank_write_file", "Escribe o modifica un archivo y automátic
|
|
|
131
142
|
.describe("Reindexar automáticamente el archivo después de escribirlo"),
|
|
132
143
|
}, async (args) => {
|
|
133
144
|
const result = await writeFile({
|
|
145
|
+
projectId: args.projectId,
|
|
134
146
|
path: args.path,
|
|
135
147
|
content: args.content,
|
|
136
148
|
autoReindex: args.autoReindex,
|
|
@@ -147,9 +159,17 @@ server.tool("memorybank_get_stats", "Obtiene estadísticas del Memory Bank: arch
|
|
|
147
159
|
};
|
|
148
160
|
});
|
|
149
161
|
// Tool: Analyze Coverage
|
|
150
|
-
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.
|
|
162
|
+
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", {
|
|
163
|
+
projectId: z
|
|
164
|
+
.string()
|
|
165
|
+
.describe("Identificador del proyecto a analizar (OBLIGATORIO)"),
|
|
166
|
+
path: z
|
|
167
|
+
.string()
|
|
168
|
+
.describe("Ruta absoluta del workspace a analizar (OBLIGATORIO). Ejemplo: 'C:/workspaces/mi-proyecto'"),
|
|
169
|
+
}, async (args) => {
|
|
151
170
|
try {
|
|
152
|
-
const
|
|
171
|
+
const targetPath = args.path;
|
|
172
|
+
const result = await analyzeCoverage(indexManager, vectorStore, targetPath, args.projectId);
|
|
153
173
|
return {
|
|
154
174
|
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
155
175
|
};
|
|
@@ -189,11 +209,10 @@ server.tool("memorybank_analyze_coverage", "Analiza la cobertura de indexación
|
|
|
189
209
|
}
|
|
190
210
|
});
|
|
191
211
|
// Tool: Generate Project Docs
|
|
192
|
-
server.tool(generateProjectDocsToolDefinition.name, generateProjectDocsToolDefinition.description, {
|
|
212
|
+
server.tool(generateProjectDocsToolDefinition.name, generateProjectDocsToolDefinition.description + ". El projectId es OBLIGATORIO", {
|
|
193
213
|
projectId: z
|
|
194
214
|
.string()
|
|
195
|
-
.
|
|
196
|
-
.describe("ID del proyecto (opcional, usa 'default' si no se especifica)"),
|
|
215
|
+
.describe("Identificador del proyecto (OBLIGATORIO). Debe coincidir con el usado al indexar"),
|
|
197
216
|
force: z
|
|
198
217
|
.boolean()
|
|
199
218
|
.optional()
|
|
@@ -209,7 +228,10 @@ server.tool(generateProjectDocsToolDefinition.name, generateProjectDocsToolDefin
|
|
|
209
228
|
};
|
|
210
229
|
});
|
|
211
230
|
// Tool: Get Project Docs
|
|
212
|
-
server.tool(getProjectDocsToolDefinition.name, getProjectDocsToolDefinition.description, {
|
|
231
|
+
server.tool(getProjectDocsToolDefinition.name, getProjectDocsToolDefinition.description + ". El projectId es OBLIGATORIO", {
|
|
232
|
+
projectId: z
|
|
233
|
+
.string()
|
|
234
|
+
.describe("Identificador del proyecto (OBLIGATORIO). Debe coincidir con el usado al generar los docs"),
|
|
213
235
|
document: z
|
|
214
236
|
.string()
|
|
215
237
|
.optional()
|
|
@@ -222,6 +244,7 @@ server.tool(getProjectDocsToolDefinition.name, getProjectDocsToolDefinition.desc
|
|
|
222
244
|
.describe("Formato de salida: 'full' devuelve contenido completo, 'summary' devuelve resumen de todos los docs"),
|
|
223
245
|
}, async (args) => {
|
|
224
246
|
const result = await getProjectDocs({
|
|
247
|
+
projectId: args.projectId,
|
|
225
248
|
document: args.document,
|
|
226
249
|
format: args.format,
|
|
227
250
|
}, projectKnowledgeService);
|
|
@@ -203,10 +203,13 @@ function generateRecommendations(stats, tree) {
|
|
|
203
203
|
/**
|
|
204
204
|
* Analyzes indexation coverage of the project
|
|
205
205
|
*/
|
|
206
|
-
export async function analyzeCoverage(indexManager, vectorStore, workspaceRoot) {
|
|
206
|
+
export async function analyzeCoverage(indexManager, vectorStore, workspaceRoot, projectId) {
|
|
207
207
|
try {
|
|
208
208
|
console.error("\n=== Analizando cobertura de indexación ===");
|
|
209
209
|
console.error(`Workspace root: ${workspaceRoot}`);
|
|
210
|
+
if (projectId) {
|
|
211
|
+
console.error(`Project ID: ${projectId}`);
|
|
212
|
+
}
|
|
210
213
|
// 1. Scan all code files in workspace with timeout protection
|
|
211
214
|
console.error("Escaneando archivos del workspace...");
|
|
212
215
|
// Add timeout and file limit protection
|
package/dist/tools/indexCode.js
CHANGED
|
@@ -15,12 +15,15 @@ export async function indexCode(params, indexManager, workspaceRoot) {
|
|
|
15
15
|
: path.join(workspaceRoot, params.path)
|
|
16
16
|
: workspaceRoot;
|
|
17
17
|
console.error(`\nIndexing code at: ${targetPath}`);
|
|
18
|
+
console.error(`Project ID: ${params.projectId}`);
|
|
18
19
|
console.error(`Workspace root: ${workspaceRoot}`);
|
|
19
20
|
console.error(`Recursive: ${params.recursive !== false}`);
|
|
20
21
|
console.error(`Force reindex: ${params.forceReindex || false}`);
|
|
21
|
-
// Run indexing
|
|
22
|
+
// Run indexing - pass workspaceRoot for consistent path normalization
|
|
22
23
|
const result = await indexManager.indexFiles({
|
|
24
|
+
projectId: params.projectId,
|
|
23
25
|
rootPath: targetPath,
|
|
26
|
+
workspaceRoot: workspaceRoot, // Always normalize paths relative to workspace
|
|
24
27
|
recursive: params.recursive !== false,
|
|
25
28
|
forceReindex: params.forceReindex || false,
|
|
26
29
|
});
|
|
@@ -17,6 +17,7 @@ export async function searchMemory(params, indexManager) {
|
|
|
17
17
|
};
|
|
18
18
|
}
|
|
19
19
|
console.error(`\nSearching Memory Bank for: "${params.query}"`);
|
|
20
|
+
console.error(`Project ID: ${params.projectId}`);
|
|
20
21
|
console.error(`Top K: ${params.topK || 10}`);
|
|
21
22
|
console.error(`Min score: ${params.minScore || 0.4}`);
|
|
22
23
|
if (params.filterByFile) {
|
|
@@ -27,6 +28,7 @@ export async function searchMemory(params, indexManager) {
|
|
|
27
28
|
}
|
|
28
29
|
// Search
|
|
29
30
|
const results = await indexManager.search(params.query, {
|
|
31
|
+
projectId: params.projectId,
|
|
30
32
|
topK: params.topK || 10,
|
|
31
33
|
minScore: params.minScore !== undefined ? params.minScore : 0.4,
|
|
32
34
|
filterByFile: params.filterByFile,
|
package/dist/tools/writeFile.js
CHANGED
|
@@ -28,8 +28,8 @@ export async function writeFile(params, indexManager, workspaceRoot) {
|
|
|
28
28
|
let chunksCreated = 0;
|
|
29
29
|
if (autoReindex) {
|
|
30
30
|
try {
|
|
31
|
-
console.error(`Auto-reindexing ${params.path}...`);
|
|
32
|
-
const reindexResult = await indexManager.reindexFile(filePath, workspaceRoot);
|
|
31
|
+
console.error(`Auto-reindexing ${params.path} for project ${params.projectId}...`);
|
|
32
|
+
const reindexResult = await indexManager.reindexFile(filePath, workspaceRoot, params.projectId);
|
|
33
33
|
if (reindexResult.success) {
|
|
34
34
|
reindexed = true;
|
|
35
35
|
chunksCreated = reindexResult.chunksCreated;
|