raggrep 0.4.0 → 0.5.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/dist/app/indexer/index.d.ts +2 -0
- package/dist/cli/main.js +1268 -622
- package/dist/cli/main.js.map +15 -10
- package/dist/domain/entities/config.d.ts +6 -0
- package/dist/domain/services/chunking.d.ts +66 -0
- package/dist/domain/services/index.d.ts +2 -0
- package/dist/domain/services/queryIntent.d.ts +55 -0
- package/dist/index.js +1248 -612
- package/dist/index.js.map +14 -9
- package/dist/modules/data/json/index.d.ts +47 -0
- package/dist/modules/docs/markdown/index.d.ts +47 -0
- package/dist/modules/language/typescript/index.d.ts +9 -1
- package/dist/modules/language/typescript/parseCode.d.ts +11 -7
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -56,6 +56,20 @@ function createDefaultConfig() {
|
|
|
56
56
|
options: {
|
|
57
57
|
embeddingModel: "all-MiniLM-L6-v2"
|
|
58
58
|
}
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
id: "data/json",
|
|
62
|
+
enabled: true,
|
|
63
|
+
options: {
|
|
64
|
+
embeddingModel: "all-MiniLM-L6-v2"
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
id: "docs/markdown",
|
|
69
|
+
enabled: true,
|
|
70
|
+
options: {
|
|
71
|
+
embeddingModel: "all-MiniLM-L6-v2"
|
|
72
|
+
}
|
|
59
73
|
}
|
|
60
74
|
]
|
|
61
75
|
};
|
|
@@ -99,16 +113,18 @@ var init_config = __esm(() => {
|
|
|
99
113
|
".jsx",
|
|
100
114
|
".mjs",
|
|
101
115
|
".cjs",
|
|
116
|
+
".mts",
|
|
117
|
+
".cts",
|
|
118
|
+
".json",
|
|
119
|
+
".md",
|
|
102
120
|
".py",
|
|
103
121
|
".go",
|
|
104
122
|
".rs",
|
|
105
123
|
".java",
|
|
106
|
-
".json",
|
|
107
124
|
".yaml",
|
|
108
125
|
".yml",
|
|
109
126
|
".toml",
|
|
110
127
|
".sql",
|
|
111
|
-
".md",
|
|
112
128
|
".txt"
|
|
113
129
|
];
|
|
114
130
|
});
|
|
@@ -2198,221 +2214,6 @@ var init_embeddings = __esm(() => {
|
|
|
2198
2214
|
init_transformersEmbedding();
|
|
2199
2215
|
});
|
|
2200
2216
|
|
|
2201
|
-
// src/domain/services/similarity.ts
|
|
2202
|
-
function cosineSimilarity(a, b) {
|
|
2203
|
-
if (a.length !== b.length) {
|
|
2204
|
-
throw new Error(`Vector length mismatch: ${a.length} vs ${b.length}`);
|
|
2205
|
-
}
|
|
2206
|
-
let dotProduct = 0;
|
|
2207
|
-
let normA = 0;
|
|
2208
|
-
let normB = 0;
|
|
2209
|
-
for (let i = 0;i < a.length; i++) {
|
|
2210
|
-
dotProduct += a[i] * b[i];
|
|
2211
|
-
normA += a[i] * a[i];
|
|
2212
|
-
normB += b[i] * b[i];
|
|
2213
|
-
}
|
|
2214
|
-
const magnitude = Math.sqrt(normA) * Math.sqrt(normB);
|
|
2215
|
-
if (magnitude === 0)
|
|
2216
|
-
return 0;
|
|
2217
|
-
return dotProduct / magnitude;
|
|
2218
|
-
}
|
|
2219
|
-
|
|
2220
|
-
// src/modules/language/typescript/parseCode.ts
|
|
2221
|
-
import * as ts from "typescript";
|
|
2222
|
-
function parseCode(content, filepath) {
|
|
2223
|
-
const ext = filepath.split(".").pop()?.toLowerCase();
|
|
2224
|
-
if (["ts", "tsx", "js", "jsx", "mts", "cts", "mjs", "cjs"].includes(ext || "")) {
|
|
2225
|
-
return parseTypeScript(content, filepath);
|
|
2226
|
-
}
|
|
2227
|
-
return parseGenericCode(content);
|
|
2228
|
-
}
|
|
2229
|
-
function parseTypeScript(content, filepath) {
|
|
2230
|
-
const chunks = [];
|
|
2231
|
-
const lines = content.split(`
|
|
2232
|
-
`);
|
|
2233
|
-
const sourceFile = ts.createSourceFile(filepath, content, ts.ScriptTarget.Latest, true, filepath.endsWith(".tsx") || filepath.endsWith(".jsx") ? ts.ScriptKind.TSX : ts.ScriptKind.TS);
|
|
2234
|
-
function getLineNumbers(node) {
|
|
2235
|
-
const start = sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
|
2236
|
-
const end = sourceFile.getLineAndCharacterOfPosition(node.getEnd());
|
|
2237
|
-
return {
|
|
2238
|
-
startLine: start.line + 1,
|
|
2239
|
-
endLine: end.line + 1
|
|
2240
|
-
};
|
|
2241
|
-
}
|
|
2242
|
-
function getNodeText(node) {
|
|
2243
|
-
return node.getText(sourceFile);
|
|
2244
|
-
}
|
|
2245
|
-
function isExported(node) {
|
|
2246
|
-
if (!ts.canHaveModifiers(node))
|
|
2247
|
-
return false;
|
|
2248
|
-
const modifiers = ts.getModifiers(node);
|
|
2249
|
-
return modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false;
|
|
2250
|
-
}
|
|
2251
|
-
function getJSDoc(node) {
|
|
2252
|
-
const jsDocNodes = ts.getJSDocCommentsAndTags(node);
|
|
2253
|
-
if (jsDocNodes.length === 0)
|
|
2254
|
-
return;
|
|
2255
|
-
return jsDocNodes.map((doc) => doc.getText(sourceFile)).join(`
|
|
2256
|
-
`);
|
|
2257
|
-
}
|
|
2258
|
-
function getFunctionName(node) {
|
|
2259
|
-
if (ts.isFunctionDeclaration(node) && node.name) {
|
|
2260
|
-
return node.name.text;
|
|
2261
|
-
}
|
|
2262
|
-
if (ts.isMethodDeclaration(node) && ts.isIdentifier(node.name)) {
|
|
2263
|
-
return node.name.text;
|
|
2264
|
-
}
|
|
2265
|
-
if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name)) {
|
|
2266
|
-
return node.name.text;
|
|
2267
|
-
}
|
|
2268
|
-
return;
|
|
2269
|
-
}
|
|
2270
|
-
function visit(node) {
|
|
2271
|
-
const { startLine, endLine } = getLineNumbers(node);
|
|
2272
|
-
if (ts.isFunctionDeclaration(node) && node.name) {
|
|
2273
|
-
chunks.push({
|
|
2274
|
-
content: getNodeText(node),
|
|
2275
|
-
startLine,
|
|
2276
|
-
endLine,
|
|
2277
|
-
type: "function",
|
|
2278
|
-
name: node.name.text,
|
|
2279
|
-
isExported: isExported(node),
|
|
2280
|
-
jsDoc: getJSDoc(node)
|
|
2281
|
-
});
|
|
2282
|
-
return;
|
|
2283
|
-
}
|
|
2284
|
-
if (ts.isVariableStatement(node)) {
|
|
2285
|
-
for (const decl of node.declarationList.declarations) {
|
|
2286
|
-
if (decl.initializer && (ts.isArrowFunction(decl.initializer) || ts.isFunctionExpression(decl.initializer))) {
|
|
2287
|
-
const name = ts.isIdentifier(decl.name) ? decl.name.text : undefined;
|
|
2288
|
-
chunks.push({
|
|
2289
|
-
content: getNodeText(node),
|
|
2290
|
-
startLine,
|
|
2291
|
-
endLine,
|
|
2292
|
-
type: "function",
|
|
2293
|
-
name,
|
|
2294
|
-
isExported: isExported(node),
|
|
2295
|
-
jsDoc: getJSDoc(node)
|
|
2296
|
-
});
|
|
2297
|
-
return;
|
|
2298
|
-
}
|
|
2299
|
-
}
|
|
2300
|
-
}
|
|
2301
|
-
if (ts.isClassDeclaration(node) && node.name) {
|
|
2302
|
-
chunks.push({
|
|
2303
|
-
content: getNodeText(node),
|
|
2304
|
-
startLine,
|
|
2305
|
-
endLine,
|
|
2306
|
-
type: "class",
|
|
2307
|
-
name: node.name.text,
|
|
2308
|
-
isExported: isExported(node),
|
|
2309
|
-
jsDoc: getJSDoc(node)
|
|
2310
|
-
});
|
|
2311
|
-
return;
|
|
2312
|
-
}
|
|
2313
|
-
if (ts.isInterfaceDeclaration(node)) {
|
|
2314
|
-
chunks.push({
|
|
2315
|
-
content: getNodeText(node),
|
|
2316
|
-
startLine,
|
|
2317
|
-
endLine,
|
|
2318
|
-
type: "interface",
|
|
2319
|
-
name: node.name.text,
|
|
2320
|
-
isExported: isExported(node),
|
|
2321
|
-
jsDoc: getJSDoc(node)
|
|
2322
|
-
});
|
|
2323
|
-
return;
|
|
2324
|
-
}
|
|
2325
|
-
if (ts.isTypeAliasDeclaration(node)) {
|
|
2326
|
-
chunks.push({
|
|
2327
|
-
content: getNodeText(node),
|
|
2328
|
-
startLine,
|
|
2329
|
-
endLine,
|
|
2330
|
-
type: "type",
|
|
2331
|
-
name: node.name.text,
|
|
2332
|
-
isExported: isExported(node),
|
|
2333
|
-
jsDoc: getJSDoc(node)
|
|
2334
|
-
});
|
|
2335
|
-
return;
|
|
2336
|
-
}
|
|
2337
|
-
if (ts.isEnumDeclaration(node)) {
|
|
2338
|
-
chunks.push({
|
|
2339
|
-
content: getNodeText(node),
|
|
2340
|
-
startLine,
|
|
2341
|
-
endLine,
|
|
2342
|
-
type: "enum",
|
|
2343
|
-
name: node.name.text,
|
|
2344
|
-
isExported: isExported(node),
|
|
2345
|
-
jsDoc: getJSDoc(node)
|
|
2346
|
-
});
|
|
2347
|
-
return;
|
|
2348
|
-
}
|
|
2349
|
-
if (ts.isVariableStatement(node) && isExported(node)) {
|
|
2350
|
-
for (const decl of node.declarationList.declarations) {
|
|
2351
|
-
if (decl.initializer && (ts.isArrowFunction(decl.initializer) || ts.isFunctionExpression(decl.initializer))) {
|
|
2352
|
-
continue;
|
|
2353
|
-
}
|
|
2354
|
-
const name = ts.isIdentifier(decl.name) ? decl.name.text : undefined;
|
|
2355
|
-
chunks.push({
|
|
2356
|
-
content: getNodeText(node),
|
|
2357
|
-
startLine,
|
|
2358
|
-
endLine,
|
|
2359
|
-
type: "variable",
|
|
2360
|
-
name,
|
|
2361
|
-
isExported: true,
|
|
2362
|
-
jsDoc: getJSDoc(node)
|
|
2363
|
-
});
|
|
2364
|
-
}
|
|
2365
|
-
return;
|
|
2366
|
-
}
|
|
2367
|
-
ts.forEachChild(node, visit);
|
|
2368
|
-
}
|
|
2369
|
-
ts.forEachChild(sourceFile, visit);
|
|
2370
|
-
if (chunks.length === 0) {
|
|
2371
|
-
return parseGenericCode(content);
|
|
2372
|
-
}
|
|
2373
|
-
return chunks;
|
|
2374
|
-
}
|
|
2375
|
-
function parseGenericCode(content) {
|
|
2376
|
-
const chunks = [];
|
|
2377
|
-
const lines = content.split(`
|
|
2378
|
-
`);
|
|
2379
|
-
const CHUNK_SIZE = 30;
|
|
2380
|
-
const OVERLAP = 5;
|
|
2381
|
-
if (lines.length <= CHUNK_SIZE) {
|
|
2382
|
-
return [
|
|
2383
|
-
{
|
|
2384
|
-
content,
|
|
2385
|
-
startLine: 1,
|
|
2386
|
-
endLine: lines.length,
|
|
2387
|
-
type: "file"
|
|
2388
|
-
}
|
|
2389
|
-
];
|
|
2390
|
-
}
|
|
2391
|
-
for (let i = 0;i < lines.length; i += CHUNK_SIZE - OVERLAP) {
|
|
2392
|
-
const endIdx = Math.min(i + CHUNK_SIZE, lines.length);
|
|
2393
|
-
chunks.push({
|
|
2394
|
-
content: lines.slice(i, endIdx).join(`
|
|
2395
|
-
`),
|
|
2396
|
-
startLine: i + 1,
|
|
2397
|
-
endLine: endIdx,
|
|
2398
|
-
type: "block"
|
|
2399
|
-
});
|
|
2400
|
-
if (endIdx >= lines.length)
|
|
2401
|
-
break;
|
|
2402
|
-
}
|
|
2403
|
-
return chunks;
|
|
2404
|
-
}
|
|
2405
|
-
function generateChunkId(filepath, startLine, endLine) {
|
|
2406
|
-
const safePath = filepath.replace(/[/\\]/g, "-").replace(/\./g, "_");
|
|
2407
|
-
return `${safePath}-${startLine}-${endLine}`;
|
|
2408
|
-
}
|
|
2409
|
-
var init_parseCode = () => {};
|
|
2410
|
-
|
|
2411
|
-
// src/infrastructure/storage/fileIndexStorage.ts
|
|
2412
|
-
var init_fileIndexStorage = __esm(() => {
|
|
2413
|
-
init_entities();
|
|
2414
|
-
});
|
|
2415
|
-
|
|
2416
2217
|
// src/domain/services/keywords.ts
|
|
2417
2218
|
function extractKeywords(content, name, maxKeywords = 50) {
|
|
2418
2219
|
const keywords = new Set;
|
|
@@ -2601,222 +2402,1105 @@ var init_keywords = __esm(() => {
|
|
|
2601
2402
|
};
|
|
2602
2403
|
});
|
|
2603
2404
|
|
|
2604
|
-
// src/
|
|
2605
|
-
|
|
2606
|
-
|
|
2405
|
+
// src/domain/services/similarity.ts
|
|
2406
|
+
function cosineSimilarity(a, b) {
|
|
2407
|
+
if (a.length !== b.length) {
|
|
2408
|
+
throw new Error(`Vector length mismatch: ${a.length} vs ${b.length}`);
|
|
2409
|
+
}
|
|
2410
|
+
let dotProduct = 0;
|
|
2411
|
+
let normA = 0;
|
|
2412
|
+
let normB = 0;
|
|
2413
|
+
for (let i = 0;i < a.length; i++) {
|
|
2414
|
+
dotProduct += a[i] * b[i];
|
|
2415
|
+
normA += a[i] * a[i];
|
|
2416
|
+
normB += b[i] * b[i];
|
|
2417
|
+
}
|
|
2418
|
+
const magnitude = Math.sqrt(normA) * Math.sqrt(normB);
|
|
2419
|
+
if (magnitude === 0)
|
|
2420
|
+
return 0;
|
|
2421
|
+
return dotProduct / magnitude;
|
|
2422
|
+
}
|
|
2607
2423
|
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
this.symbolicPath = path7.join(indexDir, "index", moduleId, "symbolic");
|
|
2616
|
-
this.moduleId = moduleId;
|
|
2424
|
+
// src/domain/services/queryIntent.ts
|
|
2425
|
+
import * as path7 from "path";
|
|
2426
|
+
function detectQueryIntent(queryTerms) {
|
|
2427
|
+
const hasImplementationTerm = queryTerms.some((term) => IMPLEMENTATION_TERMS.includes(term));
|
|
2428
|
+
const hasDocumentationTerm = queryTerms.some((term) => DOCUMENTATION_TERMS.includes(term));
|
|
2429
|
+
if (hasDocumentationTerm) {
|
|
2430
|
+
return "documentation";
|
|
2617
2431
|
}
|
|
2618
|
-
|
|
2619
|
-
|
|
2432
|
+
if (hasImplementationTerm) {
|
|
2433
|
+
return "implementation";
|
|
2434
|
+
}
|
|
2435
|
+
return "neutral";
|
|
2436
|
+
}
|
|
2437
|
+
function extractQueryTerms(query) {
|
|
2438
|
+
return query.toLowerCase().split(/\s+/).filter((t) => t.length > 2);
|
|
2439
|
+
}
|
|
2440
|
+
function isSourceCodeFile(filepath) {
|
|
2441
|
+
const ext = path7.extname(filepath).toLowerCase();
|
|
2442
|
+
return SOURCE_CODE_EXTENSIONS.includes(ext);
|
|
2443
|
+
}
|
|
2444
|
+
function isDocFile(filepath) {
|
|
2445
|
+
const ext = path7.extname(filepath).toLowerCase();
|
|
2446
|
+
return DOC_EXTENSIONS.includes(ext);
|
|
2447
|
+
}
|
|
2448
|
+
function calculateFileTypeBoost(filepath, queryTerms) {
|
|
2449
|
+
const isSourceCode = isSourceCodeFile(filepath);
|
|
2450
|
+
const isDoc = isDocFile(filepath);
|
|
2451
|
+
const intent = detectQueryIntent(queryTerms);
|
|
2452
|
+
if (intent === "implementation") {
|
|
2453
|
+
if (isSourceCode) {
|
|
2454
|
+
return 0.06;
|
|
2455
|
+
}
|
|
2456
|
+
return 0;
|
|
2457
|
+
}
|
|
2458
|
+
if (intent === "documentation") {
|
|
2459
|
+
if (isDoc) {
|
|
2460
|
+
return 0.08;
|
|
2461
|
+
}
|
|
2462
|
+
return 0;
|
|
2463
|
+
}
|
|
2464
|
+
return 0;
|
|
2465
|
+
}
|
|
2466
|
+
var IMPLEMENTATION_TERMS, DOCUMENTATION_TERMS, SOURCE_CODE_EXTENSIONS, DOC_EXTENSIONS;
|
|
2467
|
+
var init_queryIntent = __esm(() => {
|
|
2468
|
+
IMPLEMENTATION_TERMS = [
|
|
2469
|
+
"function",
|
|
2470
|
+
"method",
|
|
2471
|
+
"class",
|
|
2472
|
+
"interface",
|
|
2473
|
+
"implement",
|
|
2474
|
+
"implementation",
|
|
2475
|
+
"endpoint",
|
|
2476
|
+
"route",
|
|
2477
|
+
"handler",
|
|
2478
|
+
"controller",
|
|
2479
|
+
"module",
|
|
2480
|
+
"code"
|
|
2481
|
+
];
|
|
2482
|
+
DOCUMENTATION_TERMS = [
|
|
2483
|
+
"documentation",
|
|
2484
|
+
"docs",
|
|
2485
|
+
"guide",
|
|
2486
|
+
"tutorial",
|
|
2487
|
+
"readme",
|
|
2488
|
+
"how",
|
|
2489
|
+
"what",
|
|
2490
|
+
"why",
|
|
2491
|
+
"explain",
|
|
2492
|
+
"overview",
|
|
2493
|
+
"getting",
|
|
2494
|
+
"started",
|
|
2495
|
+
"requirements",
|
|
2496
|
+
"setup",
|
|
2497
|
+
"install",
|
|
2498
|
+
"configure",
|
|
2499
|
+
"configuration"
|
|
2500
|
+
];
|
|
2501
|
+
SOURCE_CODE_EXTENSIONS = [
|
|
2502
|
+
".ts",
|
|
2503
|
+
".tsx",
|
|
2504
|
+
".js",
|
|
2505
|
+
".jsx",
|
|
2506
|
+
".mjs",
|
|
2507
|
+
".cjs",
|
|
2508
|
+
".py",
|
|
2509
|
+
".go",
|
|
2510
|
+
".rs",
|
|
2511
|
+
".java"
|
|
2512
|
+
];
|
|
2513
|
+
DOC_EXTENSIONS = [".md", ".txt", ".rst"];
|
|
2514
|
+
});
|
|
2515
|
+
|
|
2516
|
+
// src/domain/services/chunking.ts
|
|
2517
|
+
function createLineBasedChunks(content, options = {}) {
|
|
2518
|
+
const {
|
|
2519
|
+
chunkSize = DEFAULT_CHUNK_SIZE,
|
|
2520
|
+
overlap = DEFAULT_OVERLAP,
|
|
2521
|
+
minLinesForMultipleChunks = chunkSize
|
|
2522
|
+
} = options;
|
|
2523
|
+
const lines = content.split(`
|
|
2524
|
+
`);
|
|
2525
|
+
const chunks = [];
|
|
2526
|
+
if (lines.length <= minLinesForMultipleChunks) {
|
|
2527
|
+
return [
|
|
2528
|
+
{
|
|
2529
|
+
content,
|
|
2530
|
+
startLine: 1,
|
|
2531
|
+
endLine: lines.length,
|
|
2532
|
+
type: "file"
|
|
2533
|
+
}
|
|
2534
|
+
];
|
|
2535
|
+
}
|
|
2536
|
+
for (let i = 0;i < lines.length; i += chunkSize - overlap) {
|
|
2537
|
+
const endIdx = Math.min(i + chunkSize, lines.length);
|
|
2538
|
+
chunks.push({
|
|
2539
|
+
content: lines.slice(i, endIdx).join(`
|
|
2540
|
+
`),
|
|
2541
|
+
startLine: i + 1,
|
|
2542
|
+
endLine: endIdx,
|
|
2543
|
+
type: "block"
|
|
2544
|
+
});
|
|
2545
|
+
if (endIdx >= lines.length)
|
|
2546
|
+
break;
|
|
2547
|
+
}
|
|
2548
|
+
return chunks;
|
|
2549
|
+
}
|
|
2550
|
+
function generateChunkId(filepath, startLine, endLine) {
|
|
2551
|
+
const safePath = filepath.replace(/[/\\]/g, "-").replace(/\./g, "_");
|
|
2552
|
+
return `${safePath}-${startLine}-${endLine}`;
|
|
2553
|
+
}
|
|
2554
|
+
var DEFAULT_CHUNK_SIZE = 30, DEFAULT_OVERLAP = 5;
|
|
2555
|
+
|
|
2556
|
+
// src/domain/services/index.ts
|
|
2557
|
+
var init_services = __esm(() => {
|
|
2558
|
+
init_keywords();
|
|
2559
|
+
init_queryIntent();
|
|
2560
|
+
});
|
|
2561
|
+
|
|
2562
|
+
// src/modules/language/typescript/parseCode.ts
|
|
2563
|
+
import * as ts from "typescript";
|
|
2564
|
+
function parseTypeScriptCode(content, filepath) {
|
|
2565
|
+
return parseTypeScript(content, filepath);
|
|
2566
|
+
}
|
|
2567
|
+
function parseTypeScript(content, filepath) {
|
|
2568
|
+
const chunks = [];
|
|
2569
|
+
const lines = content.split(`
|
|
2570
|
+
`);
|
|
2571
|
+
const sourceFile = ts.createSourceFile(filepath, content, ts.ScriptTarget.Latest, true, filepath.endsWith(".tsx") || filepath.endsWith(".jsx") ? ts.ScriptKind.TSX : ts.ScriptKind.TS);
|
|
2572
|
+
function getLineNumbers(node) {
|
|
2573
|
+
const start = sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
|
2574
|
+
const end = sourceFile.getLineAndCharacterOfPosition(node.getEnd());
|
|
2575
|
+
return {
|
|
2576
|
+
startLine: start.line + 1,
|
|
2577
|
+
endLine: end.line + 1
|
|
2578
|
+
};
|
|
2579
|
+
}
|
|
2580
|
+
function getNodeText(node) {
|
|
2581
|
+
return node.getText(sourceFile);
|
|
2582
|
+
}
|
|
2583
|
+
function isExported(node) {
|
|
2584
|
+
if (!ts.canHaveModifiers(node))
|
|
2585
|
+
return false;
|
|
2586
|
+
const modifiers = ts.getModifiers(node);
|
|
2587
|
+
return modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false;
|
|
2588
|
+
}
|
|
2589
|
+
function getJSDoc(node) {
|
|
2590
|
+
const jsDocNodes = ts.getJSDocCommentsAndTags(node);
|
|
2591
|
+
if (jsDocNodes.length === 0)
|
|
2592
|
+
return;
|
|
2593
|
+
return jsDocNodes.map((doc) => doc.getText(sourceFile)).join(`
|
|
2594
|
+
`);
|
|
2595
|
+
}
|
|
2596
|
+
function getFunctionName(node) {
|
|
2597
|
+
if (ts.isFunctionDeclaration(node) && node.name) {
|
|
2598
|
+
return node.name.text;
|
|
2599
|
+
}
|
|
2600
|
+
if (ts.isMethodDeclaration(node) && ts.isIdentifier(node.name)) {
|
|
2601
|
+
return node.name.text;
|
|
2602
|
+
}
|
|
2603
|
+
if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name)) {
|
|
2604
|
+
return node.name.text;
|
|
2605
|
+
}
|
|
2606
|
+
return;
|
|
2607
|
+
}
|
|
2608
|
+
function visit(node) {
|
|
2609
|
+
const { startLine, endLine } = getLineNumbers(node);
|
|
2610
|
+
if (ts.isFunctionDeclaration(node) && node.name) {
|
|
2611
|
+
chunks.push({
|
|
2612
|
+
content: getNodeText(node),
|
|
2613
|
+
startLine,
|
|
2614
|
+
endLine,
|
|
2615
|
+
type: "function",
|
|
2616
|
+
name: node.name.text,
|
|
2617
|
+
isExported: isExported(node),
|
|
2618
|
+
jsDoc: getJSDoc(node)
|
|
2619
|
+
});
|
|
2620
|
+
return;
|
|
2621
|
+
}
|
|
2622
|
+
if (ts.isVariableStatement(node)) {
|
|
2623
|
+
for (const decl of node.declarationList.declarations) {
|
|
2624
|
+
if (decl.initializer && (ts.isArrowFunction(decl.initializer) || ts.isFunctionExpression(decl.initializer))) {
|
|
2625
|
+
const name = ts.isIdentifier(decl.name) ? decl.name.text : undefined;
|
|
2626
|
+
chunks.push({
|
|
2627
|
+
content: getNodeText(node),
|
|
2628
|
+
startLine,
|
|
2629
|
+
endLine,
|
|
2630
|
+
type: "function",
|
|
2631
|
+
name,
|
|
2632
|
+
isExported: isExported(node),
|
|
2633
|
+
jsDoc: getJSDoc(node)
|
|
2634
|
+
});
|
|
2635
|
+
return;
|
|
2636
|
+
}
|
|
2637
|
+
}
|
|
2638
|
+
}
|
|
2639
|
+
if (ts.isClassDeclaration(node) && node.name) {
|
|
2640
|
+
chunks.push({
|
|
2641
|
+
content: getNodeText(node),
|
|
2642
|
+
startLine,
|
|
2643
|
+
endLine,
|
|
2644
|
+
type: "class",
|
|
2645
|
+
name: node.name.text,
|
|
2646
|
+
isExported: isExported(node),
|
|
2647
|
+
jsDoc: getJSDoc(node)
|
|
2648
|
+
});
|
|
2649
|
+
return;
|
|
2650
|
+
}
|
|
2651
|
+
if (ts.isInterfaceDeclaration(node)) {
|
|
2652
|
+
chunks.push({
|
|
2653
|
+
content: getNodeText(node),
|
|
2654
|
+
startLine,
|
|
2655
|
+
endLine,
|
|
2656
|
+
type: "interface",
|
|
2657
|
+
name: node.name.text,
|
|
2658
|
+
isExported: isExported(node),
|
|
2659
|
+
jsDoc: getJSDoc(node)
|
|
2660
|
+
});
|
|
2661
|
+
return;
|
|
2662
|
+
}
|
|
2663
|
+
if (ts.isTypeAliasDeclaration(node)) {
|
|
2664
|
+
chunks.push({
|
|
2665
|
+
content: getNodeText(node),
|
|
2666
|
+
startLine,
|
|
2667
|
+
endLine,
|
|
2668
|
+
type: "type",
|
|
2669
|
+
name: node.name.text,
|
|
2670
|
+
isExported: isExported(node),
|
|
2671
|
+
jsDoc: getJSDoc(node)
|
|
2672
|
+
});
|
|
2673
|
+
return;
|
|
2674
|
+
}
|
|
2675
|
+
if (ts.isEnumDeclaration(node)) {
|
|
2676
|
+
chunks.push({
|
|
2677
|
+
content: getNodeText(node),
|
|
2678
|
+
startLine,
|
|
2679
|
+
endLine,
|
|
2680
|
+
type: "enum",
|
|
2681
|
+
name: node.name.text,
|
|
2682
|
+
isExported: isExported(node),
|
|
2683
|
+
jsDoc: getJSDoc(node)
|
|
2684
|
+
});
|
|
2685
|
+
return;
|
|
2686
|
+
}
|
|
2687
|
+
if (ts.isVariableStatement(node) && isExported(node)) {
|
|
2688
|
+
for (const decl of node.declarationList.declarations) {
|
|
2689
|
+
if (decl.initializer && (ts.isArrowFunction(decl.initializer) || ts.isFunctionExpression(decl.initializer))) {
|
|
2690
|
+
continue;
|
|
2691
|
+
}
|
|
2692
|
+
const name = ts.isIdentifier(decl.name) ? decl.name.text : undefined;
|
|
2693
|
+
chunks.push({
|
|
2694
|
+
content: getNodeText(node),
|
|
2695
|
+
startLine,
|
|
2696
|
+
endLine,
|
|
2697
|
+
type: "variable",
|
|
2698
|
+
name,
|
|
2699
|
+
isExported: true,
|
|
2700
|
+
jsDoc: getJSDoc(node)
|
|
2701
|
+
});
|
|
2702
|
+
}
|
|
2703
|
+
return;
|
|
2704
|
+
}
|
|
2705
|
+
ts.forEachChild(node, visit);
|
|
2706
|
+
}
|
|
2707
|
+
ts.forEachChild(sourceFile, visit);
|
|
2708
|
+
if (chunks.length === 0) {
|
|
2709
|
+
const lines2 = content.split(`
|
|
2710
|
+
`);
|
|
2711
|
+
return [
|
|
2712
|
+
{
|
|
2713
|
+
content,
|
|
2714
|
+
startLine: 1,
|
|
2715
|
+
endLine: lines2.length,
|
|
2716
|
+
type: "file"
|
|
2717
|
+
}
|
|
2718
|
+
];
|
|
2719
|
+
}
|
|
2720
|
+
return chunks;
|
|
2721
|
+
}
|
|
2722
|
+
function generateChunkId2(filepath, startLine, endLine) {
|
|
2723
|
+
const safePath = filepath.replace(/[/\\]/g, "-").replace(/\./g, "_");
|
|
2724
|
+
return `${safePath}-${startLine}-${endLine}`;
|
|
2725
|
+
}
|
|
2726
|
+
var init_parseCode = () => {};
|
|
2727
|
+
|
|
2728
|
+
// src/infrastructure/storage/fileIndexStorage.ts
|
|
2729
|
+
var init_fileIndexStorage = __esm(() => {
|
|
2730
|
+
init_entities();
|
|
2731
|
+
});
|
|
2732
|
+
|
|
2733
|
+
// src/infrastructure/storage/symbolicIndex.ts
|
|
2734
|
+
import * as fs3 from "fs/promises";
|
|
2735
|
+
import * as path8 from "path";
|
|
2736
|
+
|
|
2737
|
+
class SymbolicIndex {
|
|
2738
|
+
meta = null;
|
|
2739
|
+
fileSummaries = new Map;
|
|
2740
|
+
bm25Index = null;
|
|
2741
|
+
symbolicPath;
|
|
2742
|
+
moduleId;
|
|
2743
|
+
constructor(indexDir, moduleId) {
|
|
2744
|
+
this.symbolicPath = path8.join(indexDir, "index", moduleId, "symbolic");
|
|
2745
|
+
this.moduleId = moduleId;
|
|
2746
|
+
}
|
|
2747
|
+
async initialize() {
|
|
2748
|
+
try {
|
|
2620
2749
|
await this.load();
|
|
2621
2750
|
} catch {
|
|
2622
|
-
this.meta = {
|
|
2623
|
-
version: "1.0.0",
|
|
2624
|
-
lastUpdated: new Date().toISOString(),
|
|
2625
|
-
moduleId: this.moduleId,
|
|
2626
|
-
fileCount: 0,
|
|
2627
|
-
bm25Data: {
|
|
2628
|
-
avgDocLength: 0,
|
|
2629
|
-
documentFrequencies: {},
|
|
2630
|
-
totalDocs: 0
|
|
2631
|
-
}
|
|
2751
|
+
this.meta = {
|
|
2752
|
+
version: "1.0.0",
|
|
2753
|
+
lastUpdated: new Date().toISOString(),
|
|
2754
|
+
moduleId: this.moduleId,
|
|
2755
|
+
fileCount: 0,
|
|
2756
|
+
bm25Data: {
|
|
2757
|
+
avgDocLength: 0,
|
|
2758
|
+
documentFrequencies: {},
|
|
2759
|
+
totalDocs: 0
|
|
2760
|
+
}
|
|
2761
|
+
};
|
|
2762
|
+
this.bm25Index = new BM25Index;
|
|
2763
|
+
}
|
|
2764
|
+
}
|
|
2765
|
+
addFile(summary) {
|
|
2766
|
+
this.fileSummaries.set(summary.filepath, summary);
|
|
2767
|
+
}
|
|
2768
|
+
removeFile(filepath) {
|
|
2769
|
+
return this.fileSummaries.delete(filepath);
|
|
2770
|
+
}
|
|
2771
|
+
buildBM25Index() {
|
|
2772
|
+
this.bm25Index = new BM25Index;
|
|
2773
|
+
for (const [filepath, summary] of this.fileSummaries) {
|
|
2774
|
+
const content = [
|
|
2775
|
+
...summary.keywords,
|
|
2776
|
+
...summary.exports,
|
|
2777
|
+
...extractPathKeywords(filepath)
|
|
2778
|
+
].join(" ");
|
|
2779
|
+
this.bm25Index.addDocuments([{ id: filepath, content }]);
|
|
2780
|
+
}
|
|
2781
|
+
if (this.meta) {
|
|
2782
|
+
this.meta.fileCount = this.fileSummaries.size;
|
|
2783
|
+
this.meta.bm25Data.totalDocs = this.fileSummaries.size;
|
|
2784
|
+
}
|
|
2785
|
+
}
|
|
2786
|
+
findCandidates(query, maxCandidates = 20) {
|
|
2787
|
+
if (!this.bm25Index) {
|
|
2788
|
+
return Array.from(this.fileSummaries.keys());
|
|
2789
|
+
}
|
|
2790
|
+
const results = this.bm25Index.search(query, maxCandidates);
|
|
2791
|
+
return results.map((r) => r.id);
|
|
2792
|
+
}
|
|
2793
|
+
getAllFiles() {
|
|
2794
|
+
return Array.from(this.fileSummaries.keys());
|
|
2795
|
+
}
|
|
2796
|
+
getFileSummary(filepath) {
|
|
2797
|
+
return this.fileSummaries.get(filepath);
|
|
2798
|
+
}
|
|
2799
|
+
async save() {
|
|
2800
|
+
if (!this.meta)
|
|
2801
|
+
throw new Error("Index not initialized");
|
|
2802
|
+
this.meta.lastUpdated = new Date().toISOString();
|
|
2803
|
+
this.meta.fileCount = this.fileSummaries.size;
|
|
2804
|
+
await fs3.mkdir(this.symbolicPath, { recursive: true });
|
|
2805
|
+
const metaPath = path8.join(this.symbolicPath, "_meta.json");
|
|
2806
|
+
await fs3.writeFile(metaPath, JSON.stringify(this.meta, null, 2));
|
|
2807
|
+
for (const [filepath, summary] of this.fileSummaries) {
|
|
2808
|
+
const summaryPath = this.getFileSummaryPath(filepath);
|
|
2809
|
+
await fs3.mkdir(path8.dirname(summaryPath), { recursive: true });
|
|
2810
|
+
await fs3.writeFile(summaryPath, JSON.stringify(summary, null, 2));
|
|
2811
|
+
}
|
|
2812
|
+
}
|
|
2813
|
+
async load() {
|
|
2814
|
+
const metaPath = path8.join(this.symbolicPath, "_meta.json");
|
|
2815
|
+
const metaContent = await fs3.readFile(metaPath, "utf-8");
|
|
2816
|
+
this.meta = JSON.parse(metaContent);
|
|
2817
|
+
this.fileSummaries.clear();
|
|
2818
|
+
await this.loadFileSummariesRecursive(this.symbolicPath);
|
|
2819
|
+
this.buildBM25Index();
|
|
2820
|
+
}
|
|
2821
|
+
async loadFileSummariesRecursive(dir) {
|
|
2822
|
+
try {
|
|
2823
|
+
const entries = await fs3.readdir(dir, { withFileTypes: true });
|
|
2824
|
+
for (const entry of entries) {
|
|
2825
|
+
const fullPath = path8.join(dir, entry.name);
|
|
2826
|
+
if (entry.isDirectory()) {
|
|
2827
|
+
await this.loadFileSummariesRecursive(fullPath);
|
|
2828
|
+
} else if (entry.name.endsWith(".json") && entry.name !== "_meta.json") {
|
|
2829
|
+
try {
|
|
2830
|
+
const content = await fs3.readFile(fullPath, "utf-8");
|
|
2831
|
+
const summary = JSON.parse(content);
|
|
2832
|
+
if (summary.filepath) {
|
|
2833
|
+
this.fileSummaries.set(summary.filepath, summary);
|
|
2834
|
+
}
|
|
2835
|
+
} catch {}
|
|
2836
|
+
}
|
|
2837
|
+
}
|
|
2838
|
+
} catch {}
|
|
2839
|
+
}
|
|
2840
|
+
getFileSummaryPath(filepath) {
|
|
2841
|
+
const jsonPath = filepath.replace(/\.[^.]+$/, ".json");
|
|
2842
|
+
return path8.join(this.symbolicPath, jsonPath);
|
|
2843
|
+
}
|
|
2844
|
+
async deleteFileSummary(filepath) {
|
|
2845
|
+
try {
|
|
2846
|
+
await fs3.unlink(this.getFileSummaryPath(filepath));
|
|
2847
|
+
} catch {}
|
|
2848
|
+
this.fileSummaries.delete(filepath);
|
|
2849
|
+
}
|
|
2850
|
+
async exists() {
|
|
2851
|
+
try {
|
|
2852
|
+
const metaPath = path8.join(this.symbolicPath, "_meta.json");
|
|
2853
|
+
await fs3.access(metaPath);
|
|
2854
|
+
return true;
|
|
2855
|
+
} catch {
|
|
2856
|
+
return false;
|
|
2857
|
+
}
|
|
2858
|
+
}
|
|
2859
|
+
get size() {
|
|
2860
|
+
return this.fileSummaries.size;
|
|
2861
|
+
}
|
|
2862
|
+
clear() {
|
|
2863
|
+
this.fileSummaries.clear();
|
|
2864
|
+
if (this.meta) {
|
|
2865
|
+
this.meta.fileCount = 0;
|
|
2866
|
+
this.meta.bm25Data = {
|
|
2867
|
+
avgDocLength: 0,
|
|
2868
|
+
documentFrequencies: {},
|
|
2869
|
+
totalDocs: 0
|
|
2632
2870
|
};
|
|
2633
|
-
this.bm25Index = new BM25Index;
|
|
2634
2871
|
}
|
|
2872
|
+
this.bm25Index = new BM25Index;
|
|
2873
|
+
}
|
|
2874
|
+
}
|
|
2875
|
+
var init_symbolicIndex = __esm(() => {
|
|
2876
|
+
init_keywords();
|
|
2877
|
+
});
|
|
2878
|
+
|
|
2879
|
+
// src/infrastructure/storage/index.ts
|
|
2880
|
+
var init_storage = __esm(() => {
|
|
2881
|
+
init_fileIndexStorage();
|
|
2882
|
+
init_symbolicIndex();
|
|
2883
|
+
});
|
|
2884
|
+
|
|
2885
|
+
// src/modules/language/typescript/index.ts
|
|
2886
|
+
var exports_typescript = {};
|
|
2887
|
+
__export(exports_typescript, {
|
|
2888
|
+
isTypeScriptFile: () => isTypeScriptFile,
|
|
2889
|
+
TypeScriptModule: () => TypeScriptModule,
|
|
2890
|
+
TYPESCRIPT_EXTENSIONS: () => TYPESCRIPT_EXTENSIONS,
|
|
2891
|
+
DEFAULT_TOP_K: () => DEFAULT_TOP_K2,
|
|
2892
|
+
DEFAULT_MIN_SCORE: () => DEFAULT_MIN_SCORE2
|
|
2893
|
+
});
|
|
2894
|
+
import * as path9 from "path";
|
|
2895
|
+
function isTypeScriptFile(filepath) {
|
|
2896
|
+
const ext = path9.extname(filepath).toLowerCase();
|
|
2897
|
+
return TYPESCRIPT_EXTENSIONS.includes(ext);
|
|
2898
|
+
}
|
|
2899
|
+
function calculateChunkTypeBoost(chunk) {
|
|
2900
|
+
switch (chunk.type) {
|
|
2901
|
+
case "function":
|
|
2902
|
+
return 0.05;
|
|
2903
|
+
case "class":
|
|
2904
|
+
case "interface":
|
|
2905
|
+
return 0.04;
|
|
2906
|
+
case "type":
|
|
2907
|
+
case "enum":
|
|
2908
|
+
return 0.03;
|
|
2909
|
+
case "variable":
|
|
2910
|
+
return 0.02;
|
|
2911
|
+
case "file":
|
|
2912
|
+
case "block":
|
|
2913
|
+
default:
|
|
2914
|
+
return 0;
|
|
2915
|
+
}
|
|
2916
|
+
}
|
|
2917
|
+
function calculateExportBoost(chunk) {
|
|
2918
|
+
return chunk.isExported ? 0.03 : 0;
|
|
2919
|
+
}
|
|
2920
|
+
|
|
2921
|
+
class TypeScriptModule {
|
|
2922
|
+
id = "language/typescript";
|
|
2923
|
+
name = "TypeScript Search";
|
|
2924
|
+
description = "TypeScript-aware code search with AST parsing and semantic embeddings";
|
|
2925
|
+
version = "1.0.0";
|
|
2926
|
+
embeddingConfig = null;
|
|
2927
|
+
symbolicIndex = null;
|
|
2928
|
+
pendingSummaries = new Map;
|
|
2929
|
+
rootDir = "";
|
|
2930
|
+
logger = undefined;
|
|
2931
|
+
async initialize(config) {
|
|
2932
|
+
this.embeddingConfig = getEmbeddingConfigFromModule(config);
|
|
2933
|
+
this.logger = config.options?.logger;
|
|
2934
|
+
if (this.logger) {
|
|
2935
|
+
this.embeddingConfig = {
|
|
2936
|
+
...this.embeddingConfig,
|
|
2937
|
+
logger: this.logger
|
|
2938
|
+
};
|
|
2939
|
+
}
|
|
2940
|
+
configureEmbeddings(this.embeddingConfig);
|
|
2941
|
+
this.pendingSummaries.clear();
|
|
2942
|
+
}
|
|
2943
|
+
async indexFile(filepath, content, ctx) {
|
|
2944
|
+
if (!isTypeScriptFile(filepath)) {
|
|
2945
|
+
return null;
|
|
2946
|
+
}
|
|
2947
|
+
this.rootDir = ctx.rootDir;
|
|
2948
|
+
const parsedChunks = parseTypeScriptCode(content, filepath);
|
|
2949
|
+
if (parsedChunks.length === 0) {
|
|
2950
|
+
return null;
|
|
2951
|
+
}
|
|
2952
|
+
const pathContext = parsePathContext(filepath);
|
|
2953
|
+
const pathPrefix = formatPathContextForEmbedding(pathContext);
|
|
2954
|
+
const chunkContents = parsedChunks.map((c) => {
|
|
2955
|
+
const namePrefix = c.name ? `${c.name}: ` : "";
|
|
2956
|
+
return `${pathPrefix} ${namePrefix}${c.content}`;
|
|
2957
|
+
});
|
|
2958
|
+
const embeddings = await getEmbeddings(chunkContents);
|
|
2959
|
+
const chunks = parsedChunks.map((pc) => ({
|
|
2960
|
+
id: generateChunkId2(filepath, pc.startLine, pc.endLine),
|
|
2961
|
+
content: pc.content,
|
|
2962
|
+
startLine: pc.startLine,
|
|
2963
|
+
endLine: pc.endLine,
|
|
2964
|
+
type: pc.type,
|
|
2965
|
+
name: pc.name,
|
|
2966
|
+
isExported: pc.isExported,
|
|
2967
|
+
jsDoc: pc.jsDoc
|
|
2968
|
+
}));
|
|
2969
|
+
const references = this.extractReferences(content, filepath);
|
|
2970
|
+
const stats = await ctx.getFileStats(filepath);
|
|
2971
|
+
const currentConfig = getEmbeddingConfig();
|
|
2972
|
+
const moduleData = {
|
|
2973
|
+
embeddings,
|
|
2974
|
+
embeddingModel: currentConfig.model
|
|
2975
|
+
};
|
|
2976
|
+
const chunkTypes = [
|
|
2977
|
+
...new Set(parsedChunks.map((pc) => pc.type))
|
|
2978
|
+
];
|
|
2979
|
+
const exports = parsedChunks.filter((pc) => pc.isExported && pc.name).map((pc) => pc.name);
|
|
2980
|
+
const allKeywords = new Set;
|
|
2981
|
+
for (const pc of parsedChunks) {
|
|
2982
|
+
const keywords = extractKeywords(pc.content, pc.name);
|
|
2983
|
+
keywords.forEach((k) => allKeywords.add(k));
|
|
2984
|
+
}
|
|
2985
|
+
pathContext.keywords.forEach((k) => allKeywords.add(k));
|
|
2986
|
+
const fileSummary = {
|
|
2987
|
+
filepath,
|
|
2988
|
+
chunkCount: chunks.length,
|
|
2989
|
+
chunkTypes,
|
|
2990
|
+
keywords: Array.from(allKeywords),
|
|
2991
|
+
exports,
|
|
2992
|
+
lastModified: stats.lastModified,
|
|
2993
|
+
pathContext: {
|
|
2994
|
+
segments: pathContext.segments,
|
|
2995
|
+
layer: pathContext.layer,
|
|
2996
|
+
domain: pathContext.domain,
|
|
2997
|
+
depth: pathContext.depth
|
|
2998
|
+
}
|
|
2999
|
+
};
|
|
3000
|
+
this.pendingSummaries.set(filepath, fileSummary);
|
|
3001
|
+
return {
|
|
3002
|
+
filepath,
|
|
3003
|
+
lastModified: stats.lastModified,
|
|
3004
|
+
chunks,
|
|
3005
|
+
moduleData,
|
|
3006
|
+
references
|
|
3007
|
+
};
|
|
3008
|
+
}
|
|
3009
|
+
async finalize(ctx) {
|
|
3010
|
+
const indexDir = getRaggrepDir(ctx.rootDir, ctx.config);
|
|
3011
|
+
this.symbolicIndex = new SymbolicIndex(indexDir, this.id);
|
|
3012
|
+
await this.symbolicIndex.initialize();
|
|
3013
|
+
for (const [filepath, summary] of this.pendingSummaries) {
|
|
3014
|
+
this.symbolicIndex.addFile(summary);
|
|
3015
|
+
}
|
|
3016
|
+
this.symbolicIndex.buildBM25Index();
|
|
3017
|
+
await this.symbolicIndex.save();
|
|
3018
|
+
this.pendingSummaries.clear();
|
|
3019
|
+
}
|
|
3020
|
+
async search(query, ctx, options = {}) {
|
|
3021
|
+
const {
|
|
3022
|
+
topK = DEFAULT_TOP_K2,
|
|
3023
|
+
minScore = DEFAULT_MIN_SCORE2,
|
|
3024
|
+
filePatterns
|
|
3025
|
+
} = options;
|
|
3026
|
+
const indexDir = getRaggrepDir(ctx.rootDir, ctx.config);
|
|
3027
|
+
const symbolicIndex = new SymbolicIndex(indexDir, this.id);
|
|
3028
|
+
let allFiles;
|
|
3029
|
+
try {
|
|
3030
|
+
await symbolicIndex.initialize();
|
|
3031
|
+
allFiles = symbolicIndex.getAllFiles();
|
|
3032
|
+
} catch {
|
|
3033
|
+
allFiles = await ctx.listIndexedFiles();
|
|
3034
|
+
}
|
|
3035
|
+
let filesToSearch = allFiles;
|
|
3036
|
+
if (filePatterns && filePatterns.length > 0) {
|
|
3037
|
+
filesToSearch = allFiles.filter((filepath) => {
|
|
3038
|
+
return filePatterns.some((pattern) => {
|
|
3039
|
+
if (pattern.startsWith("*.")) {
|
|
3040
|
+
const ext = pattern.slice(1);
|
|
3041
|
+
return filepath.endsWith(ext);
|
|
3042
|
+
}
|
|
3043
|
+
return filepath.includes(pattern);
|
|
3044
|
+
});
|
|
3045
|
+
});
|
|
3046
|
+
}
|
|
3047
|
+
const queryEmbedding = await getEmbedding(query);
|
|
3048
|
+
const bm25Index = new BM25Index;
|
|
3049
|
+
const allChunksData = [];
|
|
3050
|
+
for (const filepath of filesToSearch) {
|
|
3051
|
+
const fileIndex = await ctx.loadFileIndex(filepath);
|
|
3052
|
+
if (!fileIndex)
|
|
3053
|
+
continue;
|
|
3054
|
+
const moduleData = fileIndex.moduleData;
|
|
3055
|
+
if (!moduleData?.embeddings)
|
|
3056
|
+
continue;
|
|
3057
|
+
for (let i = 0;i < fileIndex.chunks.length; i++) {
|
|
3058
|
+
const chunk = fileIndex.chunks[i];
|
|
3059
|
+
const embedding = moduleData.embeddings[i];
|
|
3060
|
+
if (!embedding)
|
|
3061
|
+
continue;
|
|
3062
|
+
allChunksData.push({
|
|
3063
|
+
filepath: fileIndex.filepath,
|
|
3064
|
+
chunk,
|
|
3065
|
+
embedding
|
|
3066
|
+
});
|
|
3067
|
+
bm25Index.addDocuments([{ id: chunk.id, content: chunk.content }]);
|
|
3068
|
+
}
|
|
3069
|
+
}
|
|
3070
|
+
const bm25Results = bm25Index.search(query, topK * 3);
|
|
3071
|
+
const bm25Scores = new Map;
|
|
3072
|
+
for (const result of bm25Results) {
|
|
3073
|
+
bm25Scores.set(result.id, normalizeScore(result.score, 3));
|
|
3074
|
+
}
|
|
3075
|
+
const queryTerms = extractQueryTerms(query);
|
|
3076
|
+
const pathBoosts = new Map;
|
|
3077
|
+
for (const filepath of filesToSearch) {
|
|
3078
|
+
const summary = symbolicIndex.getFileSummary(filepath);
|
|
3079
|
+
if (summary?.pathContext) {
|
|
3080
|
+
let boost = 0;
|
|
3081
|
+
const ctx2 = summary.pathContext;
|
|
3082
|
+
if (ctx2.domain && queryTerms.some((t) => ctx2.domain.includes(t) || t.includes(ctx2.domain))) {
|
|
3083
|
+
boost += 0.1;
|
|
3084
|
+
}
|
|
3085
|
+
if (ctx2.layer && queryTerms.some((t) => ctx2.layer.includes(t) || t.includes(ctx2.layer))) {
|
|
3086
|
+
boost += 0.05;
|
|
3087
|
+
}
|
|
3088
|
+
const segmentMatch = ctx2.segments.some((seg) => queryTerms.some((t) => seg.toLowerCase().includes(t) || t.includes(seg.toLowerCase())));
|
|
3089
|
+
if (segmentMatch) {
|
|
3090
|
+
boost += 0.05;
|
|
3091
|
+
}
|
|
3092
|
+
pathBoosts.set(filepath, boost);
|
|
3093
|
+
}
|
|
3094
|
+
}
|
|
3095
|
+
const results = [];
|
|
3096
|
+
for (const { filepath, chunk, embedding } of allChunksData) {
|
|
3097
|
+
const semanticScore = cosineSimilarity(queryEmbedding, embedding);
|
|
3098
|
+
const bm25Score = bm25Scores.get(chunk.id) || 0;
|
|
3099
|
+
const pathBoost = pathBoosts.get(filepath) || 0;
|
|
3100
|
+
const fileTypeBoost = calculateFileTypeBoost(filepath, queryTerms);
|
|
3101
|
+
const chunkTypeBoost = calculateChunkTypeBoost(chunk);
|
|
3102
|
+
const exportBoost = calculateExportBoost(chunk);
|
|
3103
|
+
const totalBoost = pathBoost + fileTypeBoost + chunkTypeBoost + exportBoost;
|
|
3104
|
+
const hybridScore = SEMANTIC_WEIGHT * semanticScore + BM25_WEIGHT * bm25Score + totalBoost;
|
|
3105
|
+
if (hybridScore >= minScore || bm25Score > 0.3) {
|
|
3106
|
+
results.push({
|
|
3107
|
+
filepath,
|
|
3108
|
+
chunk,
|
|
3109
|
+
score: hybridScore,
|
|
3110
|
+
moduleId: this.id,
|
|
3111
|
+
context: {
|
|
3112
|
+
semanticScore,
|
|
3113
|
+
bm25Score,
|
|
3114
|
+
pathBoost,
|
|
3115
|
+
fileTypeBoost,
|
|
3116
|
+
chunkTypeBoost,
|
|
3117
|
+
exportBoost
|
|
3118
|
+
}
|
|
3119
|
+
});
|
|
3120
|
+
}
|
|
3121
|
+
}
|
|
3122
|
+
results.sort((a, b) => b.score - a.score);
|
|
3123
|
+
return results.slice(0, topK);
|
|
2635
3124
|
}
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
...extractPathKeywords(filepath)
|
|
2649
|
-
].join(" ");
|
|
2650
|
-
this.bm25Index.addDocuments([{ id: filepath, content }]);
|
|
3125
|
+
extractReferences(content, filepath) {
|
|
3126
|
+
const references = [];
|
|
3127
|
+
const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
|
|
3128
|
+
const requireRegex = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
3129
|
+
let match;
|
|
3130
|
+
while ((match = importRegex.exec(content)) !== null) {
|
|
3131
|
+
const importPath = match[1];
|
|
3132
|
+
if (importPath.startsWith(".")) {
|
|
3133
|
+
const dir = path9.dirname(filepath);
|
|
3134
|
+
const resolved = path9.normalize(path9.join(dir, importPath));
|
|
3135
|
+
references.push(resolved);
|
|
3136
|
+
}
|
|
2651
3137
|
}
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
3138
|
+
while ((match = requireRegex.exec(content)) !== null) {
|
|
3139
|
+
const importPath = match[1];
|
|
3140
|
+
if (importPath.startsWith(".")) {
|
|
3141
|
+
const dir = path9.dirname(filepath);
|
|
3142
|
+
const resolved = path9.normalize(path9.join(dir, importPath));
|
|
3143
|
+
references.push(resolved);
|
|
3144
|
+
}
|
|
2655
3145
|
}
|
|
3146
|
+
return references;
|
|
2656
3147
|
}
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
3148
|
+
}
|
|
3149
|
+
var DEFAULT_MIN_SCORE2 = 0.15, DEFAULT_TOP_K2 = 10, SEMANTIC_WEIGHT = 0.7, BM25_WEIGHT = 0.3, TYPESCRIPT_EXTENSIONS;
|
|
3150
|
+
var init_typescript = __esm(() => {
|
|
3151
|
+
init_embeddings();
|
|
3152
|
+
init_services();
|
|
3153
|
+
init_config2();
|
|
3154
|
+
init_parseCode();
|
|
3155
|
+
init_storage();
|
|
3156
|
+
TYPESCRIPT_EXTENSIONS = [
|
|
3157
|
+
".ts",
|
|
3158
|
+
".tsx",
|
|
3159
|
+
".js",
|
|
3160
|
+
".jsx",
|
|
3161
|
+
".mjs",
|
|
3162
|
+
".cjs",
|
|
3163
|
+
".mts",
|
|
3164
|
+
".cts"
|
|
3165
|
+
];
|
|
3166
|
+
});
|
|
3167
|
+
|
|
3168
|
+
// src/modules/data/json/index.ts
|
|
3169
|
+
var exports_json = {};
|
|
3170
|
+
__export(exports_json, {
|
|
3171
|
+
isJsonFile: () => isJsonFile,
|
|
3172
|
+
JsonModule: () => JsonModule,
|
|
3173
|
+
JSON_EXTENSIONS: () => JSON_EXTENSIONS,
|
|
3174
|
+
DEFAULT_TOP_K: () => DEFAULT_TOP_K3,
|
|
3175
|
+
DEFAULT_MIN_SCORE: () => DEFAULT_MIN_SCORE3
|
|
3176
|
+
});
|
|
3177
|
+
import * as path10 from "path";
|
|
3178
|
+
function isJsonFile(filepath) {
|
|
3179
|
+
const ext = path10.extname(filepath).toLowerCase();
|
|
3180
|
+
return JSON_EXTENSIONS.includes(ext);
|
|
3181
|
+
}
|
|
3182
|
+
function extractJsonKeys(obj, prefix = "") {
|
|
3183
|
+
const keys = [];
|
|
3184
|
+
if (obj === null || obj === undefined) {
|
|
3185
|
+
return keys;
|
|
3186
|
+
}
|
|
3187
|
+
if (Array.isArray(obj)) {
|
|
3188
|
+
obj.forEach((item, index) => {
|
|
3189
|
+
keys.push(...extractJsonKeys(item, `${prefix}[${index}]`));
|
|
3190
|
+
});
|
|
3191
|
+
} else if (typeof obj === "object") {
|
|
3192
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
3193
|
+
const fullKey = prefix ? `${prefix}.${key}` : key;
|
|
3194
|
+
keys.push(key);
|
|
3195
|
+
keys.push(...extractJsonKeys(value, fullKey));
|
|
2660
3196
|
}
|
|
2661
|
-
const results = this.bm25Index.search(query, maxCandidates);
|
|
2662
|
-
return results.map((r) => r.id);
|
|
2663
|
-
}
|
|
2664
|
-
getAllFiles() {
|
|
2665
|
-
return Array.from(this.fileSummaries.keys());
|
|
2666
3197
|
}
|
|
2667
|
-
|
|
2668
|
-
|
|
3198
|
+
return keys;
|
|
3199
|
+
}
|
|
3200
|
+
function extractJsonKeywords(content) {
|
|
3201
|
+
try {
|
|
3202
|
+
const parsed = JSON.parse(content);
|
|
3203
|
+
const keys = extractJsonKeys(parsed);
|
|
3204
|
+
const stringValues = [];
|
|
3205
|
+
const extractStrings = (obj) => {
|
|
3206
|
+
if (typeof obj === "string") {
|
|
3207
|
+
const words = obj.replace(/([a-z])([A-Z])/g, "$1 $2").toLowerCase().split(/\s+/).filter((w) => w.length > 2);
|
|
3208
|
+
stringValues.push(...words);
|
|
3209
|
+
} else if (Array.isArray(obj)) {
|
|
3210
|
+
obj.forEach(extractStrings);
|
|
3211
|
+
} else if (obj && typeof obj === "object") {
|
|
3212
|
+
Object.values(obj).forEach(extractStrings);
|
|
3213
|
+
}
|
|
3214
|
+
};
|
|
3215
|
+
extractStrings(parsed);
|
|
3216
|
+
return [...new Set([...keys, ...stringValues])];
|
|
3217
|
+
} catch {
|
|
3218
|
+
return [];
|
|
2669
3219
|
}
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
3220
|
+
}
|
|
3221
|
+
|
|
3222
|
+
class JsonModule {
|
|
3223
|
+
id = "data/json";
|
|
3224
|
+
name = "JSON Search";
|
|
3225
|
+
description = "JSON file search with structure-aware indexing";
|
|
3226
|
+
version = "1.0.0";
|
|
3227
|
+
embeddingConfig = null;
|
|
3228
|
+
symbolicIndex = null;
|
|
3229
|
+
pendingSummaries = new Map;
|
|
3230
|
+
rootDir = "";
|
|
3231
|
+
logger = undefined;
|
|
3232
|
+
async initialize(config) {
|
|
3233
|
+
this.embeddingConfig = getEmbeddingConfigFromModule(config);
|
|
3234
|
+
this.logger = config.options?.logger;
|
|
3235
|
+
if (this.logger) {
|
|
3236
|
+
this.embeddingConfig = {
|
|
3237
|
+
...this.embeddingConfig,
|
|
3238
|
+
logger: this.logger
|
|
3239
|
+
};
|
|
2682
3240
|
}
|
|
3241
|
+
configureEmbeddings(this.embeddingConfig);
|
|
3242
|
+
this.pendingSummaries.clear();
|
|
2683
3243
|
}
|
|
2684
|
-
async
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
this.
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
3244
|
+
async indexFile(filepath, content, ctx) {
|
|
3245
|
+
if (!isJsonFile(filepath)) {
|
|
3246
|
+
return null;
|
|
3247
|
+
}
|
|
3248
|
+
this.rootDir = ctx.rootDir;
|
|
3249
|
+
const textChunks = createLineBasedChunks(content, {
|
|
3250
|
+
chunkSize: 50,
|
|
3251
|
+
overlap: 10
|
|
3252
|
+
});
|
|
3253
|
+
if (textChunks.length === 0) {
|
|
3254
|
+
return null;
|
|
3255
|
+
}
|
|
3256
|
+
const chunkContents = textChunks.map((c) => {
|
|
3257
|
+
const filename = path10.basename(filepath);
|
|
3258
|
+
return `${filename}: ${c.content}`;
|
|
3259
|
+
});
|
|
3260
|
+
const embeddings = await getEmbeddings(chunkContents);
|
|
3261
|
+
const chunks = textChunks.map((tc, i) => ({
|
|
3262
|
+
id: generateChunkId(filepath, tc.startLine, tc.endLine),
|
|
3263
|
+
content: tc.content,
|
|
3264
|
+
startLine: tc.startLine,
|
|
3265
|
+
endLine: tc.endLine,
|
|
3266
|
+
type: tc.type
|
|
3267
|
+
}));
|
|
3268
|
+
const jsonKeys = extractJsonKeys((() => {
|
|
3269
|
+
try {
|
|
3270
|
+
return JSON.parse(content);
|
|
3271
|
+
} catch {
|
|
3272
|
+
return {};
|
|
2708
3273
|
}
|
|
2709
|
-
}
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
const
|
|
2713
|
-
|
|
3274
|
+
})());
|
|
3275
|
+
const stats = await ctx.getFileStats(filepath);
|
|
3276
|
+
const currentConfig = getEmbeddingConfig();
|
|
3277
|
+
const moduleData = {
|
|
3278
|
+
embeddings,
|
|
3279
|
+
embeddingModel: currentConfig.model,
|
|
3280
|
+
jsonKeys
|
|
3281
|
+
};
|
|
3282
|
+
const keywords = extractJsonKeywords(content);
|
|
3283
|
+
const fileSummary = {
|
|
3284
|
+
filepath,
|
|
3285
|
+
chunkCount: chunks.length,
|
|
3286
|
+
chunkTypes: ["file"],
|
|
3287
|
+
keywords,
|
|
3288
|
+
exports: [],
|
|
3289
|
+
lastModified: stats.lastModified
|
|
3290
|
+
};
|
|
3291
|
+
this.pendingSummaries.set(filepath, fileSummary);
|
|
3292
|
+
return {
|
|
3293
|
+
filepath,
|
|
3294
|
+
lastModified: stats.lastModified,
|
|
3295
|
+
chunks,
|
|
3296
|
+
moduleData
|
|
3297
|
+
};
|
|
2714
3298
|
}
|
|
2715
|
-
async
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
this.
|
|
3299
|
+
async finalize(ctx) {
|
|
3300
|
+
const indexDir = getRaggrepDir(ctx.rootDir, ctx.config);
|
|
3301
|
+
this.symbolicIndex = new SymbolicIndex(indexDir, this.id);
|
|
3302
|
+
await this.symbolicIndex.initialize();
|
|
3303
|
+
for (const [filepath, summary] of this.pendingSummaries) {
|
|
3304
|
+
this.symbolicIndex.addFile(summary);
|
|
3305
|
+
}
|
|
3306
|
+
this.symbolicIndex.buildBM25Index();
|
|
3307
|
+
await this.symbolicIndex.save();
|
|
3308
|
+
this.pendingSummaries.clear();
|
|
2720
3309
|
}
|
|
2721
|
-
async
|
|
3310
|
+
async search(query, ctx, options = {}) {
|
|
3311
|
+
const {
|
|
3312
|
+
topK = DEFAULT_TOP_K3,
|
|
3313
|
+
minScore = DEFAULT_MIN_SCORE3,
|
|
3314
|
+
filePatterns
|
|
3315
|
+
} = options;
|
|
3316
|
+
const indexDir = getRaggrepDir(ctx.rootDir, ctx.config);
|
|
3317
|
+
const symbolicIndex = new SymbolicIndex(indexDir, this.id);
|
|
3318
|
+
let allFiles;
|
|
2722
3319
|
try {
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
return true;
|
|
3320
|
+
await symbolicIndex.initialize();
|
|
3321
|
+
allFiles = symbolicIndex.getAllFiles();
|
|
2726
3322
|
} catch {
|
|
2727
|
-
|
|
3323
|
+
allFiles = await ctx.listIndexedFiles();
|
|
2728
3324
|
}
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
3325
|
+
let filesToSearch = allFiles.filter((f) => isJsonFile(f));
|
|
3326
|
+
if (filePatterns && filePatterns.length > 0) {
|
|
3327
|
+
filesToSearch = filesToSearch.filter((filepath) => {
|
|
3328
|
+
return filePatterns.some((pattern) => {
|
|
3329
|
+
if (pattern.startsWith("*.")) {
|
|
3330
|
+
const ext = pattern.slice(1);
|
|
3331
|
+
return filepath.endsWith(ext);
|
|
3332
|
+
}
|
|
3333
|
+
return filepath.includes(pattern);
|
|
3334
|
+
});
|
|
3335
|
+
});
|
|
3336
|
+
}
|
|
3337
|
+
const queryEmbedding = await getEmbedding(query);
|
|
3338
|
+
const bm25Index = new BM25Index;
|
|
3339
|
+
const allChunksData = [];
|
|
3340
|
+
for (const filepath of filesToSearch) {
|
|
3341
|
+
const fileIndex = await ctx.loadFileIndex(filepath);
|
|
3342
|
+
if (!fileIndex)
|
|
3343
|
+
continue;
|
|
3344
|
+
const moduleData = fileIndex.moduleData;
|
|
3345
|
+
if (!moduleData?.embeddings)
|
|
3346
|
+
continue;
|
|
3347
|
+
for (let i = 0;i < fileIndex.chunks.length; i++) {
|
|
3348
|
+
const chunk = fileIndex.chunks[i];
|
|
3349
|
+
const embedding = moduleData.embeddings[i];
|
|
3350
|
+
if (!embedding)
|
|
3351
|
+
continue;
|
|
3352
|
+
allChunksData.push({
|
|
3353
|
+
filepath: fileIndex.filepath,
|
|
3354
|
+
chunk,
|
|
3355
|
+
embedding
|
|
3356
|
+
});
|
|
3357
|
+
bm25Index.addDocuments([{ id: chunk.id, content: chunk.content }]);
|
|
3358
|
+
}
|
|
3359
|
+
}
|
|
3360
|
+
const bm25Results = bm25Index.search(query, topK * 3);
|
|
3361
|
+
const bm25Scores = new Map;
|
|
3362
|
+
for (const result of bm25Results) {
|
|
3363
|
+
bm25Scores.set(result.id, normalizeScore(result.score, 3));
|
|
3364
|
+
}
|
|
3365
|
+
const queryTerms = extractQueryTerms(query);
|
|
3366
|
+
const results = [];
|
|
3367
|
+
for (const { filepath, chunk, embedding } of allChunksData) {
|
|
3368
|
+
const semanticScore = cosineSimilarity(queryEmbedding, embedding);
|
|
3369
|
+
const bm25Score = bm25Scores.get(chunk.id) || 0;
|
|
3370
|
+
const hybridScore = SEMANTIC_WEIGHT2 * semanticScore + BM25_WEIGHT2 * bm25Score;
|
|
3371
|
+
if (hybridScore >= minScore || bm25Score > 0.3) {
|
|
3372
|
+
results.push({
|
|
3373
|
+
filepath,
|
|
3374
|
+
chunk,
|
|
3375
|
+
score: hybridScore,
|
|
3376
|
+
moduleId: this.id,
|
|
3377
|
+
context: {
|
|
3378
|
+
semanticScore,
|
|
3379
|
+
bm25Score
|
|
3380
|
+
}
|
|
3381
|
+
});
|
|
3382
|
+
}
|
|
2742
3383
|
}
|
|
2743
|
-
|
|
3384
|
+
results.sort((a, b) => b.score - a.score);
|
|
3385
|
+
return results.slice(0, topK);
|
|
2744
3386
|
}
|
|
2745
3387
|
}
|
|
2746
|
-
var
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
init_symbolicIndex();
|
|
3388
|
+
var DEFAULT_MIN_SCORE3 = 0.15, DEFAULT_TOP_K3 = 10, SEMANTIC_WEIGHT2 = 0.7, BM25_WEIGHT2 = 0.3, JSON_EXTENSIONS;
|
|
3389
|
+
var init_json = __esm(() => {
|
|
3390
|
+
init_embeddings();
|
|
3391
|
+
init_services();
|
|
3392
|
+
init_config2();
|
|
3393
|
+
init_storage();
|
|
3394
|
+
JSON_EXTENSIONS = [".json"];
|
|
2754
3395
|
});
|
|
2755
3396
|
|
|
2756
|
-
// src/modules/
|
|
2757
|
-
var
|
|
2758
|
-
__export(
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
3397
|
+
// src/modules/docs/markdown/index.ts
|
|
3398
|
+
var exports_markdown = {};
|
|
3399
|
+
__export(exports_markdown, {
|
|
3400
|
+
isMarkdownFile: () => isMarkdownFile,
|
|
3401
|
+
MarkdownModule: () => MarkdownModule,
|
|
3402
|
+
MARKDOWN_EXTENSIONS: () => MARKDOWN_EXTENSIONS,
|
|
3403
|
+
DEFAULT_TOP_K: () => DEFAULT_TOP_K4,
|
|
3404
|
+
DEFAULT_MIN_SCORE: () => DEFAULT_MIN_SCORE4
|
|
2762
3405
|
});
|
|
2763
|
-
import * as
|
|
2764
|
-
function
|
|
2765
|
-
const
|
|
2766
|
-
|
|
2767
|
-
if (hasDocumentationTerm) {
|
|
2768
|
-
return "documentation";
|
|
2769
|
-
}
|
|
2770
|
-
if (hasImplementationTerm) {
|
|
2771
|
-
return "implementation";
|
|
2772
|
-
}
|
|
2773
|
-
return "neutral";
|
|
3406
|
+
import * as path11 from "path";
|
|
3407
|
+
function isMarkdownFile(filepath) {
|
|
3408
|
+
const ext = path11.extname(filepath).toLowerCase();
|
|
3409
|
+
return MARKDOWN_EXTENSIONS.includes(ext);
|
|
2774
3410
|
}
|
|
2775
|
-
function
|
|
2776
|
-
const
|
|
2777
|
-
|
|
2778
|
-
const
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
3411
|
+
function parseMarkdownSections(content) {
|
|
3412
|
+
const lines = content.split(`
|
|
3413
|
+
`);
|
|
3414
|
+
const sections = [];
|
|
3415
|
+
let currentSection = null;
|
|
3416
|
+
let currentContent = [];
|
|
3417
|
+
let startLine = 1;
|
|
3418
|
+
for (let i = 0;i < lines.length; i++) {
|
|
3419
|
+
const line = lines[i];
|
|
3420
|
+
const headingMatch = line.match(/^(#{1,6})\s+(.+)$/);
|
|
3421
|
+
if (headingMatch) {
|
|
3422
|
+
if (currentSection) {
|
|
3423
|
+
currentSection.content = currentContent.join(`
|
|
3424
|
+
`).trim();
|
|
3425
|
+
currentSection.endLine = i;
|
|
3426
|
+
if (currentSection.content || currentSection.heading) {
|
|
3427
|
+
sections.push(currentSection);
|
|
3428
|
+
}
|
|
3429
|
+
} else if (currentContent.length > 0) {
|
|
3430
|
+
sections.push({
|
|
3431
|
+
heading: "",
|
|
3432
|
+
level: 0,
|
|
3433
|
+
content: currentContent.join(`
|
|
3434
|
+
`).trim(),
|
|
3435
|
+
startLine: 1,
|
|
3436
|
+
endLine: i
|
|
3437
|
+
});
|
|
3438
|
+
}
|
|
3439
|
+
currentSection = {
|
|
3440
|
+
heading: headingMatch[2],
|
|
3441
|
+
level: headingMatch[1].length,
|
|
3442
|
+
content: "",
|
|
3443
|
+
startLine: i + 1,
|
|
3444
|
+
endLine: lines.length
|
|
3445
|
+
};
|
|
3446
|
+
currentContent = [];
|
|
3447
|
+
} else {
|
|
3448
|
+
currentContent.push(line);
|
|
2783
3449
|
}
|
|
2784
|
-
return 0;
|
|
2785
3450
|
}
|
|
2786
|
-
if (
|
|
2787
|
-
|
|
2788
|
-
|
|
3451
|
+
if (currentSection) {
|
|
3452
|
+
currentSection.content = currentContent.join(`
|
|
3453
|
+
`).trim();
|
|
3454
|
+
currentSection.endLine = lines.length;
|
|
3455
|
+
if (currentSection.content || currentSection.heading) {
|
|
3456
|
+
sections.push(currentSection);
|
|
2789
3457
|
}
|
|
2790
|
-
|
|
3458
|
+
} else if (currentContent.length > 0) {
|
|
3459
|
+
sections.push({
|
|
3460
|
+
heading: "",
|
|
3461
|
+
level: 0,
|
|
3462
|
+
content: currentContent.join(`
|
|
3463
|
+
`).trim(),
|
|
3464
|
+
startLine: 1,
|
|
3465
|
+
endLine: lines.length
|
|
3466
|
+
});
|
|
2791
3467
|
}
|
|
2792
|
-
return
|
|
3468
|
+
return sections;
|
|
2793
3469
|
}
|
|
2794
|
-
function
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
3470
|
+
function extractMarkdownKeywords(content) {
|
|
3471
|
+
const keywords = [];
|
|
3472
|
+
const headingMatches = content.matchAll(/^#{1,6}\s+(.+)$/gm);
|
|
3473
|
+
for (const match of headingMatches) {
|
|
3474
|
+
const heading = match[1].toLowerCase();
|
|
3475
|
+
const words = heading.split(/\s+/).filter((w) => w.length > 2);
|
|
3476
|
+
keywords.push(...words);
|
|
3477
|
+
}
|
|
3478
|
+
const emphasisMatches = content.matchAll(/\*\*(.+?)\*\*|\*(.+?)\*/g);
|
|
3479
|
+
for (const match of emphasisMatches) {
|
|
3480
|
+
const text = (match[1] || match[2] || "").toLowerCase();
|
|
3481
|
+
const words = text.split(/\s+/).filter((w) => w.length > 2);
|
|
3482
|
+
keywords.push(...words);
|
|
3483
|
+
}
|
|
3484
|
+
const codeMatches = content.matchAll(/`([^`]+)`/g);
|
|
3485
|
+
for (const match of codeMatches) {
|
|
3486
|
+
const code = match[1].toLowerCase();
|
|
3487
|
+
if (code.length > 2 && code.length < 50) {
|
|
3488
|
+
keywords.push(code);
|
|
3489
|
+
}
|
|
2810
3490
|
}
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
3491
|
+
const linkMatches = content.matchAll(/\[([^\]]+)\]/g);
|
|
3492
|
+
for (const match of linkMatches) {
|
|
3493
|
+
const text = match[1].toLowerCase();
|
|
3494
|
+
const words = text.split(/\s+/).filter((w) => w.length > 2);
|
|
3495
|
+
keywords.push(...words);
|
|
3496
|
+
}
|
|
3497
|
+
return [...new Set(keywords)];
|
|
2814
3498
|
}
|
|
2815
3499
|
|
|
2816
|
-
class
|
|
2817
|
-
id = "
|
|
2818
|
-
name = "
|
|
2819
|
-
description = "
|
|
3500
|
+
class MarkdownModule {
|
|
3501
|
+
id = "docs/markdown";
|
|
3502
|
+
name = "Markdown Search";
|
|
3503
|
+
description = "Markdown documentation search with section-aware indexing";
|
|
2820
3504
|
version = "1.0.0";
|
|
2821
3505
|
embeddingConfig = null;
|
|
2822
3506
|
symbolicIndex = null;
|
|
@@ -2836,66 +3520,53 @@ class TypeScriptModule {
|
|
|
2836
3520
|
this.pendingSummaries.clear();
|
|
2837
3521
|
}
|
|
2838
3522
|
async indexFile(filepath, content, ctx) {
|
|
3523
|
+
if (!isMarkdownFile(filepath)) {
|
|
3524
|
+
return null;
|
|
3525
|
+
}
|
|
2839
3526
|
this.rootDir = ctx.rootDir;
|
|
2840
|
-
const
|
|
2841
|
-
if (
|
|
3527
|
+
const sections = parseMarkdownSections(content);
|
|
3528
|
+
if (sections.length === 0) {
|
|
2842
3529
|
return null;
|
|
2843
3530
|
}
|
|
2844
|
-
const
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
return `${pathPrefix} ${namePrefix}${c.content}`;
|
|
3531
|
+
const chunkContents = sections.map((s) => {
|
|
3532
|
+
const filename = path11.basename(filepath);
|
|
3533
|
+
const headingContext = s.heading ? `${s.heading}: ` : "";
|
|
3534
|
+
return `${filename} ${headingContext}${s.content}`;
|
|
2849
3535
|
});
|
|
2850
3536
|
const embeddings = await getEmbeddings(chunkContents);
|
|
2851
|
-
const chunks =
|
|
2852
|
-
id: generateChunkId(filepath,
|
|
2853
|
-
content:
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
3537
|
+
const chunks = sections.map((section, i) => ({
|
|
3538
|
+
id: generateChunkId(filepath, section.startLine, section.endLine),
|
|
3539
|
+
content: section.heading ? `## ${section.heading}
|
|
3540
|
+
|
|
3541
|
+
${section.content}` : section.content,
|
|
3542
|
+
startLine: section.startLine,
|
|
3543
|
+
endLine: section.endLine,
|
|
3544
|
+
type: "block",
|
|
3545
|
+
name: section.heading || undefined
|
|
2860
3546
|
}));
|
|
2861
|
-
const
|
|
3547
|
+
const headings = sections.filter((s) => s.heading).map((s) => s.heading);
|
|
2862
3548
|
const stats = await ctx.getFileStats(filepath);
|
|
2863
3549
|
const currentConfig = getEmbeddingConfig();
|
|
2864
3550
|
const moduleData = {
|
|
2865
3551
|
embeddings,
|
|
2866
|
-
embeddingModel: currentConfig.model
|
|
3552
|
+
embeddingModel: currentConfig.model,
|
|
3553
|
+
headings
|
|
2867
3554
|
};
|
|
2868
|
-
const
|
|
2869
|
-
...new Set(parsedChunks.map((pc) => pc.type))
|
|
2870
|
-
];
|
|
2871
|
-
const exports = parsedChunks.filter((pc) => pc.isExported && pc.name).map((pc) => pc.name);
|
|
2872
|
-
const allKeywords = new Set;
|
|
2873
|
-
for (const pc of parsedChunks) {
|
|
2874
|
-
const keywords = extractKeywords(pc.content, pc.name);
|
|
2875
|
-
keywords.forEach((k) => allKeywords.add(k));
|
|
2876
|
-
}
|
|
2877
|
-
pathContext.keywords.forEach((k) => allKeywords.add(k));
|
|
3555
|
+
const keywords = extractMarkdownKeywords(content);
|
|
2878
3556
|
const fileSummary = {
|
|
2879
3557
|
filepath,
|
|
2880
3558
|
chunkCount: chunks.length,
|
|
2881
|
-
chunkTypes,
|
|
2882
|
-
keywords
|
|
2883
|
-
exports,
|
|
2884
|
-
lastModified: stats.lastModified
|
|
2885
|
-
pathContext: {
|
|
2886
|
-
segments: pathContext.segments,
|
|
2887
|
-
layer: pathContext.layer,
|
|
2888
|
-
domain: pathContext.domain,
|
|
2889
|
-
depth: pathContext.depth
|
|
2890
|
-
}
|
|
3559
|
+
chunkTypes: ["block"],
|
|
3560
|
+
keywords,
|
|
3561
|
+
exports: headings,
|
|
3562
|
+
lastModified: stats.lastModified
|
|
2891
3563
|
};
|
|
2892
3564
|
this.pendingSummaries.set(filepath, fileSummary);
|
|
2893
3565
|
return {
|
|
2894
3566
|
filepath,
|
|
2895
3567
|
lastModified: stats.lastModified,
|
|
2896
3568
|
chunks,
|
|
2897
|
-
moduleData
|
|
2898
|
-
references
|
|
3569
|
+
moduleData
|
|
2899
3570
|
};
|
|
2900
3571
|
}
|
|
2901
3572
|
async finalize(ctx) {
|
|
@@ -2911,8 +3582,8 @@ class TypeScriptModule {
|
|
|
2911
3582
|
}
|
|
2912
3583
|
async search(query, ctx, options = {}) {
|
|
2913
3584
|
const {
|
|
2914
|
-
topK =
|
|
2915
|
-
minScore =
|
|
3585
|
+
topK = DEFAULT_TOP_K4,
|
|
3586
|
+
minScore = DEFAULT_MIN_SCORE4,
|
|
2916
3587
|
filePatterns
|
|
2917
3588
|
} = options;
|
|
2918
3589
|
const indexDir = getRaggrepDir(ctx.rootDir, ctx.config);
|
|
@@ -2924,9 +3595,9 @@ class TypeScriptModule {
|
|
|
2924
3595
|
} catch {
|
|
2925
3596
|
allFiles = await ctx.listIndexedFiles();
|
|
2926
3597
|
}
|
|
2927
|
-
let filesToSearch = allFiles;
|
|
3598
|
+
let filesToSearch = allFiles.filter((f) => isMarkdownFile(f));
|
|
2928
3599
|
if (filePatterns && filePatterns.length > 0) {
|
|
2929
|
-
filesToSearch =
|
|
3600
|
+
filesToSearch = filesToSearch.filter((filepath) => {
|
|
2930
3601
|
return filePatterns.some((pattern) => {
|
|
2931
3602
|
if (pattern.startsWith("*.")) {
|
|
2932
3603
|
const ext = pattern.slice(1);
|
|
@@ -2964,36 +3635,24 @@ class TypeScriptModule {
|
|
|
2964
3635
|
for (const result of bm25Results) {
|
|
2965
3636
|
bm25Scores.set(result.id, normalizeScore(result.score, 3));
|
|
2966
3637
|
}
|
|
2967
|
-
const queryTerms = query
|
|
2968
|
-
const pathBoosts = new Map;
|
|
2969
|
-
for (const filepath of filesToSearch) {
|
|
2970
|
-
const summary = symbolicIndex.getFileSummary(filepath);
|
|
2971
|
-
if (summary?.pathContext) {
|
|
2972
|
-
let boost = 0;
|
|
2973
|
-
const ctx2 = summary.pathContext;
|
|
2974
|
-
if (ctx2.domain && queryTerms.some((t) => ctx2.domain.includes(t) || t.includes(ctx2.domain))) {
|
|
2975
|
-
boost += 0.1;
|
|
2976
|
-
}
|
|
2977
|
-
if (ctx2.layer && queryTerms.some((t) => ctx2.layer.includes(t) || t.includes(ctx2.layer))) {
|
|
2978
|
-
boost += 0.05;
|
|
2979
|
-
}
|
|
2980
|
-
const segmentMatch = ctx2.segments.some((seg) => queryTerms.some((t) => seg.toLowerCase().includes(t) || t.includes(seg.toLowerCase())));
|
|
2981
|
-
if (segmentMatch) {
|
|
2982
|
-
boost += 0.05;
|
|
2983
|
-
}
|
|
2984
|
-
pathBoosts.set(filepath, boost);
|
|
2985
|
-
}
|
|
2986
|
-
}
|
|
3638
|
+
const queryTerms = extractQueryTerms(query);
|
|
2987
3639
|
const results = [];
|
|
2988
3640
|
for (const { filepath, chunk, embedding } of allChunksData) {
|
|
2989
3641
|
const semanticScore = cosineSimilarity(queryEmbedding, embedding);
|
|
2990
3642
|
const bm25Score = bm25Scores.get(chunk.id) || 0;
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
3643
|
+
let docBoost = 0;
|
|
3644
|
+
if (queryTerms.some((t) => [
|
|
3645
|
+
"docs",
|
|
3646
|
+
"documentation",
|
|
3647
|
+
"readme",
|
|
3648
|
+
"guide",
|
|
3649
|
+
"how",
|
|
3650
|
+
"what",
|
|
3651
|
+
"explain"
|
|
3652
|
+
].includes(t))) {
|
|
3653
|
+
docBoost = 0.05;
|
|
3654
|
+
}
|
|
3655
|
+
const hybridScore = SEMANTIC_WEIGHT3 * semanticScore + BM25_WEIGHT3 * bm25Score + docBoost;
|
|
2997
3656
|
if (hybridScore >= minScore || bm25Score > 0.3) {
|
|
2998
3657
|
results.push({
|
|
2999
3658
|
filepath,
|
|
@@ -3003,10 +3662,7 @@ class TypeScriptModule {
|
|
|
3003
3662
|
context: {
|
|
3004
3663
|
semanticScore,
|
|
3005
3664
|
bm25Score,
|
|
3006
|
-
|
|
3007
|
-
fileTypeBoost,
|
|
3008
|
-
chunkTypeBoost,
|
|
3009
|
-
exportBoost
|
|
3665
|
+
docBoost
|
|
3010
3666
|
}
|
|
3011
3667
|
});
|
|
3012
3668
|
}
|
|
@@ -3014,91 +3670,21 @@ class TypeScriptModule {
|
|
|
3014
3670
|
results.sort((a, b) => b.score - a.score);
|
|
3015
3671
|
return results.slice(0, topK);
|
|
3016
3672
|
}
|
|
3017
|
-
extractReferences(content, filepath) {
|
|
3018
|
-
const references = [];
|
|
3019
|
-
const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
|
|
3020
|
-
const requireRegex = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
3021
|
-
let match;
|
|
3022
|
-
while ((match = importRegex.exec(content)) !== null) {
|
|
3023
|
-
const importPath = match[1];
|
|
3024
|
-
if (importPath.startsWith(".")) {
|
|
3025
|
-
const dir = path8.dirname(filepath);
|
|
3026
|
-
const resolved = path8.normalize(path8.join(dir, importPath));
|
|
3027
|
-
references.push(resolved);
|
|
3028
|
-
}
|
|
3029
|
-
}
|
|
3030
|
-
while ((match = requireRegex.exec(content)) !== null) {
|
|
3031
|
-
const importPath = match[1];
|
|
3032
|
-
if (importPath.startsWith(".")) {
|
|
3033
|
-
const dir = path8.dirname(filepath);
|
|
3034
|
-
const resolved = path8.normalize(path8.join(dir, importPath));
|
|
3035
|
-
references.push(resolved);
|
|
3036
|
-
}
|
|
3037
|
-
}
|
|
3038
|
-
return references;
|
|
3039
|
-
}
|
|
3040
3673
|
}
|
|
3041
|
-
var
|
|
3042
|
-
var
|
|
3674
|
+
var DEFAULT_MIN_SCORE4 = 0.15, DEFAULT_TOP_K4 = 10, SEMANTIC_WEIGHT3 = 0.7, BM25_WEIGHT3 = 0.3, MARKDOWN_EXTENSIONS;
|
|
3675
|
+
var init_markdown = __esm(() => {
|
|
3043
3676
|
init_embeddings();
|
|
3677
|
+
init_services();
|
|
3044
3678
|
init_config2();
|
|
3045
|
-
init_parseCode();
|
|
3046
3679
|
init_storage();
|
|
3047
|
-
|
|
3048
|
-
init_keywords();
|
|
3049
|
-
IMPLEMENTATION_TERMS = [
|
|
3050
|
-
"function",
|
|
3051
|
-
"method",
|
|
3052
|
-
"class",
|
|
3053
|
-
"interface",
|
|
3054
|
-
"implement",
|
|
3055
|
-
"implementation",
|
|
3056
|
-
"endpoint",
|
|
3057
|
-
"route",
|
|
3058
|
-
"handler",
|
|
3059
|
-
"controller",
|
|
3060
|
-
"module",
|
|
3061
|
-
"code"
|
|
3062
|
-
];
|
|
3063
|
-
DOCUMENTATION_TERMS = [
|
|
3064
|
-
"documentation",
|
|
3065
|
-
"docs",
|
|
3066
|
-
"guide",
|
|
3067
|
-
"tutorial",
|
|
3068
|
-
"readme",
|
|
3069
|
-
"how",
|
|
3070
|
-
"what",
|
|
3071
|
-
"why",
|
|
3072
|
-
"explain",
|
|
3073
|
-
"overview",
|
|
3074
|
-
"getting",
|
|
3075
|
-
"started",
|
|
3076
|
-
"requirements",
|
|
3077
|
-
"setup",
|
|
3078
|
-
"install",
|
|
3079
|
-
"configure",
|
|
3080
|
-
"configuration"
|
|
3081
|
-
];
|
|
3082
|
-
SOURCE_CODE_EXTENSIONS = [
|
|
3083
|
-
".ts",
|
|
3084
|
-
".tsx",
|
|
3085
|
-
".js",
|
|
3086
|
-
".jsx",
|
|
3087
|
-
".mjs",
|
|
3088
|
-
".cjs",
|
|
3089
|
-
".py",
|
|
3090
|
-
".go",
|
|
3091
|
-
".rs",
|
|
3092
|
-
".java"
|
|
3093
|
-
];
|
|
3094
|
-
DOC_EXTENSIONS = [".md", ".txt", ".rst"];
|
|
3680
|
+
MARKDOWN_EXTENSIONS = [".md", ".txt"];
|
|
3095
3681
|
});
|
|
3096
3682
|
|
|
3097
3683
|
// src/app/indexer/index.ts
|
|
3098
3684
|
init_config2();
|
|
3099
3685
|
import { glob } from "glob";
|
|
3100
3686
|
import * as fs6 from "fs/promises";
|
|
3101
|
-
import * as
|
|
3687
|
+
import * as path14 from "path";
|
|
3102
3688
|
|
|
3103
3689
|
// src/modules/registry.ts
|
|
3104
3690
|
class ModuleRegistryImpl {
|
|
@@ -3123,16 +3709,20 @@ var registry = new ModuleRegistryImpl;
|
|
|
3123
3709
|
async function registerBuiltInModules() {
|
|
3124
3710
|
const { CoreModule: CoreModule2 } = await Promise.resolve().then(() => (init_core(), exports_core));
|
|
3125
3711
|
const { TypeScriptModule: TypeScriptModule2 } = await Promise.resolve().then(() => (init_typescript(), exports_typescript));
|
|
3712
|
+
const { JsonModule: JsonModule2 } = await Promise.resolve().then(() => (init_json(), exports_json));
|
|
3713
|
+
const { MarkdownModule: MarkdownModule2 } = await Promise.resolve().then(() => (init_markdown(), exports_markdown));
|
|
3126
3714
|
registry.register(new CoreModule2);
|
|
3127
3715
|
registry.register(new TypeScriptModule2);
|
|
3716
|
+
registry.register(new JsonModule2);
|
|
3717
|
+
registry.register(new MarkdownModule2);
|
|
3128
3718
|
}
|
|
3129
3719
|
|
|
3130
3720
|
// src/infrastructure/introspection/IntrospectionIndex.ts
|
|
3131
|
-
import * as
|
|
3721
|
+
import * as path13 from "path";
|
|
3132
3722
|
import * as fs5 from "fs/promises";
|
|
3133
3723
|
|
|
3134
3724
|
// src/infrastructure/introspection/projectDetector.ts
|
|
3135
|
-
import * as
|
|
3725
|
+
import * as path12 from "path";
|
|
3136
3726
|
import * as fs4 from "fs/promises";
|
|
3137
3727
|
var MAX_SCAN_DEPTH = 4;
|
|
3138
3728
|
var SKIP_DIRS = new Set([
|
|
@@ -3149,7 +3739,7 @@ async function scanForPackageJsons(rootDir, currentDir = "", depth = 0) {
|
|
|
3149
3739
|
if (depth > MAX_SCAN_DEPTH)
|
|
3150
3740
|
return [];
|
|
3151
3741
|
const results = [];
|
|
3152
|
-
const fullDir = currentDir ?
|
|
3742
|
+
const fullDir = currentDir ? path12.join(rootDir, currentDir) : rootDir;
|
|
3153
3743
|
try {
|
|
3154
3744
|
const entries = await fs4.readdir(fullDir, { withFileTypes: true });
|
|
3155
3745
|
const hasPackageJson = entries.some((e) => e.isFile() && e.name === "package.json");
|
|
@@ -3172,10 +3762,10 @@ async function scanForPackageJsons(rootDir, currentDir = "", depth = 0) {
|
|
|
3172
3762
|
}
|
|
3173
3763
|
async function parsePackageJson(rootDir, relativePath) {
|
|
3174
3764
|
try {
|
|
3175
|
-
const packageJsonPath =
|
|
3765
|
+
const packageJsonPath = path12.join(rootDir, relativePath, "package.json");
|
|
3176
3766
|
const content = await fs4.readFile(packageJsonPath, "utf-8");
|
|
3177
3767
|
const pkg = JSON.parse(content);
|
|
3178
|
-
const name = pkg.name ||
|
|
3768
|
+
const name = pkg.name || path12.basename(relativePath);
|
|
3179
3769
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
3180
3770
|
let type = "unknown";
|
|
3181
3771
|
if (deps["next"] || deps["react"] || deps["vue"] || deps["svelte"]) {
|
|
@@ -3220,7 +3810,7 @@ async function detectProjectStructure(rootDir) {
|
|
|
3220
3810
|
for (const pattern of monorepoPatterns) {
|
|
3221
3811
|
if (!dirNames.includes(pattern))
|
|
3222
3812
|
continue;
|
|
3223
|
-
const patternDir =
|
|
3813
|
+
const patternDir = path12.join(rootDir, pattern);
|
|
3224
3814
|
try {
|
|
3225
3815
|
const subDirs = await fs4.readdir(patternDir, { withFileTypes: true });
|
|
3226
3816
|
for (const subDir of subDirs) {
|
|
@@ -3251,7 +3841,7 @@ async function detectProjectStructure(rootDir) {
|
|
|
3251
3841
|
}
|
|
3252
3842
|
let rootType = "unknown";
|
|
3253
3843
|
try {
|
|
3254
|
-
const rootPkgPath =
|
|
3844
|
+
const rootPkgPath = path12.join(rootDir, "package.json");
|
|
3255
3845
|
const rootPkg = JSON.parse(await fs4.readFile(rootPkgPath, "utf-8"));
|
|
3256
3846
|
if (rootPkg.workspaces)
|
|
3257
3847
|
isMonorepo = true;
|
|
@@ -3292,7 +3882,7 @@ class IntrospectionIndex {
|
|
|
3292
3882
|
async initialize() {
|
|
3293
3883
|
this.structure = await detectProjectStructure(this.rootDir);
|
|
3294
3884
|
try {
|
|
3295
|
-
const configPath =
|
|
3885
|
+
const configPath = path13.join(this.rootDir, ".raggrep", "config.json");
|
|
3296
3886
|
const configContent = await fs5.readFile(configPath, "utf-8");
|
|
3297
3887
|
const config = JSON.parse(configContent);
|
|
3298
3888
|
this.config = config.introspection || {};
|
|
@@ -3332,28 +3922,28 @@ class IntrospectionIndex {
|
|
|
3332
3922
|
}
|
|
3333
3923
|
}
|
|
3334
3924
|
async save(config) {
|
|
3335
|
-
const introDir =
|
|
3925
|
+
const introDir = path13.join(getRaggrepDir(this.rootDir, config), "introspection");
|
|
3336
3926
|
await fs5.mkdir(introDir, { recursive: true });
|
|
3337
|
-
const projectPath =
|
|
3927
|
+
const projectPath = path13.join(introDir, "_project.json");
|
|
3338
3928
|
await fs5.writeFile(projectPath, JSON.stringify({
|
|
3339
3929
|
version: "1.0.0",
|
|
3340
3930
|
lastUpdated: new Date().toISOString(),
|
|
3341
3931
|
structure: this.structure
|
|
3342
3932
|
}, null, 2));
|
|
3343
3933
|
for (const [filepath, intro] of this.files) {
|
|
3344
|
-
const introFilePath =
|
|
3345
|
-
await fs5.mkdir(
|
|
3934
|
+
const introFilePath = path13.join(introDir, "files", filepath.replace(/\.[^.]+$/, ".json"));
|
|
3935
|
+
await fs5.mkdir(path13.dirname(introFilePath), { recursive: true });
|
|
3346
3936
|
await fs5.writeFile(introFilePath, JSON.stringify(intro, null, 2));
|
|
3347
3937
|
}
|
|
3348
3938
|
}
|
|
3349
3939
|
async load(config) {
|
|
3350
|
-
const introDir =
|
|
3940
|
+
const introDir = path13.join(getRaggrepDir(this.rootDir, config), "introspection");
|
|
3351
3941
|
try {
|
|
3352
|
-
const projectPath =
|
|
3942
|
+
const projectPath = path13.join(introDir, "_project.json");
|
|
3353
3943
|
const projectContent = await fs5.readFile(projectPath, "utf-8");
|
|
3354
3944
|
const projectData = JSON.parse(projectContent);
|
|
3355
3945
|
this.structure = projectData.structure;
|
|
3356
|
-
await this.loadFilesRecursive(
|
|
3946
|
+
await this.loadFilesRecursive(path13.join(introDir, "files"), "");
|
|
3357
3947
|
} catch {
|
|
3358
3948
|
this.structure = null;
|
|
3359
3949
|
this.files.clear();
|
|
@@ -3363,7 +3953,7 @@ class IntrospectionIndex {
|
|
|
3363
3953
|
try {
|
|
3364
3954
|
const entries = await fs5.readdir(basePath, { withFileTypes: true });
|
|
3365
3955
|
for (const entry of entries) {
|
|
3366
|
-
const entryPath =
|
|
3956
|
+
const entryPath = path13.join(basePath, entry.name);
|
|
3367
3957
|
const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
3368
3958
|
if (entry.isDirectory()) {
|
|
3369
3959
|
await this.loadFilesRecursive(entryPath, relativePath);
|
|
@@ -3471,15 +4061,37 @@ import { watch } from "chokidar";
|
|
|
3471
4061
|
init_config2();
|
|
3472
4062
|
|
|
3473
4063
|
// src/app/indexer/index.ts
|
|
4064
|
+
async function parallelMap(items, processor, concurrency) {
|
|
4065
|
+
const results = new Array(items.length);
|
|
4066
|
+
let nextIndex = 0;
|
|
4067
|
+
async function worker() {
|
|
4068
|
+
while (nextIndex < items.length) {
|
|
4069
|
+
const index = nextIndex++;
|
|
4070
|
+
const item = items[index];
|
|
4071
|
+
try {
|
|
4072
|
+
const value = await processor(item, index);
|
|
4073
|
+
results[index] = { success: true, value };
|
|
4074
|
+
} catch (error) {
|
|
4075
|
+
results[index] = { success: false, error };
|
|
4076
|
+
}
|
|
4077
|
+
}
|
|
4078
|
+
}
|
|
4079
|
+
const workers = Array(Math.min(concurrency, items.length)).fill(null).map(() => worker());
|
|
4080
|
+
await Promise.all(workers);
|
|
4081
|
+
return results;
|
|
4082
|
+
}
|
|
3474
4083
|
var INDEX_SCHEMA_VERSION = "1.0.0";
|
|
4084
|
+
var DEFAULT_CONCURRENCY = 4;
|
|
3475
4085
|
async function indexDirectory(rootDir, options = {}) {
|
|
3476
4086
|
const verbose = options.verbose ?? false;
|
|
3477
4087
|
const quiet = options.quiet ?? false;
|
|
4088
|
+
const concurrency = options.concurrency ?? DEFAULT_CONCURRENCY;
|
|
3478
4089
|
const logger = options.logger ? options.logger : quiet ? createSilentLogger() : createLogger({ verbose });
|
|
3479
|
-
rootDir =
|
|
4090
|
+
rootDir = path14.resolve(rootDir);
|
|
3480
4091
|
const location = getIndexLocation(rootDir);
|
|
3481
4092
|
logger.info(`Indexing directory: ${rootDir}`);
|
|
3482
4093
|
logger.info(`Index location: ${location.indexDir}`);
|
|
4094
|
+
logger.debug(`Concurrency: ${concurrency}`);
|
|
3483
4095
|
const config = await loadConfig(rootDir);
|
|
3484
4096
|
const introspection = new IntrospectionIndex(rootDir);
|
|
3485
4097
|
await introspection.initialize();
|
|
@@ -3515,7 +4127,7 @@ async function indexDirectory(rootDir, options = {}) {
|
|
|
3515
4127
|
};
|
|
3516
4128
|
await module.initialize(configWithOverrides);
|
|
3517
4129
|
}
|
|
3518
|
-
const result = await indexWithModule(rootDir, files, module, config, verbose, introspection, logger);
|
|
4130
|
+
const result = await indexWithModule(rootDir, files, module, config, verbose, introspection, logger, concurrency);
|
|
3519
4131
|
results.push(result);
|
|
3520
4132
|
if (module.finalize) {
|
|
3521
4133
|
logger.info(`[${module.name}] Building secondary indexes...`);
|
|
@@ -3523,11 +4135,11 @@ async function indexDirectory(rootDir, options = {}) {
|
|
|
3523
4135
|
rootDir,
|
|
3524
4136
|
config,
|
|
3525
4137
|
readFile: async (filepath) => {
|
|
3526
|
-
const fullPath =
|
|
4138
|
+
const fullPath = path14.isAbsolute(filepath) ? filepath : path14.join(rootDir, filepath);
|
|
3527
4139
|
return fs6.readFile(fullPath, "utf-8");
|
|
3528
4140
|
},
|
|
3529
4141
|
getFileStats: async (filepath) => {
|
|
3530
|
-
const fullPath =
|
|
4142
|
+
const fullPath = path14.isAbsolute(filepath) ? filepath : path14.join(rootDir, filepath);
|
|
3531
4143
|
const stats = await fs6.stat(fullPath);
|
|
3532
4144
|
return { lastModified: stats.mtime.toISOString() };
|
|
3533
4145
|
}
|
|
@@ -3558,7 +4170,7 @@ async function deleteIndex(rootDir) {
|
|
|
3558
4170
|
} catch {}
|
|
3559
4171
|
}
|
|
3560
4172
|
async function resetIndex(rootDir) {
|
|
3561
|
-
rootDir =
|
|
4173
|
+
rootDir = path14.resolve(rootDir);
|
|
3562
4174
|
const status = await getIndexStatus(rootDir);
|
|
3563
4175
|
if (!status.exists) {
|
|
3564
4176
|
throw new Error(`No index found for ${rootDir}`);
|
|
@@ -3573,7 +4185,7 @@ async function ensureIndexFresh(rootDir, options = {}) {
|
|
|
3573
4185
|
const verbose = options.verbose ?? false;
|
|
3574
4186
|
const quiet = options.quiet ?? false;
|
|
3575
4187
|
const logger = options.logger ? options.logger : quiet ? createSilentLogger() : createLogger({ verbose });
|
|
3576
|
-
rootDir =
|
|
4188
|
+
rootDir = path14.resolve(rootDir);
|
|
3577
4189
|
const status = await getIndexStatus(rootDir);
|
|
3578
4190
|
if (!status.exists) {
|
|
3579
4191
|
logger.info(`No index found. Creating index...
|
|
@@ -3600,7 +4212,7 @@ async function ensureIndexFresh(rootDir, options = {}) {
|
|
|
3600
4212
|
const introspection = new IntrospectionIndex(rootDir);
|
|
3601
4213
|
await introspection.initialize();
|
|
3602
4214
|
const currentFiles = await findFiles(rootDir, config);
|
|
3603
|
-
const currentFileSet = new Set(currentFiles.map((f) =>
|
|
4215
|
+
const currentFileSet = new Set(currentFiles.map((f) => path14.relative(rootDir, f)));
|
|
3604
4216
|
let totalIndexed = 0;
|
|
3605
4217
|
let totalRemoved = 0;
|
|
3606
4218
|
let totalUnchanged = 0;
|
|
@@ -3630,11 +4242,11 @@ async function ensureIndexFresh(rootDir, options = {}) {
|
|
|
3630
4242
|
}
|
|
3631
4243
|
for (const filepath of filesToRemove) {
|
|
3632
4244
|
logger.debug(` Removing stale: ${filepath}`);
|
|
3633
|
-
const indexFilePath =
|
|
4245
|
+
const indexFilePath = path14.join(indexPath, filepath.replace(/\.[^.]+$/, ".json"));
|
|
3634
4246
|
try {
|
|
3635
4247
|
await fs6.unlink(indexFilePath);
|
|
3636
4248
|
} catch {}
|
|
3637
|
-
const symbolicFilePath =
|
|
4249
|
+
const symbolicFilePath = path14.join(indexPath, "symbolic", filepath.replace(/\.[^.]+$/, ".json"));
|
|
3638
4250
|
try {
|
|
3639
4251
|
await fs6.unlink(symbolicFilePath);
|
|
3640
4252
|
} catch {}
|
|
@@ -3645,11 +4257,11 @@ async function ensureIndexFresh(rootDir, options = {}) {
|
|
|
3645
4257
|
rootDir,
|
|
3646
4258
|
config,
|
|
3647
4259
|
readFile: async (filepath) => {
|
|
3648
|
-
const fullPath =
|
|
4260
|
+
const fullPath = path14.isAbsolute(filepath) ? filepath : path14.join(rootDir, filepath);
|
|
3649
4261
|
return fs6.readFile(fullPath, "utf-8");
|
|
3650
4262
|
},
|
|
3651
4263
|
getFileStats: async (filepath) => {
|
|
3652
|
-
const fullPath =
|
|
4264
|
+
const fullPath = path14.isAbsolute(filepath) ? filepath : path14.join(rootDir, filepath);
|
|
3653
4265
|
const stats = await fs6.stat(fullPath);
|
|
3654
4266
|
return { lastModified: stats.mtime.toISOString() };
|
|
3655
4267
|
},
|
|
@@ -3658,7 +4270,7 @@ async function ensureIndexFresh(rootDir, options = {}) {
|
|
|
3658
4270
|
const totalFiles = currentFiles.length;
|
|
3659
4271
|
for (let i = 0;i < currentFiles.length; i++) {
|
|
3660
4272
|
const filepath = currentFiles[i];
|
|
3661
|
-
const relativePath =
|
|
4273
|
+
const relativePath = path14.relative(rootDir, filepath);
|
|
3662
4274
|
const progress = `[${i + 1}/${totalFiles}]`;
|
|
3663
4275
|
try {
|
|
3664
4276
|
const stats = await fs6.stat(filepath);
|
|
@@ -3709,7 +4321,7 @@ async function ensureIndexFresh(rootDir, options = {}) {
|
|
|
3709
4321
|
unchanged: totalUnchanged
|
|
3710
4322
|
};
|
|
3711
4323
|
}
|
|
3712
|
-
async function indexWithModule(rootDir, files, module, config, verbose, introspection, logger) {
|
|
4324
|
+
async function indexWithModule(rootDir, files, module, config, verbose, introspection, logger, concurrency = DEFAULT_CONCURRENCY) {
|
|
3713
4325
|
const result = {
|
|
3714
4326
|
moduleId: module.id,
|
|
3715
4327
|
indexed: 0,
|
|
@@ -3718,7 +4330,7 @@ async function indexWithModule(rootDir, files, module, config, verbose, introspe
|
|
|
3718
4330
|
};
|
|
3719
4331
|
const manifest = await loadModuleManifest(rootDir, module.id, config);
|
|
3720
4332
|
const indexPath = getModuleIndexPath(rootDir, module.id, config);
|
|
3721
|
-
const currentFileSet = new Set(files.map((f) =>
|
|
4333
|
+
const currentFileSet = new Set(files.map((f) => path14.relative(rootDir, f)));
|
|
3722
4334
|
const filesToRemove = [];
|
|
3723
4335
|
for (const filepath of Object.keys(manifest.files)) {
|
|
3724
4336
|
if (!currentFileSet.has(filepath)) {
|
|
@@ -3729,11 +4341,11 @@ async function indexWithModule(rootDir, files, module, config, verbose, introspe
|
|
|
3729
4341
|
logger.info(` Removing ${filesToRemove.length} stale entries...`);
|
|
3730
4342
|
for (const filepath of filesToRemove) {
|
|
3731
4343
|
logger.debug(` Removing: ${filepath}`);
|
|
3732
|
-
const indexFilePath =
|
|
4344
|
+
const indexFilePath = path14.join(indexPath, filepath.replace(/\.[^.]+$/, ".json"));
|
|
3733
4345
|
try {
|
|
3734
4346
|
await fs6.unlink(indexFilePath);
|
|
3735
4347
|
} catch {}
|
|
3736
|
-
const symbolicFilePath =
|
|
4348
|
+
const symbolicFilePath = path14.join(indexPath, "symbolic", filepath.replace(/\.[^.]+$/, ".json"));
|
|
3737
4349
|
try {
|
|
3738
4350
|
await fs6.unlink(symbolicFilePath);
|
|
3739
4351
|
} catch {}
|
|
@@ -3745,52 +4357,76 @@ async function indexWithModule(rootDir, files, module, config, verbose, introspe
|
|
|
3745
4357
|
rootDir,
|
|
3746
4358
|
config,
|
|
3747
4359
|
readFile: async (filepath) => {
|
|
3748
|
-
const fullPath =
|
|
4360
|
+
const fullPath = path14.isAbsolute(filepath) ? filepath : path14.join(rootDir, filepath);
|
|
3749
4361
|
return fs6.readFile(fullPath, "utf-8");
|
|
3750
4362
|
},
|
|
3751
4363
|
getFileStats: async (filepath) => {
|
|
3752
|
-
const fullPath =
|
|
4364
|
+
const fullPath = path14.isAbsolute(filepath) ? filepath : path14.join(rootDir, filepath);
|
|
3753
4365
|
const stats = await fs6.stat(fullPath);
|
|
3754
4366
|
return { lastModified: stats.mtime.toISOString() };
|
|
3755
4367
|
},
|
|
3756
4368
|
getIntrospection: (filepath) => introspection.getFile(filepath)
|
|
3757
4369
|
};
|
|
3758
4370
|
const totalFiles = files.length;
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
const relativePath =
|
|
3762
|
-
const progress = `[${i + 1}/${totalFiles}]`;
|
|
4371
|
+
let completedCount = 0;
|
|
4372
|
+
const processFile = async (filepath, _index) => {
|
|
4373
|
+
const relativePath = path14.relative(rootDir, filepath);
|
|
3763
4374
|
try {
|
|
3764
4375
|
const stats = await fs6.stat(filepath);
|
|
3765
4376
|
const lastModified = stats.mtime.toISOString();
|
|
3766
4377
|
const existingEntry = manifest.files[relativePath];
|
|
3767
4378
|
if (existingEntry && existingEntry.lastModified === lastModified) {
|
|
3768
|
-
|
|
3769
|
-
|
|
3770
|
-
|
|
4379
|
+
completedCount++;
|
|
4380
|
+
logger.debug(` [${completedCount}/${totalFiles}] Skipped ${relativePath} (unchanged)`);
|
|
4381
|
+
return { relativePath, status: "skipped" };
|
|
3771
4382
|
}
|
|
3772
4383
|
const content = await fs6.readFile(filepath, "utf-8");
|
|
3773
4384
|
introspection.addFile(relativePath, content);
|
|
3774
|
-
|
|
4385
|
+
completedCount++;
|
|
4386
|
+
logger.progress(` [${completedCount}/${totalFiles}] Processing: ${relativePath}`);
|
|
3775
4387
|
const fileIndex = await module.indexFile(relativePath, content, ctx);
|
|
3776
4388
|
if (!fileIndex) {
|
|
3777
|
-
logger.debug(` ${
|
|
3778
|
-
|
|
3779
|
-
continue;
|
|
4389
|
+
logger.debug(` [${completedCount}/${totalFiles}] Skipped ${relativePath} (no chunks)`);
|
|
4390
|
+
return { relativePath, status: "skipped" };
|
|
3780
4391
|
}
|
|
3781
4392
|
await writeFileIndex(rootDir, module.id, relativePath, fileIndex, config);
|
|
3782
|
-
|
|
4393
|
+
return {
|
|
4394
|
+
relativePath,
|
|
4395
|
+
status: "indexed",
|
|
3783
4396
|
lastModified,
|
|
3784
4397
|
chunkCount: fileIndex.chunks.length
|
|
3785
4398
|
};
|
|
3786
|
-
result.indexed++;
|
|
3787
4399
|
} catch (error) {
|
|
3788
|
-
|
|
3789
|
-
|
|
4400
|
+
completedCount++;
|
|
4401
|
+
return { relativePath, status: "error", error };
|
|
4402
|
+
}
|
|
4403
|
+
};
|
|
4404
|
+
logger.debug(` Using concurrency: ${concurrency}`);
|
|
4405
|
+
const results = await parallelMap(files, processFile, concurrency);
|
|
4406
|
+
logger.clearProgress();
|
|
4407
|
+
for (const item of results) {
|
|
4408
|
+
if (!item.success) {
|
|
3790
4409
|
result.errors++;
|
|
4410
|
+
continue;
|
|
4411
|
+
}
|
|
4412
|
+
const fileResult = item.value;
|
|
4413
|
+
switch (fileResult.status) {
|
|
4414
|
+
case "indexed":
|
|
4415
|
+
manifest.files[fileResult.relativePath] = {
|
|
4416
|
+
lastModified: fileResult.lastModified,
|
|
4417
|
+
chunkCount: fileResult.chunkCount
|
|
4418
|
+
};
|
|
4419
|
+
result.indexed++;
|
|
4420
|
+
break;
|
|
4421
|
+
case "skipped":
|
|
4422
|
+
result.skipped++;
|
|
4423
|
+
break;
|
|
4424
|
+
case "error":
|
|
4425
|
+
logger.error(` Error indexing ${fileResult.relativePath}: ${fileResult.error}`);
|
|
4426
|
+
result.errors++;
|
|
4427
|
+
break;
|
|
3791
4428
|
}
|
|
3792
4429
|
}
|
|
3793
|
-
logger.clearProgress();
|
|
3794
4430
|
manifest.lastUpdated = new Date().toISOString();
|
|
3795
4431
|
await writeModuleManifest(rootDir, module.id, manifest, config);
|
|
3796
4432
|
return result;
|
|
@@ -3825,13 +4461,13 @@ async function loadModuleManifest(rootDir, moduleId, config) {
|
|
|
3825
4461
|
}
|
|
3826
4462
|
async function writeModuleManifest(rootDir, moduleId, manifest, config) {
|
|
3827
4463
|
const manifestPath = getModuleManifestPath(rootDir, moduleId, config);
|
|
3828
|
-
await fs6.mkdir(
|
|
4464
|
+
await fs6.mkdir(path14.dirname(manifestPath), { recursive: true });
|
|
3829
4465
|
await fs6.writeFile(manifestPath, JSON.stringify(manifest, null, 2));
|
|
3830
4466
|
}
|
|
3831
4467
|
async function writeFileIndex(rootDir, moduleId, filepath, fileIndex, config) {
|
|
3832
4468
|
const indexPath = getModuleIndexPath(rootDir, moduleId, config);
|
|
3833
|
-
const indexFilePath =
|
|
3834
|
-
await fs6.mkdir(
|
|
4469
|
+
const indexFilePath = path14.join(indexPath, filepath.replace(/\.[^.]+$/, ".json"));
|
|
4470
|
+
await fs6.mkdir(path14.dirname(indexFilePath), { recursive: true });
|
|
3835
4471
|
await fs6.writeFile(indexFilePath, JSON.stringify(fileIndex, null, 2));
|
|
3836
4472
|
}
|
|
3837
4473
|
async function updateGlobalManifest(rootDir, modules, config) {
|
|
@@ -3841,13 +4477,13 @@ async function updateGlobalManifest(rootDir, modules, config) {
|
|
|
3841
4477
|
lastUpdated: new Date().toISOString(),
|
|
3842
4478
|
modules: modules.map((m) => m.id)
|
|
3843
4479
|
};
|
|
3844
|
-
await fs6.mkdir(
|
|
4480
|
+
await fs6.mkdir(path14.dirname(manifestPath), { recursive: true });
|
|
3845
4481
|
await fs6.writeFile(manifestPath, JSON.stringify(manifest, null, 2));
|
|
3846
4482
|
}
|
|
3847
4483
|
async function cleanupIndex(rootDir, options = {}) {
|
|
3848
4484
|
const verbose = options.verbose ?? false;
|
|
3849
4485
|
const logger = options.logger ?? createLogger({ verbose });
|
|
3850
|
-
rootDir =
|
|
4486
|
+
rootDir = path14.resolve(rootDir);
|
|
3851
4487
|
logger.info(`Cleaning up index in: ${rootDir}`);
|
|
3852
4488
|
const config = await loadConfig(rootDir);
|
|
3853
4489
|
await registerBuiltInModules();
|
|
@@ -3877,7 +4513,7 @@ async function cleanupModuleIndex(rootDir, moduleId, config, logger) {
|
|
|
3877
4513
|
const filesToRemove = [];
|
|
3878
4514
|
const updatedFiles = {};
|
|
3879
4515
|
for (const [filepath, entry] of Object.entries(manifest.files)) {
|
|
3880
|
-
const fullPath =
|
|
4516
|
+
const fullPath = path14.join(rootDir, filepath);
|
|
3881
4517
|
try {
|
|
3882
4518
|
await fs6.access(fullPath);
|
|
3883
4519
|
updatedFiles[filepath] = entry;
|
|
@@ -3889,7 +4525,7 @@ async function cleanupModuleIndex(rootDir, moduleId, config, logger) {
|
|
|
3889
4525
|
}
|
|
3890
4526
|
}
|
|
3891
4527
|
for (const filepath of filesToRemove) {
|
|
3892
|
-
const indexFilePath =
|
|
4528
|
+
const indexFilePath = path14.join(indexPath, filepath.replace(/\.[^.]+$/, ".json"));
|
|
3893
4529
|
try {
|
|
3894
4530
|
await fs6.unlink(indexFilePath);
|
|
3895
4531
|
} catch {}
|
|
@@ -3905,7 +4541,7 @@ async function cleanupEmptyDirectories(dir) {
|
|
|
3905
4541
|
const entries = await fs6.readdir(dir, { withFileTypes: true });
|
|
3906
4542
|
for (const entry of entries) {
|
|
3907
4543
|
if (entry.isDirectory()) {
|
|
3908
|
-
const subDir =
|
|
4544
|
+
const subDir = path14.join(dir, entry.name);
|
|
3909
4545
|
await cleanupEmptyDirectories(subDir);
|
|
3910
4546
|
}
|
|
3911
4547
|
}
|
|
@@ -3920,7 +4556,7 @@ async function cleanupEmptyDirectories(dir) {
|
|
|
3920
4556
|
}
|
|
3921
4557
|
}
|
|
3922
4558
|
async function getIndexStatus(rootDir) {
|
|
3923
|
-
rootDir =
|
|
4559
|
+
rootDir = path14.resolve(rootDir);
|
|
3924
4560
|
const config = await loadConfig(rootDir);
|
|
3925
4561
|
const location = getIndexLocation(rootDir);
|
|
3926
4562
|
const indexDir = location.indexDir;
|
|
@@ -3956,7 +4592,7 @@ async function getIndexStatus(rootDir) {
|
|
|
3956
4592
|
}
|
|
3957
4593
|
} catch {
|
|
3958
4594
|
try {
|
|
3959
|
-
const entries = await fs6.readdir(
|
|
4595
|
+
const entries = await fs6.readdir(path14.join(indexDir, "index"));
|
|
3960
4596
|
if (entries.length > 0) {
|
|
3961
4597
|
status.exists = true;
|
|
3962
4598
|
for (const entry of entries) {
|
|
@@ -3979,7 +4615,7 @@ async function getIndexStatus(rootDir) {
|
|
|
3979
4615
|
|
|
3980
4616
|
// src/app/search/index.ts
|
|
3981
4617
|
import * as fs7 from "fs/promises";
|
|
3982
|
-
import * as
|
|
4618
|
+
import * as path15 from "path";
|
|
3983
4619
|
|
|
3984
4620
|
// src/types.ts
|
|
3985
4621
|
init_entities();
|
|
@@ -3987,7 +4623,7 @@ init_entities();
|
|
|
3987
4623
|
// src/app/search/index.ts
|
|
3988
4624
|
init_config2();
|
|
3989
4625
|
async function search(rootDir, query, options = {}) {
|
|
3990
|
-
rootDir =
|
|
4626
|
+
rootDir = path15.resolve(rootDir);
|
|
3991
4627
|
const ensureFresh = options.ensureFresh ?? DEFAULT_SEARCH_OPTIONS.ensureFresh;
|
|
3992
4628
|
if (ensureFresh) {
|
|
3993
4629
|
await ensureIndexFresh(rootDir, { quiet: true });
|
|
@@ -4032,7 +4668,7 @@ function createSearchContext(rootDir, moduleId, config) {
|
|
|
4032
4668
|
config,
|
|
4033
4669
|
loadFileIndex: async (filepath) => {
|
|
4034
4670
|
const hasExtension = /\.[^./]+$/.test(filepath);
|
|
4035
|
-
const indexFilePath = hasExtension ?
|
|
4671
|
+
const indexFilePath = hasExtension ? path15.join(indexPath, filepath.replace(/\.[^.]+$/, ".json")) : path15.join(indexPath, filepath + ".json");
|
|
4036
4672
|
try {
|
|
4037
4673
|
const content = await fs7.readFile(indexFilePath, "utf-8");
|
|
4038
4674
|
return JSON.parse(content);
|
|
@@ -4044,7 +4680,7 @@ function createSearchContext(rootDir, moduleId, config) {
|
|
|
4044
4680
|
const files = [];
|
|
4045
4681
|
await traverseDirectory(indexPath, files, indexPath);
|
|
4046
4682
|
return files.filter((f) => f.endsWith(".json") && !f.endsWith("manifest.json")).map((f) => {
|
|
4047
|
-
const relative3 =
|
|
4683
|
+
const relative3 = path15.relative(indexPath, f);
|
|
4048
4684
|
return relative3.replace(/\.json$/, "");
|
|
4049
4685
|
});
|
|
4050
4686
|
}
|
|
@@ -4054,7 +4690,7 @@ async function traverseDirectory(dir, files, basePath) {
|
|
|
4054
4690
|
try {
|
|
4055
4691
|
const entries = await fs7.readdir(dir, { withFileTypes: true });
|
|
4056
4692
|
for (const entry of entries) {
|
|
4057
|
-
const fullPath =
|
|
4693
|
+
const fullPath = path15.join(dir, entry.name);
|
|
4058
4694
|
if (entry.isDirectory()) {
|
|
4059
4695
|
await traverseDirectory(fullPath, files, basePath);
|
|
4060
4696
|
} else if (entry.isFile()) {
|
|
@@ -4156,4 +4792,4 @@ export {
|
|
|
4156
4792
|
ConsoleLogger
|
|
4157
4793
|
};
|
|
4158
4794
|
|
|
4159
|
-
//# debugId=
|
|
4795
|
+
//# debugId=984F0AA3FD08D5A664756E2164756E21
|