@liendev/lien 0.11.0 → 0.13.0
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/CURSOR_RULES_TEMPLATE.md +176 -0
- package/dist/index.js +968 -291
- package/dist/index.js.map +1 -1
- package/package.json +7 -2
package/dist/index.js
CHANGED
|
@@ -9,11 +9,39 @@ var __export = (target, all) => {
|
|
|
9
9
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
+
// src/utils/version.ts
|
|
13
|
+
import { createRequire } from "module";
|
|
14
|
+
import { fileURLToPath } from "url";
|
|
15
|
+
import { dirname, join } from "path";
|
|
16
|
+
function getPackageVersion() {
|
|
17
|
+
return packageJson.version;
|
|
18
|
+
}
|
|
19
|
+
var __filename, __dirname, require2, packageJson;
|
|
20
|
+
var init_version = __esm({
|
|
21
|
+
"src/utils/version.ts"() {
|
|
22
|
+
"use strict";
|
|
23
|
+
__filename = fileURLToPath(import.meta.url);
|
|
24
|
+
__dirname = dirname(__filename);
|
|
25
|
+
require2 = createRequire(import.meta.url);
|
|
26
|
+
try {
|
|
27
|
+
packageJson = require2(join(__dirname, "../package.json"));
|
|
28
|
+
} catch {
|
|
29
|
+
try {
|
|
30
|
+
packageJson = require2(join(__dirname, "../../package.json"));
|
|
31
|
+
} catch {
|
|
32
|
+
console.warn("[Lien] Warning: Could not load package.json, using fallback version");
|
|
33
|
+
packageJson = { version: "0.0.0-unknown" };
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
|
|
12
39
|
// src/constants.ts
|
|
13
40
|
var DEFAULT_CHUNK_SIZE, DEFAULT_CHUNK_OVERLAP, DEFAULT_CONCURRENCY, DEFAULT_EMBEDDING_BATCH_SIZE, EMBEDDING_MICRO_BATCH_SIZE, VECTOR_DB_MAX_BATCH_SIZE, VECTOR_DB_MIN_BATCH_SIZE, EMBEDDING_DIMENSIONS, DEFAULT_EMBEDDING_MODEL, DEFAULT_PORT, VERSION_CHECK_INTERVAL_MS, DEFAULT_GIT_POLL_INTERVAL_MS, DEFAULT_DEBOUNCE_MS, CURRENT_CONFIG_VERSION, INDEX_FORMAT_VERSION;
|
|
14
41
|
var init_constants = __esm({
|
|
15
42
|
"src/constants.ts"() {
|
|
16
43
|
"use strict";
|
|
44
|
+
init_version();
|
|
17
45
|
DEFAULT_CHUNK_SIZE = 75;
|
|
18
46
|
DEFAULT_CHUNK_OVERLAP = 10;
|
|
19
47
|
DEFAULT_CONCURRENCY = 4;
|
|
@@ -27,8 +55,8 @@ var init_constants = __esm({
|
|
|
27
55
|
VERSION_CHECK_INTERVAL_MS = 2e3;
|
|
28
56
|
DEFAULT_GIT_POLL_INTERVAL_MS = 1e4;
|
|
29
57
|
DEFAULT_DEBOUNCE_MS = 1e3;
|
|
30
|
-
CURRENT_CONFIG_VERSION =
|
|
31
|
-
INDEX_FORMAT_VERSION =
|
|
58
|
+
CURRENT_CONFIG_VERSION = getPackageVersion();
|
|
59
|
+
INDEX_FORMAT_VERSION = 2;
|
|
32
60
|
}
|
|
33
61
|
});
|
|
34
62
|
|
|
@@ -52,6 +80,12 @@ var init_schema = __esm({
|
|
|
52
80
|
concurrency: DEFAULT_CONCURRENCY,
|
|
53
81
|
embeddingBatchSize: DEFAULT_EMBEDDING_BATCH_SIZE
|
|
54
82
|
},
|
|
83
|
+
chunking: {
|
|
84
|
+
useAST: true,
|
|
85
|
+
// AST-based chunking enabled by default (v0.13.0)
|
|
86
|
+
astFallback: "line-based"
|
|
87
|
+
// Fallback to line-based on errors
|
|
88
|
+
},
|
|
55
89
|
mcp: {
|
|
56
90
|
port: DEFAULT_PORT,
|
|
57
91
|
transport: "stdio",
|
|
@@ -80,6 +114,10 @@ function deepMergeConfig(defaults, user) {
|
|
|
80
114
|
...defaults.core,
|
|
81
115
|
...user.core
|
|
82
116
|
},
|
|
117
|
+
chunking: {
|
|
118
|
+
...defaults.chunking,
|
|
119
|
+
...user.chunking
|
|
120
|
+
},
|
|
83
121
|
mcp: {
|
|
84
122
|
...defaults.mcp,
|
|
85
123
|
...user.mcp
|
|
@@ -125,7 +163,10 @@ function needsMigration(config) {
|
|
|
125
163
|
if (!config) {
|
|
126
164
|
return false;
|
|
127
165
|
}
|
|
128
|
-
if (config.frameworks !== void 0) {
|
|
166
|
+
if (config.frameworks !== void 0 && !config.chunking) {
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
if (config.frameworks !== void 0 && config.chunking !== void 0) {
|
|
129
170
|
return false;
|
|
130
171
|
}
|
|
131
172
|
if (config.indexing !== void 0) {
|
|
@@ -138,12 +179,16 @@ function needsMigration(config) {
|
|
|
138
179
|
}
|
|
139
180
|
function migrateConfig(oldConfig) {
|
|
140
181
|
const newConfig = {
|
|
141
|
-
version:
|
|
182
|
+
version: CURRENT_CONFIG_VERSION,
|
|
142
183
|
core: {
|
|
143
|
-
chunkSize: oldConfig.indexing?.chunkSize ?? defaultConfig.core.chunkSize,
|
|
144
|
-
chunkOverlap: oldConfig.indexing?.chunkOverlap ?? defaultConfig.core.chunkOverlap,
|
|
145
|
-
concurrency: oldConfig.indexing?.concurrency ?? defaultConfig.core.concurrency,
|
|
146
|
-
embeddingBatchSize: oldConfig.indexing?.embeddingBatchSize ?? defaultConfig.core.embeddingBatchSize
|
|
184
|
+
chunkSize: oldConfig.indexing?.chunkSize ?? oldConfig.core?.chunkSize ?? defaultConfig.core.chunkSize,
|
|
185
|
+
chunkOverlap: oldConfig.indexing?.chunkOverlap ?? oldConfig.core?.chunkOverlap ?? defaultConfig.core.chunkOverlap,
|
|
186
|
+
concurrency: oldConfig.indexing?.concurrency ?? oldConfig.core?.concurrency ?? defaultConfig.core.concurrency,
|
|
187
|
+
embeddingBatchSize: oldConfig.indexing?.embeddingBatchSize ?? oldConfig.core?.embeddingBatchSize ?? defaultConfig.core.embeddingBatchSize
|
|
188
|
+
},
|
|
189
|
+
chunking: {
|
|
190
|
+
useAST: oldConfig.chunking?.useAST ?? defaultConfig.chunking.useAST,
|
|
191
|
+
astFallback: oldConfig.chunking?.astFallback ?? defaultConfig.chunking.astFallback
|
|
147
192
|
},
|
|
148
193
|
mcp: {
|
|
149
194
|
port: oldConfig.mcp?.port ?? defaultConfig.mcp.port,
|
|
@@ -158,9 +203,9 @@ function migrateConfig(oldConfig) {
|
|
|
158
203
|
enabled: oldConfig.fileWatching?.enabled ?? defaultConfig.fileWatching.enabled,
|
|
159
204
|
debounceMs: oldConfig.fileWatching?.debounceMs ?? defaultConfig.fileWatching.debounceMs
|
|
160
205
|
},
|
|
161
|
-
frameworks: []
|
|
206
|
+
frameworks: oldConfig.frameworks ?? []
|
|
162
207
|
};
|
|
163
|
-
if (oldConfig.indexing) {
|
|
208
|
+
if (oldConfig.indexing && newConfig.frameworks.length === 0) {
|
|
164
209
|
const genericFramework = {
|
|
165
210
|
name: "generic",
|
|
166
211
|
path: ".",
|
|
@@ -180,7 +225,7 @@ function migrateConfig(oldConfig) {
|
|
|
180
225
|
}
|
|
181
226
|
};
|
|
182
227
|
newConfig.frameworks.push(genericFramework);
|
|
183
|
-
} else {
|
|
228
|
+
} else if (newConfig.frameworks.length === 0) {
|
|
184
229
|
const genericFramework = {
|
|
185
230
|
name: "generic",
|
|
186
231
|
path: ".",
|
|
@@ -207,6 +252,14 @@ var init_migration = __esm({
|
|
|
207
252
|
"src/config/migration.ts"() {
|
|
208
253
|
"use strict";
|
|
209
254
|
init_schema();
|
|
255
|
+
init_constants();
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
// src/errors/codes.ts
|
|
260
|
+
var init_codes = __esm({
|
|
261
|
+
"src/errors/codes.ts"() {
|
|
262
|
+
"use strict";
|
|
210
263
|
}
|
|
211
264
|
});
|
|
212
265
|
|
|
@@ -216,7 +269,7 @@ function wrapError(error, context, additionalContext) {
|
|
|
216
269
|
const stack = error instanceof Error ? error.stack : void 0;
|
|
217
270
|
const wrappedError = new LienError(
|
|
218
271
|
`${context}: ${message}`,
|
|
219
|
-
"
|
|
272
|
+
"INTERNAL_ERROR" /* INTERNAL_ERROR */,
|
|
220
273
|
additionalContext
|
|
221
274
|
);
|
|
222
275
|
if (stack) {
|
|
@@ -231,32 +284,61 @@ var LienError, ConfigError, EmbeddingError, DatabaseError;
|
|
|
231
284
|
var init_errors = __esm({
|
|
232
285
|
"src/errors/index.ts"() {
|
|
233
286
|
"use strict";
|
|
287
|
+
init_codes();
|
|
288
|
+
init_codes();
|
|
234
289
|
LienError = class extends Error {
|
|
235
|
-
constructor(message, code, context) {
|
|
290
|
+
constructor(message, code, context, severity = "medium", recoverable = true, retryable = false) {
|
|
236
291
|
super(message);
|
|
237
292
|
this.code = code;
|
|
238
293
|
this.context = context;
|
|
294
|
+
this.severity = severity;
|
|
295
|
+
this.recoverable = recoverable;
|
|
296
|
+
this.retryable = retryable;
|
|
239
297
|
this.name = "LienError";
|
|
240
298
|
if (Error.captureStackTrace) {
|
|
241
299
|
Error.captureStackTrace(this, this.constructor);
|
|
242
300
|
}
|
|
243
301
|
}
|
|
302
|
+
/**
|
|
303
|
+
* Serialize error to JSON for MCP responses
|
|
304
|
+
*/
|
|
305
|
+
toJSON() {
|
|
306
|
+
return {
|
|
307
|
+
error: this.message,
|
|
308
|
+
code: this.code,
|
|
309
|
+
severity: this.severity,
|
|
310
|
+
recoverable: this.recoverable,
|
|
311
|
+
context: this.context
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Check if this error is retryable
|
|
316
|
+
*/
|
|
317
|
+
isRetryable() {
|
|
318
|
+
return this.retryable;
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Check if this error is recoverable
|
|
322
|
+
*/
|
|
323
|
+
isRecoverable() {
|
|
324
|
+
return this.recoverable;
|
|
325
|
+
}
|
|
244
326
|
};
|
|
245
327
|
ConfigError = class extends LienError {
|
|
246
328
|
constructor(message, context) {
|
|
247
|
-
super(message, "
|
|
329
|
+
super(message, "CONFIG_INVALID" /* CONFIG_INVALID */, context, "medium", true, false);
|
|
248
330
|
this.name = "ConfigError";
|
|
249
331
|
}
|
|
250
332
|
};
|
|
251
333
|
EmbeddingError = class extends LienError {
|
|
252
334
|
constructor(message, context) {
|
|
253
|
-
super(message, "
|
|
335
|
+
super(message, "EMBEDDING_GENERATION_FAILED" /* EMBEDDING_GENERATION_FAILED */, context, "high", true, true);
|
|
254
336
|
this.name = "EmbeddingError";
|
|
255
337
|
}
|
|
256
338
|
};
|
|
257
339
|
DatabaseError = class extends LienError {
|
|
258
340
|
constructor(message, context) {
|
|
259
|
-
super(message, "
|
|
341
|
+
super(message, "INTERNAL_ERROR" /* INTERNAL_ERROR */, context, "high", true, true);
|
|
260
342
|
this.name = "DatabaseError";
|
|
261
343
|
}
|
|
262
344
|
};
|
|
@@ -839,7 +921,7 @@ async function readVersionFile(indexPath) {
|
|
|
839
921
|
}
|
|
840
922
|
}
|
|
841
923
|
var VERSION_FILE;
|
|
842
|
-
var
|
|
924
|
+
var init_version2 = __esm({
|
|
843
925
|
"src/vectordb/version.ts"() {
|
|
844
926
|
"use strict";
|
|
845
927
|
VERSION_FILE = ".lien-index-version";
|
|
@@ -1269,9 +1351,501 @@ var init_symbol_extractor = __esm({
|
|
|
1269
1351
|
}
|
|
1270
1352
|
});
|
|
1271
1353
|
|
|
1354
|
+
// src/indexer/ast/parser.ts
|
|
1355
|
+
import Parser from "tree-sitter";
|
|
1356
|
+
import TypeScript from "tree-sitter-typescript";
|
|
1357
|
+
import JavaScript from "tree-sitter-javascript";
|
|
1358
|
+
import { extname } from "path";
|
|
1359
|
+
function getParser(language) {
|
|
1360
|
+
if (!parserCache.has(language)) {
|
|
1361
|
+
const parser = new Parser();
|
|
1362
|
+
const grammar = languageConfig[language];
|
|
1363
|
+
if (!grammar) {
|
|
1364
|
+
throw new Error(`No grammar available for language: ${language}`);
|
|
1365
|
+
}
|
|
1366
|
+
parser.setLanguage(grammar);
|
|
1367
|
+
parserCache.set(language, parser);
|
|
1368
|
+
}
|
|
1369
|
+
return parserCache.get(language);
|
|
1370
|
+
}
|
|
1371
|
+
function detectLanguage2(filePath) {
|
|
1372
|
+
const ext = extname(filePath).slice(1).toLowerCase();
|
|
1373
|
+
switch (ext) {
|
|
1374
|
+
case "ts":
|
|
1375
|
+
case "tsx":
|
|
1376
|
+
return "typescript";
|
|
1377
|
+
case "js":
|
|
1378
|
+
case "jsx":
|
|
1379
|
+
case "mjs":
|
|
1380
|
+
case "cjs":
|
|
1381
|
+
return "javascript";
|
|
1382
|
+
default:
|
|
1383
|
+
return null;
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
function isASTSupported(filePath) {
|
|
1387
|
+
return detectLanguage2(filePath) !== null;
|
|
1388
|
+
}
|
|
1389
|
+
function parseAST(content, language) {
|
|
1390
|
+
try {
|
|
1391
|
+
const parser = getParser(language);
|
|
1392
|
+
const tree = parser.parse(content);
|
|
1393
|
+
if (tree.rootNode.hasError) {
|
|
1394
|
+
return {
|
|
1395
|
+
tree,
|
|
1396
|
+
error: "Parse completed with errors"
|
|
1397
|
+
};
|
|
1398
|
+
}
|
|
1399
|
+
return { tree };
|
|
1400
|
+
} catch (error) {
|
|
1401
|
+
return {
|
|
1402
|
+
tree: null,
|
|
1403
|
+
error: error instanceof Error ? error.message : "Unknown parse error"
|
|
1404
|
+
};
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
var parserCache, languageConfig;
|
|
1408
|
+
var init_parser = __esm({
|
|
1409
|
+
"src/indexer/ast/parser.ts"() {
|
|
1410
|
+
"use strict";
|
|
1411
|
+
parserCache = /* @__PURE__ */ new Map();
|
|
1412
|
+
languageConfig = {
|
|
1413
|
+
typescript: TypeScript.typescript,
|
|
1414
|
+
javascript: JavaScript
|
|
1415
|
+
// Use proper JavaScript parser
|
|
1416
|
+
};
|
|
1417
|
+
}
|
|
1418
|
+
});
|
|
1419
|
+
|
|
1420
|
+
// src/indexer/ast/symbols.ts
|
|
1421
|
+
function extractSymbolInfo(node, content, parentClass) {
|
|
1422
|
+
const type = node.type;
|
|
1423
|
+
if (type === "function_declaration" || type === "function") {
|
|
1424
|
+
const nameNode = node.childForFieldName("name");
|
|
1425
|
+
if (!nameNode) return null;
|
|
1426
|
+
return {
|
|
1427
|
+
name: nameNode.text,
|
|
1428
|
+
type: parentClass ? "method" : "function",
|
|
1429
|
+
startLine: node.startPosition.row + 1,
|
|
1430
|
+
endLine: node.endPosition.row + 1,
|
|
1431
|
+
parentClass,
|
|
1432
|
+
signature: extractSignature(node, content),
|
|
1433
|
+
parameters: extractParameters(node, content),
|
|
1434
|
+
returnType: extractReturnType(node, content),
|
|
1435
|
+
complexity: calculateComplexity(node)
|
|
1436
|
+
};
|
|
1437
|
+
}
|
|
1438
|
+
if (type === "arrow_function" || type === "function_expression") {
|
|
1439
|
+
const parent = node.parent;
|
|
1440
|
+
let name = "anonymous";
|
|
1441
|
+
if (parent?.type === "variable_declarator") {
|
|
1442
|
+
const nameNode = parent.childForFieldName("name");
|
|
1443
|
+
name = nameNode?.text || "anonymous";
|
|
1444
|
+
}
|
|
1445
|
+
return {
|
|
1446
|
+
name,
|
|
1447
|
+
type: parentClass ? "method" : "function",
|
|
1448
|
+
startLine: node.startPosition.row + 1,
|
|
1449
|
+
endLine: node.endPosition.row + 1,
|
|
1450
|
+
parentClass,
|
|
1451
|
+
signature: extractSignature(node, content),
|
|
1452
|
+
parameters: extractParameters(node, content),
|
|
1453
|
+
complexity: calculateComplexity(node)
|
|
1454
|
+
};
|
|
1455
|
+
}
|
|
1456
|
+
if (type === "method_definition") {
|
|
1457
|
+
const nameNode = node.childForFieldName("name");
|
|
1458
|
+
if (!nameNode) return null;
|
|
1459
|
+
return {
|
|
1460
|
+
name: nameNode.text,
|
|
1461
|
+
type: "method",
|
|
1462
|
+
startLine: node.startPosition.row + 1,
|
|
1463
|
+
endLine: node.endPosition.row + 1,
|
|
1464
|
+
parentClass,
|
|
1465
|
+
signature: extractSignature(node, content),
|
|
1466
|
+
parameters: extractParameters(node, content),
|
|
1467
|
+
returnType: extractReturnType(node, content),
|
|
1468
|
+
complexity: calculateComplexity(node)
|
|
1469
|
+
};
|
|
1470
|
+
}
|
|
1471
|
+
if (type === "class_declaration") {
|
|
1472
|
+
const nameNode = node.childForFieldName("name");
|
|
1473
|
+
if (!nameNode) return null;
|
|
1474
|
+
return {
|
|
1475
|
+
name: nameNode.text,
|
|
1476
|
+
type: "class",
|
|
1477
|
+
startLine: node.startPosition.row + 1,
|
|
1478
|
+
endLine: node.endPosition.row + 1,
|
|
1479
|
+
signature: `class ${nameNode.text}`
|
|
1480
|
+
};
|
|
1481
|
+
}
|
|
1482
|
+
if (type === "interface_declaration") {
|
|
1483
|
+
const nameNode = node.childForFieldName("name");
|
|
1484
|
+
if (!nameNode) return null;
|
|
1485
|
+
return {
|
|
1486
|
+
name: nameNode.text,
|
|
1487
|
+
type: "interface",
|
|
1488
|
+
startLine: node.startPosition.row + 1,
|
|
1489
|
+
endLine: node.endPosition.row + 1,
|
|
1490
|
+
signature: `interface ${nameNode.text}`
|
|
1491
|
+
};
|
|
1492
|
+
}
|
|
1493
|
+
return null;
|
|
1494
|
+
}
|
|
1495
|
+
function extractSignature(node, content) {
|
|
1496
|
+
const startLine = node.startPosition.row;
|
|
1497
|
+
const lines = content.split("\n");
|
|
1498
|
+
let signature = lines[startLine] || "";
|
|
1499
|
+
let currentLine = startLine;
|
|
1500
|
+
while (currentLine < node.endPosition.row && !signature.includes("{") && !signature.includes("=>")) {
|
|
1501
|
+
currentLine++;
|
|
1502
|
+
signature += " " + (lines[currentLine] || "");
|
|
1503
|
+
}
|
|
1504
|
+
signature = signature.split("{")[0].split("=>")[0].trim();
|
|
1505
|
+
if (signature.length > 200) {
|
|
1506
|
+
signature = signature.substring(0, 197) + "...";
|
|
1507
|
+
}
|
|
1508
|
+
return signature;
|
|
1509
|
+
}
|
|
1510
|
+
function extractParameters(node, _content) {
|
|
1511
|
+
const parameters = [];
|
|
1512
|
+
const paramsNode = node.childForFieldName("parameters");
|
|
1513
|
+
if (!paramsNode) return parameters;
|
|
1514
|
+
for (let i = 0; i < paramsNode.namedChildCount; i++) {
|
|
1515
|
+
const param = paramsNode.namedChild(i);
|
|
1516
|
+
if (param) {
|
|
1517
|
+
parameters.push(param.text);
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
return parameters;
|
|
1521
|
+
}
|
|
1522
|
+
function extractReturnType(node, _content) {
|
|
1523
|
+
const returnTypeNode = node.childForFieldName("return_type");
|
|
1524
|
+
if (!returnTypeNode) return void 0;
|
|
1525
|
+
return returnTypeNode.text;
|
|
1526
|
+
}
|
|
1527
|
+
function calculateComplexity(node) {
|
|
1528
|
+
let complexity = 1;
|
|
1529
|
+
const decisionPoints = [
|
|
1530
|
+
"if_statement",
|
|
1531
|
+
"while_statement",
|
|
1532
|
+
"do_statement",
|
|
1533
|
+
// do...while loops
|
|
1534
|
+
"for_statement",
|
|
1535
|
+
"for_in_statement",
|
|
1536
|
+
"for_of_statement",
|
|
1537
|
+
// for...of loops
|
|
1538
|
+
"switch_case",
|
|
1539
|
+
"catch_clause",
|
|
1540
|
+
"ternary_expression",
|
|
1541
|
+
"binary_expression"
|
|
1542
|
+
// For && and ||
|
|
1543
|
+
];
|
|
1544
|
+
function traverse(n) {
|
|
1545
|
+
if (decisionPoints.includes(n.type)) {
|
|
1546
|
+
if (n.type === "binary_expression") {
|
|
1547
|
+
const operator = n.childForFieldName("operator");
|
|
1548
|
+
if (operator && (operator.text === "&&" || operator.text === "||")) {
|
|
1549
|
+
complexity++;
|
|
1550
|
+
}
|
|
1551
|
+
} else {
|
|
1552
|
+
complexity++;
|
|
1553
|
+
}
|
|
1554
|
+
}
|
|
1555
|
+
for (let i = 0; i < n.namedChildCount; i++) {
|
|
1556
|
+
const child = n.namedChild(i);
|
|
1557
|
+
if (child) traverse(child);
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
1560
|
+
traverse(node);
|
|
1561
|
+
return complexity;
|
|
1562
|
+
}
|
|
1563
|
+
function extractImports(rootNode) {
|
|
1564
|
+
const imports = [];
|
|
1565
|
+
function traverse(node) {
|
|
1566
|
+
if (node.type === "import_statement") {
|
|
1567
|
+
const sourceNode = node.childForFieldName("source");
|
|
1568
|
+
if (sourceNode) {
|
|
1569
|
+
const importPath = sourceNode.text.replace(/['"]/g, "");
|
|
1570
|
+
imports.push(importPath);
|
|
1571
|
+
}
|
|
1572
|
+
}
|
|
1573
|
+
if (node === rootNode) {
|
|
1574
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
1575
|
+
const child = node.namedChild(i);
|
|
1576
|
+
if (child) traverse(child);
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1579
|
+
}
|
|
1580
|
+
traverse(rootNode);
|
|
1581
|
+
return imports;
|
|
1582
|
+
}
|
|
1583
|
+
var init_symbols = __esm({
|
|
1584
|
+
"src/indexer/ast/symbols.ts"() {
|
|
1585
|
+
"use strict";
|
|
1586
|
+
}
|
|
1587
|
+
});
|
|
1588
|
+
|
|
1589
|
+
// src/indexer/ast/chunker.ts
|
|
1590
|
+
function chunkByAST(filepath, content, options = {}) {
|
|
1591
|
+
const { minChunkSize = 5 } = options;
|
|
1592
|
+
const language = detectLanguage2(filepath);
|
|
1593
|
+
if (!language) {
|
|
1594
|
+
throw new Error(`Unsupported language for file: ${filepath}`);
|
|
1595
|
+
}
|
|
1596
|
+
const parseResult = parseAST(content, language);
|
|
1597
|
+
if (!parseResult.tree) {
|
|
1598
|
+
throw new Error(`Failed to parse ${filepath}: ${parseResult.error}`);
|
|
1599
|
+
}
|
|
1600
|
+
const chunks = [];
|
|
1601
|
+
const lines = content.split("\n");
|
|
1602
|
+
const rootNode = parseResult.tree.rootNode;
|
|
1603
|
+
const fileImports = extractImports(rootNode);
|
|
1604
|
+
const topLevelNodes = findTopLevelNodes(rootNode);
|
|
1605
|
+
for (const node of topLevelNodes) {
|
|
1606
|
+
let actualNode = node;
|
|
1607
|
+
if (node.type === "lexical_declaration" || node.type === "variable_declaration") {
|
|
1608
|
+
const funcNode = findActualFunctionNode(node);
|
|
1609
|
+
if (funcNode) {
|
|
1610
|
+
actualNode = funcNode;
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1613
|
+
let parentClassName;
|
|
1614
|
+
if (actualNode.type === "method_definition") {
|
|
1615
|
+
parentClassName = findParentClassName(actualNode);
|
|
1616
|
+
}
|
|
1617
|
+
const symbolInfo = extractSymbolInfo(actualNode, content, parentClassName);
|
|
1618
|
+
const nodeContent = getNodeContent(node, lines);
|
|
1619
|
+
chunks.push(createChunk(filepath, node, nodeContent, symbolInfo, fileImports, language));
|
|
1620
|
+
}
|
|
1621
|
+
const coveredRanges = topLevelNodes.map((n) => ({
|
|
1622
|
+
start: n.startPosition.row,
|
|
1623
|
+
end: n.endPosition.row
|
|
1624
|
+
}));
|
|
1625
|
+
const uncoveredChunks = extractUncoveredCode(
|
|
1626
|
+
lines,
|
|
1627
|
+
coveredRanges,
|
|
1628
|
+
filepath,
|
|
1629
|
+
minChunkSize,
|
|
1630
|
+
fileImports,
|
|
1631
|
+
language
|
|
1632
|
+
);
|
|
1633
|
+
chunks.push(...uncoveredChunks);
|
|
1634
|
+
chunks.sort((a, b) => a.metadata.startLine - b.metadata.startLine);
|
|
1635
|
+
return chunks;
|
|
1636
|
+
}
|
|
1637
|
+
function findParentClassName(methodNode) {
|
|
1638
|
+
let current = methodNode.parent;
|
|
1639
|
+
while (current) {
|
|
1640
|
+
if (current.type === "class_declaration") {
|
|
1641
|
+
const nameNode = current.childForFieldName("name");
|
|
1642
|
+
return nameNode?.text;
|
|
1643
|
+
}
|
|
1644
|
+
current = current.parent;
|
|
1645
|
+
}
|
|
1646
|
+
return void 0;
|
|
1647
|
+
}
|
|
1648
|
+
function findTopLevelNodes(rootNode) {
|
|
1649
|
+
const nodes = [];
|
|
1650
|
+
const targetTypes = [
|
|
1651
|
+
"function_declaration",
|
|
1652
|
+
"function",
|
|
1653
|
+
// Note: 'class_declaration' is NOT included here - we extract methods individually
|
|
1654
|
+
"interface_declaration",
|
|
1655
|
+
"method_definition",
|
|
1656
|
+
"lexical_declaration",
|
|
1657
|
+
// For const/let with arrow functions
|
|
1658
|
+
"variable_declaration"
|
|
1659
|
+
// For var with functions
|
|
1660
|
+
];
|
|
1661
|
+
function traverse(node, depth) {
|
|
1662
|
+
if ((node.type === "lexical_declaration" || node.type === "variable_declaration") && depth === 0) {
|
|
1663
|
+
const hasFunction = findFunctionInDeclaration(node);
|
|
1664
|
+
if (hasFunction) {
|
|
1665
|
+
nodes.push(node);
|
|
1666
|
+
return;
|
|
1667
|
+
}
|
|
1668
|
+
}
|
|
1669
|
+
if (depth <= 1 && targetTypes.includes(node.type)) {
|
|
1670
|
+
nodes.push(node);
|
|
1671
|
+
return;
|
|
1672
|
+
}
|
|
1673
|
+
if (node.type === "class_body") {
|
|
1674
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
1675
|
+
const child = node.namedChild(i);
|
|
1676
|
+
if (child) traverse(child, depth);
|
|
1677
|
+
}
|
|
1678
|
+
return;
|
|
1679
|
+
}
|
|
1680
|
+
if (node.type === "class_declaration") {
|
|
1681
|
+
const body = node.childForFieldName("body");
|
|
1682
|
+
if (body) {
|
|
1683
|
+
traverse(body, depth + 1);
|
|
1684
|
+
}
|
|
1685
|
+
return;
|
|
1686
|
+
}
|
|
1687
|
+
if (node.type === "program" || node.type === "export_statement") {
|
|
1688
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
1689
|
+
const child = node.namedChild(i);
|
|
1690
|
+
if (child) traverse(child, depth);
|
|
1691
|
+
}
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1694
|
+
traverse(rootNode, 0);
|
|
1695
|
+
return nodes;
|
|
1696
|
+
}
|
|
1697
|
+
function findFunctionInDeclaration(node) {
|
|
1698
|
+
const functionTypes = ["arrow_function", "function_expression", "function"];
|
|
1699
|
+
function search(n, depth) {
|
|
1700
|
+
if (depth > 3) return false;
|
|
1701
|
+
if (functionTypes.includes(n.type)) {
|
|
1702
|
+
return true;
|
|
1703
|
+
}
|
|
1704
|
+
for (let i = 0; i < n.childCount; i++) {
|
|
1705
|
+
const child = n.child(i);
|
|
1706
|
+
if (child && search(child, depth + 1)) {
|
|
1707
|
+
return true;
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
return false;
|
|
1711
|
+
}
|
|
1712
|
+
return search(node, 0);
|
|
1713
|
+
}
|
|
1714
|
+
function findActualFunctionNode(node) {
|
|
1715
|
+
const functionTypes = ["arrow_function", "function_expression", "function"];
|
|
1716
|
+
function search(n, depth) {
|
|
1717
|
+
if (depth > 3) return null;
|
|
1718
|
+
if (functionTypes.includes(n.type)) {
|
|
1719
|
+
return n;
|
|
1720
|
+
}
|
|
1721
|
+
for (let i = 0; i < n.childCount; i++) {
|
|
1722
|
+
const child = n.child(i);
|
|
1723
|
+
if (child) {
|
|
1724
|
+
const result = search(child, depth + 1);
|
|
1725
|
+
if (result) return result;
|
|
1726
|
+
}
|
|
1727
|
+
}
|
|
1728
|
+
return null;
|
|
1729
|
+
}
|
|
1730
|
+
return search(node, 0);
|
|
1731
|
+
}
|
|
1732
|
+
function getNodeContent(node, lines) {
|
|
1733
|
+
const startLine = node.startPosition.row;
|
|
1734
|
+
const endLine = node.endPosition.row;
|
|
1735
|
+
return lines.slice(startLine, endLine + 1).join("\n");
|
|
1736
|
+
}
|
|
1737
|
+
function createChunk(filepath, node, content, symbolInfo, imports, language) {
|
|
1738
|
+
const symbols = {
|
|
1739
|
+
functions: [],
|
|
1740
|
+
classes: [],
|
|
1741
|
+
interfaces: []
|
|
1742
|
+
};
|
|
1743
|
+
if (symbolInfo?.name) {
|
|
1744
|
+
if (symbolInfo.type === "function" || symbolInfo.type === "method") {
|
|
1745
|
+
symbols.functions.push(symbolInfo.name);
|
|
1746
|
+
} else if (symbolInfo.type === "class") {
|
|
1747
|
+
symbols.classes.push(symbolInfo.name);
|
|
1748
|
+
} else if (symbolInfo.type === "interface") {
|
|
1749
|
+
symbols.interfaces.push(symbolInfo.name);
|
|
1750
|
+
}
|
|
1751
|
+
}
|
|
1752
|
+
return {
|
|
1753
|
+
content,
|
|
1754
|
+
metadata: {
|
|
1755
|
+
file: filepath,
|
|
1756
|
+
startLine: node.startPosition.row + 1,
|
|
1757
|
+
endLine: node.endPosition.row + 1,
|
|
1758
|
+
type: symbolInfo == null ? "block" : symbolInfo.type === "class" ? "class" : "function",
|
|
1759
|
+
language,
|
|
1760
|
+
// Legacy symbols field for backward compatibility
|
|
1761
|
+
symbols,
|
|
1762
|
+
// New AST-derived metadata
|
|
1763
|
+
symbolName: symbolInfo?.name,
|
|
1764
|
+
symbolType: symbolInfo?.type,
|
|
1765
|
+
parentClass: symbolInfo?.parentClass,
|
|
1766
|
+
complexity: symbolInfo?.complexity,
|
|
1767
|
+
parameters: symbolInfo?.parameters,
|
|
1768
|
+
signature: symbolInfo?.signature,
|
|
1769
|
+
imports
|
|
1770
|
+
}
|
|
1771
|
+
};
|
|
1772
|
+
}
|
|
1773
|
+
function extractUncoveredCode(lines, coveredRanges, filepath, minChunkSize, imports, language) {
|
|
1774
|
+
const chunks = [];
|
|
1775
|
+
let currentStart = 0;
|
|
1776
|
+
coveredRanges.sort((a, b) => a.start - b.start);
|
|
1777
|
+
for (const range of coveredRanges) {
|
|
1778
|
+
if (currentStart < range.start) {
|
|
1779
|
+
const uncoveredLines = lines.slice(currentStart, range.start);
|
|
1780
|
+
const content = uncoveredLines.join("\n").trim();
|
|
1781
|
+
if (content.length > 0 && uncoveredLines.length >= minChunkSize) {
|
|
1782
|
+
chunks.push({
|
|
1783
|
+
content,
|
|
1784
|
+
metadata: {
|
|
1785
|
+
file: filepath,
|
|
1786
|
+
startLine: currentStart + 1,
|
|
1787
|
+
endLine: range.start,
|
|
1788
|
+
type: "block",
|
|
1789
|
+
language,
|
|
1790
|
+
// Empty symbols for uncovered code (imports, exports, etc.)
|
|
1791
|
+
symbols: { functions: [], classes: [], interfaces: [] },
|
|
1792
|
+
imports
|
|
1793
|
+
}
|
|
1794
|
+
});
|
|
1795
|
+
}
|
|
1796
|
+
}
|
|
1797
|
+
currentStart = range.end + 1;
|
|
1798
|
+
}
|
|
1799
|
+
if (currentStart < lines.length) {
|
|
1800
|
+
const uncoveredLines = lines.slice(currentStart);
|
|
1801
|
+
const content = uncoveredLines.join("\n").trim();
|
|
1802
|
+
if (content.length > 0 && uncoveredLines.length >= minChunkSize) {
|
|
1803
|
+
chunks.push({
|
|
1804
|
+
content,
|
|
1805
|
+
metadata: {
|
|
1806
|
+
file: filepath,
|
|
1807
|
+
startLine: currentStart + 1,
|
|
1808
|
+
endLine: lines.length,
|
|
1809
|
+
type: "block",
|
|
1810
|
+
language,
|
|
1811
|
+
// Empty symbols for uncovered code (imports, exports, etc.)
|
|
1812
|
+
symbols: { functions: [], classes: [], interfaces: [] },
|
|
1813
|
+
imports
|
|
1814
|
+
}
|
|
1815
|
+
});
|
|
1816
|
+
}
|
|
1817
|
+
}
|
|
1818
|
+
return chunks;
|
|
1819
|
+
}
|
|
1820
|
+
function shouldUseAST(filepath) {
|
|
1821
|
+
return isASTSupported(filepath);
|
|
1822
|
+
}
|
|
1823
|
+
var init_chunker = __esm({
|
|
1824
|
+
"src/indexer/ast/chunker.ts"() {
|
|
1825
|
+
"use strict";
|
|
1826
|
+
init_parser();
|
|
1827
|
+
init_symbols();
|
|
1828
|
+
}
|
|
1829
|
+
});
|
|
1830
|
+
|
|
1272
1831
|
// src/indexer/chunker.ts
|
|
1273
1832
|
function chunkFile(filepath, content, options = {}) {
|
|
1274
|
-
const { chunkSize = 75, chunkOverlap = 10 } = options;
|
|
1833
|
+
const { chunkSize = 75, chunkOverlap = 10, useAST = true, astFallback = "line-based" } = options;
|
|
1834
|
+
if (useAST && shouldUseAST(filepath)) {
|
|
1835
|
+
try {
|
|
1836
|
+
return chunkByAST(filepath, content, {
|
|
1837
|
+
minChunkSize: Math.floor(chunkSize / 10)
|
|
1838
|
+
});
|
|
1839
|
+
} catch (error) {
|
|
1840
|
+
if (astFallback === "error") {
|
|
1841
|
+
throw new Error(`AST chunking failed for ${filepath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
1842
|
+
}
|
|
1843
|
+
console.warn(`AST chunking failed for ${filepath}, falling back to line-based:`, error);
|
|
1844
|
+
}
|
|
1845
|
+
}
|
|
1846
|
+
return chunkByLines(filepath, content, chunkSize, chunkOverlap);
|
|
1847
|
+
}
|
|
1848
|
+
function chunkByLines(filepath, content, chunkSize, chunkOverlap) {
|
|
1275
1849
|
const lines = content.split("\n");
|
|
1276
1850
|
const chunks = [];
|
|
1277
1851
|
const language = detectLanguage(filepath);
|
|
@@ -1304,11 +1878,12 @@ function chunkFile(filepath, content, options = {}) {
|
|
|
1304
1878
|
}
|
|
1305
1879
|
return chunks;
|
|
1306
1880
|
}
|
|
1307
|
-
var
|
|
1881
|
+
var init_chunker2 = __esm({
|
|
1308
1882
|
"src/indexer/chunker.ts"() {
|
|
1309
1883
|
"use strict";
|
|
1310
1884
|
init_scanner();
|
|
1311
1885
|
init_symbol_extractor();
|
|
1886
|
+
init_chunker();
|
|
1312
1887
|
}
|
|
1313
1888
|
});
|
|
1314
1889
|
|
|
@@ -1570,7 +2145,7 @@ var init_lancedb = __esm({
|
|
|
1570
2145
|
"src/vectordb/lancedb.ts"() {
|
|
1571
2146
|
"use strict";
|
|
1572
2147
|
init_types();
|
|
1573
|
-
|
|
2148
|
+
init_version2();
|
|
1574
2149
|
init_errors();
|
|
1575
2150
|
init_relevance();
|
|
1576
2151
|
init_intent_classifier();
|
|
@@ -1655,7 +2230,15 @@ var init_lancedb = __esm({
|
|
|
1655
2230
|
// Ensure arrays have at least empty string for Arrow type inference
|
|
1656
2231
|
functionNames: batch.metadatas[i].symbols?.functions && batch.metadatas[i].symbols.functions.length > 0 ? batch.metadatas[i].symbols.functions : [""],
|
|
1657
2232
|
classNames: batch.metadatas[i].symbols?.classes && batch.metadatas[i].symbols.classes.length > 0 ? batch.metadatas[i].symbols.classes : [""],
|
|
1658
|
-
interfaceNames: batch.metadatas[i].symbols?.interfaces && batch.metadatas[i].symbols.interfaces.length > 0 ? batch.metadatas[i].symbols.interfaces : [""]
|
|
2233
|
+
interfaceNames: batch.metadatas[i].symbols?.interfaces && batch.metadatas[i].symbols.interfaces.length > 0 ? batch.metadatas[i].symbols.interfaces : [""],
|
|
2234
|
+
// AST-derived metadata (v0.13.0)
|
|
2235
|
+
symbolName: batch.metadatas[i].symbolName || "",
|
|
2236
|
+
symbolType: batch.metadatas[i].symbolType || "",
|
|
2237
|
+
parentClass: batch.metadatas[i].parentClass || "",
|
|
2238
|
+
complexity: batch.metadatas[i].complexity || 0,
|
|
2239
|
+
parameters: batch.metadatas[i].parameters && batch.metadatas[i].parameters.length > 0 ? batch.metadatas[i].parameters : [""],
|
|
2240
|
+
signature: batch.metadatas[i].signature || "",
|
|
2241
|
+
imports: batch.metadatas[i].imports && batch.metadatas[i].imports.length > 0 ? batch.metadatas[i].imports : [""]
|
|
1659
2242
|
}));
|
|
1660
2243
|
if (!this.table) {
|
|
1661
2244
|
this.table = await this.db.createTable(this.tableName, records);
|
|
@@ -1710,7 +2293,15 @@ var init_lancedb = __esm({
|
|
|
1710
2293
|
startLine: r.startLine,
|
|
1711
2294
|
endLine: r.endLine,
|
|
1712
2295
|
type: r.type,
|
|
1713
|
-
language: r.language
|
|
2296
|
+
language: r.language,
|
|
2297
|
+
// AST-derived metadata (v0.13.0)
|
|
2298
|
+
symbolName: r.symbolName || void 0,
|
|
2299
|
+
symbolType: r.symbolType,
|
|
2300
|
+
parentClass: r.parentClass || void 0,
|
|
2301
|
+
complexity: r.complexity || void 0,
|
|
2302
|
+
parameters: r.parameters && r.parameters.length > 0 && r.parameters[0] !== "" ? r.parameters : void 0,
|
|
2303
|
+
signature: r.signature || void 0,
|
|
2304
|
+
imports: r.imports && r.imports.length > 0 && r.imports[0] !== "" ? r.imports : void 0
|
|
1714
2305
|
},
|
|
1715
2306
|
score: boostedScore,
|
|
1716
2307
|
relevance: calculateRelevance(boostedScore)
|
|
@@ -1783,7 +2374,15 @@ var init_lancedb = __esm({
|
|
|
1783
2374
|
startLine: r.startLine,
|
|
1784
2375
|
endLine: r.endLine,
|
|
1785
2376
|
type: r.type,
|
|
1786
|
-
language: r.language
|
|
2377
|
+
language: r.language,
|
|
2378
|
+
// AST-derived metadata (v0.13.0)
|
|
2379
|
+
symbolName: r.symbolName || void 0,
|
|
2380
|
+
symbolType: r.symbolType,
|
|
2381
|
+
parentClass: r.parentClass || void 0,
|
|
2382
|
+
complexity: r.complexity || void 0,
|
|
2383
|
+
parameters: r.parameters && r.parameters.length > 0 && r.parameters[0] !== "" ? r.parameters : void 0,
|
|
2384
|
+
signature: r.signature || void 0,
|
|
2385
|
+
imports: r.imports && r.imports.length > 0 && r.imports[0] !== "" ? r.imports : void 0
|
|
1787
2386
|
},
|
|
1788
2387
|
score,
|
|
1789
2388
|
relevance: calculateRelevance(score)
|
|
@@ -1813,12 +2412,43 @@ var init_lancedb = __esm({
|
|
|
1813
2412
|
return false;
|
|
1814
2413
|
}
|
|
1815
2414
|
const symbols = symbolType === "function" ? r.functionNames || [] : symbolType === "class" ? r.classNames || [] : symbolType === "interface" ? r.interfaceNames || [] : [...r.functionNames || [], ...r.classNames || [], ...r.interfaceNames || []];
|
|
1816
|
-
|
|
2415
|
+
const astSymbolName = r.symbolName || "";
|
|
2416
|
+
if (symbols.length === 0 && !astSymbolName) {
|
|
1817
2417
|
return false;
|
|
1818
2418
|
}
|
|
1819
2419
|
if (pattern) {
|
|
1820
2420
|
const regex = new RegExp(pattern, "i");
|
|
1821
|
-
|
|
2421
|
+
const matchesOldSymbols = symbols.some((s) => regex.test(s));
|
|
2422
|
+
const matchesASTSymbol = regex.test(astSymbolName);
|
|
2423
|
+
const nameMatches = matchesOldSymbols || matchesASTSymbol;
|
|
2424
|
+
if (!nameMatches) return false;
|
|
2425
|
+
if (symbolType) {
|
|
2426
|
+
if (r.symbolType) {
|
|
2427
|
+
if (symbolType === "function") {
|
|
2428
|
+
return r.symbolType === "function" || r.symbolType === "method";
|
|
2429
|
+
} else if (symbolType === "class") {
|
|
2430
|
+
return r.symbolType === "class";
|
|
2431
|
+
} else if (symbolType === "interface") {
|
|
2432
|
+
return r.symbolType === "interface";
|
|
2433
|
+
}
|
|
2434
|
+
return false;
|
|
2435
|
+
}
|
|
2436
|
+
return nameMatches;
|
|
2437
|
+
}
|
|
2438
|
+
return nameMatches;
|
|
2439
|
+
}
|
|
2440
|
+
if (symbolType) {
|
|
2441
|
+
if (r.symbolType) {
|
|
2442
|
+
if (symbolType === "function") {
|
|
2443
|
+
return r.symbolType === "function" || r.symbolType === "method";
|
|
2444
|
+
} else if (symbolType === "class") {
|
|
2445
|
+
return r.symbolType === "class";
|
|
2446
|
+
} else if (symbolType === "interface") {
|
|
2447
|
+
return r.symbolType === "interface";
|
|
2448
|
+
}
|
|
2449
|
+
return false;
|
|
2450
|
+
}
|
|
2451
|
+
return symbols.length > 0 && symbols.some((s) => s.length > 0 && s !== "");
|
|
1822
2452
|
}
|
|
1823
2453
|
return true;
|
|
1824
2454
|
});
|
|
@@ -1836,7 +2466,15 @@ var init_lancedb = __esm({
|
|
|
1836
2466
|
functions: r.functionNames || [],
|
|
1837
2467
|
classes: r.classNames || [],
|
|
1838
2468
|
interfaces: r.interfaceNames || []
|
|
1839
|
-
}
|
|
2469
|
+
},
|
|
2470
|
+
// AST-derived metadata (v0.13.0)
|
|
2471
|
+
symbolName: r.symbolName || void 0,
|
|
2472
|
+
symbolType: r.symbolType,
|
|
2473
|
+
parentClass: r.parentClass || void 0,
|
|
2474
|
+
complexity: r.complexity || void 0,
|
|
2475
|
+
parameters: r.parameters && r.parameters.length > 0 && r.parameters[0] !== "" ? r.parameters : void 0,
|
|
2476
|
+
signature: r.signature || void 0,
|
|
2477
|
+
imports: r.imports && r.imports.length > 0 && r.imports[0] !== "" ? r.imports : void 0
|
|
1840
2478
|
},
|
|
1841
2479
|
score,
|
|
1842
2480
|
relevance: calculateRelevance(score)
|
|
@@ -1987,33 +2625,6 @@ var init_lancedb = __esm({
|
|
|
1987
2625
|
}
|
|
1988
2626
|
});
|
|
1989
2627
|
|
|
1990
|
-
// src/utils/version.ts
|
|
1991
|
-
import { createRequire as createRequire2 } from "module";
|
|
1992
|
-
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
1993
|
-
import { dirname as dirname2, join as join2 } from "path";
|
|
1994
|
-
function getPackageVersion() {
|
|
1995
|
-
return packageJson2.version;
|
|
1996
|
-
}
|
|
1997
|
-
var __filename3, __dirname3, require3, packageJson2;
|
|
1998
|
-
var init_version2 = __esm({
|
|
1999
|
-
"src/utils/version.ts"() {
|
|
2000
|
-
"use strict";
|
|
2001
|
-
__filename3 = fileURLToPath3(import.meta.url);
|
|
2002
|
-
__dirname3 = dirname2(__filename3);
|
|
2003
|
-
require3 = createRequire2(import.meta.url);
|
|
2004
|
-
try {
|
|
2005
|
-
packageJson2 = require3(join2(__dirname3, "../package.json"));
|
|
2006
|
-
} catch {
|
|
2007
|
-
try {
|
|
2008
|
-
packageJson2 = require3(join2(__dirname3, "../../package.json"));
|
|
2009
|
-
} catch {
|
|
2010
|
-
console.warn("[Lien] Warning: Could not load package.json, using fallback version");
|
|
2011
|
-
packageJson2 = { version: "0.0.0-unknown" };
|
|
2012
|
-
}
|
|
2013
|
-
}
|
|
2014
|
-
}
|
|
2015
|
-
});
|
|
2016
|
-
|
|
2017
2628
|
// src/indexer/manifest.ts
|
|
2018
2629
|
var manifest_exports = {};
|
|
2019
2630
|
__export(manifest_exports, {
|
|
@@ -2026,7 +2637,7 @@ var init_manifest = __esm({
|
|
|
2026
2637
|
"src/indexer/manifest.ts"() {
|
|
2027
2638
|
"use strict";
|
|
2028
2639
|
init_constants();
|
|
2029
|
-
|
|
2640
|
+
init_version();
|
|
2030
2641
|
MANIFEST_FILE = "manifest.json";
|
|
2031
2642
|
ManifestManager = class {
|
|
2032
2643
|
manifestPath;
|
|
@@ -2586,9 +3197,13 @@ import fs14 from "fs/promises";
|
|
|
2586
3197
|
async function processFileContent(filepath, content, embeddings, config, verbose) {
|
|
2587
3198
|
const chunkSize = isModernConfig(config) ? config.core.chunkSize : isLegacyConfig(config) ? config.indexing.chunkSize : 75;
|
|
2588
3199
|
const chunkOverlap = isModernConfig(config) ? config.core.chunkOverlap : isLegacyConfig(config) ? config.indexing.chunkOverlap : 10;
|
|
3200
|
+
const useAST = isModernConfig(config) ? config.chunking.useAST : true;
|
|
3201
|
+
const astFallback = isModernConfig(config) ? config.chunking.astFallback : "line-based";
|
|
2589
3202
|
const chunks = chunkFile(filepath, content, {
|
|
2590
3203
|
chunkSize,
|
|
2591
|
-
chunkOverlap
|
|
3204
|
+
chunkOverlap,
|
|
3205
|
+
useAST,
|
|
3206
|
+
astFallback
|
|
2592
3207
|
});
|
|
2593
3208
|
if (chunks.length === 0) {
|
|
2594
3209
|
if (verbose) {
|
|
@@ -2739,7 +3354,7 @@ async function indexMultipleFiles(filepaths, vectorDB, embeddings, config, optio
|
|
|
2739
3354
|
var init_incremental = __esm({
|
|
2740
3355
|
"src/indexer/incremental.ts"() {
|
|
2741
3356
|
"use strict";
|
|
2742
|
-
|
|
3357
|
+
init_chunker2();
|
|
2743
3358
|
init_schema();
|
|
2744
3359
|
init_manifest();
|
|
2745
3360
|
init_constants();
|
|
@@ -3001,9 +3616,13 @@ async function indexCodebase(options = {}) {
|
|
|
3001
3616
|
const content = await fs15.readFile(file, "utf-8");
|
|
3002
3617
|
const chunkSize = isModernConfig(config) ? config.core.chunkSize : 75;
|
|
3003
3618
|
const chunkOverlap = isModernConfig(config) ? config.core.chunkOverlap : 10;
|
|
3619
|
+
const useAST = isModernConfig(config) ? config.chunking.useAST : true;
|
|
3620
|
+
const astFallback = isModernConfig(config) ? config.chunking.astFallback : "line-based";
|
|
3004
3621
|
const chunks = chunkFile(file, content, {
|
|
3005
3622
|
chunkSize,
|
|
3006
|
-
chunkOverlap
|
|
3623
|
+
chunkOverlap,
|
|
3624
|
+
useAST,
|
|
3625
|
+
astFallback
|
|
3007
3626
|
});
|
|
3008
3627
|
if (chunks.length === 0) {
|
|
3009
3628
|
processedFiles++;
|
|
@@ -3081,11 +3700,11 @@ var init_indexer = __esm({
|
|
|
3081
3700
|
"src/indexer/index.ts"() {
|
|
3082
3701
|
"use strict";
|
|
3083
3702
|
init_scanner();
|
|
3084
|
-
|
|
3703
|
+
init_chunker2();
|
|
3085
3704
|
init_local();
|
|
3086
3705
|
init_lancedb();
|
|
3087
3706
|
init_service();
|
|
3088
|
-
|
|
3707
|
+
init_version2();
|
|
3089
3708
|
init_schema();
|
|
3090
3709
|
init_manifest();
|
|
3091
3710
|
init_change_detector();
|
|
@@ -3106,27 +3725,27 @@ init_schema();
|
|
|
3106
3725
|
init_merge();
|
|
3107
3726
|
import fs5 from "fs/promises";
|
|
3108
3727
|
import path5 from "path";
|
|
3109
|
-
import { fileURLToPath as
|
|
3728
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
3110
3729
|
import chalk2 from "chalk";
|
|
3111
3730
|
import inquirer from "inquirer";
|
|
3112
3731
|
|
|
3113
3732
|
// src/utils/banner.ts
|
|
3114
3733
|
import figlet from "figlet";
|
|
3115
3734
|
import chalk from "chalk";
|
|
3116
|
-
import { createRequire } from "module";
|
|
3117
|
-
import { fileURLToPath } from "url";
|
|
3118
|
-
import { dirname, join } from "path";
|
|
3119
|
-
var
|
|
3120
|
-
var
|
|
3121
|
-
var
|
|
3122
|
-
var
|
|
3735
|
+
import { createRequire as createRequire2 } from "module";
|
|
3736
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
3737
|
+
import { dirname as dirname2, join as join2 } from "path";
|
|
3738
|
+
var __filename2 = fileURLToPath2(import.meta.url);
|
|
3739
|
+
var __dirname2 = dirname2(__filename2);
|
|
3740
|
+
var require3 = createRequire2(import.meta.url);
|
|
3741
|
+
var packageJson2;
|
|
3123
3742
|
try {
|
|
3124
|
-
|
|
3743
|
+
packageJson2 = require3(join2(__dirname2, "../package.json"));
|
|
3125
3744
|
} catch {
|
|
3126
|
-
|
|
3745
|
+
packageJson2 = require3(join2(__dirname2, "../../package.json"));
|
|
3127
3746
|
}
|
|
3128
|
-
var PACKAGE_NAME =
|
|
3129
|
-
var VERSION =
|
|
3747
|
+
var PACKAGE_NAME = packageJson2.name;
|
|
3748
|
+
var VERSION = packageJson2.version;
|
|
3130
3749
|
function wrapInBox(text, footer, padding = 1) {
|
|
3131
3750
|
const lines = text.split("\n").filter((line) => line.trim().length > 0);
|
|
3132
3751
|
const maxLength = Math.max(...lines.map((line) => line.length));
|
|
@@ -3675,8 +4294,9 @@ async function scanSubdirectories(rootDir, relativePath, results, visited, depth
|
|
|
3675
4294
|
}
|
|
3676
4295
|
|
|
3677
4296
|
// src/cli/init.ts
|
|
3678
|
-
|
|
3679
|
-
var
|
|
4297
|
+
init_constants();
|
|
4298
|
+
var __filename3 = fileURLToPath3(import.meta.url);
|
|
4299
|
+
var __dirname3 = path5.dirname(__filename3);
|
|
3680
4300
|
async function initCommand(options = {}) {
|
|
3681
4301
|
const rootDir = options.path || process.cwd();
|
|
3682
4302
|
const configPath = path5.join(rootDir, ".lien.config.json");
|
|
@@ -3821,7 +4441,7 @@ async function createNewConfig(rootDir, options) {
|
|
|
3821
4441
|
try {
|
|
3822
4442
|
const cursorRulesDir = path5.join(rootDir, ".cursor");
|
|
3823
4443
|
await fs5.mkdir(cursorRulesDir, { recursive: true });
|
|
3824
|
-
const templatePath = path5.join(
|
|
4444
|
+
const templatePath = path5.join(__dirname3, "../CURSOR_RULES_TEMPLATE.md");
|
|
3825
4445
|
const rulesPath = path5.join(cursorRulesDir, "rules");
|
|
3826
4446
|
let targetPath;
|
|
3827
4447
|
let isDirectory = false;
|
|
@@ -3909,23 +4529,28 @@ Customizing ${frameworkName} settings:`));
|
|
|
3909
4529
|
}
|
|
3910
4530
|
async function upgradeConfig(configPath) {
|
|
3911
4531
|
try {
|
|
3912
|
-
const backupPath = `${configPath}.backup`;
|
|
3913
|
-
await fs5.copyFile(configPath, backupPath);
|
|
3914
4532
|
const existingContent = await fs5.readFile(configPath, "utf-8");
|
|
3915
4533
|
const existingConfig = JSON.parse(existingContent);
|
|
4534
|
+
const migrationNeeded = needsMigration(existingConfig);
|
|
4535
|
+
const newFields = migrationNeeded ? [] : detectNewFields(existingConfig, defaultConfig);
|
|
4536
|
+
const hasChanges = migrationNeeded || newFields.length > 0;
|
|
4537
|
+
if (!hasChanges) {
|
|
4538
|
+
console.log(chalk2.green("\u2713 Config is already up to date"));
|
|
4539
|
+
console.log(chalk2.dim("No changes needed"));
|
|
4540
|
+
return;
|
|
4541
|
+
}
|
|
4542
|
+
const backupPath = `${configPath}.backup`;
|
|
4543
|
+
await fs5.copyFile(configPath, backupPath);
|
|
3916
4544
|
let upgradedConfig;
|
|
3917
4545
|
let migrated = false;
|
|
3918
|
-
if (
|
|
3919
|
-
console.log(chalk2.blue(
|
|
4546
|
+
if (migrationNeeded) {
|
|
4547
|
+
console.log(chalk2.blue(`\u{1F504} Migrating config from v0.2.0 to v${CURRENT_CONFIG_VERSION}...`));
|
|
3920
4548
|
upgradedConfig = migrateConfig(existingConfig);
|
|
3921
4549
|
migrated = true;
|
|
3922
4550
|
} else {
|
|
3923
|
-
const newFields = detectNewFields(existingConfig, defaultConfig);
|
|
3924
4551
|
upgradedConfig = deepMergeConfig(defaultConfig, existingConfig);
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
newFields.forEach((field) => console.log(chalk2.dim(" \u2022"), chalk2.bold(field)));
|
|
3928
|
-
}
|
|
4552
|
+
console.log(chalk2.dim("\nNew options added:"));
|
|
4553
|
+
newFields.forEach((field) => console.log(chalk2.dim(" \u2022"), chalk2.bold(field)));
|
|
3929
4554
|
}
|
|
3930
4555
|
await fs5.writeFile(
|
|
3931
4556
|
configPath,
|
|
@@ -3946,7 +4571,7 @@ async function upgradeConfig(configPath) {
|
|
|
3946
4571
|
// src/cli/status.ts
|
|
3947
4572
|
init_service();
|
|
3948
4573
|
init_utils();
|
|
3949
|
-
|
|
4574
|
+
init_version2();
|
|
3950
4575
|
import chalk3 from "chalk";
|
|
3951
4576
|
import fs9 from "fs/promises";
|
|
3952
4577
|
import path9 from "path";
|
|
@@ -4082,82 +4707,85 @@ import { createRequire as createRequire3 } from "module";
|
|
|
4082
4707
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
4083
4708
|
import { dirname as dirname3, join as join3 } from "path";
|
|
4084
4709
|
|
|
4710
|
+
// src/mcp/utils/zod-to-json-schema.ts
|
|
4711
|
+
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
4712
|
+
function toMCPToolSchema(zodSchema, name, description) {
|
|
4713
|
+
return {
|
|
4714
|
+
name,
|
|
4715
|
+
description,
|
|
4716
|
+
inputSchema: zodToJsonSchema(zodSchema, {
|
|
4717
|
+
target: "jsonSchema7",
|
|
4718
|
+
$refStrategy: "none"
|
|
4719
|
+
})
|
|
4720
|
+
};
|
|
4721
|
+
}
|
|
4722
|
+
|
|
4723
|
+
// src/mcp/schemas/search.schema.ts
|
|
4724
|
+
import { z } from "zod";
|
|
4725
|
+
var SemanticSearchSchema = z.object({
|
|
4726
|
+
query: z.string().min(3, "Query must be at least 3 characters").max(500, "Query too long (max 500 characters)").describe(
|
|
4727
|
+
"Natural language description of what you're looking for.\n\nUse full sentences describing functionality, not exact names.\n\nGood examples:\n - 'handles user authentication'\n - 'validates email format'\n - 'processes payment transactions'\n\nBad examples:\n - 'auth' (too vague)\n - 'validateEmail' (use grep for exact names)"
|
|
4728
|
+
),
|
|
4729
|
+
limit: z.number().int().min(1, "Limit must be at least 1").max(50, "Limit cannot exceed 50").default(5).describe(
|
|
4730
|
+
"Number of results to return.\n\nDefault: 5\nIncrease to 10-15 for broad exploration."
|
|
4731
|
+
)
|
|
4732
|
+
});
|
|
4733
|
+
|
|
4734
|
+
// src/mcp/schemas/similarity.schema.ts
|
|
4735
|
+
import { z as z2 } from "zod";
|
|
4736
|
+
var FindSimilarSchema = z2.object({
|
|
4737
|
+
code: z2.string().min(10, "Code snippet must be at least 10 characters").describe(
|
|
4738
|
+
"Code snippet to find similar implementations for.\n\nProvide a representative code sample that demonstrates the pattern you want to find similar examples of in the codebase."
|
|
4739
|
+
),
|
|
4740
|
+
limit: z2.number().int().min(1, "Limit must be at least 1").max(20, "Limit cannot exceed 20").default(5).describe(
|
|
4741
|
+
"Number of similar code blocks to return.\n\nDefault: 5"
|
|
4742
|
+
)
|
|
4743
|
+
});
|
|
4744
|
+
|
|
4745
|
+
// src/mcp/schemas/file.schema.ts
|
|
4746
|
+
import { z as z3 } from "zod";
|
|
4747
|
+
var GetFileContextSchema = z3.object({
|
|
4748
|
+
filepath: z3.string().min(1, "Filepath cannot be empty").describe(
|
|
4749
|
+
"Relative path to file from workspace root.\n\nExample: 'src/components/Button.tsx'"
|
|
4750
|
+
),
|
|
4751
|
+
includeRelated: z3.boolean().default(true).describe(
|
|
4752
|
+
"Include semantically related chunks from nearby code.\n\nDefault: true\n\nWhen enabled, also returns related code from other files that are semantically similar to the target file's contents."
|
|
4753
|
+
)
|
|
4754
|
+
});
|
|
4755
|
+
|
|
4756
|
+
// src/mcp/schemas/symbols.schema.ts
|
|
4757
|
+
import { z as z4 } from "zod";
|
|
4758
|
+
var ListFunctionsSchema = z4.object({
|
|
4759
|
+
pattern: z4.string().optional().describe(
|
|
4760
|
+
"Regex pattern to match symbol names.\n\nExamples:\n - '.*Controller.*' to find all Controllers\n - 'handle.*' to find handlers\n - '.*Service$' to find Services\n\nIf omitted, returns all symbols."
|
|
4761
|
+
),
|
|
4762
|
+
language: z4.string().optional().describe(
|
|
4763
|
+
"Filter by programming language.\n\nExamples: 'typescript', 'python', 'javascript', 'php'\n\nIf omitted, searches all languages."
|
|
4764
|
+
)
|
|
4765
|
+
});
|
|
4766
|
+
|
|
4085
4767
|
// src/mcp/tools.ts
|
|
4086
4768
|
var tools = [
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
name: "find_similar",
|
|
4108
|
-
description: "Find code similar to a given code snippet. Results include a relevance category (highly_relevant, relevant, loosely_related, not_relevant) based on semantic similarity.",
|
|
4109
|
-
inputSchema: {
|
|
4110
|
-
type: "object",
|
|
4111
|
-
properties: {
|
|
4112
|
-
code: {
|
|
4113
|
-
type: "string",
|
|
4114
|
-
description: "Code snippet to find similar implementations"
|
|
4115
|
-
},
|
|
4116
|
-
limit: {
|
|
4117
|
-
type: "number",
|
|
4118
|
-
description: "Maximum number of results to return",
|
|
4119
|
-
default: 5
|
|
4120
|
-
}
|
|
4121
|
-
},
|
|
4122
|
-
required: ["code"]
|
|
4123
|
-
}
|
|
4124
|
-
},
|
|
4125
|
-
{
|
|
4126
|
-
name: "get_file_context",
|
|
4127
|
-
description: "Get all chunks and related context for a specific file. Results include a relevance category (highly_relevant, relevant, loosely_related, not_relevant) based on semantic similarity.",
|
|
4128
|
-
inputSchema: {
|
|
4129
|
-
type: "object",
|
|
4130
|
-
properties: {
|
|
4131
|
-
filepath: {
|
|
4132
|
-
type: "string",
|
|
4133
|
-
description: "Path to the file (relative to project root)"
|
|
4134
|
-
},
|
|
4135
|
-
includeRelated: {
|
|
4136
|
-
type: "boolean",
|
|
4137
|
-
description: "Include semantically related chunks from other files",
|
|
4138
|
-
default: true
|
|
4139
|
-
}
|
|
4140
|
-
},
|
|
4141
|
-
required: ["filepath"]
|
|
4142
|
-
}
|
|
4143
|
-
},
|
|
4144
|
-
{
|
|
4145
|
-
name: "list_functions",
|
|
4146
|
-
description: "List functions, classes, and interfaces by name pattern and language",
|
|
4147
|
-
inputSchema: {
|
|
4148
|
-
type: "object",
|
|
4149
|
-
properties: {
|
|
4150
|
-
pattern: {
|
|
4151
|
-
type: "string",
|
|
4152
|
-
description: 'Regex pattern to match symbol names (e.g., ".*Service$", "handle.*")'
|
|
4153
|
-
},
|
|
4154
|
-
language: {
|
|
4155
|
-
type: "string",
|
|
4156
|
-
description: 'Language filter (e.g., "typescript", "python", "php")'
|
|
4157
|
-
}
|
|
4158
|
-
}
|
|
4159
|
-
}
|
|
4160
|
-
}
|
|
4769
|
+
toMCPToolSchema(
|
|
4770
|
+
SemanticSearchSchema,
|
|
4771
|
+
"semantic_search",
|
|
4772
|
+
"Search the codebase semantically for relevant code using natural language. Results include a relevance category (highly_relevant, relevant, loosely_related, not_relevant) based on semantic similarity."
|
|
4773
|
+
),
|
|
4774
|
+
toMCPToolSchema(
|
|
4775
|
+
FindSimilarSchema,
|
|
4776
|
+
"find_similar",
|
|
4777
|
+
"Find code similar to a given code snippet. Results include a relevance category (highly_relevant, relevant, loosely_related, not_relevant) based on semantic similarity."
|
|
4778
|
+
),
|
|
4779
|
+
toMCPToolSchema(
|
|
4780
|
+
GetFileContextSchema,
|
|
4781
|
+
"get_file_context",
|
|
4782
|
+
"Get all chunks and related context for a specific file. Results include a relevance category (highly_relevant, relevant, loosely_related, not_relevant) based on semantic similarity."
|
|
4783
|
+
),
|
|
4784
|
+
toMCPToolSchema(
|
|
4785
|
+
ListFunctionsSchema,
|
|
4786
|
+
"list_functions",
|
|
4787
|
+
"List functions, classes, and interfaces by name pattern and language"
|
|
4788
|
+
)
|
|
4161
4789
|
];
|
|
4162
4790
|
|
|
4163
4791
|
// src/mcp/server.ts
|
|
@@ -4300,6 +4928,64 @@ var FileWatcher = class {
|
|
|
4300
4928
|
|
|
4301
4929
|
// src/mcp/server.ts
|
|
4302
4930
|
init_constants();
|
|
4931
|
+
|
|
4932
|
+
// src/mcp/utils/tool-wrapper.ts
|
|
4933
|
+
init_errors();
|
|
4934
|
+
import { ZodError } from "zod";
|
|
4935
|
+
function wrapToolHandler(schema, handler) {
|
|
4936
|
+
return async (args) => {
|
|
4937
|
+
try {
|
|
4938
|
+
const validated = schema.parse(args);
|
|
4939
|
+
const result = await handler(validated);
|
|
4940
|
+
return {
|
|
4941
|
+
content: [{
|
|
4942
|
+
type: "text",
|
|
4943
|
+
text: JSON.stringify(result, null, 2)
|
|
4944
|
+
}]
|
|
4945
|
+
};
|
|
4946
|
+
} catch (error) {
|
|
4947
|
+
if (error instanceof ZodError) {
|
|
4948
|
+
return {
|
|
4949
|
+
isError: true,
|
|
4950
|
+
content: [{
|
|
4951
|
+
type: "text",
|
|
4952
|
+
text: JSON.stringify({
|
|
4953
|
+
error: "Invalid parameters",
|
|
4954
|
+
code: "INVALID_INPUT" /* INVALID_INPUT */,
|
|
4955
|
+
details: error.errors.map((e) => ({
|
|
4956
|
+
field: e.path.join("."),
|
|
4957
|
+
message: e.message
|
|
4958
|
+
}))
|
|
4959
|
+
}, null, 2)
|
|
4960
|
+
}]
|
|
4961
|
+
};
|
|
4962
|
+
}
|
|
4963
|
+
if (error instanceof LienError) {
|
|
4964
|
+
return {
|
|
4965
|
+
isError: true,
|
|
4966
|
+
content: [{
|
|
4967
|
+
type: "text",
|
|
4968
|
+
text: JSON.stringify(error.toJSON(), null, 2)
|
|
4969
|
+
}]
|
|
4970
|
+
};
|
|
4971
|
+
}
|
|
4972
|
+
console.error("Unexpected error in tool handler:", error);
|
|
4973
|
+
return {
|
|
4974
|
+
isError: true,
|
|
4975
|
+
content: [{
|
|
4976
|
+
type: "text",
|
|
4977
|
+
text: JSON.stringify({
|
|
4978
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
4979
|
+
code: "INTERNAL_ERROR" /* INTERNAL_ERROR */
|
|
4980
|
+
}, null, 2)
|
|
4981
|
+
}]
|
|
4982
|
+
};
|
|
4983
|
+
}
|
|
4984
|
+
};
|
|
4985
|
+
}
|
|
4986
|
+
|
|
4987
|
+
// src/mcp/server.ts
|
|
4988
|
+
init_errors();
|
|
4303
4989
|
var __filename4 = fileURLToPath4(import.meta.url);
|
|
4304
4990
|
var __dirname4 = dirname3(__filename4);
|
|
4305
4991
|
var require4 = createRequire3(import.meta.url);
|
|
@@ -4364,148 +5050,139 @@ async function startMCPServer(options) {
|
|
|
4364
5050
|
}, VERSION_CHECK_INTERVAL_MS);
|
|
4365
5051
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
4366
5052
|
const { name, arguments: args } = request.params;
|
|
5053
|
+
log(`Handling tool call: ${name}`);
|
|
4367
5054
|
try {
|
|
4368
|
-
log(`Handling tool call: ${name}`);
|
|
4369
5055
|
switch (name) {
|
|
4370
|
-
case "semantic_search":
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
|
|
4395
|
-
|
|
4396
|
-
|
|
4397
|
-
|
|
4398
|
-
|
|
4399
|
-
|
|
4400
|
-
|
|
4401
|
-
|
|
4402
|
-
|
|
4403
|
-
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
const fileChunks = allResults.filter(
|
|
4420
|
-
(r) => r.metadata.file.includes(filepath) || filepath.includes(r.metadata.file)
|
|
4421
|
-
);
|
|
4422
|
-
let results = fileChunks;
|
|
4423
|
-
if (includeRelated && fileChunks.length > 0) {
|
|
4424
|
-
const relatedEmbedding = await embeddings.embed(fileChunks[0].content);
|
|
4425
|
-
const related = await vectorDB.search(relatedEmbedding, 5, fileChunks[0].content);
|
|
4426
|
-
const relatedOtherFiles = related.filter(
|
|
4427
|
-
(r) => !r.metadata.file.includes(filepath) && !filepath.includes(r.metadata.file)
|
|
4428
|
-
);
|
|
4429
|
-
results = [...fileChunks, ...relatedOtherFiles];
|
|
4430
|
-
}
|
|
4431
|
-
log(`Found ${results.length} chunks`);
|
|
4432
|
-
const response = {
|
|
4433
|
-
indexInfo: getIndexMetadata(),
|
|
4434
|
-
file: filepath,
|
|
4435
|
-
chunks: results
|
|
4436
|
-
};
|
|
4437
|
-
return {
|
|
4438
|
-
content: [
|
|
4439
|
-
{
|
|
4440
|
-
type: "text",
|
|
4441
|
-
text: JSON.stringify(response, null, 2)
|
|
5056
|
+
case "semantic_search":
|
|
5057
|
+
return await wrapToolHandler(
|
|
5058
|
+
SemanticSearchSchema,
|
|
5059
|
+
async (validatedArgs) => {
|
|
5060
|
+
log(`Searching for: "${validatedArgs.query}"`);
|
|
5061
|
+
await checkAndReconnect();
|
|
5062
|
+
const queryEmbedding = await embeddings.embed(validatedArgs.query);
|
|
5063
|
+
const results = await vectorDB.search(queryEmbedding, validatedArgs.limit, validatedArgs.query);
|
|
5064
|
+
log(`Found ${results.length} results`);
|
|
5065
|
+
return {
|
|
5066
|
+
indexInfo: getIndexMetadata(),
|
|
5067
|
+
results
|
|
5068
|
+
};
|
|
5069
|
+
}
|
|
5070
|
+
)(args);
|
|
5071
|
+
case "find_similar":
|
|
5072
|
+
return await wrapToolHandler(
|
|
5073
|
+
FindSimilarSchema,
|
|
5074
|
+
async (validatedArgs) => {
|
|
5075
|
+
log(`Finding similar code...`);
|
|
5076
|
+
await checkAndReconnect();
|
|
5077
|
+
const codeEmbedding = await embeddings.embed(validatedArgs.code);
|
|
5078
|
+
const results = await vectorDB.search(codeEmbedding, validatedArgs.limit, validatedArgs.code);
|
|
5079
|
+
log(`Found ${results.length} similar chunks`);
|
|
5080
|
+
return {
|
|
5081
|
+
indexInfo: getIndexMetadata(),
|
|
5082
|
+
results
|
|
5083
|
+
};
|
|
5084
|
+
}
|
|
5085
|
+
)(args);
|
|
5086
|
+
case "get_file_context":
|
|
5087
|
+
return await wrapToolHandler(
|
|
5088
|
+
GetFileContextSchema,
|
|
5089
|
+
async (validatedArgs) => {
|
|
5090
|
+
log(`Getting context for: ${validatedArgs.filepath}`);
|
|
5091
|
+
await checkAndReconnect();
|
|
5092
|
+
const fileEmbedding = await embeddings.embed(validatedArgs.filepath);
|
|
5093
|
+
const allResults = await vectorDB.search(fileEmbedding, 50, validatedArgs.filepath);
|
|
5094
|
+
const fileChunks = allResults.filter(
|
|
5095
|
+
(r) => r.metadata.file.includes(validatedArgs.filepath) || validatedArgs.filepath.includes(r.metadata.file)
|
|
5096
|
+
);
|
|
5097
|
+
let results = fileChunks;
|
|
5098
|
+
if (validatedArgs.includeRelated && fileChunks.length > 0) {
|
|
5099
|
+
const relatedEmbedding = await embeddings.embed(fileChunks[0].content);
|
|
5100
|
+
const related = await vectorDB.search(relatedEmbedding, 5, fileChunks[0].content);
|
|
5101
|
+
const relatedOtherFiles = related.filter(
|
|
5102
|
+
(r) => !r.metadata.file.includes(validatedArgs.filepath) && !validatedArgs.filepath.includes(r.metadata.file)
|
|
5103
|
+
);
|
|
5104
|
+
results = [...fileChunks, ...relatedOtherFiles];
|
|
4442
5105
|
}
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
|
|
4449
|
-
log("Listing functions with symbol metadata...");
|
|
4450
|
-
await checkAndReconnect();
|
|
4451
|
-
let results;
|
|
4452
|
-
let usedMethod = "symbols";
|
|
4453
|
-
try {
|
|
4454
|
-
results = await vectorDB.querySymbols({
|
|
4455
|
-
language,
|
|
4456
|
-
pattern,
|
|
4457
|
-
limit: 50
|
|
4458
|
-
});
|
|
4459
|
-
if (results.length === 0 && (language || pattern)) {
|
|
4460
|
-
log("No symbol results, falling back to content scan...");
|
|
4461
|
-
results = await vectorDB.scanWithFilter({
|
|
4462
|
-
language,
|
|
4463
|
-
pattern,
|
|
4464
|
-
limit: 50
|
|
4465
|
-
});
|
|
4466
|
-
usedMethod = "content";
|
|
5106
|
+
log(`Found ${results.length} chunks`);
|
|
5107
|
+
return {
|
|
5108
|
+
indexInfo: getIndexMetadata(),
|
|
5109
|
+
file: validatedArgs.filepath,
|
|
5110
|
+
chunks: results
|
|
5111
|
+
};
|
|
4467
5112
|
}
|
|
4468
|
-
|
|
4469
|
-
|
|
4470
|
-
|
|
4471
|
-
|
|
4472
|
-
|
|
4473
|
-
|
|
4474
|
-
|
|
4475
|
-
|
|
4476
|
-
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
4485
|
-
|
|
4486
|
-
|
|
4487
|
-
|
|
4488
|
-
|
|
5113
|
+
)(args);
|
|
5114
|
+
case "list_functions":
|
|
5115
|
+
return await wrapToolHandler(
|
|
5116
|
+
ListFunctionsSchema,
|
|
5117
|
+
async (validatedArgs) => {
|
|
5118
|
+
log("Listing functions with symbol metadata...");
|
|
5119
|
+
await checkAndReconnect();
|
|
5120
|
+
let results;
|
|
5121
|
+
let usedMethod = "symbols";
|
|
5122
|
+
try {
|
|
5123
|
+
results = await vectorDB.querySymbols({
|
|
5124
|
+
language: validatedArgs.language,
|
|
5125
|
+
pattern: validatedArgs.pattern,
|
|
5126
|
+
limit: 50
|
|
5127
|
+
});
|
|
5128
|
+
if (results.length === 0 && (validatedArgs.language || validatedArgs.pattern)) {
|
|
5129
|
+
log("No symbol results, falling back to content scan...");
|
|
5130
|
+
results = await vectorDB.scanWithFilter({
|
|
5131
|
+
language: validatedArgs.language,
|
|
5132
|
+
pattern: validatedArgs.pattern,
|
|
5133
|
+
limit: 50
|
|
5134
|
+
});
|
|
5135
|
+
usedMethod = "content";
|
|
5136
|
+
}
|
|
5137
|
+
} catch (error) {
|
|
5138
|
+
log(`Symbol query failed, falling back to content scan: ${error}`);
|
|
5139
|
+
results = await vectorDB.scanWithFilter({
|
|
5140
|
+
language: validatedArgs.language,
|
|
5141
|
+
pattern: validatedArgs.pattern,
|
|
5142
|
+
limit: 50
|
|
5143
|
+
});
|
|
5144
|
+
usedMethod = "content";
|
|
4489
5145
|
}
|
|
4490
|
-
|
|
4491
|
-
|
|
4492
|
-
|
|
5146
|
+
log(`Found ${results.length} matches using ${usedMethod} method`);
|
|
5147
|
+
return {
|
|
5148
|
+
indexInfo: getIndexMetadata(),
|
|
5149
|
+
method: usedMethod,
|
|
5150
|
+
results,
|
|
5151
|
+
note: usedMethod === "content" ? 'Using content search. Run "lien reindex" to enable faster symbol-based queries.' : void 0
|
|
5152
|
+
};
|
|
5153
|
+
}
|
|
5154
|
+
)(args);
|
|
4493
5155
|
default:
|
|
4494
|
-
throw new
|
|
5156
|
+
throw new LienError(
|
|
5157
|
+
`Unknown tool: ${name}`,
|
|
5158
|
+
"INVALID_INPUT" /* INVALID_INPUT */,
|
|
5159
|
+
{ requestedTool: name, availableTools: tools.map((t) => t.name) },
|
|
5160
|
+
"medium",
|
|
5161
|
+
false,
|
|
5162
|
+
false
|
|
5163
|
+
);
|
|
4495
5164
|
}
|
|
4496
5165
|
} catch (error) {
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
{
|
|
5166
|
+
if (error instanceof LienError) {
|
|
5167
|
+
return {
|
|
5168
|
+
isError: true,
|
|
5169
|
+
content: [{
|
|
4501
5170
|
type: "text",
|
|
4502
|
-
text: JSON.stringify(
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
|
|
4506
|
-
|
|
4507
|
-
|
|
4508
|
-
isError: true
|
|
5171
|
+
text: JSON.stringify(error.toJSON(), null, 2)
|
|
5172
|
+
}]
|
|
5173
|
+
};
|
|
5174
|
+
}
|
|
5175
|
+
console.error(`Unexpected error handling tool call ${name}:`, error);
|
|
5176
|
+
return {
|
|
5177
|
+
isError: true,
|
|
5178
|
+
content: [{
|
|
5179
|
+
type: "text",
|
|
5180
|
+
text: JSON.stringify({
|
|
5181
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
5182
|
+
code: "INTERNAL_ERROR" /* INTERNAL_ERROR */,
|
|
5183
|
+
tool: name
|
|
5184
|
+
}, null, 2)
|
|
5185
|
+
}]
|
|
4509
5186
|
};
|
|
4510
5187
|
}
|
|
4511
5188
|
});
|