@codemap-ai/mcp 1.1.5 → 1.1.10
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/dist/index.js +999 -52
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -3173,6 +3173,7 @@ var require_file_discovery = __commonJS({
|
|
|
3173
3173
|
};
|
|
3174
3174
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3175
3175
|
exports.PARSE_TOOL_VERSION = exports.PARSE_TOOL_NAME = exports.MAX_PARSE_BYTES_BY_LANGUAGE = exports.MAX_PARSE_BYTES = exports.IGNORED_NAMES = void 0;
|
|
3176
|
+
exports.isPathIgnored = isPathIgnored;
|
|
3176
3177
|
exports.normalizeRepositoryFilePath = normalizeRepositoryFilePath;
|
|
3177
3178
|
exports.collectSingleFile = collectSingleFile2;
|
|
3178
3179
|
exports.collectWorkspaceFiles = collectWorkspaceFiles2;
|
|
@@ -3183,13 +3184,35 @@ var require_file_discovery = __commonJS({
|
|
|
3183
3184
|
".git",
|
|
3184
3185
|
".codemap",
|
|
3185
3186
|
"node_modules",
|
|
3186
|
-
"
|
|
3187
|
+
".pnpm",
|
|
3188
|
+
".pnpm-store",
|
|
3189
|
+
".dist",
|
|
3187
3190
|
"build",
|
|
3188
3191
|
".next",
|
|
3189
3192
|
"coverage",
|
|
3190
3193
|
".turbo",
|
|
3191
|
-
".cache"
|
|
3194
|
+
".cache",
|
|
3195
|
+
".agents",
|
|
3196
|
+
".claude",
|
|
3197
|
+
".codex",
|
|
3198
|
+
".vercel",
|
|
3199
|
+
"tmp",
|
|
3200
|
+
"temp",
|
|
3201
|
+
"lib",
|
|
3202
|
+
".continue",
|
|
3203
|
+
".github",
|
|
3204
|
+
".vscode",
|
|
3205
|
+
".cursor",
|
|
3206
|
+
".opencode",
|
|
3207
|
+
".windsurf",
|
|
3208
|
+
".zed",
|
|
3209
|
+
".gemini",
|
|
3210
|
+
".ideamrc"
|
|
3192
3211
|
]);
|
|
3212
|
+
function isPathIgnored(path19) {
|
|
3213
|
+
const parts = path19.split("/");
|
|
3214
|
+
return parts.some((part) => exports.IGNORED_NAMES.has(part));
|
|
3215
|
+
}
|
|
3193
3216
|
exports.MAX_PARSE_BYTES = 2 * 1024 * 1024;
|
|
3194
3217
|
exports.MAX_PARSE_BYTES_BY_LANGUAGE = {
|
|
3195
3218
|
Gettext: 10 * 1024 * 1024
|
|
@@ -232764,19 +232787,6 @@ function stableId(...parts) {
|
|
|
232764
232787
|
function terms(query) {
|
|
232765
232788
|
return query.toLowerCase().split(/[\s\-_/.,:]+/).map((term) => term.replace(/[^a-z0-9]/g, "")).filter((term) => term.length > 1);
|
|
232766
232789
|
}
|
|
232767
|
-
function includesAll(input, queryTerms2) {
|
|
232768
|
-
const lower = input.toLowerCase();
|
|
232769
|
-
return queryTerms2.every((term) => lower.includes(term));
|
|
232770
|
-
}
|
|
232771
|
-
function scoreText(input, queryTerms2, baseRank) {
|
|
232772
|
-
const lower = input.toLowerCase();
|
|
232773
|
-
let score = 100 - baseRank;
|
|
232774
|
-
for (const term of queryTerms2) {
|
|
232775
|
-
if (lower === term) score += 30;
|
|
232776
|
-
else if (lower.includes(term)) score += 12;
|
|
232777
|
-
}
|
|
232778
|
-
return score;
|
|
232779
|
-
}
|
|
232780
232790
|
function resolveContentStatus(isBinary, parseStatus, content) {
|
|
232781
232791
|
if (content != null) return "ready";
|
|
232782
232792
|
if (isBinary) return "binary";
|
|
@@ -232878,6 +232888,61 @@ var SCHEMA_SQL = `
|
|
|
232878
232888
|
CREATE INDEX IF NOT EXISTS idx_exports_filePath ON exports(filePath);
|
|
232879
232889
|
CREATE INDEX IF NOT EXISTS idx_exports_exportName ON exports(lower(exportName));
|
|
232880
232890
|
`;
|
|
232891
|
+
var FTS_SCHEMA_SQL = `
|
|
232892
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS files_fts USING fts5(
|
|
232893
|
+
path,
|
|
232894
|
+
content='files',
|
|
232895
|
+
tokenize='unicode61 separators ''/._-'''
|
|
232896
|
+
);
|
|
232897
|
+
|
|
232898
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS symbols_fts USING fts5(
|
|
232899
|
+
displayName, filePath, signature,
|
|
232900
|
+
content='symbols',
|
|
232901
|
+
tokenize='unicode61 separators ''/._-'''
|
|
232902
|
+
);
|
|
232903
|
+
|
|
232904
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS exports_fts USING fts5(
|
|
232905
|
+
exportName, filePath,
|
|
232906
|
+
content='exports',
|
|
232907
|
+
tokenize='unicode61 separators ''/._-'''
|
|
232908
|
+
);
|
|
232909
|
+
|
|
232910
|
+
-- files_fts triggers
|
|
232911
|
+
CREATE TRIGGER IF NOT EXISTS files_fts_insert AFTER INSERT ON files BEGIN
|
|
232912
|
+
INSERT INTO files_fts(rowid, path) VALUES (new.rowid, new.path);
|
|
232913
|
+
END;
|
|
232914
|
+
CREATE TRIGGER IF NOT EXISTS files_fts_delete AFTER DELETE ON files BEGIN
|
|
232915
|
+
INSERT INTO files_fts(files_fts, rowid, path) VALUES('delete', old.rowid, old.path);
|
|
232916
|
+
END;
|
|
232917
|
+
CREATE TRIGGER IF NOT EXISTS files_fts_update AFTER UPDATE ON files BEGIN
|
|
232918
|
+
INSERT INTO files_fts(files_fts, rowid, path) VALUES('delete', old.rowid, old.path);
|
|
232919
|
+
INSERT INTO files_fts(rowid, path) VALUES (new.rowid, new.path);
|
|
232920
|
+
END;
|
|
232921
|
+
|
|
232922
|
+
-- symbols_fts triggers
|
|
232923
|
+
CREATE TRIGGER IF NOT EXISTS symbols_fts_insert AFTER INSERT ON symbols BEGIN
|
|
232924
|
+
INSERT INTO symbols_fts(rowid, displayName, filePath, signature) VALUES (new.id, new.displayName, new.filePath, new.signature);
|
|
232925
|
+
END;
|
|
232926
|
+
CREATE TRIGGER IF NOT EXISTS symbols_fts_delete AFTER DELETE ON symbols BEGIN
|
|
232927
|
+
INSERT INTO symbols_fts(symbols_fts, rowid, displayName, filePath, signature) VALUES('delete', old.id, old.displayName, old.filePath, old.signature);
|
|
232928
|
+
END;
|
|
232929
|
+
CREATE TRIGGER IF NOT EXISTS symbols_fts_update AFTER UPDATE ON symbols BEGIN
|
|
232930
|
+
INSERT INTO symbols_fts(symbols_fts, rowid, displayName, filePath, signature) VALUES('delete', old.id, old.displayName, old.filePath, old.signature);
|
|
232931
|
+
INSERT INTO symbols_fts(rowid, displayName, filePath, signature) VALUES (new.id, new.displayName, new.filePath, new.signature);
|
|
232932
|
+
END;
|
|
232933
|
+
|
|
232934
|
+
-- exports_fts triggers
|
|
232935
|
+
CREATE TRIGGER IF NOT EXISTS exports_fts_insert AFTER INSERT ON exports BEGIN
|
|
232936
|
+
INSERT INTO exports_fts(rowid, exportName, filePath) VALUES (new.id, new.exportName, new.filePath);
|
|
232937
|
+
END;
|
|
232938
|
+
CREATE TRIGGER IF NOT EXISTS exports_fts_delete AFTER DELETE ON exports BEGIN
|
|
232939
|
+
INSERT INTO exports_fts(exports_fts, rowid, exportName, filePath) VALUES('delete', old.id, old.exportName, old.filePath);
|
|
232940
|
+
END;
|
|
232941
|
+
CREATE TRIGGER IF NOT EXISTS exports_fts_update AFTER UPDATE ON exports BEGIN
|
|
232942
|
+
INSERT INTO exports_fts(exports_fts, rowid, exportName, filePath) VALUES('delete', old.id, old.exportName, old.filePath);
|
|
232943
|
+
INSERT INTO exports_fts(rowid, exportName, filePath) VALUES (new.id, new.exportName, new.filePath);
|
|
232944
|
+
END;
|
|
232945
|
+
`;
|
|
232881
232946
|
var SQLiteIndexStore = class _SQLiteIndexStore {
|
|
232882
232947
|
db;
|
|
232883
232948
|
dbPath;
|
|
@@ -232886,6 +232951,20 @@ var SQLiteIndexStore = class _SQLiteIndexStore {
|
|
|
232886
232951
|
this.db = new DatabaseSync(dbPath);
|
|
232887
232952
|
this.db.exec("PRAGMA journal_mode=WAL; PRAGMA synchronous=NORMAL;");
|
|
232888
232953
|
this.db.exec(SCHEMA_SQL);
|
|
232954
|
+
this.db.exec(FTS_SCHEMA_SQL);
|
|
232955
|
+
this.migrateFts();
|
|
232956
|
+
}
|
|
232957
|
+
migrateFts() {
|
|
232958
|
+
const { n } = this.db.prepare("SELECT count(*) as n FROM files_fts").get();
|
|
232959
|
+
if (n === 0) {
|
|
232960
|
+
this.db.exec(`
|
|
232961
|
+
INSERT INTO files_fts(rowid, path) SELECT rowid, path FROM files;
|
|
232962
|
+
INSERT INTO symbols_fts(rowid, displayName, filePath, signature)
|
|
232963
|
+
SELECT id, displayName, filePath, signature FROM symbols;
|
|
232964
|
+
INSERT INTO exports_fts(rowid, exportName, filePath)
|
|
232965
|
+
SELECT id, exportName, filePath FROM exports;
|
|
232966
|
+
`);
|
|
232967
|
+
}
|
|
232889
232968
|
}
|
|
232890
232969
|
static open(dbPath) {
|
|
232891
232970
|
mkdirSync(path8.dirname(dbPath), { recursive: true });
|
|
@@ -233210,26 +233289,157 @@ var SQLiteIndexStore = class _SQLiteIndexStore {
|
|
|
233210
233289
|
throw error;
|
|
233211
233290
|
}
|
|
233212
233291
|
}
|
|
233292
|
+
/**
|
|
233293
|
+
* Batch update multiple files' data. More efficient than calling upsertFile repeatedly
|
|
233294
|
+
* when reindexing dependent files after a source file change.
|
|
233295
|
+
*/
|
|
233296
|
+
batchUpsertFiles(files) {
|
|
233297
|
+
this.db.exec("BEGIN");
|
|
233298
|
+
try {
|
|
233299
|
+
const statements = /* @__PURE__ */ new Map();
|
|
233300
|
+
const createStmt = (sql) => {
|
|
233301
|
+
if (!statements.has(sql)) {
|
|
233302
|
+
statements.set(sql, this.db.prepare(sql));
|
|
233303
|
+
}
|
|
233304
|
+
return statements.get(sql);
|
|
233305
|
+
};
|
|
233306
|
+
for (const { file, skipImportedByRebuild } of files) {
|
|
233307
|
+
createStmt("DELETE FROM manifest WHERE path = ?").run(file.path);
|
|
233308
|
+
createStmt("DELETE FROM files WHERE path = ?").run(file.path);
|
|
233309
|
+
createStmt("DELETE FROM symbols WHERE filePath = ?").run(file.path);
|
|
233310
|
+
createStmt("DELETE FROM imports WHERE filePath = ?").run(file.path);
|
|
233311
|
+
createStmt("DELETE FROM exports WHERE filePath = ?").run(file.path);
|
|
233312
|
+
if (!skipImportedByRebuild) {
|
|
233313
|
+
createStmt("DELETE FROM imported_by WHERE targetFilePath = ? OR sourceFilePath = ?").run(file.path, file.path);
|
|
233314
|
+
}
|
|
233315
|
+
createStmt(
|
|
233316
|
+
"INSERT INTO manifest(path, sizeBytes, contentSha256, parseStatus) VALUES(?, ?, ?, ?)"
|
|
233317
|
+
).run(file.path, file.sizeBytes, file.contentSha256 ?? null, file.parseStatus);
|
|
233318
|
+
createStmt(
|
|
233319
|
+
"INSERT INTO files(path, dirPath, baseName, extension, language, mimeType, sizeBytes, lineCount, parseStatus, isBinary, isText, contentSha256, content) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
|
|
233320
|
+
).run(
|
|
233321
|
+
file.path,
|
|
233322
|
+
file.dirPath,
|
|
233323
|
+
file.baseName,
|
|
233324
|
+
file.extension ?? null,
|
|
233325
|
+
file.language ?? null,
|
|
233326
|
+
file.mimeType ?? null,
|
|
233327
|
+
file.sizeBytes,
|
|
233328
|
+
file.lineCount ?? null,
|
|
233329
|
+
file.parseStatus,
|
|
233330
|
+
file.isBinary ? 1 : 0,
|
|
233331
|
+
file.isText ? 1 : 0,
|
|
233332
|
+
file.contentSha256 ?? null,
|
|
233333
|
+
file.content ?? null
|
|
233334
|
+
);
|
|
233335
|
+
const insertSymbol = createStmt(
|
|
233336
|
+
"INSERT INTO symbols(filePath, localKey, stableKey, displayName, kind, signature, returnType, doc, isExported, parentSymbolLocalKey, line, col, endLine, endCol) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
|
|
233337
|
+
);
|
|
233338
|
+
for (const sym of file.symbols) {
|
|
233339
|
+
insertSymbol.run(
|
|
233340
|
+
file.path,
|
|
233341
|
+
sym.localKey,
|
|
233342
|
+
sym.stableKey,
|
|
233343
|
+
sym.displayName,
|
|
233344
|
+
sym.kind,
|
|
233345
|
+
sym.signature ?? null,
|
|
233346
|
+
sym.returnType ?? null,
|
|
233347
|
+
sym.doc ?? null,
|
|
233348
|
+
sym.isExported ? 1 : 0,
|
|
233349
|
+
sym.parentSymbolLocalKey ?? null,
|
|
233350
|
+
sym.line,
|
|
233351
|
+
sym.col,
|
|
233352
|
+
sym.endLine,
|
|
233353
|
+
sym.endCol
|
|
233354
|
+
);
|
|
233355
|
+
}
|
|
233356
|
+
const insertImport = createStmt(
|
|
233357
|
+
"INSERT INTO imports(filePath, localKey, moduleSpecifier, importKind, resolutionKind, targetPathText, targetExternalSymbolKey, line, col, endLine, endCol) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
|
|
233358
|
+
);
|
|
233359
|
+
for (const imp of file.imports) {
|
|
233360
|
+
insertImport.run(
|
|
233361
|
+
file.path,
|
|
233362
|
+
imp.localKey,
|
|
233363
|
+
imp.moduleSpecifier,
|
|
233364
|
+
imp.importKind,
|
|
233365
|
+
imp.resolutionKind,
|
|
233366
|
+
imp.targetPathText ?? null,
|
|
233367
|
+
imp.targetExternalSymbolKey ?? null,
|
|
233368
|
+
imp.line,
|
|
233369
|
+
imp.col,
|
|
233370
|
+
imp.endLine,
|
|
233371
|
+
imp.endCol
|
|
233372
|
+
);
|
|
233373
|
+
}
|
|
233374
|
+
const insertIB = createStmt(
|
|
233375
|
+
"INSERT INTO imported_by(targetFilePath, sourceFilePath, moduleSpecifier, importKind, resolutionKind, startLine, startCol, endLine, endCol) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)"
|
|
233376
|
+
);
|
|
233377
|
+
for (const imp of file.imports) {
|
|
233378
|
+
if (!imp.targetPathText) continue;
|
|
233379
|
+
insertIB.run(
|
|
233380
|
+
imp.targetPathText,
|
|
233381
|
+
file.path,
|
|
233382
|
+
imp.moduleSpecifier,
|
|
233383
|
+
imp.importKind,
|
|
233384
|
+
imp.resolutionKind,
|
|
233385
|
+
imp.line,
|
|
233386
|
+
imp.col,
|
|
233387
|
+
imp.endLine,
|
|
233388
|
+
imp.endCol
|
|
233389
|
+
);
|
|
233390
|
+
}
|
|
233391
|
+
const insertExport = createStmt(
|
|
233392
|
+
"INSERT INTO exports(filePath, exportName, exportKind, symbolLocalKey, line, col, endLine, endCol) VALUES(?, ?, ?, ?, ?, ?, ?, ?)"
|
|
233393
|
+
);
|
|
233394
|
+
for (const exp of file.exports) {
|
|
233395
|
+
insertExport.run(
|
|
233396
|
+
file.path,
|
|
233397
|
+
exp.exportName,
|
|
233398
|
+
exp.exportKind,
|
|
233399
|
+
exp.symbolLocalKey ?? null,
|
|
233400
|
+
exp.line,
|
|
233401
|
+
exp.col,
|
|
233402
|
+
exp.endLine,
|
|
233403
|
+
exp.endCol
|
|
233404
|
+
);
|
|
233405
|
+
}
|
|
233406
|
+
}
|
|
233407
|
+
this.db.exec("COMMIT");
|
|
233408
|
+
} catch (error) {
|
|
233409
|
+
this.db.exec("ROLLBACK");
|
|
233410
|
+
throw error;
|
|
233411
|
+
}
|
|
233412
|
+
}
|
|
233213
233413
|
search(query, symbolKinds) {
|
|
233214
233414
|
const queryTerms2 = terms(query);
|
|
233215
233415
|
if (queryTerms2.length === 0) return { files: [], symbols: [], exports: [] };
|
|
233216
|
-
const
|
|
233217
|
-
const
|
|
233218
|
-
|
|
233219
|
-
|
|
233220
|
-
|
|
233221
|
-
|
|
233416
|
+
const ftsQuery = queryTerms2.map((t) => `"${t.replace(/"/g, '""')}"`).join(" ");
|
|
233417
|
+
const fileRows = this.db.prepare(
|
|
233418
|
+
`SELECT f.path, f.language
|
|
233419
|
+
FROM files_fts
|
|
233420
|
+
JOIN files f ON files_fts.rowid = f.rowid
|
|
233421
|
+
WHERE files_fts MATCH ?
|
|
233422
|
+
ORDER BY bm25(files_fts)
|
|
233423
|
+
LIMIT 25`
|
|
233424
|
+
).all(ftsQuery);
|
|
233425
|
+
const files = fileRows.map((r) => ({
|
|
233426
|
+
kind: "file",
|
|
233427
|
+
path: r.path,
|
|
233428
|
+
language: r.language
|
|
233429
|
+
}));
|
|
233222
233430
|
let symSql = `
|
|
233223
233431
|
SELECT s.filePath, s.localKey, s.stableKey, s.displayName, s.kind, s.signature,
|
|
233224
233432
|
s.parentSymbolLocalKey, s.line, s.col, s.endLine, s.endCol
|
|
233225
|
-
FROM
|
|
233226
|
-
|
|
233433
|
+
FROM symbols_fts
|
|
233434
|
+
JOIN symbols s ON symbols_fts.rowid = s.id
|
|
233435
|
+
WHERE symbols_fts MATCH ?
|
|
233227
233436
|
`;
|
|
233437
|
+
const symArgs = [ftsQuery];
|
|
233228
233438
|
if (symbolKinds && symbolKinds.length > 0) {
|
|
233229
233439
|
symSql += ` AND s.kind IN (${symbolKinds.map(() => "?").join(",")})`;
|
|
233230
233440
|
symArgs.push(...symbolKinds);
|
|
233231
233441
|
}
|
|
233232
|
-
symSql += " LIMIT
|
|
233442
|
+
symSql += " ORDER BY bm25(symbols_fts) LIMIT 25";
|
|
233233
233443
|
const symRows = this.db.prepare(symSql).all(...symArgs);
|
|
233234
233444
|
const parentKeys = [...new Set(symRows.map((r) => r.parentSymbolLocalKey).filter(Boolean))];
|
|
233235
233445
|
const parentNameMap = /* @__PURE__ */ new Map();
|
|
@@ -233237,9 +233447,7 @@ var SQLiteIndexStore = class _SQLiteIndexStore {
|
|
|
233237
233447
|
const parentRows = this.db.prepare(`SELECT localKey, displayName FROM symbols WHERE localKey IN (${parentKeys.map(() => "?").join(",")})`).all(...parentKeys);
|
|
233238
233448
|
for (const pr of parentRows) parentNameMap.set(pr.localKey, pr.displayName);
|
|
233239
233449
|
}
|
|
233240
|
-
const symbols = symRows.
|
|
233241
|
-
(a, b) => scoreText(`${b.displayName} ${b.filePath}`, queryTerms2, 0) - scoreText(`${a.displayName} ${a.filePath}`, queryTerms2, 0)
|
|
233242
|
-
).slice(0, 25).map((r) => ({
|
|
233450
|
+
const symbols = symRows.map((r) => ({
|
|
233243
233451
|
kind: "symbol",
|
|
233244
233452
|
id: stableId(r.filePath, r.stableKey),
|
|
233245
233453
|
displayName: r.displayName,
|
|
@@ -233254,10 +233462,12 @@ var SQLiteIndexStore = class _SQLiteIndexStore {
|
|
|
233254
233462
|
}));
|
|
233255
233463
|
const expRows = this.db.prepare(
|
|
233256
233464
|
`SELECT e.filePath, e.exportName, e.exportKind, e.symbolLocalKey, e.line, e.col, e.endLine, e.endCol
|
|
233257
|
-
FROM
|
|
233258
|
-
|
|
233259
|
-
|
|
233260
|
-
|
|
233465
|
+
FROM exports_fts
|
|
233466
|
+
JOIN exports e ON exports_fts.rowid = e.id
|
|
233467
|
+
WHERE exports_fts MATCH ?
|
|
233468
|
+
ORDER BY bm25(exports_fts)
|
|
233469
|
+
LIMIT 25`
|
|
233470
|
+
).all(ftsQuery);
|
|
233261
233471
|
const expSymKeys = [...new Set(expRows.map((r) => r.symbolLocalKey).filter(Boolean))];
|
|
233262
233472
|
const expSymMap = /* @__PURE__ */ new Map();
|
|
233263
233473
|
if (expSymKeys.length > 0) {
|
|
@@ -233266,9 +233476,7 @@ var SQLiteIndexStore = class _SQLiteIndexStore {
|
|
|
233266
233476
|
).all(...expSymKeys);
|
|
233267
233477
|
for (const sr of symInfoRows) expSymMap.set(sr.localKey, sr);
|
|
233268
233478
|
}
|
|
233269
|
-
const exports = expRows.
|
|
233270
|
-
(a, b) => scoreText(`${b.exportName} ${b.filePath}`, queryTerms2, 0) - scoreText(`${a.exportName} ${a.filePath}`, queryTerms2, 0)
|
|
233271
|
-
).slice(0, 25).map((r) => {
|
|
233479
|
+
const exports = expRows.map((r) => {
|
|
233272
233480
|
const sym = r.symbolLocalKey ? expSymMap.get(r.symbolLocalKey) ?? null : null;
|
|
233273
233481
|
return {
|
|
233274
233482
|
kind: "export",
|
|
@@ -233576,6 +233784,28 @@ async function ensureLocalIndex(input) {
|
|
|
233576
233784
|
}
|
|
233577
233785
|
return buildLocalIndex(input);
|
|
233578
233786
|
}
|
|
233787
|
+
async function refreshLocalFile(relativePath, workspaceRootPath) {
|
|
233788
|
+
const store = _cachedStore ?? await readLocalIndex(workspaceRootPath) ?? await buildLocalIndex({ workspaceRootPath });
|
|
233789
|
+
const meta = store.getMeta();
|
|
233790
|
+
if (!meta) return false;
|
|
233791
|
+
const candidate = await (0, import_code_index.collectSingleFile)(relativePath, meta.workspaceRootPath);
|
|
233792
|
+
if (!candidate || !candidate.isParseable) return false;
|
|
233793
|
+
const existingFiles = store.getAllFilePaths();
|
|
233794
|
+
const filePathSet = new Set(existingFiles);
|
|
233795
|
+
filePathSet.add(candidate.path);
|
|
233796
|
+
const resolverConfigs = await (0, import_code_index.loadTypeScriptResolverConfigs)(meta.workspaceRootPath);
|
|
233797
|
+
const semantics = await (0, import_code_index.parseWorkspaceFileSemantics)({
|
|
233798
|
+
file: candidate,
|
|
233799
|
+
filePathSet,
|
|
233800
|
+
projectImportId: "local",
|
|
233801
|
+
workspacePath: meta.workspaceRootPath,
|
|
233802
|
+
resolverConfigs
|
|
233803
|
+
});
|
|
233804
|
+
const localFile = toLocalFile(candidate, semantics);
|
|
233805
|
+
store.upsertFile(localFile);
|
|
233806
|
+
_cachedStore = null;
|
|
233807
|
+
return true;
|
|
233808
|
+
}
|
|
233579
233809
|
async function getLocalIndexSummary(store) {
|
|
233580
233810
|
const files = await collectFilesForStore(store);
|
|
233581
233811
|
return store.getSummary(files.length > 0 ? store.isStale(files) : false);
|
|
@@ -233619,6 +233849,16 @@ function toRepoRelativePath(filePath, workspaceRootPath) {
|
|
|
233619
233849
|
}
|
|
233620
233850
|
return filePath;
|
|
233621
233851
|
}
|
|
233852
|
+
async function refreshLocalFiles(filePaths, workspaceRootPath) {
|
|
233853
|
+
const store = _cachedStore ?? await readLocalIndex(workspaceRootPath);
|
|
233854
|
+
if (!store) {
|
|
233855
|
+
throw new Error("Could not access local index store");
|
|
233856
|
+
}
|
|
233857
|
+
for (const filePath of filePaths) {
|
|
233858
|
+
await refreshLocalFile(filePath, workspaceRootPath);
|
|
233859
|
+
}
|
|
233860
|
+
_cachedStore = null;
|
|
233861
|
+
}
|
|
233622
233862
|
|
|
233623
233863
|
// ../core/src/lib/session-context.ts
|
|
233624
233864
|
function formatAge(date) {
|
|
@@ -234018,6 +234258,458 @@ ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
|
234018
234258
|
}
|
|
234019
234259
|
}
|
|
234020
234260
|
|
|
234261
|
+
// ../core/src/lib/file-watcher.ts
|
|
234262
|
+
var import_code_index2 = __toESM(require_dist(), 1);
|
|
234263
|
+
import * as parcelWatcher from "@parcel/watcher";
|
|
234264
|
+
var IndexWatcher = class {
|
|
234265
|
+
subscription = null;
|
|
234266
|
+
config;
|
|
234267
|
+
pendingEvents = /* @__PURE__ */ new Map();
|
|
234268
|
+
flushTimer = null;
|
|
234269
|
+
isRunning = false;
|
|
234270
|
+
constructor(config) {
|
|
234271
|
+
this.config = {
|
|
234272
|
+
workspaceRootPath: config.workspaceRootPath,
|
|
234273
|
+
debounceMs: config.debounceMs ?? 200,
|
|
234274
|
+
ignoredPatterns: config.ignoredPatterns ?? [],
|
|
234275
|
+
onEvent: config.onEvent ?? (() => {
|
|
234276
|
+
})
|
|
234277
|
+
};
|
|
234278
|
+
}
|
|
234279
|
+
async start() {
|
|
234280
|
+
if (this.isRunning) {
|
|
234281
|
+
return;
|
|
234282
|
+
}
|
|
234283
|
+
try {
|
|
234284
|
+
this.subscription = await parcelWatcher.subscribe(
|
|
234285
|
+
this.config.workspaceRootPath,
|
|
234286
|
+
(err, events) => {
|
|
234287
|
+
if (err) {
|
|
234288
|
+
console.error("[IndexWatcher] Error:", err);
|
|
234289
|
+
return;
|
|
234290
|
+
}
|
|
234291
|
+
for (const event of events) {
|
|
234292
|
+
this.handleRawEvent(event);
|
|
234293
|
+
}
|
|
234294
|
+
},
|
|
234295
|
+
{
|
|
234296
|
+
ignore: [...import_code_index2.IGNORED_NAMES, ...this.config.ignoredPatterns]
|
|
234297
|
+
}
|
|
234298
|
+
);
|
|
234299
|
+
this.isRunning = true;
|
|
234300
|
+
console.log(
|
|
234301
|
+
`[IndexWatcher] Started watching ${this.config.workspaceRootPath}`
|
|
234302
|
+
);
|
|
234303
|
+
} catch (error) {
|
|
234304
|
+
console.error("[IndexWatcher] Failed to start:", error);
|
|
234305
|
+
throw error;
|
|
234306
|
+
}
|
|
234307
|
+
}
|
|
234308
|
+
async stop() {
|
|
234309
|
+
if (!this.isRunning) {
|
|
234310
|
+
return;
|
|
234311
|
+
}
|
|
234312
|
+
await this.flush();
|
|
234313
|
+
if (this.flushTimer) {
|
|
234314
|
+
clearTimeout(this.flushTimer);
|
|
234315
|
+
this.flushTimer = null;
|
|
234316
|
+
}
|
|
234317
|
+
if (this.subscription) {
|
|
234318
|
+
await this.subscription.unsubscribe();
|
|
234319
|
+
this.subscription = null;
|
|
234320
|
+
}
|
|
234321
|
+
this.isRunning = false;
|
|
234322
|
+
this.pendingEvents.clear();
|
|
234323
|
+
console.log("[IndexWatcher] Stopped");
|
|
234324
|
+
}
|
|
234325
|
+
async restart() {
|
|
234326
|
+
await this.stop();
|
|
234327
|
+
await this.start();
|
|
234328
|
+
}
|
|
234329
|
+
isActive() {
|
|
234330
|
+
return this.isRunning;
|
|
234331
|
+
}
|
|
234332
|
+
handleRawEvent(event) {
|
|
234333
|
+
const relativePath = event.path.replace(
|
|
234334
|
+
this.config.workspaceRootPath + "/",
|
|
234335
|
+
""
|
|
234336
|
+
);
|
|
234337
|
+
let type;
|
|
234338
|
+
if (event.type === "create") {
|
|
234339
|
+
type = "create";
|
|
234340
|
+
} else if (event.type === "update") {
|
|
234341
|
+
type = "update";
|
|
234342
|
+
} else if (event.type === "delete") {
|
|
234343
|
+
type = "delete";
|
|
234344
|
+
} else {
|
|
234345
|
+
return;
|
|
234346
|
+
}
|
|
234347
|
+
this.pendingEvents.set(relativePath, {
|
|
234348
|
+
type,
|
|
234349
|
+
path: event.path,
|
|
234350
|
+
relativePath,
|
|
234351
|
+
timestamp: Date.now()
|
|
234352
|
+
});
|
|
234353
|
+
this.scheduleFlush();
|
|
234354
|
+
}
|
|
234355
|
+
scheduleFlush() {
|
|
234356
|
+
if (this.flushTimer) {
|
|
234357
|
+
clearTimeout(this.flushTimer);
|
|
234358
|
+
}
|
|
234359
|
+
this.flushTimer = setTimeout(() => {
|
|
234360
|
+
this.flush().catch((err) => {
|
|
234361
|
+
console.error("[IndexWatcher] Flush error:", err);
|
|
234362
|
+
});
|
|
234363
|
+
}, this.config.debounceMs);
|
|
234364
|
+
}
|
|
234365
|
+
async flush() {
|
|
234366
|
+
if (this.pendingEvents.size === 0) {
|
|
234367
|
+
return;
|
|
234368
|
+
}
|
|
234369
|
+
const events = Array.from(this.pendingEvents.values());
|
|
234370
|
+
this.pendingEvents.clear();
|
|
234371
|
+
for (const event of events) {
|
|
234372
|
+
const watchEvent = {
|
|
234373
|
+
type: event.type,
|
|
234374
|
+
path: event.path,
|
|
234375
|
+
relativePath: event.relativePath
|
|
234376
|
+
};
|
|
234377
|
+
try {
|
|
234378
|
+
await this.config.onEvent(watchEvent);
|
|
234379
|
+
} catch (error) {
|
|
234380
|
+
console.error(
|
|
234381
|
+
`[IndexWatcher] Error processing event for ${event.relativePath}:`,
|
|
234382
|
+
error
|
|
234383
|
+
);
|
|
234384
|
+
}
|
|
234385
|
+
}
|
|
234386
|
+
}
|
|
234387
|
+
};
|
|
234388
|
+
|
|
234389
|
+
// ../core/src/lib/symbol-dependency.ts
|
|
234390
|
+
var SymbolDependencyGraph = class {
|
|
234391
|
+
edges = /* @__PURE__ */ new Map();
|
|
234392
|
+
reverseEdges = /* @__PURE__ */ new Map();
|
|
234393
|
+
/**
|
|
234394
|
+
* Build the dependency graph from the SQLite index store.
|
|
234395
|
+
* Call this once after initial index build or when restarting the watcher.
|
|
234396
|
+
*/
|
|
234397
|
+
buildFromStore(store) {
|
|
234398
|
+
this.edges.clear();
|
|
234399
|
+
this.reverseEdges.clear();
|
|
234400
|
+
const allFilePaths = store.getAllFilePaths();
|
|
234401
|
+
for (const filePath of allFilePaths) {
|
|
234402
|
+
const fileParse = store.getFileParse(filePath);
|
|
234403
|
+
if (!fileParse) continue;
|
|
234404
|
+
const fileEdges = [];
|
|
234405
|
+
for (const imp of fileParse.imports) {
|
|
234406
|
+
if (!imp.targetPathText) continue;
|
|
234407
|
+
const targetFile = store.getFileParse(imp.targetPathText);
|
|
234408
|
+
if (!targetFile) continue;
|
|
234409
|
+
const importedSymbols = this.extractImportedSymbols(
|
|
234410
|
+
imp,
|
|
234411
|
+
targetFile.exports
|
|
234412
|
+
);
|
|
234413
|
+
if (importedSymbols.length > 0) {
|
|
234414
|
+
fileEdges.push({
|
|
234415
|
+
sourceFilePath: filePath,
|
|
234416
|
+
targetFilePath: imp.targetPathText,
|
|
234417
|
+
importedSymbols
|
|
234418
|
+
});
|
|
234419
|
+
if (!this.reverseEdges.has(imp.targetPathText)) {
|
|
234420
|
+
this.reverseEdges.set(imp.targetPathText, /* @__PURE__ */ new Set());
|
|
234421
|
+
}
|
|
234422
|
+
this.reverseEdges.get(imp.targetPathText).add(filePath);
|
|
234423
|
+
}
|
|
234424
|
+
}
|
|
234425
|
+
if (fileEdges.length > 0) {
|
|
234426
|
+
this.edges.set(filePath, fileEdges);
|
|
234427
|
+
}
|
|
234428
|
+
}
|
|
234429
|
+
console.log(
|
|
234430
|
+
`[SymbolDependencyGraph] Built graph: ${this.edges.size} files with dependencies`
|
|
234431
|
+
);
|
|
234432
|
+
}
|
|
234433
|
+
/**
|
|
234434
|
+
* Get all files that import symbols from the given file.
|
|
234435
|
+
* Returns a map of source file -> imported symbol names.
|
|
234436
|
+
*/
|
|
234437
|
+
getImporters(targetFilePath) {
|
|
234438
|
+
const result = /* @__PURE__ */ new Map();
|
|
234439
|
+
const importers = this.reverseEdges.get(targetFilePath);
|
|
234440
|
+
if (!importers) return result;
|
|
234441
|
+
for (const sourceFile of importers) {
|
|
234442
|
+
const edges = this.edges.get(sourceFile);
|
|
234443
|
+
if (!edges) continue;
|
|
234444
|
+
for (const edge of edges) {
|
|
234445
|
+
if (edge.targetFilePath === targetFilePath) {
|
|
234446
|
+
if (!result.has(sourceFile)) {
|
|
234447
|
+
result.set(sourceFile, /* @__PURE__ */ new Set());
|
|
234448
|
+
}
|
|
234449
|
+
const symbolSet = result.get(sourceFile);
|
|
234450
|
+
for (const sym of edge.importedSymbols) {
|
|
234451
|
+
symbolSet.add(sym.displayName);
|
|
234452
|
+
}
|
|
234453
|
+
}
|
|
234454
|
+
}
|
|
234455
|
+
}
|
|
234456
|
+
return result;
|
|
234457
|
+
}
|
|
234458
|
+
/**
|
|
234459
|
+
* Get all files that should be reindexed when the given symbols in
|
|
234460
|
+
* targetFile change. Only returns files that actually import the
|
|
234461
|
+
* changed symbols, not all files that import targetFile.
|
|
234462
|
+
*/
|
|
234463
|
+
getAffectedFiles(targetFilePath, changedSymbols) {
|
|
234464
|
+
const affected = /* @__PURE__ */ new Set();
|
|
234465
|
+
const importers = this.getImporters(targetFilePath);
|
|
234466
|
+
for (const [sourceFile, importedSymbols] of importers) {
|
|
234467
|
+
for (const changedSymbol of changedSymbols) {
|
|
234468
|
+
if (importedSymbols.has(changedSymbol)) {
|
|
234469
|
+
affected.add(sourceFile);
|
|
234470
|
+
break;
|
|
234471
|
+
}
|
|
234472
|
+
}
|
|
234473
|
+
}
|
|
234474
|
+
return affected;
|
|
234475
|
+
}
|
|
234476
|
+
/**
|
|
234477
|
+
* Update the graph when a single file changes.
|
|
234478
|
+
* Call this after reindexing a file to keep the graph fresh.
|
|
234479
|
+
*/
|
|
234480
|
+
updateFile(store, filePath) {
|
|
234481
|
+
this.edges.delete(filePath);
|
|
234482
|
+
for (const [target, sources] of this.reverseEdges) {
|
|
234483
|
+
sources.delete(filePath);
|
|
234484
|
+
if (sources.size === 0) {
|
|
234485
|
+
this.reverseEdges.delete(target);
|
|
234486
|
+
}
|
|
234487
|
+
}
|
|
234488
|
+
const fileParse = store.getFileParse(filePath);
|
|
234489
|
+
if (!fileParse) return;
|
|
234490
|
+
const fileEdges = [];
|
|
234491
|
+
for (const imp of fileParse.imports) {
|
|
234492
|
+
if (!imp.targetPathText) continue;
|
|
234493
|
+
const targetFile = store.getFileParse(imp.targetPathText);
|
|
234494
|
+
if (!targetFile) continue;
|
|
234495
|
+
const importedSymbols = this.extractImportedSymbols(
|
|
234496
|
+
imp,
|
|
234497
|
+
targetFile.exports
|
|
234498
|
+
);
|
|
234499
|
+
if (importedSymbols.length > 0) {
|
|
234500
|
+
fileEdges.push({
|
|
234501
|
+
sourceFilePath: filePath,
|
|
234502
|
+
targetFilePath: imp.targetPathText,
|
|
234503
|
+
importedSymbols
|
|
234504
|
+
});
|
|
234505
|
+
if (!this.reverseEdges.has(imp.targetPathText)) {
|
|
234506
|
+
this.reverseEdges.set(imp.targetPathText, /* @__PURE__ */ new Set());
|
|
234507
|
+
}
|
|
234508
|
+
this.reverseEdges.get(imp.targetPathText).add(filePath);
|
|
234509
|
+
}
|
|
234510
|
+
}
|
|
234511
|
+
if (fileEdges.length > 0) {
|
|
234512
|
+
this.edges.set(filePath, fileEdges);
|
|
234513
|
+
}
|
|
234514
|
+
}
|
|
234515
|
+
/**
|
|
234516
|
+
* Remove a file from the graph (e.g., when it's deleted).
|
|
234517
|
+
*/
|
|
234518
|
+
removeFile(filePath) {
|
|
234519
|
+
this.edges.delete(filePath);
|
|
234520
|
+
for (const [target, sources] of this.reverseEdges) {
|
|
234521
|
+
sources.delete(filePath);
|
|
234522
|
+
if (sources.size === 0) {
|
|
234523
|
+
this.reverseEdges.delete(target);
|
|
234524
|
+
}
|
|
234525
|
+
}
|
|
234526
|
+
}
|
|
234527
|
+
/**
|
|
234528
|
+
* Get the number of files tracked in the graph.
|
|
234529
|
+
*/
|
|
234530
|
+
size() {
|
|
234531
|
+
return this.edges.size;
|
|
234532
|
+
}
|
|
234533
|
+
extractImportedSymbols(imp, targetExports) {
|
|
234534
|
+
const symbols = [];
|
|
234535
|
+
if (imp.importKind === "namespace") {
|
|
234536
|
+
for (const exp of targetExports) {
|
|
234537
|
+
if (exp.symbolDisplayName) {
|
|
234538
|
+
symbols.push({
|
|
234539
|
+
displayName: exp.symbolDisplayName,
|
|
234540
|
+
kind: exp.exportKind
|
|
234541
|
+
});
|
|
234542
|
+
}
|
|
234543
|
+
}
|
|
234544
|
+
} else if (imp.importKind === "default") {
|
|
234545
|
+
const defaultExport = targetExports.find(
|
|
234546
|
+
(e) => e.exportKind === "default"
|
|
234547
|
+
);
|
|
234548
|
+
if (defaultExport?.symbolDisplayName) {
|
|
234549
|
+
symbols.push({
|
|
234550
|
+
displayName: defaultExport.symbolDisplayName,
|
|
234551
|
+
kind: "default"
|
|
234552
|
+
});
|
|
234553
|
+
}
|
|
234554
|
+
} else {
|
|
234555
|
+
for (const exp of targetExports) {
|
|
234556
|
+
if (exp.exportKind === "named" && exp.symbolDisplayName) {
|
|
234557
|
+
symbols.push({
|
|
234558
|
+
displayName: exp.symbolDisplayName,
|
|
234559
|
+
kind: exp.exportKind
|
|
234560
|
+
});
|
|
234561
|
+
}
|
|
234562
|
+
}
|
|
234563
|
+
}
|
|
234564
|
+
return symbols;
|
|
234565
|
+
}
|
|
234566
|
+
};
|
|
234567
|
+
|
|
234568
|
+
// ../core/src/lib/watch-event-handler.ts
|
|
234569
|
+
var WatchEventHandler = class {
|
|
234570
|
+
config;
|
|
234571
|
+
graph;
|
|
234572
|
+
constructor(config) {
|
|
234573
|
+
this.config = config;
|
|
234574
|
+
this.graph = config.symbolDependencyGraph;
|
|
234575
|
+
}
|
|
234576
|
+
/**
|
|
234577
|
+
* Process a file watch event and determine if/which files should be reindexed.
|
|
234578
|
+
*/
|
|
234579
|
+
async handleEvent(event) {
|
|
234580
|
+
switch (event.type) {
|
|
234581
|
+
case "create":
|
|
234582
|
+
await this.handleFileCreate(event);
|
|
234583
|
+
break;
|
|
234584
|
+
case "update":
|
|
234585
|
+
await this.handleFileUpdate(event);
|
|
234586
|
+
break;
|
|
234587
|
+
case "delete":
|
|
234588
|
+
await this.handleFileDelete(event);
|
|
234589
|
+
break;
|
|
234590
|
+
}
|
|
234591
|
+
}
|
|
234592
|
+
async handleFileCreate(event) {
|
|
234593
|
+
console.log(`[WatchEventHandler] New file detected: ${event.relativePath}`);
|
|
234594
|
+
await this.config.onReindexFile(event.relativePath);
|
|
234595
|
+
this.graph.updateFile(this.config.store, event.relativePath);
|
|
234596
|
+
}
|
|
234597
|
+
getExportNames(filePath) {
|
|
234598
|
+
const parse = this.config.store.getFileParse(filePath);
|
|
234599
|
+
if (!parse) return /* @__PURE__ */ new Set();
|
|
234600
|
+
return new Set(parse.exports.map((e) => e.exportName));
|
|
234601
|
+
}
|
|
234602
|
+
async handleFileUpdate(event) {
|
|
234603
|
+
const filePath = event.relativePath;
|
|
234604
|
+
const importers = this.graph.getImporters(filePath);
|
|
234605
|
+
if (importers.size === 0) {
|
|
234606
|
+
console.log(`[WatchEventHandler] File updated: ${filePath} (no dependents)`);
|
|
234607
|
+
await this.config.onReindexFile(filePath);
|
|
234608
|
+
this.graph.updateFile(this.config.store, filePath);
|
|
234609
|
+
return;
|
|
234610
|
+
}
|
|
234611
|
+
const exportsBefore = this.getExportNames(filePath);
|
|
234612
|
+
await this.config.onReindexFile(filePath);
|
|
234613
|
+
this.graph.updateFile(this.config.store, filePath);
|
|
234614
|
+
const exportsAfter = this.getExportNames(filePath);
|
|
234615
|
+
const exportsChanged = exportsBefore.size !== exportsAfter.size || [...exportsBefore].some((name) => !exportsAfter.has(name)) || [...exportsAfter].some((name) => !exportsBefore.has(name));
|
|
234616
|
+
if (!exportsChanged) {
|
|
234617
|
+
console.log(`[WatchEventHandler] File updated: ${filePath} (exports unchanged, skipping ${importers.size} dependents)`);
|
|
234618
|
+
return;
|
|
234619
|
+
}
|
|
234620
|
+
const dependentFiles = Array.from(importers.keys());
|
|
234621
|
+
console.log(`[WatchEventHandler] File updated: ${filePath} (exports changed, reindexing ${dependentFiles.length} dependents)`);
|
|
234622
|
+
await this.config.onBatchReindex(dependentFiles);
|
|
234623
|
+
for (const importer of dependentFiles) {
|
|
234624
|
+
this.graph.updateFile(this.config.store, importer);
|
|
234625
|
+
}
|
|
234626
|
+
}
|
|
234627
|
+
async handleFileDelete(event) {
|
|
234628
|
+
const filePath = event.relativePath;
|
|
234629
|
+
console.log(`[WatchEventHandler] File deleted: ${filePath}`);
|
|
234630
|
+
this.config.store.removeFileFromIndex(filePath);
|
|
234631
|
+
const importers = this.graph.getImporters(filePath);
|
|
234632
|
+
this.graph.removeFile(filePath);
|
|
234633
|
+
for (const importer of importers.keys()) {
|
|
234634
|
+
try {
|
|
234635
|
+
await this.config.onReindexFile(importer);
|
|
234636
|
+
this.graph.updateFile(this.config.store, importer);
|
|
234637
|
+
} catch (err) {
|
|
234638
|
+
console.error(`[WatchEventHandler] Error reindexing importer ${importer}:`, err);
|
|
234639
|
+
}
|
|
234640
|
+
}
|
|
234641
|
+
}
|
|
234642
|
+
};
|
|
234643
|
+
|
|
234644
|
+
// ../core/src/lib/auto-indexing.ts
|
|
234645
|
+
var _watcher = null;
|
|
234646
|
+
var _dependencyGraph = null;
|
|
234647
|
+
var _eventHandler = null;
|
|
234648
|
+
async function enableAutoIndexing(store, workspaceRootPath) {
|
|
234649
|
+
if (_watcher) {
|
|
234650
|
+
if (_watcher.isActive()) {
|
|
234651
|
+
console.log("[AutoIndexing] Already active");
|
|
234652
|
+
return;
|
|
234653
|
+
}
|
|
234654
|
+
await _watcher.stop().catch(() => {
|
|
234655
|
+
});
|
|
234656
|
+
_watcher = null;
|
|
234657
|
+
_dependencyGraph = null;
|
|
234658
|
+
_eventHandler = null;
|
|
234659
|
+
}
|
|
234660
|
+
_dependencyGraph = new SymbolDependencyGraph();
|
|
234661
|
+
_dependencyGraph.buildFromStore(store);
|
|
234662
|
+
const defaultCallbacks = {
|
|
234663
|
+
onFileChange: async (filePath) => {
|
|
234664
|
+
try {
|
|
234665
|
+
await refreshLocalFile(filePath, workspaceRootPath);
|
|
234666
|
+
console.log(`[AutoIndexing] Reindexed: ${filePath}`);
|
|
234667
|
+
} catch (err) {
|
|
234668
|
+
console.error(`[AutoIndexing] Failed to reindex ${filePath}:`, err);
|
|
234669
|
+
}
|
|
234670
|
+
},
|
|
234671
|
+
onBatchChanges: async (filePaths) => {
|
|
234672
|
+
try {
|
|
234673
|
+
await refreshLocalFiles(filePaths, workspaceRootPath);
|
|
234674
|
+
console.log(`[AutoIndexing] Batch reindexed ${filePaths.length} files`);
|
|
234675
|
+
} catch (err) {
|
|
234676
|
+
console.error(`[AutoIndexing] Batch reindex failed:`, err);
|
|
234677
|
+
}
|
|
234678
|
+
}
|
|
234679
|
+
};
|
|
234680
|
+
_eventHandler = new WatchEventHandler({
|
|
234681
|
+
store,
|
|
234682
|
+
symbolDependencyGraph: _dependencyGraph,
|
|
234683
|
+
onReindexFile: defaultCallbacks.onFileChange,
|
|
234684
|
+
onBatchReindex: defaultCallbacks.onBatchChanges
|
|
234685
|
+
});
|
|
234686
|
+
_watcher = new IndexWatcher({
|
|
234687
|
+
workspaceRootPath,
|
|
234688
|
+
onEvent: async (event) => {
|
|
234689
|
+
try {
|
|
234690
|
+
await _eventHandler.handleEvent(event);
|
|
234691
|
+
} catch (err) {
|
|
234692
|
+
console.error(`[AutoIndexing] Error handling watch event:`, err);
|
|
234693
|
+
}
|
|
234694
|
+
}
|
|
234695
|
+
});
|
|
234696
|
+
await _watcher.start();
|
|
234697
|
+
console.log("[AutoIndexing] Started for:", workspaceRootPath);
|
|
234698
|
+
}
|
|
234699
|
+
async function disableAutoIndexing() {
|
|
234700
|
+
if (!_watcher?.isActive()) {
|
|
234701
|
+
return;
|
|
234702
|
+
}
|
|
234703
|
+
await _watcher.stop();
|
|
234704
|
+
_watcher = null;
|
|
234705
|
+
_dependencyGraph = null;
|
|
234706
|
+
_eventHandler = null;
|
|
234707
|
+
console.log("[AutoIndexing] Stopped");
|
|
234708
|
+
}
|
|
234709
|
+
function isAutoIndexingActive() {
|
|
234710
|
+
return _watcher?.isActive() ?? false;
|
|
234711
|
+
}
|
|
234712
|
+
|
|
234021
234713
|
// src/tools/manage-git-connection.ts
|
|
234022
234714
|
import { z } from "zod";
|
|
234023
234715
|
|
|
@@ -237317,6 +238009,117 @@ function registerRefreshLocalIndexTool(server2) {
|
|
|
237317
238009
|
);
|
|
237318
238010
|
}
|
|
237319
238011
|
|
|
238012
|
+
// src/tools/auto-index-control.ts
|
|
238013
|
+
import { performance as performance3 } from "perf_hooks";
|
|
238014
|
+
function registerEnableAutoIndexingTool(server2) {
|
|
238015
|
+
server2.registerTool(
|
|
238016
|
+
"enable_auto_indexing",
|
|
238017
|
+
{
|
|
238018
|
+
title: "Enable Auto Indexing",
|
|
238019
|
+
description: "Enables automatic file watching and index refresh for the current workspace. When enabled, CodeMap will automatically reindex files when they change, keeping your local SQLite index up-to-date without manual intervention.",
|
|
238020
|
+
inputSchema: {}
|
|
238021
|
+
},
|
|
238022
|
+
withToolError(async () => {
|
|
238023
|
+
const startedAt = performance3.now();
|
|
238024
|
+
const workspaceRoot = process.cwd();
|
|
238025
|
+
const store = await ensureLocalIndex({ force: false });
|
|
238026
|
+
await enableAutoIndexing(store, workspaceRoot);
|
|
238027
|
+
const elapsedMs = Math.round(performance3.now() - startedAt);
|
|
238028
|
+
const summary = await getLocalIndexSummary(store);
|
|
238029
|
+
const output = [
|
|
238030
|
+
"Auto-indexing enabled successfully.",
|
|
238031
|
+
`Workspace: ${workspaceRoot}`,
|
|
238032
|
+
"",
|
|
238033
|
+
"Current index status:",
|
|
238034
|
+
` Files: ${summary.fileCount}`,
|
|
238035
|
+
` Symbols: ${summary.symbolCount}`,
|
|
238036
|
+
` Stale: ${summary.stale ? "yes" : "no"}`,
|
|
238037
|
+
"",
|
|
238038
|
+
"The index will now automatically update when files change."
|
|
238039
|
+
].join("\n");
|
|
238040
|
+
return success(output, {
|
|
238041
|
+
status: "completed",
|
|
238042
|
+
mode: "local",
|
|
238043
|
+
workspacePath: workspaceRoot,
|
|
238044
|
+
fileCount: summary.fileCount,
|
|
238045
|
+
symbolCount: summary.symbolCount,
|
|
238046
|
+
stale: summary.stale,
|
|
238047
|
+
elapsedMs,
|
|
238048
|
+
suggestedNextTools: ["diff()", "get_project_map()"]
|
|
238049
|
+
});
|
|
238050
|
+
})
|
|
238051
|
+
);
|
|
238052
|
+
}
|
|
238053
|
+
function registerDisableAutoIndexingTool(server2) {
|
|
238054
|
+
server2.registerTool(
|
|
238055
|
+
"disable_auto_indexing",
|
|
238056
|
+
{
|
|
238057
|
+
title: "Disable Auto Indexing",
|
|
238058
|
+
description: "Disables automatic file watching and index refresh for the current workspace. After disabling, you'll need to manually refresh the index when files change using 'refresh_local_index'.",
|
|
238059
|
+
inputSchema: {}
|
|
238060
|
+
},
|
|
238061
|
+
withToolError(async () => {
|
|
238062
|
+
const startedAt = performance3.now();
|
|
238063
|
+
disableAutoIndexing();
|
|
238064
|
+
const elapsedMs = Math.round(performance3.now() - startedAt);
|
|
238065
|
+
const output = [
|
|
238066
|
+
"Auto-indexing disabled successfully.",
|
|
238067
|
+
"The file watcher has been stopped.",
|
|
238068
|
+
"",
|
|
238069
|
+
"To enable again in the future, use 'enable_auto_indexing'.",
|
|
238070
|
+
"To manually refresh the index when needed, use 'refresh_local_index'."
|
|
238071
|
+
].join("\n");
|
|
238072
|
+
return success(output, {
|
|
238073
|
+
status: "completed",
|
|
238074
|
+
mode: "local",
|
|
238075
|
+
elapsedMs,
|
|
238076
|
+
suggestedNextTools: ["refresh_local_index(force=true)"]
|
|
238077
|
+
});
|
|
238078
|
+
})
|
|
238079
|
+
);
|
|
238080
|
+
}
|
|
238081
|
+
function registerCheckAutoIndexStatusTool(server2) {
|
|
238082
|
+
server2.registerTool(
|
|
238083
|
+
"check_auto_index_status",
|
|
238084
|
+
{
|
|
238085
|
+
title: "Check Auto Index Status",
|
|
238086
|
+
description: "Checks the current status of automatic file watching and index refresh. Returns whether auto-indexing is active, the workspace being watched, and current index statistics.",
|
|
238087
|
+
inputSchema: {}
|
|
238088
|
+
},
|
|
238089
|
+
withToolError(async () => {
|
|
238090
|
+
const startedAt = performance3.now();
|
|
238091
|
+
const isActive = isAutoIndexingActive();
|
|
238092
|
+
const workspaceRoot = process.cwd();
|
|
238093
|
+
let statusInfo = [
|
|
238094
|
+
"Auto-indexing status report:",
|
|
238095
|
+
` Active: ${isActive ? "Yes \u2713" : "No \u2717"}`,
|
|
238096
|
+
` Workspace: ${workspaceRoot}`
|
|
238097
|
+
];
|
|
238098
|
+
if (isActive) {
|
|
238099
|
+
statusInfo.push("");
|
|
238100
|
+
statusInfo.push("Auto-indexing is running. Files will be automatically reindexed when changed.");
|
|
238101
|
+
statusInfo.push("Tip: Use 'disable_auto_indexing' to stop watching or 'refresh_local_index' for manual refresh.");
|
|
238102
|
+
} else {
|
|
238103
|
+
statusInfo.push("");
|
|
238104
|
+
statusInfo.push("Auto-indexing is disabled. Use 'enable_auto_indexing' to start watching files automatically.");
|
|
238105
|
+
statusInfo.push("Tip: You can still manually refresh using 'refresh_local_index'.");
|
|
238106
|
+
}
|
|
238107
|
+
const elapsedMs = Math.round(performance3.now() - startedAt);
|
|
238108
|
+
return success(statusInfo.join("\n"), {
|
|
238109
|
+
status: "completed",
|
|
238110
|
+
mode: "local",
|
|
238111
|
+
workspacePath: workspaceRoot,
|
|
238112
|
+
isActive,
|
|
238113
|
+
elapsedMs,
|
|
238114
|
+
suggestedNextTools: [
|
|
238115
|
+
isActive ? "disable_auto_indexing()" : "enable_auto_indexing()",
|
|
238116
|
+
"refresh_local_index(force=true)"
|
|
238117
|
+
]
|
|
238118
|
+
});
|
|
238119
|
+
})
|
|
238120
|
+
);
|
|
238121
|
+
}
|
|
238122
|
+
|
|
237320
238123
|
// src/tools/get-file.ts
|
|
237321
238124
|
import { z as z13 } from "zod";
|
|
237322
238125
|
|
|
@@ -240527,6 +241330,149 @@ function formatReadCall(path19, plan) {
|
|
|
240527
241330
|
return `get_file("${path19}", ${parts.join(", ")})`;
|
|
240528
241331
|
}
|
|
240529
241332
|
var OUTLINE_PLAN = { include: ["outline"] };
|
|
241333
|
+
function buildLocalReadPlan(symbol) {
|
|
241334
|
+
if (!symbol?.name) return OUTLINE_PLAN;
|
|
241335
|
+
return { include: ["symbols"], symbolNames: [symbol.name] };
|
|
241336
|
+
}
|
|
241337
|
+
function tokenizeLocalQuery(query) {
|
|
241338
|
+
return query.toLowerCase().split(/[\s\-_/.,:]+/).map((term) => term.trim()).filter((term) => term.length > 1);
|
|
241339
|
+
}
|
|
241340
|
+
function buildLocalReason(path19, query, symbol) {
|
|
241341
|
+
const parts = [];
|
|
241342
|
+
if (symbol?.name) parts.push(`symbol match: ${symbol.name}`);
|
|
241343
|
+
const terms2 = tokenizeLocalQuery(query);
|
|
241344
|
+
const lowerPath = path19.toLowerCase();
|
|
241345
|
+
const matchedTerms = terms2.filter((term) => lowerPath.includes(term));
|
|
241346
|
+
if (matchedTerms.length > 0) {
|
|
241347
|
+
parts.push(`path matches: ${matchedTerms.slice(0, 3).join(", ")}`);
|
|
241348
|
+
}
|
|
241349
|
+
return parts[0] ?? "local index match";
|
|
241350
|
+
}
|
|
241351
|
+
function buildLocalExploreData(task, results, importerCountsByPath) {
|
|
241352
|
+
const likelyFiles = [];
|
|
241353
|
+
const likelyFilePaths = /* @__PURE__ */ new Set();
|
|
241354
|
+
const importerCounts = /* @__PURE__ */ new Map();
|
|
241355
|
+
const symbolByPath = /* @__PURE__ */ new Map();
|
|
241356
|
+
const symbols = results.symbols.slice(0, 8).map((s) => ({
|
|
241357
|
+
name: s.displayName,
|
|
241358
|
+
kind: s.symbolKind,
|
|
241359
|
+
filePath: s.filePath,
|
|
241360
|
+
startLine: s.startLine ?? null,
|
|
241361
|
+
signature: s.signature ?? null
|
|
241362
|
+
}));
|
|
241363
|
+
for (const symbol of symbols) {
|
|
241364
|
+
const existing = symbolByPath.get(symbol.filePath) ?? [];
|
|
241365
|
+
existing.push(symbol);
|
|
241366
|
+
symbolByPath.set(symbol.filePath, existing);
|
|
241367
|
+
}
|
|
241368
|
+
const pushLikelyFile = (path19, language, confidence, baseReason, blastRadius) => {
|
|
241369
|
+
if (likelyFilePaths.has(path19)) return;
|
|
241370
|
+
const topSymbol = symbolByPath.get(path19)?.[0] ?? null;
|
|
241371
|
+
likelyFiles.push({
|
|
241372
|
+
path: path19,
|
|
241373
|
+
language,
|
|
241374
|
+
confidence,
|
|
241375
|
+
reason: baseReason ?? buildLocalReason(path19, task, topSymbol),
|
|
241376
|
+
readPlan: buildLocalReadPlan(topSymbol),
|
|
241377
|
+
...blastRadius !== void 0 ? { blastRadius } : {}
|
|
241378
|
+
});
|
|
241379
|
+
likelyFilePaths.add(path19);
|
|
241380
|
+
};
|
|
241381
|
+
for (const symbol of results.symbols.slice(0, 8)) {
|
|
241382
|
+
const importerCount = importerCountsByPath.get(symbol.filePath);
|
|
241383
|
+
if (typeof importerCount === "number") importerCounts.set(symbol.filePath, importerCount);
|
|
241384
|
+
pushLikelyFile(
|
|
241385
|
+
symbol.filePath,
|
|
241386
|
+
null,
|
|
241387
|
+
"high",
|
|
241388
|
+
`symbol match: ${symbol.displayName}`,
|
|
241389
|
+
importerCount
|
|
241390
|
+
);
|
|
241391
|
+
}
|
|
241392
|
+
for (const file of results.files.slice(0, 8)) {
|
|
241393
|
+
const importerCount = importerCountsByPath.get(file.path);
|
|
241394
|
+
if (typeof importerCount === "number") importerCounts.set(file.path, importerCount);
|
|
241395
|
+
pushLikelyFile(
|
|
241396
|
+
file.path,
|
|
241397
|
+
file.language ?? null,
|
|
241398
|
+
likelyFilePaths.size < 4 ? "high" : "medium",
|
|
241399
|
+
void 0,
|
|
241400
|
+
importerCount
|
|
241401
|
+
);
|
|
241402
|
+
}
|
|
241403
|
+
const entrypointMap = /* @__PURE__ */ new Map();
|
|
241404
|
+
for (const path19 of likelyFiles.map((f) => f.path)) {
|
|
241405
|
+
const label = detectEntrypoint(path19);
|
|
241406
|
+
if (label && !entrypointMap.has(path19)) entrypointMap.set(path19, label);
|
|
241407
|
+
}
|
|
241408
|
+
const entrypoints = [...entrypointMap.entries()].map(([path19, label]) => ({
|
|
241409
|
+
path: path19,
|
|
241410
|
+
language: null,
|
|
241411
|
+
confidence: "medium",
|
|
241412
|
+
reason: label,
|
|
241413
|
+
readPlan: OUTLINE_PLAN,
|
|
241414
|
+
...importerCounts.has(path19) ? { blastRadius: importerCounts.get(path19) } : {}
|
|
241415
|
+
}));
|
|
241416
|
+
return { likelyFiles, entrypoints, symbols, importerCounts };
|
|
241417
|
+
}
|
|
241418
|
+
async function buildLocalFallbackResponse(projectId, task, fallbackReason) {
|
|
241419
|
+
const { store } = await ensureLocalIndexWithSummary();
|
|
241420
|
+
const localSearch = store.search(task, null);
|
|
241421
|
+
const importerCountsByPath = /* @__PURE__ */ new Map();
|
|
241422
|
+
for (const file of localSearch.files.slice(0, 8)) {
|
|
241423
|
+
const parse = store.getFileParse(file.path);
|
|
241424
|
+
importerCountsByPath.set(file.path, parse?.importedBy.length ?? 0);
|
|
241425
|
+
}
|
|
241426
|
+
for (const symbol of localSearch.symbols.slice(0, 8)) {
|
|
241427
|
+
if (importerCountsByPath.has(symbol.filePath)) continue;
|
|
241428
|
+
const parse = store.getFileParse(symbol.filePath);
|
|
241429
|
+
importerCountsByPath.set(symbol.filePath, parse?.importedBy.length ?? 0);
|
|
241430
|
+
}
|
|
241431
|
+
const localData = buildLocalExploreData(task, localSearch, importerCountsByPath);
|
|
241432
|
+
const risks = [];
|
|
241433
|
+
const risksSeen = /* @__PURE__ */ new Set();
|
|
241434
|
+
for (const path19 of [
|
|
241435
|
+
...localData.likelyFiles.map((f) => f.path),
|
|
241436
|
+
...localData.entrypoints.map((f) => f.path)
|
|
241437
|
+
]) {
|
|
241438
|
+
if (risksSeen.has(path19)) continue;
|
|
241439
|
+
const risk = detectPathRisk(path19);
|
|
241440
|
+
if (risk) {
|
|
241441
|
+
risks.push(risk);
|
|
241442
|
+
risksSeen.add(path19);
|
|
241443
|
+
}
|
|
241444
|
+
}
|
|
241445
|
+
const recommendedReads = [];
|
|
241446
|
+
let priority = 1;
|
|
241447
|
+
for (const f of [...localData.entrypoints, ...localData.likelyFiles]) {
|
|
241448
|
+
recommendedReads.push({
|
|
241449
|
+
path: f.path,
|
|
241450
|
+
priority: priority++,
|
|
241451
|
+
readPlan: f.readPlan,
|
|
241452
|
+
why: f.reason
|
|
241453
|
+
});
|
|
241454
|
+
}
|
|
241455
|
+
const packBase = {
|
|
241456
|
+
task,
|
|
241457
|
+
likelyFiles: localData.likelyFiles,
|
|
241458
|
+
entrypoints: localData.entrypoints,
|
|
241459
|
+
symbols: localData.symbols,
|
|
241460
|
+
risks,
|
|
241461
|
+
recommendedReads
|
|
241462
|
+
};
|
|
241463
|
+
const summary = [
|
|
241464
|
+
buildSummary(packBase),
|
|
241465
|
+
`Source: local SQLite index (${fallbackReason})`
|
|
241466
|
+
].join("\n");
|
|
241467
|
+
const suggestedNextTools = buildNextTools(packBase);
|
|
241468
|
+
const pack = { ...packBase, summary, suggestedNextTools };
|
|
241469
|
+
return success(buildTextOutput(pack), {
|
|
241470
|
+
projectId,
|
|
241471
|
+
available: true,
|
|
241472
|
+
source: "local",
|
|
241473
|
+
...pack
|
|
241474
|
+
});
|
|
241475
|
+
}
|
|
240530
241476
|
function buildSummary(pack) {
|
|
240531
241477
|
const lines = [];
|
|
240532
241478
|
const domains = [
|
|
@@ -240672,19 +241618,10 @@ function registerExploreTaskTool(server2, config) {
|
|
|
240672
241618
|
);
|
|
240673
241619
|
}
|
|
240674
241620
|
if (await shouldUseLocalIndexBeforeRemote(client, resolvedProjectId)) {
|
|
240675
|
-
|
|
240676
|
-
|
|
240677
|
-
|
|
240678
|
-
|
|
240679
|
-
Use search_codebase with the local index instead:
|
|
240680
|
-
\u2192 ${hint}`,
|
|
240681
|
-
{
|
|
240682
|
-
projectId: resolvedProjectId,
|
|
240683
|
-
task,
|
|
240684
|
-
available: false,
|
|
240685
|
-
source: "local",
|
|
240686
|
-
suggestedNextTools: [hint, "get_project_map() // browse project structure"]
|
|
240687
|
-
}
|
|
241621
|
+
return buildLocalFallbackResponse(
|
|
241622
|
+
resolvedProjectId,
|
|
241623
|
+
task,
|
|
241624
|
+
"cloud index not ready"
|
|
240688
241625
|
);
|
|
240689
241626
|
}
|
|
240690
241627
|
const [searchResult, editLocsResult, semanticResult] = await Promise.allSettled([
|
|
@@ -240708,6 +241645,13 @@ Use search_codebase with the local index instead:
|
|
|
240708
241645
|
const cloudFailed = bothFailed && shouldFallbackToLocal(
|
|
240709
241646
|
searchResult.status === "rejected" ? searchResult.reason : null
|
|
240710
241647
|
);
|
|
241648
|
+
if (cloudFailed) {
|
|
241649
|
+
return buildLocalFallbackResponse(
|
|
241650
|
+
resolvedProjectId,
|
|
241651
|
+
task,
|
|
241652
|
+
"cloud API unavailable"
|
|
241653
|
+
);
|
|
241654
|
+
}
|
|
240711
241655
|
const likelyFiles = editLocs.suggestions.filter((s) => s.confidence === "high" || s.confidence === "medium").slice(0, 8).map((s) => ({
|
|
240712
241656
|
path: s.path,
|
|
240713
241657
|
language: s.language ?? null,
|
|
@@ -240841,11 +241785,6 @@ Use search_codebase with the local index instead:
|
|
|
240841
241785
|
const packBase = { task, likelyFiles, entrypoints, symbols, risks, recommendedReads };
|
|
240842
241786
|
const summary = buildSummary(packBase);
|
|
240843
241787
|
const suggestedNextTools = buildNextTools(packBase);
|
|
240844
|
-
if (cloudFailed) {
|
|
240845
|
-
suggestedNextTools.unshift(
|
|
240846
|
-
`search_codebase("${task.slice(0, 60)}") // cloud unavailable \u2014 use local index`
|
|
240847
|
-
);
|
|
240848
|
-
}
|
|
240849
241788
|
const pack = { ...packBase, summary, suggestedNextTools };
|
|
240850
241789
|
return success(buildTextOutput(pack), {
|
|
240851
241790
|
projectId: resolvedProjectId,
|
|
@@ -240878,6 +241817,9 @@ async function runMcpServer() {
|
|
|
240878
241817
|
registerGetProjectMapTool(server2, config);
|
|
240879
241818
|
registerDiffTool(server2, config);
|
|
240880
241819
|
registerRefreshLocalIndexTool(server2);
|
|
241820
|
+
registerEnableAutoIndexingTool(server2);
|
|
241821
|
+
registerDisableAutoIndexingTool(server2);
|
|
241822
|
+
registerCheckAutoIndexStatusTool(server2);
|
|
240881
241823
|
registerWebSearchTool(server2);
|
|
240882
241824
|
registerReimportTool(server2, config);
|
|
240883
241825
|
if (toolMode === "standard" || toolMode === "full") {
|
|
@@ -240898,6 +241840,11 @@ async function runMcpServer() {
|
|
|
240898
241840
|
registerAgentRuleResources(server2);
|
|
240899
241841
|
const transport = new StdioServerTransport();
|
|
240900
241842
|
await server2.connect(transport);
|
|
241843
|
+
ensureLocalIndex({ force: false }).then((store) => {
|
|
241844
|
+
const workspaceRootPath = store.getMeta()?.workspaceRootPath;
|
|
241845
|
+
if (workspaceRootPath) return enableAutoIndexing(store, workspaceRootPath);
|
|
241846
|
+
}).catch(() => {
|
|
241847
|
+
});
|
|
240901
241848
|
await autoInjectRules(server2, process.cwd());
|
|
240902
241849
|
const sessionCtx = await buildSessionContext(process.cwd()).catch(() => null);
|
|
240903
241850
|
if (sessionCtx) process.stderr.write(sessionCtx + "\n");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codemap-ai/mcp",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.10",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "CodeMap MCP server for IDE integrations",
|
|
6
6
|
"license": "MIT",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"tsup": "^8.5.1",
|
|
23
23
|
"tsx": "^4.21.0",
|
|
24
24
|
"typescript": "~5.9.2",
|
|
25
|
-
"@codemap-ai/core": "1.1.
|
|
25
|
+
"@codemap-ai/core": "1.1.10"
|
|
26
26
|
},
|
|
27
27
|
"publishConfig": {
|
|
28
28
|
"access": "public"
|