raggrep 0.2.3 → 0.4.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
@@ -1,4 +1,20 @@
1
+ import { createRequire } from "node:module";
2
+ var __create = Object.create;
3
+ var __getProtoOf = Object.getPrototypeOf;
1
4
  var __defProp = Object.defineProperty;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __toESM = (mod, isNodeMode, target) => {
8
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
9
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
10
+ for (let key of __getOwnPropNames(mod))
11
+ if (!__hasOwnProp.call(to, key))
12
+ __defProp(to, key, {
13
+ get: () => mod[key],
14
+ enumerable: true
15
+ });
16
+ return to;
17
+ };
2
18
  var __export = (target, all) => {
3
19
  for (var name in all)
4
20
  __defProp(target, name, {
@@ -9,8 +25,17 @@ var __export = (target, all) => {
9
25
  });
10
26
  };
11
27
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
28
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
12
29
  // src/domain/entities/searchResult.ts
13
- var init_searchResult = () => {};
30
+ var DEFAULT_SEARCH_OPTIONS;
31
+ var init_searchResult = __esm(() => {
32
+ DEFAULT_SEARCH_OPTIONS = {
33
+ topK: 10,
34
+ minScore: 0.15,
35
+ filePatterns: [],
36
+ ensureFresh: true
37
+ };
38
+ });
14
39
 
15
40
  // src/domain/entities/config.ts
16
41
  function createDefaultConfig() {
@@ -72,10 +97,17 @@ var init_config = __esm(() => {
72
97
  ".tsx",
73
98
  ".js",
74
99
  ".jsx",
100
+ ".mjs",
101
+ ".cjs",
75
102
  ".py",
76
103
  ".go",
77
104
  ".rs",
78
105
  ".java",
106
+ ".json",
107
+ ".yaml",
108
+ ".yml",
109
+ ".toml",
110
+ ".sql",
79
111
  ".md",
80
112
  ".txt"
81
113
  ];
@@ -1969,7 +2001,10 @@ var init_core = __esm(() => {
1969
2001
  });
1970
2002
 
1971
2003
  // src/infrastructure/embeddings/transformersEmbedding.ts
1972
- import { pipeline, env } from "@xenova/transformers";
2004
+ import {
2005
+ pipeline,
2006
+ env
2007
+ } from "@xenova/transformers";
1973
2008
  import * as path6 from "path";
1974
2009
  import * as os2 from "os";
1975
2010
 
@@ -1981,7 +2016,8 @@ class TransformersEmbeddingProvider {
1981
2016
  constructor(config) {
1982
2017
  this.config = {
1983
2018
  model: config?.model ?? "all-MiniLM-L6-v2",
1984
- showProgress: config?.showProgress ?? false
2019
+ showProgress: config?.showProgress ?? false,
2020
+ logger: config?.logger
1985
2021
  };
1986
2022
  }
1987
2023
  async initialize(config) {
@@ -2003,29 +2039,55 @@ class TransformersEmbeddingProvider {
2003
2039
  this.isInitializing = true;
2004
2040
  this.initPromise = (async () => {
2005
2041
  const modelId = EMBEDDING_MODELS2[this.config.model];
2006
- if (this.config.showProgress) {
2007
- console.log(`
2008
- Loading embedding model: ${this.config.model}`);
2009
- console.log(` Cache: ${CACHE_DIR}`);
2010
- }
2042
+ const logger = this.config.logger;
2043
+ const showProgress = this.config.showProgress || !!logger;
2044
+ const isCached = await isModelCached(this.config.model);
2045
+ let hasDownloads = false;
2011
2046
  try {
2012
2047
  this.pipeline = await pipeline("feature-extraction", modelId, {
2013
- progress_callback: this.config.showProgress ? (progress) => {
2048
+ progress_callback: showProgress && !isCached ? (progress) => {
2014
2049
  if (progress.status === "progress" && progress.file) {
2050
+ if (!hasDownloads) {
2051
+ hasDownloads = true;
2052
+ if (logger) {
2053
+ logger.info(`Downloading embedding model: ${this.config.model}`);
2054
+ } else {
2055
+ console.log(`
2056
+ Loading embedding model: ${this.config.model}`);
2057
+ console.log(` Cache: ${CACHE_DIR}`);
2058
+ }
2059
+ }
2015
2060
  const pct = progress.progress ? Math.round(progress.progress) : 0;
2016
- process.stdout.write(`\r Downloading ${progress.file}: ${pct}% `);
2061
+ if (logger) {
2062
+ logger.progress(` Downloading ${progress.file}: ${pct}%`);
2063
+ } else {
2064
+ process.stdout.write(`\r Downloading ${progress.file}: ${pct}% `);
2065
+ }
2017
2066
  } else if (progress.status === "done" && progress.file) {
2018
- process.stdout.write(`\r Downloaded ${progress.file}
2067
+ if (logger) {
2068
+ logger.clearProgress();
2069
+ logger.info(` Downloaded ${progress.file}`);
2070
+ } else if (hasDownloads) {
2071
+ process.stdout.write(`\r Downloaded ${progress.file}
2019
2072
  `);
2073
+ }
2020
2074
  }
2021
2075
  } : undefined
2022
2076
  });
2023
- if (this.config.showProgress) {
2024
- console.log(` Model ready.
2077
+ if (hasDownloads) {
2078
+ if (logger) {
2079
+ logger.clearProgress();
2080
+ logger.info(`Model ready: ${this.config.model}`);
2081
+ } else {
2082
+ console.log(` Model ready.
2025
2083
  `);
2084
+ }
2026
2085
  }
2027
2086
  } catch (error) {
2028
2087
  this.pipeline = null;
2088
+ if (logger) {
2089
+ logger.clearProgress();
2090
+ }
2029
2091
  throw new Error(`Failed to load embedding model: ${error}`);
2030
2092
  } finally {
2031
2093
  this.isInitializing = false;
@@ -2076,9 +2138,21 @@ class TransformersEmbeddingProvider {
2076
2138
  this.pipeline = null;
2077
2139
  }
2078
2140
  }
2141
+ async function isModelCached(model) {
2142
+ const modelId = EMBEDDING_MODELS2[model];
2143
+ const modelPath = path6.join(CACHE_DIR, modelId);
2144
+ try {
2145
+ const fs3 = await import("fs/promises");
2146
+ const onnxPath = path6.join(modelPath, "onnx", "model_quantized.onnx");
2147
+ await fs3.access(onnxPath);
2148
+ return true;
2149
+ } catch {
2150
+ return false;
2151
+ }
2152
+ }
2079
2153
  function configureEmbeddings(config) {
2080
2154
  const newConfig = { ...globalConfig, ...config };
2081
- if (newConfig.model !== globalConfig.model) {
2155
+ if (newConfig.model !== globalConfig.model || newConfig.logger !== globalConfig.logger) {
2082
2156
  globalProvider = null;
2083
2157
  }
2084
2158
  globalConfig = newConfig;
@@ -2114,7 +2188,8 @@ var init_transformersEmbedding = __esm(() => {
2114
2188
  };
2115
2189
  globalConfig = {
2116
2190
  model: "all-MiniLM-L6-v2",
2117
- showProgress: false
2191
+ showProgress: false,
2192
+ logger: undefined
2118
2193
  };
2119
2194
  });
2120
2195
 
@@ -2686,6 +2761,57 @@ __export(exports_typescript, {
2686
2761
  DEFAULT_MIN_SCORE: () => DEFAULT_MIN_SCORE2
2687
2762
  });
2688
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";
2774
+ }
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;
2783
+ }
2784
+ return 0;
2785
+ }
2786
+ if (intent === "documentation") {
2787
+ if (isDoc) {
2788
+ return 0.08;
2789
+ }
2790
+ return 0;
2791
+ }
2792
+ return 0;
2793
+ }
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;
2810
+ }
2811
+ }
2812
+ function calculateExportBoost(chunk) {
2813
+ return chunk.isExported ? 0.03 : 0;
2814
+ }
2689
2815
 
2690
2816
  class TypeScriptModule {
2691
2817
  id = "language/typescript";
@@ -2696,8 +2822,16 @@ class TypeScriptModule {
2696
2822
  symbolicIndex = null;
2697
2823
  pendingSummaries = new Map;
2698
2824
  rootDir = "";
2825
+ logger = undefined;
2699
2826
  async initialize(config) {
2700
2827
  this.embeddingConfig = getEmbeddingConfigFromModule(config);
2828
+ this.logger = config.options?.logger;
2829
+ if (this.logger) {
2830
+ this.embeddingConfig = {
2831
+ ...this.embeddingConfig,
2832
+ logger: this.logger
2833
+ };
2834
+ }
2701
2835
  configureEmbeddings(this.embeddingConfig);
2702
2836
  this.pendingSummaries.clear();
2703
2837
  }
@@ -2855,7 +2989,11 @@ class TypeScriptModule {
2855
2989
  const semanticScore = cosineSimilarity(queryEmbedding, embedding);
2856
2990
  const bm25Score = bm25Scores.get(chunk.id) || 0;
2857
2991
  const pathBoost = pathBoosts.get(filepath) || 0;
2858
- const hybridScore = SEMANTIC_WEIGHT * semanticScore + BM25_WEIGHT * bm25Score + pathBoost;
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;
2859
2997
  if (hybridScore >= minScore || bm25Score > 0.3) {
2860
2998
  results.push({
2861
2999
  filepath,
@@ -2865,7 +3003,10 @@ class TypeScriptModule {
2865
3003
  context: {
2866
3004
  semanticScore,
2867
3005
  bm25Score,
2868
- pathBoost
3006
+ pathBoost,
3007
+ fileTypeBoost,
3008
+ chunkTypeBoost,
3009
+ exportBoost
2869
3010
  }
2870
3011
  });
2871
3012
  }
@@ -2897,7 +3038,7 @@ class TypeScriptModule {
2897
3038
  return references;
2898
3039
  }
2899
3040
  }
2900
- var DEFAULT_MIN_SCORE2 = 0.15, DEFAULT_TOP_K2 = 10, SEMANTIC_WEIGHT = 0.7, BM25_WEIGHT = 0.3;
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;
2901
3042
  var init_typescript = __esm(() => {
2902
3043
  init_embeddings();
2903
3044
  init_config2();
@@ -2905,6 +3046,52 @@ var init_typescript = __esm(() => {
2905
3046
  init_storage();
2906
3047
  init_keywords();
2907
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"];
2908
3095
  });
2909
3096
 
2910
3097
  // src/app/indexer/index.ts
@@ -3193,6 +3380,92 @@ class IntrospectionIndex {
3193
3380
  this.structure = null;
3194
3381
  }
3195
3382
  }
3383
+ // src/infrastructure/logger/loggers.ts
3384
+ class ConsoleLogger {
3385
+ verbose;
3386
+ constructor(options) {
3387
+ this.verbose = options?.verbose ?? false;
3388
+ }
3389
+ info(message) {
3390
+ console.log(message);
3391
+ }
3392
+ warn(message) {
3393
+ console.warn(message);
3394
+ }
3395
+ error(message) {
3396
+ console.error(message);
3397
+ }
3398
+ debug(message) {
3399
+ if (this.verbose) {
3400
+ console.log(message);
3401
+ }
3402
+ }
3403
+ progress(message) {
3404
+ console.log(message);
3405
+ }
3406
+ clearProgress() {}
3407
+ }
3408
+
3409
+ class InlineProgressLogger {
3410
+ verbose;
3411
+ lastProgressLength = 0;
3412
+ hasProgress = false;
3413
+ constructor(options) {
3414
+ this.verbose = options?.verbose ?? false;
3415
+ }
3416
+ info(message) {
3417
+ this.clearProgress();
3418
+ console.log(message);
3419
+ }
3420
+ warn(message) {
3421
+ this.clearProgress();
3422
+ console.warn(message);
3423
+ }
3424
+ error(message) {
3425
+ this.clearProgress();
3426
+ console.error(message);
3427
+ }
3428
+ debug(message) {
3429
+ if (this.verbose) {
3430
+ this.clearProgress();
3431
+ console.log(message);
3432
+ }
3433
+ }
3434
+ progress(message) {
3435
+ process.stdout.write(`\r${message}`);
3436
+ const padding = Math.max(0, this.lastProgressLength - message.length);
3437
+ if (padding > 0) {
3438
+ process.stdout.write(" ".repeat(padding));
3439
+ }
3440
+ this.lastProgressLength = message.length;
3441
+ this.hasProgress = true;
3442
+ }
3443
+ clearProgress() {
3444
+ if (this.hasProgress && this.lastProgressLength > 0) {
3445
+ process.stdout.write("\r" + " ".repeat(this.lastProgressLength) + "\r");
3446
+ this.lastProgressLength = 0;
3447
+ this.hasProgress = false;
3448
+ }
3449
+ }
3450
+ }
3451
+
3452
+ class SilentLogger {
3453
+ info() {}
3454
+ warn() {}
3455
+ error() {}
3456
+ debug() {}
3457
+ progress() {}
3458
+ clearProgress() {}
3459
+ }
3460
+ function createLogger(options) {
3461
+ return new ConsoleLogger(options);
3462
+ }
3463
+ function createInlineLogger(options) {
3464
+ return new InlineProgressLogger(options);
3465
+ }
3466
+ function createSilentLogger() {
3467
+ return new SilentLogger;
3468
+ }
3196
3469
  // src/app/indexer/watcher.ts
3197
3470
  import { watch } from "chokidar";
3198
3471
  init_config2();
@@ -3202,42 +3475,31 @@ var INDEX_SCHEMA_VERSION = "1.0.0";
3202
3475
  async function indexDirectory(rootDir, options = {}) {
3203
3476
  const verbose = options.verbose ?? false;
3204
3477
  const quiet = options.quiet ?? false;
3478
+ const logger = options.logger ? options.logger : quiet ? createSilentLogger() : createLogger({ verbose });
3205
3479
  rootDir = path11.resolve(rootDir);
3206
3480
  const location = getIndexLocation(rootDir);
3207
- if (!quiet) {
3208
- console.log(`Indexing directory: ${rootDir}`);
3209
- console.log(`Index location: ${location.indexDir}`);
3210
- }
3481
+ logger.info(`Indexing directory: ${rootDir}`);
3482
+ logger.info(`Index location: ${location.indexDir}`);
3211
3483
  const config = await loadConfig(rootDir);
3212
3484
  const introspection = new IntrospectionIndex(rootDir);
3213
3485
  await introspection.initialize();
3214
- if (verbose) {
3215
- const structure = introspection.getStructure();
3216
- if (structure?.isMonorepo) {
3217
- console.log(`Detected monorepo with ${structure.projects.length} projects`);
3218
- }
3486
+ const structure = introspection.getStructure();
3487
+ if (structure?.isMonorepo) {
3488
+ logger.debug(`Detected monorepo with ${structure.projects.length} projects`);
3219
3489
  }
3220
3490
  await registerBuiltInModules();
3221
3491
  const enabledModules = registry.getEnabled(config);
3222
3492
  if (enabledModules.length === 0) {
3223
- if (!quiet) {
3224
- console.log("No modules enabled. Check your configuration.");
3225
- }
3493
+ logger.info("No modules enabled. Check your configuration.");
3226
3494
  return [];
3227
3495
  }
3228
- if (!quiet) {
3229
- console.log(`Enabled modules: ${enabledModules.map((m) => m.id).join(", ")}`);
3230
- }
3496
+ logger.info(`Enabled modules: ${enabledModules.map((m) => m.id).join(", ")}`);
3231
3497
  const files = await findFiles(rootDir, config);
3232
- if (!quiet) {
3233
- console.log(`Found ${files.length} files to index`);
3234
- }
3498
+ logger.info(`Found ${files.length} files to index`);
3235
3499
  const results = [];
3236
3500
  for (const module of enabledModules) {
3237
- if (!quiet) {
3238
- console.log(`
3501
+ logger.info(`
3239
3502
  [${module.name}] Starting indexing...`);
3240
- }
3241
3503
  const moduleConfig = getModuleConfig(config, module.id);
3242
3504
  if (module.initialize && moduleConfig) {
3243
3505
  const configWithOverrides = { ...moduleConfig };
@@ -3247,14 +3509,16 @@ async function indexDirectory(rootDir, options = {}) {
3247
3509
  embeddingModel: options.model
3248
3510
  };
3249
3511
  }
3512
+ configWithOverrides.options = {
3513
+ ...configWithOverrides.options,
3514
+ logger
3515
+ };
3250
3516
  await module.initialize(configWithOverrides);
3251
3517
  }
3252
- const result = await indexWithModule(rootDir, files, module, config, verbose, introspection);
3518
+ const result = await indexWithModule(rootDir, files, module, config, verbose, introspection, logger);
3253
3519
  results.push(result);
3254
3520
  if (module.finalize) {
3255
- if (!quiet) {
3256
- console.log(`[${module.name}] Building secondary indexes...`);
3257
- }
3521
+ logger.info(`[${module.name}] Building secondary indexes...`);
3258
3522
  const ctx = {
3259
3523
  rootDir,
3260
3524
  config,
@@ -3270,15 +3534,182 @@ async function indexDirectory(rootDir, options = {}) {
3270
3534
  };
3271
3535
  await module.finalize(ctx);
3272
3536
  }
3273
- if (!quiet) {
3274
- console.log(`[${module.name}] Complete: ${result.indexed} indexed, ${result.skipped} skipped, ${result.errors} errors`);
3275
- }
3537
+ logger.info(`[${module.name}] Complete: ${result.indexed} indexed, ${result.skipped} skipped, ${result.errors} errors`);
3276
3538
  }
3277
3539
  await introspection.save(config);
3278
3540
  await updateGlobalManifest(rootDir, enabledModules, config);
3279
3541
  return results;
3280
3542
  }
3281
- async function indexWithModule(rootDir, files, module, config, verbose, introspection) {
3543
+ async function isIndexVersionCompatible(rootDir) {
3544
+ const config = await loadConfig(rootDir);
3545
+ const globalManifestPath = getGlobalManifestPath(rootDir, config);
3546
+ try {
3547
+ const content = await fs6.readFile(globalManifestPath, "utf-8");
3548
+ const manifest = JSON.parse(content);
3549
+ return manifest.version === INDEX_SCHEMA_VERSION;
3550
+ } catch {
3551
+ return false;
3552
+ }
3553
+ }
3554
+ async function deleteIndex(rootDir) {
3555
+ const indexDir = getRaggrepDir(rootDir);
3556
+ try {
3557
+ await fs6.rm(indexDir, { recursive: true, force: true });
3558
+ } catch {}
3559
+ }
3560
+ async function resetIndex(rootDir) {
3561
+ rootDir = path11.resolve(rootDir);
3562
+ const status = await getIndexStatus(rootDir);
3563
+ if (!status.exists) {
3564
+ throw new Error(`No index found for ${rootDir}`);
3565
+ }
3566
+ await deleteIndex(rootDir);
3567
+ return {
3568
+ success: true,
3569
+ indexDir: status.indexDir
3570
+ };
3571
+ }
3572
+ async function ensureIndexFresh(rootDir, options = {}) {
3573
+ const verbose = options.verbose ?? false;
3574
+ const quiet = options.quiet ?? false;
3575
+ const logger = options.logger ? options.logger : quiet ? createSilentLogger() : createLogger({ verbose });
3576
+ rootDir = path11.resolve(rootDir);
3577
+ const status = await getIndexStatus(rootDir);
3578
+ if (!status.exists) {
3579
+ logger.info(`No index found. Creating index...
3580
+ `);
3581
+ const results = await indexDirectory(rootDir, { ...options, logger });
3582
+ const totalIndexed2 = results.reduce((sum, r) => sum + r.indexed, 0);
3583
+ return { indexed: totalIndexed2, removed: 0, unchanged: 0 };
3584
+ }
3585
+ const versionCompatible = await isIndexVersionCompatible(rootDir);
3586
+ if (!versionCompatible) {
3587
+ logger.info(`Index version incompatible. Rebuilding...
3588
+ `);
3589
+ await deleteIndex(rootDir);
3590
+ const results = await indexDirectory(rootDir, { ...options, logger });
3591
+ const totalIndexed2 = results.reduce((sum, r) => sum + r.indexed, 0);
3592
+ return { indexed: totalIndexed2, removed: 0, unchanged: 0 };
3593
+ }
3594
+ const config = await loadConfig(rootDir);
3595
+ await registerBuiltInModules();
3596
+ const enabledModules = registry.getEnabled(config);
3597
+ if (enabledModules.length === 0) {
3598
+ return { indexed: 0, removed: 0, unchanged: 0 };
3599
+ }
3600
+ const introspection = new IntrospectionIndex(rootDir);
3601
+ await introspection.initialize();
3602
+ const currentFiles = await findFiles(rootDir, config);
3603
+ const currentFileSet = new Set(currentFiles.map((f) => path11.relative(rootDir, f)));
3604
+ let totalIndexed = 0;
3605
+ let totalRemoved = 0;
3606
+ let totalUnchanged = 0;
3607
+ for (const module of enabledModules) {
3608
+ const moduleConfig = getModuleConfig(config, module.id);
3609
+ if (module.initialize && moduleConfig) {
3610
+ const configWithOverrides = { ...moduleConfig };
3611
+ if (options.model && module.id === "language/typescript") {
3612
+ configWithOverrides.options = {
3613
+ ...configWithOverrides.options,
3614
+ embeddingModel: options.model
3615
+ };
3616
+ }
3617
+ configWithOverrides.options = {
3618
+ ...configWithOverrides.options,
3619
+ logger
3620
+ };
3621
+ await module.initialize(configWithOverrides);
3622
+ }
3623
+ const manifest = await loadModuleManifest(rootDir, module.id, config);
3624
+ const indexPath = getModuleIndexPath(rootDir, module.id, config);
3625
+ const filesToRemove = [];
3626
+ for (const filepath of Object.keys(manifest.files)) {
3627
+ if (!currentFileSet.has(filepath)) {
3628
+ filesToRemove.push(filepath);
3629
+ }
3630
+ }
3631
+ for (const filepath of filesToRemove) {
3632
+ logger.debug(` Removing stale: ${filepath}`);
3633
+ const indexFilePath = path11.join(indexPath, filepath.replace(/\.[^.]+$/, ".json"));
3634
+ try {
3635
+ await fs6.unlink(indexFilePath);
3636
+ } catch {}
3637
+ const symbolicFilePath = path11.join(indexPath, "symbolic", filepath.replace(/\.[^.]+$/, ".json"));
3638
+ try {
3639
+ await fs6.unlink(symbolicFilePath);
3640
+ } catch {}
3641
+ delete manifest.files[filepath];
3642
+ totalRemoved++;
3643
+ }
3644
+ const ctx = {
3645
+ rootDir,
3646
+ config,
3647
+ readFile: async (filepath) => {
3648
+ const fullPath = path11.isAbsolute(filepath) ? filepath : path11.join(rootDir, filepath);
3649
+ return fs6.readFile(fullPath, "utf-8");
3650
+ },
3651
+ getFileStats: async (filepath) => {
3652
+ const fullPath = path11.isAbsolute(filepath) ? filepath : path11.join(rootDir, filepath);
3653
+ const stats = await fs6.stat(fullPath);
3654
+ return { lastModified: stats.mtime.toISOString() };
3655
+ },
3656
+ getIntrospection: (filepath) => introspection.getFile(filepath)
3657
+ };
3658
+ const totalFiles = currentFiles.length;
3659
+ for (let i = 0;i < currentFiles.length; i++) {
3660
+ const filepath = currentFiles[i];
3661
+ const relativePath = path11.relative(rootDir, filepath);
3662
+ const progress = `[${i + 1}/${totalFiles}]`;
3663
+ try {
3664
+ const stats = await fs6.stat(filepath);
3665
+ const lastModified = stats.mtime.toISOString();
3666
+ const existingEntry = manifest.files[relativePath];
3667
+ if (existingEntry && existingEntry.lastModified === lastModified) {
3668
+ totalUnchanged++;
3669
+ continue;
3670
+ }
3671
+ logger.progress(` ${progress} Indexing: ${relativePath}`);
3672
+ const content = await fs6.readFile(filepath, "utf-8");
3673
+ introspection.addFile(relativePath, content);
3674
+ const fileIndex = await module.indexFile(relativePath, content, ctx);
3675
+ if (fileIndex) {
3676
+ await writeFileIndex(rootDir, module.id, relativePath, fileIndex, config);
3677
+ manifest.files[relativePath] = {
3678
+ lastModified,
3679
+ chunkCount: fileIndex.chunks.length
3680
+ };
3681
+ totalIndexed++;
3682
+ }
3683
+ } catch (error) {
3684
+ logger.clearProgress();
3685
+ logger.error(` ${progress} Error indexing ${relativePath}: ${error}`);
3686
+ }
3687
+ }
3688
+ logger.clearProgress();
3689
+ if (totalIndexed > 0 || totalRemoved > 0) {
3690
+ manifest.lastUpdated = new Date().toISOString();
3691
+ await writeModuleManifest(rootDir, module.id, manifest, config);
3692
+ if (module.finalize) {
3693
+ await module.finalize(ctx);
3694
+ }
3695
+ }
3696
+ if (totalRemoved > 0) {
3697
+ await cleanupEmptyDirectories(indexPath);
3698
+ }
3699
+ }
3700
+ if (totalIndexed > 0) {
3701
+ await introspection.save(config);
3702
+ }
3703
+ if (totalIndexed > 0 || totalRemoved > 0) {
3704
+ await updateGlobalManifest(rootDir, enabledModules, config);
3705
+ }
3706
+ return {
3707
+ indexed: totalIndexed,
3708
+ removed: totalRemoved,
3709
+ unchanged: totalUnchanged
3710
+ };
3711
+ }
3712
+ async function indexWithModule(rootDir, files, module, config, verbose, introspection, logger) {
3282
3713
  const result = {
3283
3714
  moduleId: module.id,
3284
3715
  indexed: 0,
@@ -3286,6 +3717,30 @@ async function indexWithModule(rootDir, files, module, config, verbose, introspe
3286
3717
  errors: 0
3287
3718
  };
3288
3719
  const manifest = await loadModuleManifest(rootDir, module.id, config);
3720
+ const indexPath = getModuleIndexPath(rootDir, module.id, config);
3721
+ const currentFileSet = new Set(files.map((f) => path11.relative(rootDir, f)));
3722
+ const filesToRemove = [];
3723
+ for (const filepath of Object.keys(manifest.files)) {
3724
+ if (!currentFileSet.has(filepath)) {
3725
+ filesToRemove.push(filepath);
3726
+ }
3727
+ }
3728
+ if (filesToRemove.length > 0) {
3729
+ logger.info(` Removing ${filesToRemove.length} stale entries...`);
3730
+ for (const filepath of filesToRemove) {
3731
+ logger.debug(` Removing: ${filepath}`);
3732
+ const indexFilePath = path11.join(indexPath, filepath.replace(/\.[^.]+$/, ".json"));
3733
+ try {
3734
+ await fs6.unlink(indexFilePath);
3735
+ } catch {}
3736
+ const symbolicFilePath = path11.join(indexPath, "symbolic", filepath.replace(/\.[^.]+$/, ".json"));
3737
+ try {
3738
+ await fs6.unlink(symbolicFilePath);
3739
+ } catch {}
3740
+ delete manifest.files[filepath];
3741
+ }
3742
+ await cleanupEmptyDirectories(indexPath);
3743
+ }
3289
3744
  const ctx = {
3290
3745
  rootDir,
3291
3746
  config,
@@ -3300,29 +3755,26 @@ async function indexWithModule(rootDir, files, module, config, verbose, introspe
3300
3755
  },
3301
3756
  getIntrospection: (filepath) => introspection.getFile(filepath)
3302
3757
  };
3303
- for (const filepath of files) {
3758
+ const totalFiles = files.length;
3759
+ for (let i = 0;i < files.length; i++) {
3760
+ const filepath = files[i];
3304
3761
  const relativePath = path11.relative(rootDir, filepath);
3762
+ const progress = `[${i + 1}/${totalFiles}]`;
3305
3763
  try {
3306
3764
  const stats = await fs6.stat(filepath);
3307
3765
  const lastModified = stats.mtime.toISOString();
3308
3766
  const existingEntry = manifest.files[relativePath];
3309
3767
  if (existingEntry && existingEntry.lastModified === lastModified) {
3310
- if (verbose) {
3311
- console.log(` Skipped ${relativePath} (unchanged)`);
3312
- }
3768
+ logger.debug(` ${progress} Skipped ${relativePath} (unchanged)`);
3313
3769
  result.skipped++;
3314
3770
  continue;
3315
3771
  }
3316
3772
  const content = await fs6.readFile(filepath, "utf-8");
3317
3773
  introspection.addFile(relativePath, content);
3318
- if (verbose) {
3319
- console.log(` Processing ${relativePath}...`);
3320
- }
3774
+ logger.progress(` ${progress} Processing: ${relativePath}`);
3321
3775
  const fileIndex = await module.indexFile(relativePath, content, ctx);
3322
3776
  if (!fileIndex) {
3323
- if (verbose) {
3324
- console.log(` Skipped ${relativePath} (no chunks)`);
3325
- }
3777
+ logger.debug(` ${progress} Skipped ${relativePath} (no chunks)`);
3326
3778
  result.skipped++;
3327
3779
  continue;
3328
3780
  }
@@ -3333,10 +3785,12 @@ async function indexWithModule(rootDir, files, module, config, verbose, introspe
3333
3785
  };
3334
3786
  result.indexed++;
3335
3787
  } catch (error) {
3336
- console.error(` Error indexing ${relativePath}:`, error);
3788
+ logger.clearProgress();
3789
+ logger.error(` ${progress} Error indexing ${relativePath}: ${error}`);
3337
3790
  result.errors++;
3338
3791
  }
3339
3792
  }
3793
+ logger.clearProgress();
3340
3794
  manifest.lastUpdated = new Date().toISOString();
3341
3795
  await writeModuleManifest(rootDir, module.id, manifest, config);
3342
3796
  return result;
@@ -3392,26 +3846,27 @@ async function updateGlobalManifest(rootDir, modules, config) {
3392
3846
  }
3393
3847
  async function cleanupIndex(rootDir, options = {}) {
3394
3848
  const verbose = options.verbose ?? false;
3849
+ const logger = options.logger ?? createLogger({ verbose });
3395
3850
  rootDir = path11.resolve(rootDir);
3396
- console.log(`Cleaning up index in: ${rootDir}`);
3851
+ logger.info(`Cleaning up index in: ${rootDir}`);
3397
3852
  const config = await loadConfig(rootDir);
3398
3853
  await registerBuiltInModules();
3399
3854
  const enabledModules = registry.getEnabled(config);
3400
3855
  if (enabledModules.length === 0) {
3401
- console.log("No modules enabled.");
3856
+ logger.info("No modules enabled.");
3402
3857
  return [];
3403
3858
  }
3404
3859
  const results = [];
3405
3860
  for (const module of enabledModules) {
3406
- console.log(`
3861
+ logger.info(`
3407
3862
  [${module.name}] Checking for stale entries...`);
3408
- const result = await cleanupModuleIndex(rootDir, module.id, config, verbose);
3863
+ const result = await cleanupModuleIndex(rootDir, module.id, config, logger);
3409
3864
  results.push(result);
3410
- console.log(`[${module.name}] Removed ${result.removed} stale entries, kept ${result.kept} valid entries`);
3865
+ logger.info(`[${module.name}] Removed ${result.removed} stale entries, kept ${result.kept} valid entries`);
3411
3866
  }
3412
3867
  return results;
3413
3868
  }
3414
- async function cleanupModuleIndex(rootDir, moduleId, config, verbose) {
3869
+ async function cleanupModuleIndex(rootDir, moduleId, config, logger) {
3415
3870
  const result = {
3416
3871
  moduleId,
3417
3872
  removed: 0,
@@ -3430,9 +3885,7 @@ async function cleanupModuleIndex(rootDir, moduleId, config, verbose) {
3430
3885
  } catch {
3431
3886
  filesToRemove.push(filepath);
3432
3887
  result.removed++;
3433
- if (verbose) {
3434
- console.log(` Removing stale entry: ${filepath}`);
3435
- }
3888
+ logger.debug(` Removing stale entry: ${filepath}`);
3436
3889
  }
3437
3890
  }
3438
3891
  for (const filepath of filesToRemove) {
@@ -3466,19 +3919,85 @@ async function cleanupEmptyDirectories(dir) {
3466
3919
  return false;
3467
3920
  }
3468
3921
  }
3922
+ async function getIndexStatus(rootDir) {
3923
+ rootDir = path11.resolve(rootDir);
3924
+ const config = await loadConfig(rootDir);
3925
+ const location = getIndexLocation(rootDir);
3926
+ const indexDir = location.indexDir;
3927
+ const status = {
3928
+ exists: false,
3929
+ rootDir,
3930
+ indexDir,
3931
+ modules: [],
3932
+ totalFiles: 0
3933
+ };
3934
+ try {
3935
+ await fs6.access(indexDir);
3936
+ } catch {
3937
+ return status;
3938
+ }
3939
+ try {
3940
+ const globalManifestPath = getGlobalManifestPath(rootDir, config);
3941
+ const content = await fs6.readFile(globalManifestPath, "utf-8");
3942
+ const globalManifest = JSON.parse(content);
3943
+ status.exists = true;
3944
+ status.lastUpdated = globalManifest.lastUpdated;
3945
+ for (const moduleId of globalManifest.modules) {
3946
+ try {
3947
+ const manifest = await loadModuleManifest(rootDir, moduleId, config);
3948
+ const fileCount = Object.keys(manifest.files).length;
3949
+ status.modules.push({
3950
+ id: moduleId,
3951
+ fileCount,
3952
+ lastUpdated: manifest.lastUpdated
3953
+ });
3954
+ status.totalFiles += fileCount;
3955
+ } catch {}
3956
+ }
3957
+ } catch {
3958
+ try {
3959
+ const entries = await fs6.readdir(path11.join(indexDir, "index"));
3960
+ if (entries.length > 0) {
3961
+ status.exists = true;
3962
+ for (const entry of entries) {
3963
+ try {
3964
+ const manifest = await loadModuleManifest(rootDir, entry, config);
3965
+ const fileCount = Object.keys(manifest.files).length;
3966
+ status.modules.push({
3967
+ id: entry,
3968
+ fileCount,
3969
+ lastUpdated: manifest.lastUpdated
3970
+ });
3971
+ status.totalFiles += fileCount;
3972
+ } catch {}
3973
+ }
3974
+ }
3975
+ } catch {}
3976
+ }
3977
+ return status;
3978
+ }
3469
3979
 
3470
3980
  // src/app/search/index.ts
3471
- init_config2();
3472
3981
  import * as fs7 from "fs/promises";
3473
3982
  import * as path12 from "path";
3983
+
3984
+ // src/types.ts
3985
+ init_entities();
3986
+
3987
+ // src/app/search/index.ts
3988
+ init_config2();
3474
3989
  async function search(rootDir, query, options = {}) {
3475
3990
  rootDir = path12.resolve(rootDir);
3991
+ const ensureFresh = options.ensureFresh ?? DEFAULT_SEARCH_OPTIONS.ensureFresh;
3992
+ if (ensureFresh) {
3993
+ await ensureIndexFresh(rootDir, { quiet: true });
3994
+ }
3476
3995
  console.log(`Searching for: "${query}"`);
3477
3996
  const config = await loadConfig(rootDir);
3478
3997
  await registerBuiltInModules();
3479
3998
  const globalManifest = await loadGlobalManifest(rootDir, config);
3480
3999
  if (!globalManifest || globalManifest.modules.length === 0) {
3481
- console.log('No index found. Run "bun run index" first.');
4000
+ console.log('No index found. Run "raggrep index" first.');
3482
4001
  return [];
3483
4002
  }
3484
4003
  const modulesToSearch = [];
@@ -3611,19 +4130,30 @@ async function search2(directory, query, options = {}) {
3611
4130
  async function cleanup(directory, options = {}) {
3612
4131
  return cleanupIndex(directory, options);
3613
4132
  }
4133
+ async function reset(directory) {
4134
+ return resetIndex(directory);
4135
+ }
3614
4136
  var raggrep = {
3615
4137
  index,
3616
4138
  search: search2,
3617
4139
  cleanup,
4140
+ reset,
3618
4141
  formatSearchResults
3619
4142
  };
3620
4143
  var src_default = raggrep;
3621
4144
  export {
3622
4145
  search2 as search,
4146
+ reset,
3623
4147
  index,
3624
4148
  formatSearchResults,
3625
4149
  src_default as default,
3626
- cleanup
4150
+ createSilentLogger,
4151
+ createLogger,
4152
+ createInlineLogger,
4153
+ cleanup,
4154
+ SilentLogger,
4155
+ InlineProgressLogger,
4156
+ ConsoleLogger
3627
4157
  };
3628
4158
 
3629
- //# debugId=22D9AEEC336F77A764756E2164756E21
4159
+ //# debugId=3E17C296D218EF4F64756E2164756E21