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/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/infrastructure/storage/symbolicIndex.ts
2605
- import * as fs3 from "fs/promises";
2606
- import * as path7 from "path";
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
- class SymbolicIndex {
2609
- meta = null;
2610
- fileSummaries = new Map;
2611
- bm25Index = null;
2612
- symbolicPath;
2613
- moduleId;
2614
- constructor(indexDir, moduleId) {
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
- async initialize() {
2619
- try {
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
- addFile(summary) {
2637
- this.fileSummaries.set(summary.filepath, summary);
2638
- }
2639
- removeFile(filepath) {
2640
- return this.fileSummaries.delete(filepath);
2641
- }
2642
- buildBM25Index() {
2643
- this.bm25Index = new BM25Index;
2644
- for (const [filepath, summary] of this.fileSummaries) {
2645
- const content = [
2646
- ...summary.keywords,
2647
- ...summary.exports,
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
- if (this.meta) {
2653
- this.meta.fileCount = this.fileSummaries.size;
2654
- this.meta.bm25Data.totalDocs = this.fileSummaries.size;
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
- findCandidates(query, maxCandidates = 20) {
2658
- if (!this.bm25Index) {
2659
- return Array.from(this.fileSummaries.keys());
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
- getFileSummary(filepath) {
2668
- return this.fileSummaries.get(filepath);
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
- async save() {
2671
- if (!this.meta)
2672
- throw new Error("Index not initialized");
2673
- this.meta.lastUpdated = new Date().toISOString();
2674
- this.meta.fileCount = this.fileSummaries.size;
2675
- await fs3.mkdir(this.symbolicPath, { recursive: true });
2676
- const metaPath = path7.join(this.symbolicPath, "_meta.json");
2677
- await fs3.writeFile(metaPath, JSON.stringify(this.meta, null, 2));
2678
- for (const [filepath, summary] of this.fileSummaries) {
2679
- const summaryPath = this.getFileSummaryPath(filepath);
2680
- await fs3.mkdir(path7.dirname(summaryPath), { recursive: true });
2681
- await fs3.writeFile(summaryPath, JSON.stringify(summary, null, 2));
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 load() {
2685
- const metaPath = path7.join(this.symbolicPath, "_meta.json");
2686
- const metaContent = await fs3.readFile(metaPath, "utf-8");
2687
- this.meta = JSON.parse(metaContent);
2688
- this.fileSummaries.clear();
2689
- await this.loadFileSummariesRecursive(this.symbolicPath);
2690
- this.buildBM25Index();
2691
- }
2692
- async loadFileSummariesRecursive(dir) {
2693
- try {
2694
- const entries = await fs3.readdir(dir, { withFileTypes: true });
2695
- for (const entry of entries) {
2696
- const fullPath = path7.join(dir, entry.name);
2697
- if (entry.isDirectory()) {
2698
- await this.loadFileSummariesRecursive(fullPath);
2699
- } else if (entry.name.endsWith(".json") && entry.name !== "_meta.json") {
2700
- try {
2701
- const content = await fs3.readFile(fullPath, "utf-8");
2702
- const summary = JSON.parse(content);
2703
- if (summary.filepath) {
2704
- this.fileSummaries.set(summary.filepath, summary);
2705
- }
2706
- } catch {}
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
- } catch {}
2710
- }
2711
- getFileSummaryPath(filepath) {
2712
- const jsonPath = filepath.replace(/\.[^.]+$/, ".json");
2713
- return path7.join(this.symbolicPath, jsonPath);
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 deleteFileSummary(filepath) {
2716
- try {
2717
- await fs3.unlink(this.getFileSummaryPath(filepath));
2718
- } catch {}
2719
- this.fileSummaries.delete(filepath);
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 exists() {
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
- const metaPath = path7.join(this.symbolicPath, "_meta.json");
2724
- await fs3.access(metaPath);
2725
- return true;
3320
+ await symbolicIndex.initialize();
3321
+ allFiles = symbolicIndex.getAllFiles();
2726
3322
  } catch {
2727
- return false;
3323
+ allFiles = await ctx.listIndexedFiles();
2728
3324
  }
2729
- }
2730
- get size() {
2731
- return this.fileSummaries.size;
2732
- }
2733
- clear() {
2734
- this.fileSummaries.clear();
2735
- if (this.meta) {
2736
- this.meta.fileCount = 0;
2737
- this.meta.bm25Data = {
2738
- avgDocLength: 0,
2739
- documentFrequencies: {},
2740
- totalDocs: 0
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
- this.bm25Index = new BM25Index;
3384
+ results.sort((a, b) => b.score - a.score);
3385
+ return results.slice(0, topK);
2744
3386
  }
2745
3387
  }
2746
- var init_symbolicIndex = __esm(() => {
2747
- init_keywords();
2748
- });
2749
-
2750
- // src/infrastructure/storage/index.ts
2751
- var init_storage = __esm(() => {
2752
- init_fileIndexStorage();
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/language/typescript/index.ts
2757
- var exports_typescript = {};
2758
- __export(exports_typescript, {
2759
- TypeScriptModule: () => TypeScriptModule,
2760
- DEFAULT_TOP_K: () => DEFAULT_TOP_K2,
2761
- DEFAULT_MIN_SCORE: () => DEFAULT_MIN_SCORE2
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 path8 from "path";
2764
- function detectQueryIntent(queryTerms) {
2765
- const hasImplementationTerm = queryTerms.some((term) => IMPLEMENTATION_TERMS.includes(term));
2766
- const hasDocumentationTerm = queryTerms.some((term) => DOCUMENTATION_TERMS.includes(term));
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 calculateFileTypeBoost(filepath, queryTerms) {
2776
- const ext = path8.extname(filepath).toLowerCase();
2777
- const isSourceCode = SOURCE_CODE_EXTENSIONS.includes(ext);
2778
- const isDoc = DOC_EXTENSIONS.includes(ext);
2779
- const intent = detectQueryIntent(queryTerms);
2780
- if (intent === "implementation") {
2781
- if (isSourceCode) {
2782
- return 0.06;
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 (intent === "documentation") {
2787
- if (isDoc) {
2788
- return 0.08;
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
- return 0;
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 0;
3468
+ return sections;
2793
3469
  }
2794
- function calculateChunkTypeBoost(chunk) {
2795
- switch (chunk.type) {
2796
- case "function":
2797
- return 0.05;
2798
- case "class":
2799
- case "interface":
2800
- return 0.04;
2801
- case "type":
2802
- case "enum":
2803
- return 0.03;
2804
- case "variable":
2805
- return 0.02;
2806
- case "file":
2807
- case "block":
2808
- default:
2809
- return 0;
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
- function calculateExportBoost(chunk) {
2813
- return chunk.isExported ? 0.03 : 0;
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 TypeScriptModule {
2817
- id = "language/typescript";
2818
- name = "TypeScript Search";
2819
- description = "TypeScript-aware code search with AST parsing and semantic embeddings";
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 parsedChunks = parseCode(content, filepath);
2841
- if (parsedChunks.length === 0) {
3527
+ const sections = parseMarkdownSections(content);
3528
+ if (sections.length === 0) {
2842
3529
  return null;
2843
3530
  }
2844
- const pathContext = parsePathContext(filepath);
2845
- const pathPrefix = formatPathContextForEmbedding(pathContext);
2846
- const chunkContents = parsedChunks.map((c) => {
2847
- const namePrefix = c.name ? `${c.name}: ` : "";
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 = parsedChunks.map((pc) => ({
2852
- id: generateChunkId(filepath, pc.startLine, pc.endLine),
2853
- content: pc.content,
2854
- startLine: pc.startLine,
2855
- endLine: pc.endLine,
2856
- type: pc.type,
2857
- name: pc.name,
2858
- isExported: pc.isExported,
2859
- jsDoc: pc.jsDoc
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 references = this.extractReferences(content, filepath);
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 chunkTypes = [
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: Array.from(allKeywords),
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 = DEFAULT_TOP_K2,
2915
- minScore = DEFAULT_MIN_SCORE2,
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 = allFiles.filter((filepath) => {
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.toLowerCase().split(/\s+/).filter((t) => t.length > 2);
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
- const pathBoost = pathBoosts.get(filepath) || 0;
2992
- const fileTypeBoost = calculateFileTypeBoost(filepath, queryTerms);
2993
- const chunkTypeBoost = calculateChunkTypeBoost(chunk);
2994
- const exportBoost = calculateExportBoost(chunk);
2995
- const totalBoost = pathBoost + fileTypeBoost + chunkTypeBoost + exportBoost;
2996
- const hybridScore = SEMANTIC_WEIGHT * semanticScore + BM25_WEIGHT * bm25Score + totalBoost;
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
- pathBoost,
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 DEFAULT_MIN_SCORE2 = 0.15, DEFAULT_TOP_K2 = 10, SEMANTIC_WEIGHT = 0.7, BM25_WEIGHT = 0.3, IMPLEMENTATION_TERMS, DOCUMENTATION_TERMS, SOURCE_CODE_EXTENSIONS, DOC_EXTENSIONS;
3042
- var init_typescript = __esm(() => {
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
- init_keywords();
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 path11 from "path";
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 path10 from "path";
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 path9 from "path";
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 ? path9.join(rootDir, currentDir) : rootDir;
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 = path9.join(rootDir, relativePath, "package.json");
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 || path9.basename(relativePath);
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 = path9.join(rootDir, pattern);
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 = path9.join(rootDir, "package.json");
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 = path10.join(this.rootDir, ".raggrep", "config.json");
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 = path10.join(getRaggrepDir(this.rootDir, config), "introspection");
3925
+ const introDir = path13.join(getRaggrepDir(this.rootDir, config), "introspection");
3336
3926
  await fs5.mkdir(introDir, { recursive: true });
3337
- const projectPath = path10.join(introDir, "_project.json");
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 = path10.join(introDir, "files", filepath.replace(/\.[^.]+$/, ".json"));
3345
- await fs5.mkdir(path10.dirname(introFilePath), { recursive: true });
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 = path10.join(getRaggrepDir(this.rootDir, config), "introspection");
3940
+ const introDir = path13.join(getRaggrepDir(this.rootDir, config), "introspection");
3351
3941
  try {
3352
- const projectPath = path10.join(introDir, "_project.json");
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(path10.join(introDir, "files"), "");
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 = path10.join(basePath, entry.name);
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 = path11.resolve(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 = path11.isAbsolute(filepath) ? filepath : path11.join(rootDir, filepath);
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 = path11.isAbsolute(filepath) ? filepath : path11.join(rootDir, filepath);
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 = path11.resolve(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 = path11.resolve(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) => path11.relative(rootDir, 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 = path11.join(indexPath, filepath.replace(/\.[^.]+$/, ".json"));
4245
+ const indexFilePath = path14.join(indexPath, filepath.replace(/\.[^.]+$/, ".json"));
3634
4246
  try {
3635
4247
  await fs6.unlink(indexFilePath);
3636
4248
  } catch {}
3637
- const symbolicFilePath = path11.join(indexPath, "symbolic", filepath.replace(/\.[^.]+$/, ".json"));
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 = path11.isAbsolute(filepath) ? filepath : path11.join(rootDir, filepath);
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 = path11.isAbsolute(filepath) ? filepath : path11.join(rootDir, filepath);
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 = path11.relative(rootDir, filepath);
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) => path11.relative(rootDir, 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 = path11.join(indexPath, filepath.replace(/\.[^.]+$/, ".json"));
4344
+ const indexFilePath = path14.join(indexPath, filepath.replace(/\.[^.]+$/, ".json"));
3733
4345
  try {
3734
4346
  await fs6.unlink(indexFilePath);
3735
4347
  } catch {}
3736
- const symbolicFilePath = path11.join(indexPath, "symbolic", filepath.replace(/\.[^.]+$/, ".json"));
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 = path11.isAbsolute(filepath) ? filepath : path11.join(rootDir, filepath);
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 = path11.isAbsolute(filepath) ? filepath : path11.join(rootDir, filepath);
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
- for (let i = 0;i < files.length; i++) {
3760
- const filepath = files[i];
3761
- const relativePath = path11.relative(rootDir, filepath);
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
- logger.debug(` ${progress} Skipped ${relativePath} (unchanged)`);
3769
- result.skipped++;
3770
- continue;
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
- logger.progress(` ${progress} Processing: ${relativePath}`);
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(` ${progress} Skipped ${relativePath} (no chunks)`);
3778
- result.skipped++;
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
- manifest.files[relativePath] = {
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
- logger.clearProgress();
3789
- logger.error(` ${progress} Error indexing ${relativePath}: ${error}`);
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(path11.dirname(manifestPath), { recursive: true });
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 = path11.join(indexPath, filepath.replace(/\.[^.]+$/, ".json"));
3834
- await fs6.mkdir(path11.dirname(indexFilePath), { recursive: true });
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(path11.dirname(manifestPath), { recursive: true });
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 = path11.resolve(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 = path11.join(rootDir, filepath);
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 = path11.join(indexPath, filepath.replace(/\.[^.]+$/, ".json"));
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 = path11.join(dir, entry.name);
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 = path11.resolve(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(path11.join(indexDir, "index"));
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 path12 from "path";
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 = path12.resolve(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 ? path12.join(indexPath, filepath.replace(/\.[^.]+$/, ".json")) : path12.join(indexPath, filepath + ".json");
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 = path12.relative(indexPath, f);
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 = path12.join(dir, entry.name);
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=3E17C296D218EF4F64756E2164756E21
4795
+ //# debugId=984F0AA3FD08D5A664756E2164756E21