@grec0/memory-bank-mcp 0.0.3 → 0.0.5
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 +642 -420
- package/dist/common/chunker.js +166 -534
- package/dist/common/embeddingService.js +39 -51
- package/dist/common/fileScanner.js +123 -58
- package/dist/common/indexManager.js +185 -108
- package/dist/common/projectKnowledgeService.js +627 -0
- package/dist/common/setup.js +49 -0
- package/dist/common/utils.js +215 -0
- package/dist/common/vectorStore.js +80 -67
- package/dist/index.js +106 -14
- package/dist/operations/boardMemberships.js +186 -0
- package/dist/operations/boards.js +268 -0
- package/dist/operations/cards.js +426 -0
- package/dist/operations/comments.js +249 -0
- package/dist/operations/labels.js +258 -0
- package/dist/operations/lists.js +157 -0
- package/dist/operations/projects.js +102 -0
- package/dist/operations/tasks.js +238 -0
- package/dist/tools/analyzeCoverage.js +50 -67
- package/dist/tools/board-summary.js +151 -0
- package/dist/tools/card-details.js +106 -0
- package/dist/tools/create-card-with-tasks.js +81 -0
- package/dist/tools/generateProjectDocs.js +133 -0
- package/dist/tools/getProjectDocs.js +126 -0
- package/dist/tools/index.js +3 -0
- package/dist/tools/indexCode.js +4 -2
- package/dist/tools/searchMemory.js +4 -2
- package/dist/tools/workflow-actions.js +145 -0
- package/dist/tools/writeFile.js +2 -2
- package/package.json +2 -2
|
@@ -6,8 +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
|
-
|
|
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
|
+
}
|
|
11
15
|
/**
|
|
12
16
|
* Index manager coordinating the entire indexing pipeline
|
|
13
17
|
*/
|
|
@@ -16,34 +20,49 @@ export class IndexManager {
|
|
|
16
20
|
vectorStore;
|
|
17
21
|
metadataPath;
|
|
18
22
|
metadata;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
constructor(embeddingService, vectorStore, storagePath = ".memorybank"
|
|
23
|
+
projectKnowledgeService = null;
|
|
24
|
+
autoUpdateDocs = false;
|
|
25
|
+
constructor(embeddingService, vectorStore, storagePath = ".memorybank") {
|
|
22
26
|
this.embeddingService = embeddingService;
|
|
23
27
|
this.vectorStore = vectorStore;
|
|
24
28
|
this.metadataPath = path.join(storagePath, "index-metadata.json");
|
|
25
|
-
this.projectRoot = projectRoot || process.cwd();
|
|
26
|
-
this.projectId = this.generateProjectId(this.projectRoot);
|
|
27
29
|
this.metadata = this.loadMetadata();
|
|
30
|
+
// Check if auto-update docs is enabled via environment variable
|
|
31
|
+
this.autoUpdateDocs = process.env.MEMORYBANK_AUTO_UPDATE_DOCS === "true";
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Sets the Project Knowledge Service for auto-generating docs
|
|
35
|
+
*/
|
|
36
|
+
setProjectKnowledgeService(service) {
|
|
37
|
+
this.projectKnowledgeService = service;
|
|
38
|
+
console.error("Project Knowledge Service attached to Index Manager");
|
|
28
39
|
}
|
|
29
40
|
/**
|
|
30
|
-
*
|
|
41
|
+
* Enables or disables auto-update of project docs after indexing
|
|
31
42
|
*/
|
|
32
|
-
|
|
33
|
-
|
|
43
|
+
setAutoUpdateDocs(enabled) {
|
|
44
|
+
this.autoUpdateDocs = enabled;
|
|
45
|
+
console.error(`Auto-update project docs: ${enabled ? "enabled" : "disabled"}`);
|
|
34
46
|
}
|
|
35
47
|
/**
|
|
36
48
|
* Loads index metadata from disk
|
|
37
49
|
*/
|
|
38
50
|
loadMetadata() {
|
|
39
51
|
try {
|
|
52
|
+
console.error(`Loading metadata from: ${this.metadataPath}`);
|
|
40
53
|
if (fs.existsSync(this.metadataPath)) {
|
|
41
54
|
const data = fs.readFileSync(this.metadataPath, "utf-8");
|
|
42
|
-
|
|
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}`);
|
|
43
62
|
}
|
|
44
63
|
}
|
|
45
64
|
catch (error) {
|
|
46
|
-
|
|
65
|
+
console.error(`Warning: Could not load index metadata: ${error}`);
|
|
47
66
|
}
|
|
48
67
|
return {
|
|
49
68
|
version: "1.0",
|
|
@@ -60,10 +79,12 @@ export class IndexManager {
|
|
|
60
79
|
if (!fs.existsSync(dir)) {
|
|
61
80
|
fs.mkdirSync(dir, { recursive: true });
|
|
62
81
|
}
|
|
82
|
+
const fileCount = Object.keys(this.metadata.files).length;
|
|
63
83
|
fs.writeFileSync(this.metadataPath, JSON.stringify(this.metadata, null, 2));
|
|
84
|
+
console.error(` Saved metadata: ${fileCount} files tracked → ${this.metadataPath}`);
|
|
64
85
|
}
|
|
65
86
|
catch (error) {
|
|
66
|
-
|
|
87
|
+
console.error(`Warning: Could not save index metadata: ${error}`);
|
|
67
88
|
}
|
|
68
89
|
}
|
|
69
90
|
/**
|
|
@@ -73,11 +94,21 @@ export class IndexManager {
|
|
|
73
94
|
if (forceReindex) {
|
|
74
95
|
return true;
|
|
75
96
|
}
|
|
76
|
-
|
|
97
|
+
// Use normalized path for consistent lookup
|
|
98
|
+
const normalizedPath = normalizePath(file.path);
|
|
99
|
+
const fileInfo = this.metadata.files[normalizedPath];
|
|
77
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
|
+
}
|
|
78
106
|
return true; // New file
|
|
79
107
|
}
|
|
80
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)}...`);
|
|
81
112
|
return true; // File changed
|
|
82
113
|
}
|
|
83
114
|
return false;
|
|
@@ -85,106 +116,142 @@ export class IndexManager {
|
|
|
85
116
|
/**
|
|
86
117
|
* Indexes a single file
|
|
87
118
|
*/
|
|
88
|
-
async indexFile(file, forceReindex = false,
|
|
119
|
+
async indexFile(file, forceReindex = false, projectId = "default") {
|
|
89
120
|
try {
|
|
90
121
|
// Check if file needs reindexing
|
|
91
122
|
if (!this.needsReindexing(file, forceReindex)) {
|
|
92
|
-
|
|
123
|
+
console.error(`Skipping ${file.path} (no changes)`);
|
|
93
124
|
return { chunksCreated: 0 };
|
|
94
125
|
}
|
|
95
|
-
|
|
126
|
+
console.error(`Indexing: ${file.path}`);
|
|
96
127
|
// Read file content
|
|
97
128
|
const content = fs.readFileSync(file.absolutePath, "utf-8");
|
|
98
|
-
// Get
|
|
99
|
-
|
|
100
|
-
const
|
|
101
|
-
|
|
129
|
+
// Get token limits from environment or use defaults
|
|
130
|
+
// text-embedding-3-small has 8192 token limit, default to 7500 for safety
|
|
131
|
+
const maxTokens = parseInt(process.env.MEMORYBANK_MAX_TOKENS || "7500");
|
|
132
|
+
const chunkOverlapTokens = parseInt(process.env.MEMORYBANK_CHUNK_OVERLAP_TOKENS || "200");
|
|
133
|
+
// Chunk the code using token-based chunking
|
|
102
134
|
const chunks = chunkCode({
|
|
103
135
|
filePath: file.path,
|
|
104
136
|
content,
|
|
105
137
|
language: file.language,
|
|
106
|
-
|
|
107
|
-
|
|
138
|
+
maxTokens,
|
|
139
|
+
chunkOverlapTokens,
|
|
108
140
|
});
|
|
109
141
|
if (chunks.length === 0) {
|
|
110
|
-
|
|
111
|
-
return { chunksCreated: 0 };
|
|
112
|
-
}
|
|
113
|
-
logger.debug(` Created ${chunks.length} chunks`);
|
|
114
|
-
// Filter out invalid chunks (fail-safe)
|
|
115
|
-
const validChunks = chunks.filter(c => c.content && c.content.trim().length > 0 && c.content.trim() !== "}");
|
|
116
|
-
if (validChunks.length === 0) {
|
|
117
|
-
logger.warn(`No valid chunks after filtering for ${file.path}`);
|
|
142
|
+
console.error(`Warning: No chunks created for ${file.path}`);
|
|
118
143
|
return { chunksCreated: 0 };
|
|
119
144
|
}
|
|
145
|
+
console.error(` Created ${chunks.length} chunks`);
|
|
120
146
|
// Generate embeddings
|
|
121
|
-
const embeddingInputs =
|
|
147
|
+
const embeddingInputs = chunks.map((chunk) => ({
|
|
122
148
|
id: chunk.id,
|
|
123
149
|
content: chunk.content,
|
|
124
150
|
}));
|
|
125
151
|
const embeddings = await this.embeddingService.generateBatchEmbeddings(embeddingInputs);
|
|
126
|
-
|
|
127
|
-
// Prepare chunk records for storage
|
|
152
|
+
console.error(` Generated ${embeddings.length} embeddings`);
|
|
153
|
+
// Prepare chunk records for storage (using snake_case for LanceDB)
|
|
154
|
+
// Note: All fields must have non-undefined values for LanceDB Arrow conversion
|
|
128
155
|
const timestamp = Date.now();
|
|
129
|
-
const
|
|
156
|
+
const normalizedFilePath = normalizePath(file.path);
|
|
157
|
+
console.error(` Storing chunks with project_id: '${projectId}', file: '${normalizedFilePath}'`);
|
|
158
|
+
const chunkRecords = chunks.map((chunk, i) => ({
|
|
130
159
|
id: chunk.id,
|
|
131
160
|
vector: embeddings[i].vector,
|
|
132
|
-
|
|
161
|
+
file_path: normalizedFilePath, // Use normalized path for consistency
|
|
133
162
|
content: chunk.content,
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
name: chunk.name || "",
|
|
163
|
+
start_line: chunk.startLine,
|
|
164
|
+
end_line: chunk.endLine,
|
|
165
|
+
chunk_type: chunk.chunkType,
|
|
166
|
+
name: chunk.name || "", // Ensure non-undefined for LanceDB
|
|
138
167
|
language: chunk.language,
|
|
139
|
-
|
|
168
|
+
file_hash: file.hash,
|
|
140
169
|
timestamp,
|
|
141
|
-
context: chunk.context,
|
|
142
|
-
|
|
170
|
+
context: chunk.context || "", // Ensure non-undefined for LanceDB
|
|
171
|
+
project_id: projectId,
|
|
143
172
|
}));
|
|
144
|
-
// Delete old chunks for this file
|
|
145
|
-
await this.vectorStore.deleteChunksByFile(
|
|
173
|
+
// Delete old chunks for this file using normalized path
|
|
174
|
+
await this.vectorStore.deleteChunksByFile(normalizedFilePath);
|
|
146
175
|
// Insert new chunks
|
|
147
176
|
await this.vectorStore.insertChunks(chunkRecords);
|
|
148
|
-
|
|
149
|
-
// Update metadata
|
|
150
|
-
this.metadata.files[
|
|
177
|
+
console.error(` Stored ${chunkRecords.length} chunks in vector store`);
|
|
178
|
+
// Update metadata with normalized path for consistent lookups
|
|
179
|
+
this.metadata.files[normalizedFilePath] = {
|
|
151
180
|
hash: file.hash,
|
|
152
181
|
lastIndexed: timestamp,
|
|
153
182
|
chunkCount: chunks.length,
|
|
154
183
|
};
|
|
155
184
|
this.metadata.lastIndexed = timestamp;
|
|
156
|
-
|
|
157
|
-
this.saveMetadata();
|
|
158
|
-
}
|
|
185
|
+
this.saveMetadata();
|
|
159
186
|
return { chunksCreated: chunks.length };
|
|
160
187
|
}
|
|
161
188
|
catch (error) {
|
|
162
189
|
const errorMsg = `Error indexing ${file.path}: ${error}`;
|
|
163
|
-
|
|
190
|
+
console.error(errorMsg);
|
|
164
191
|
return { chunksCreated: 0, error: errorMsg };
|
|
165
192
|
}
|
|
166
193
|
}
|
|
194
|
+
/**
|
|
195
|
+
* Derives a project ID from the root path if not provided
|
|
196
|
+
*/
|
|
197
|
+
deriveProjectId(rootPath, providedId) {
|
|
198
|
+
if (providedId) {
|
|
199
|
+
return providedId;
|
|
200
|
+
}
|
|
201
|
+
// Use the directory name as project ID
|
|
202
|
+
const dirName = path.basename(path.resolve(rootPath));
|
|
203
|
+
// Sanitize: remove special chars, lowercase, replace spaces with dashes
|
|
204
|
+
const sanitized = dirName
|
|
205
|
+
.toLowerCase()
|
|
206
|
+
.replace(/[^a-z0-9-_]/g, "-")
|
|
207
|
+
.replace(/-+/g, "-")
|
|
208
|
+
.replace(/^-|-$/g, "");
|
|
209
|
+
return sanitized || "default";
|
|
210
|
+
}
|
|
167
211
|
/**
|
|
168
212
|
* Indexes multiple files or a directory
|
|
169
213
|
*/
|
|
170
214
|
async indexFiles(options) {
|
|
171
215
|
const startTime = Date.now();
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
216
|
+
const projectId = this.deriveProjectId(options.rootPath, options.projectId);
|
|
217
|
+
const shouldAutoUpdateDocs = options.autoUpdateDocs !== undefined
|
|
218
|
+
? options.autoUpdateDocs
|
|
219
|
+
: this.autoUpdateDocs;
|
|
220
|
+
// Use workspaceRoot for consistent path normalization, fallback to rootPath
|
|
221
|
+
const workspaceRoot = options.workspaceRoot || options.rootPath;
|
|
222
|
+
console.error(`\n=== Starting indexing process ===`);
|
|
223
|
+
console.error(`Root path: ${options.rootPath}`);
|
|
224
|
+
console.error(`Workspace root: ${workspaceRoot}`);
|
|
225
|
+
console.error(`Project ID: ${projectId}`);
|
|
226
|
+
console.error(`Force reindex: ${options.forceReindex || false}`);
|
|
227
|
+
console.error(`Auto-update docs: ${shouldAutoUpdateDocs}`);
|
|
175
228
|
// Initialize vector store
|
|
176
229
|
await this.vectorStore.initialize();
|
|
177
|
-
// Scan files
|
|
178
|
-
|
|
179
|
-
const files =
|
|
230
|
+
// Scan files - always use workspaceRoot for consistent relative paths
|
|
231
|
+
console.error(`\nScanning files...`);
|
|
232
|
+
const files = scanFiles({
|
|
180
233
|
rootPath: options.rootPath,
|
|
181
|
-
projectRoot: options.projectRoot,
|
|
182
234
|
recursive: options.recursive !== undefined ? options.recursive : true,
|
|
183
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
|
+
}
|
|
184
250
|
if (files.length === 0) {
|
|
185
|
-
|
|
251
|
+
console.error("No files found to index");
|
|
186
252
|
return {
|
|
187
253
|
filesProcessed: 0,
|
|
254
|
+
changedFiles: [],
|
|
188
255
|
chunksCreated: 0,
|
|
189
256
|
errors: [],
|
|
190
257
|
duration: Date.now() - startTime,
|
|
@@ -192,69 +259,76 @@ export class IndexManager {
|
|
|
192
259
|
}
|
|
193
260
|
// Filter files that need reindexing
|
|
194
261
|
const filesToIndex = files.filter((file) => this.needsReindexing(file, options.forceReindex || false));
|
|
195
|
-
|
|
262
|
+
console.error(`\nFound ${files.length} files, ${filesToIndex.length} need indexing`);
|
|
196
263
|
if (filesToIndex.length === 0) {
|
|
197
|
-
|
|
264
|
+
console.error("All files are up to date");
|
|
198
265
|
return {
|
|
199
266
|
filesProcessed: 0,
|
|
267
|
+
changedFiles: [],
|
|
200
268
|
chunksCreated: 0,
|
|
201
269
|
errors: [],
|
|
202
270
|
duration: Date.now() - startTime,
|
|
203
271
|
};
|
|
204
272
|
}
|
|
205
|
-
// Index files
|
|
273
|
+
// Index files
|
|
206
274
|
const errors = [];
|
|
275
|
+
const changedFiles = [];
|
|
207
276
|
let totalChunks = 0;
|
|
208
277
|
let processedFiles = 0;
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
const
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
const batchPromises = batch.map(async (file, index) => {
|
|
216
|
-
logger.debug(`[${i + index + 1}/${filesToIndex.length}] Processing ${file.path}`);
|
|
217
|
-
return this.indexFile(file, options.forceReindex || false, false); // Don't save metadata per file
|
|
218
|
-
});
|
|
219
|
-
const results = await Promise.all(batchPromises);
|
|
220
|
-
// Process results
|
|
221
|
-
for (const result of results) {
|
|
222
|
-
if (result.error) {
|
|
223
|
-
errors.push(result.error);
|
|
224
|
-
}
|
|
225
|
-
else {
|
|
226
|
-
processedFiles++;
|
|
227
|
-
totalChunks += result.chunksCreated;
|
|
228
|
-
}
|
|
278
|
+
for (let i = 0; i < filesToIndex.length; i++) {
|
|
279
|
+
const file = filesToIndex[i];
|
|
280
|
+
console.error(`\n[${i + 1}/${filesToIndex.length}] Processing ${file.path}`);
|
|
281
|
+
const result = await this.indexFile(file, options.forceReindex || false, projectId);
|
|
282
|
+
if (result.error) {
|
|
283
|
+
errors.push(result.error);
|
|
229
284
|
}
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
285
|
+
else {
|
|
286
|
+
processedFiles++;
|
|
287
|
+
totalChunks += result.chunksCreated;
|
|
288
|
+
changedFiles.push(file.path);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
const indexDuration = Date.now() - startTime;
|
|
292
|
+
console.error(`\n=== Indexing complete ===`);
|
|
293
|
+
console.error(`Files processed: ${processedFiles}`);
|
|
294
|
+
console.error(`Chunks created: ${totalChunks}`);
|
|
295
|
+
console.error(`Errors: ${errors.length}`);
|
|
296
|
+
console.error(`Duration: ${(indexDuration / 1000).toFixed(2)}s`);
|
|
297
|
+
// Run post-indexing hook to update project documentation
|
|
298
|
+
let docsGeneration;
|
|
299
|
+
if (shouldAutoUpdateDocs && this.projectKnowledgeService && changedFiles.length > 0) {
|
|
300
|
+
console.error(`\n=== Updating project documentation ===`);
|
|
301
|
+
try {
|
|
302
|
+
// Get all chunks for the project
|
|
303
|
+
const allChunks = await this.vectorStore.getAllChunks(projectId);
|
|
304
|
+
// Update docs incrementally based on changed files
|
|
305
|
+
docsGeneration = await this.projectKnowledgeService.updateDocuments(allChunks, changedFiles);
|
|
306
|
+
console.error(`Docs updated: ${docsGeneration.documentsUpdated.length}`);
|
|
307
|
+
console.error(`Docs generated: ${docsGeneration.documentsGenerated.length}`);
|
|
308
|
+
console.error(`Reasoning tokens: ${docsGeneration.totalReasoningTokens}`);
|
|
309
|
+
}
|
|
310
|
+
catch (error) {
|
|
311
|
+
console.error(`Warning: Failed to update project docs: ${error.message}`);
|
|
312
|
+
errors.push(`Project docs update failed: ${error.message}`);
|
|
236
313
|
}
|
|
237
314
|
}
|
|
238
|
-
const
|
|
239
|
-
logger.info(`=== Indexing complete ===`);
|
|
240
|
-
logger.info(`Files processed: ${processedFiles}`);
|
|
241
|
-
logger.info(`Chunks created: ${totalChunks}`);
|
|
242
|
-
logger.info(`Errors: ${errors.length}`);
|
|
243
|
-
logger.info(`Duration: ${(duration / 1000).toFixed(2)}s`);
|
|
315
|
+
const totalDuration = Date.now() - startTime;
|
|
244
316
|
return {
|
|
245
317
|
filesProcessed: processedFiles,
|
|
318
|
+
changedFiles,
|
|
246
319
|
chunksCreated: totalChunks,
|
|
247
320
|
errors,
|
|
248
|
-
duration,
|
|
321
|
+
duration: totalDuration,
|
|
322
|
+
docsGeneration,
|
|
249
323
|
};
|
|
250
324
|
}
|
|
251
325
|
/**
|
|
252
326
|
* Re-indexes a specific file by path
|
|
253
327
|
*/
|
|
254
|
-
async reindexFile(filePath, rootPath,
|
|
328
|
+
async reindexFile(filePath, rootPath, projectId) {
|
|
255
329
|
try {
|
|
256
330
|
// Scan the specific file
|
|
257
|
-
const file =
|
|
331
|
+
const file = scanSingleFile(filePath, rootPath);
|
|
258
332
|
if (!file) {
|
|
259
333
|
return {
|
|
260
334
|
success: false,
|
|
@@ -262,10 +336,12 @@ export class IndexManager {
|
|
|
262
336
|
error: "File not found or not a code file",
|
|
263
337
|
};
|
|
264
338
|
}
|
|
339
|
+
// Derive project ID from root path if not provided
|
|
340
|
+
const resolvedProjectId = this.deriveProjectId(rootPath, projectId);
|
|
265
341
|
// Initialize vector store
|
|
266
342
|
await this.vectorStore.initialize();
|
|
267
343
|
// Index the file
|
|
268
|
-
const result = await this.indexFile(file, true);
|
|
344
|
+
const result = await this.indexFile(file, true, resolvedProjectId);
|
|
269
345
|
if (result.error) {
|
|
270
346
|
return {
|
|
271
347
|
success: false,
|
|
@@ -318,6 +394,7 @@ export class IndexManager {
|
|
|
318
394
|
const queryVector = await this.embeddingService.generateQueryEmbedding(query);
|
|
319
395
|
// Search vector store
|
|
320
396
|
const results = await this.vectorStore.search(queryVector, {
|
|
397
|
+
filterByProject: options.projectId,
|
|
321
398
|
topK: options.topK || 10,
|
|
322
399
|
minScore: options.minScore || 0.0,
|
|
323
400
|
filterByFile: options.filterByFile,
|
|
@@ -325,11 +402,11 @@ export class IndexManager {
|
|
|
325
402
|
});
|
|
326
403
|
// Format results
|
|
327
404
|
return results.map((result) => ({
|
|
328
|
-
filePath: result.chunk.
|
|
405
|
+
filePath: result.chunk.file_path,
|
|
329
406
|
content: result.chunk.content,
|
|
330
|
-
startLine: result.chunk.
|
|
331
|
-
endLine: result.chunk.
|
|
332
|
-
chunkType: result.chunk.
|
|
407
|
+
startLine: result.chunk.start_line,
|
|
408
|
+
endLine: result.chunk.end_line,
|
|
409
|
+
chunkType: result.chunk.chunk_type,
|
|
333
410
|
name: result.chunk.name,
|
|
334
411
|
language: result.chunk.language,
|
|
335
412
|
score: result.score,
|
|
@@ -349,23 +426,23 @@ export class IndexManager {
|
|
|
349
426
|
this.saveMetadata();
|
|
350
427
|
// Clear embedding cache
|
|
351
428
|
this.embeddingService.clearCache();
|
|
352
|
-
|
|
429
|
+
console.error("Index cleared");
|
|
353
430
|
}
|
|
354
431
|
/**
|
|
355
432
|
* Removes a file from the index
|
|
356
433
|
*/
|
|
357
434
|
async removeFile(filePath) {
|
|
358
435
|
await this.vectorStore.initialize();
|
|
359
|
-
await this.vectorStore.deleteChunksByFile(filePath
|
|
436
|
+
await this.vectorStore.deleteChunksByFile(filePath);
|
|
360
437
|
delete this.metadata.files[filePath];
|
|
361
438
|
this.saveMetadata();
|
|
362
|
-
|
|
439
|
+
console.error(`Removed ${filePath} from index`);
|
|
363
440
|
}
|
|
364
441
|
}
|
|
365
442
|
/**
|
|
366
443
|
* Creates an index manager from environment variables
|
|
367
444
|
*/
|
|
368
|
-
export function createIndexManager(embeddingService, vectorStore
|
|
445
|
+
export function createIndexManager(embeddingService, vectorStore) {
|
|
369
446
|
const storagePath = process.env.MEMORYBANK_STORAGE_PATH || ".memorybank";
|
|
370
|
-
return new IndexManager(embeddingService, vectorStore, storagePath
|
|
447
|
+
return new IndexManager(embeddingService, vectorStore, storagePath);
|
|
371
448
|
}
|