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/cli/main.js CHANGED
@@ -1,5 +1,21 @@
1
1
  #!/usr/bin/env node
2
+ import { createRequire } from "node:module";
3
+ var __create = Object.create;
4
+ var __getProtoOf = Object.getPrototypeOf;
2
5
  var __defProp = Object.defineProperty;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __toESM = (mod, isNodeMode, target) => {
9
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
10
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
11
+ for (let key of __getOwnPropNames(mod))
12
+ if (!__hasOwnProp.call(to, key))
13
+ __defProp(to, key, {
14
+ get: () => mod[key],
15
+ enumerable: true
16
+ });
17
+ return to;
18
+ };
3
19
  var __export = (target, all) => {
4
20
  for (var name in all)
5
21
  __defProp(target, name, {
@@ -10,9 +26,13 @@ var __export = (target, all) => {
10
26
  });
11
27
  };
12
28
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
29
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
13
30
 
14
31
  // src/infrastructure/embeddings/transformersEmbedding.ts
15
- import { pipeline, env } from "@xenova/transformers";
32
+ import {
33
+ pipeline,
34
+ env
35
+ } from "@xenova/transformers";
16
36
  import * as path from "path";
17
37
  import * as os from "os";
18
38
 
@@ -24,7 +44,8 @@ class TransformersEmbeddingProvider {
24
44
  constructor(config) {
25
45
  this.config = {
26
46
  model: config?.model ?? "all-MiniLM-L6-v2",
27
- showProgress: config?.showProgress ?? false
47
+ showProgress: config?.showProgress ?? false,
48
+ logger: config?.logger
28
49
  };
29
50
  }
30
51
  async initialize(config) {
@@ -46,29 +67,55 @@ class TransformersEmbeddingProvider {
46
67
  this.isInitializing = true;
47
68
  this.initPromise = (async () => {
48
69
  const modelId = EMBEDDING_MODELS[this.config.model];
49
- if (this.config.showProgress) {
50
- console.log(`
51
- Loading embedding model: ${this.config.model}`);
52
- console.log(` Cache: ${CACHE_DIR}`);
53
- }
70
+ const logger = this.config.logger;
71
+ const showProgress = this.config.showProgress || !!logger;
72
+ const isCached = await isModelCached(this.config.model);
73
+ let hasDownloads = false;
54
74
  try {
55
75
  this.pipeline = await pipeline("feature-extraction", modelId, {
56
- progress_callback: this.config.showProgress ? (progress) => {
76
+ progress_callback: showProgress && !isCached ? (progress) => {
57
77
  if (progress.status === "progress" && progress.file) {
78
+ if (!hasDownloads) {
79
+ hasDownloads = true;
80
+ if (logger) {
81
+ logger.info(`Downloading embedding model: ${this.config.model}`);
82
+ } else {
83
+ console.log(`
84
+ Loading embedding model: ${this.config.model}`);
85
+ console.log(` Cache: ${CACHE_DIR}`);
86
+ }
87
+ }
58
88
  const pct = progress.progress ? Math.round(progress.progress) : 0;
59
- process.stdout.write(`\r Downloading ${progress.file}: ${pct}% `);
89
+ if (logger) {
90
+ logger.progress(` Downloading ${progress.file}: ${pct}%`);
91
+ } else {
92
+ process.stdout.write(`\r Downloading ${progress.file}: ${pct}% `);
93
+ }
60
94
  } else if (progress.status === "done" && progress.file) {
61
- process.stdout.write(`\r Downloaded ${progress.file}
95
+ if (logger) {
96
+ logger.clearProgress();
97
+ logger.info(` Downloaded ${progress.file}`);
98
+ } else if (hasDownloads) {
99
+ process.stdout.write(`\r Downloaded ${progress.file}
62
100
  `);
101
+ }
63
102
  }
64
103
  } : undefined
65
104
  });
66
- if (this.config.showProgress) {
67
- console.log(` Model ready.
105
+ if (hasDownloads) {
106
+ if (logger) {
107
+ logger.clearProgress();
108
+ logger.info(`Model ready: ${this.config.model}`);
109
+ } else {
110
+ console.log(` Model ready.
68
111
  `);
112
+ }
69
113
  }
70
114
  } catch (error) {
71
115
  this.pipeline = null;
116
+ if (logger) {
117
+ logger.clearProgress();
118
+ }
72
119
  throw new Error(`Failed to load embedding model: ${error}`);
73
120
  } finally {
74
121
  this.isInitializing = false;
@@ -122,9 +169,21 @@ class TransformersEmbeddingProvider {
122
169
  function getCacheDir() {
123
170
  return CACHE_DIR;
124
171
  }
172
+ async function isModelCached(model) {
173
+ const modelId = EMBEDDING_MODELS[model];
174
+ const modelPath = path.join(CACHE_DIR, modelId);
175
+ try {
176
+ const fs = await import("fs/promises");
177
+ const onnxPath = path.join(modelPath, "onnx", "model_quantized.onnx");
178
+ await fs.access(onnxPath);
179
+ return true;
180
+ } catch {
181
+ return false;
182
+ }
183
+ }
125
184
  function configureEmbeddings(config) {
126
185
  const newConfig = { ...globalConfig, ...config };
127
- if (newConfig.model !== globalConfig.model) {
186
+ if (newConfig.model !== globalConfig.model || newConfig.logger !== globalConfig.logger) {
128
187
  globalProvider = null;
129
188
  }
130
189
  globalConfig = newConfig;
@@ -160,7 +219,8 @@ var init_transformersEmbedding = __esm(() => {
160
219
  };
161
220
  globalConfig = {
162
221
  model: "all-MiniLM-L6-v2",
163
- showProgress: false
222
+ showProgress: false,
223
+ logger: undefined
164
224
  };
165
225
  });
166
226
 
@@ -168,8 +228,106 @@ var init_transformersEmbedding = __esm(() => {
168
228
  var init_embeddings = __esm(() => {
169
229
  init_transformersEmbedding();
170
230
  });
231
+
232
+ // src/infrastructure/logger/loggers.ts
233
+ class ConsoleLogger {
234
+ verbose;
235
+ constructor(options) {
236
+ this.verbose = options?.verbose ?? false;
237
+ }
238
+ info(message) {
239
+ console.log(message);
240
+ }
241
+ warn(message) {
242
+ console.warn(message);
243
+ }
244
+ error(message) {
245
+ console.error(message);
246
+ }
247
+ debug(message) {
248
+ if (this.verbose) {
249
+ console.log(message);
250
+ }
251
+ }
252
+ progress(message) {
253
+ console.log(message);
254
+ }
255
+ clearProgress() {}
256
+ }
257
+
258
+ class InlineProgressLogger {
259
+ verbose;
260
+ lastProgressLength = 0;
261
+ hasProgress = false;
262
+ constructor(options) {
263
+ this.verbose = options?.verbose ?? false;
264
+ }
265
+ info(message) {
266
+ this.clearProgress();
267
+ console.log(message);
268
+ }
269
+ warn(message) {
270
+ this.clearProgress();
271
+ console.warn(message);
272
+ }
273
+ error(message) {
274
+ this.clearProgress();
275
+ console.error(message);
276
+ }
277
+ debug(message) {
278
+ if (this.verbose) {
279
+ this.clearProgress();
280
+ console.log(message);
281
+ }
282
+ }
283
+ progress(message) {
284
+ process.stdout.write(`\r${message}`);
285
+ const padding = Math.max(0, this.lastProgressLength - message.length);
286
+ if (padding > 0) {
287
+ process.stdout.write(" ".repeat(padding));
288
+ }
289
+ this.lastProgressLength = message.length;
290
+ this.hasProgress = true;
291
+ }
292
+ clearProgress() {
293
+ if (this.hasProgress && this.lastProgressLength > 0) {
294
+ process.stdout.write("\r" + " ".repeat(this.lastProgressLength) + "\r");
295
+ this.lastProgressLength = 0;
296
+ this.hasProgress = false;
297
+ }
298
+ }
299
+ }
300
+
301
+ class SilentLogger {
302
+ info() {}
303
+ warn() {}
304
+ error() {}
305
+ debug() {}
306
+ progress() {}
307
+ clearProgress() {}
308
+ }
309
+ function createLogger(options) {
310
+ return new ConsoleLogger(options);
311
+ }
312
+ function createInlineLogger(options) {
313
+ return new InlineProgressLogger(options);
314
+ }
315
+ function createSilentLogger() {
316
+ return new SilentLogger;
317
+ }
318
+
319
+ // src/infrastructure/logger/index.ts
320
+ var init_logger = () => {};
171
321
  // src/domain/entities/searchResult.ts
172
- var init_searchResult = () => {};
322
+ var DEFAULT_SEARCH_OPTIONS;
323
+ var init_searchResult = __esm(() => {
324
+ DEFAULT_SEARCH_OPTIONS = {
325
+ topK: 10,
326
+ minScore: 0.15,
327
+ filePatterns: [],
328
+ ensureFresh: true
329
+ };
330
+ });
173
331
 
174
332
  // src/domain/entities/config.ts
175
333
  function createDefaultConfig() {
@@ -231,10 +389,17 @@ var init_config = __esm(() => {
231
389
  ".tsx",
232
390
  ".js",
233
391
  ".jsx",
392
+ ".mjs",
393
+ ".cjs",
234
394
  ".py",
235
395
  ".go",
236
396
  ".rs",
237
397
  ".java",
398
+ ".json",
399
+ ".yaml",
400
+ ".yml",
401
+ ".toml",
402
+ ".sql",
238
403
  ".md",
239
404
  ".txt"
240
405
  ];
@@ -2690,6 +2855,57 @@ __export(exports_typescript, {
2690
2855
  DEFAULT_MIN_SCORE: () => DEFAULT_MIN_SCORE2
2691
2856
  });
2692
2857
  import * as path8 from "path";
2858
+ function detectQueryIntent(queryTerms) {
2859
+ const hasImplementationTerm = queryTerms.some((term) => IMPLEMENTATION_TERMS.includes(term));
2860
+ const hasDocumentationTerm = queryTerms.some((term) => DOCUMENTATION_TERMS.includes(term));
2861
+ if (hasDocumentationTerm) {
2862
+ return "documentation";
2863
+ }
2864
+ if (hasImplementationTerm) {
2865
+ return "implementation";
2866
+ }
2867
+ return "neutral";
2868
+ }
2869
+ function calculateFileTypeBoost(filepath, queryTerms) {
2870
+ const ext = path8.extname(filepath).toLowerCase();
2871
+ const isSourceCode = SOURCE_CODE_EXTENSIONS.includes(ext);
2872
+ const isDoc = DOC_EXTENSIONS.includes(ext);
2873
+ const intent = detectQueryIntent(queryTerms);
2874
+ if (intent === "implementation") {
2875
+ if (isSourceCode) {
2876
+ return 0.06;
2877
+ }
2878
+ return 0;
2879
+ }
2880
+ if (intent === "documentation") {
2881
+ if (isDoc) {
2882
+ return 0.08;
2883
+ }
2884
+ return 0;
2885
+ }
2886
+ return 0;
2887
+ }
2888
+ function calculateChunkTypeBoost(chunk) {
2889
+ switch (chunk.type) {
2890
+ case "function":
2891
+ return 0.05;
2892
+ case "class":
2893
+ case "interface":
2894
+ return 0.04;
2895
+ case "type":
2896
+ case "enum":
2897
+ return 0.03;
2898
+ case "variable":
2899
+ return 0.02;
2900
+ case "file":
2901
+ case "block":
2902
+ default:
2903
+ return 0;
2904
+ }
2905
+ }
2906
+ function calculateExportBoost(chunk) {
2907
+ return chunk.isExported ? 0.03 : 0;
2908
+ }
2693
2909
 
2694
2910
  class TypeScriptModule {
2695
2911
  id = "language/typescript";
@@ -2700,8 +2916,16 @@ class TypeScriptModule {
2700
2916
  symbolicIndex = null;
2701
2917
  pendingSummaries = new Map;
2702
2918
  rootDir = "";
2919
+ logger = undefined;
2703
2920
  async initialize(config) {
2704
2921
  this.embeddingConfig = getEmbeddingConfigFromModule(config);
2922
+ this.logger = config.options?.logger;
2923
+ if (this.logger) {
2924
+ this.embeddingConfig = {
2925
+ ...this.embeddingConfig,
2926
+ logger: this.logger
2927
+ };
2928
+ }
2705
2929
  configureEmbeddings(this.embeddingConfig);
2706
2930
  this.pendingSummaries.clear();
2707
2931
  }
@@ -2859,7 +3083,11 @@ class TypeScriptModule {
2859
3083
  const semanticScore = cosineSimilarity(queryEmbedding, embedding);
2860
3084
  const bm25Score = bm25Scores.get(chunk.id) || 0;
2861
3085
  const pathBoost = pathBoosts.get(filepath) || 0;
2862
- const hybridScore = SEMANTIC_WEIGHT * semanticScore + BM25_WEIGHT * bm25Score + pathBoost;
3086
+ const fileTypeBoost = calculateFileTypeBoost(filepath, queryTerms);
3087
+ const chunkTypeBoost = calculateChunkTypeBoost(chunk);
3088
+ const exportBoost = calculateExportBoost(chunk);
3089
+ const totalBoost = pathBoost + fileTypeBoost + chunkTypeBoost + exportBoost;
3090
+ const hybridScore = SEMANTIC_WEIGHT * semanticScore + BM25_WEIGHT * bm25Score + totalBoost;
2863
3091
  if (hybridScore >= minScore || bm25Score > 0.3) {
2864
3092
  results.push({
2865
3093
  filepath,
@@ -2869,7 +3097,10 @@ class TypeScriptModule {
2869
3097
  context: {
2870
3098
  semanticScore,
2871
3099
  bm25Score,
2872
- pathBoost
3100
+ pathBoost,
3101
+ fileTypeBoost,
3102
+ chunkTypeBoost,
3103
+ exportBoost
2873
3104
  }
2874
3105
  });
2875
3106
  }
@@ -2901,7 +3132,7 @@ class TypeScriptModule {
2901
3132
  return references;
2902
3133
  }
2903
3134
  }
2904
- var DEFAULT_MIN_SCORE2 = 0.15, DEFAULT_TOP_K2 = 10, SEMANTIC_WEIGHT = 0.7, BM25_WEIGHT = 0.3;
3135
+ 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;
2905
3136
  var init_typescript = __esm(() => {
2906
3137
  init_embeddings();
2907
3138
  init_config2();
@@ -2909,6 +3140,52 @@ var init_typescript = __esm(() => {
2909
3140
  init_storage();
2910
3141
  init_keywords();
2911
3142
  init_keywords();
3143
+ IMPLEMENTATION_TERMS = [
3144
+ "function",
3145
+ "method",
3146
+ "class",
3147
+ "interface",
3148
+ "implement",
3149
+ "implementation",
3150
+ "endpoint",
3151
+ "route",
3152
+ "handler",
3153
+ "controller",
3154
+ "module",
3155
+ "code"
3156
+ ];
3157
+ DOCUMENTATION_TERMS = [
3158
+ "documentation",
3159
+ "docs",
3160
+ "guide",
3161
+ "tutorial",
3162
+ "readme",
3163
+ "how",
3164
+ "what",
3165
+ "why",
3166
+ "explain",
3167
+ "overview",
3168
+ "getting",
3169
+ "started",
3170
+ "requirements",
3171
+ "setup",
3172
+ "install",
3173
+ "configure",
3174
+ "configuration"
3175
+ ];
3176
+ SOURCE_CODE_EXTENSIONS = [
3177
+ ".ts",
3178
+ ".tsx",
3179
+ ".js",
3180
+ ".jsx",
3181
+ ".mjs",
3182
+ ".cjs",
3183
+ ".py",
3184
+ ".go",
3185
+ ".rs",
3186
+ ".java"
3187
+ ];
3188
+ DOC_EXTENSIONS = [".md", ".txt", ".rst"];
2912
3189
  });
2913
3190
 
2914
3191
  // src/modules/registry.ts
@@ -3380,6 +3657,7 @@ var init_watcher = __esm(() => {
3380
3657
  var exports_indexer = {};
3381
3658
  __export(exports_indexer, {
3382
3659
  watchDirectory: () => watchDirectory,
3660
+ resetIndex: () => resetIndex,
3383
3661
  indexDirectory: () => indexDirectory,
3384
3662
  getIndexStatus: () => getIndexStatus,
3385
3663
  ensureIndexFresh: () => ensureIndexFresh,
@@ -3391,42 +3669,31 @@ import * as path12 from "path";
3391
3669
  async function indexDirectory(rootDir, options = {}) {
3392
3670
  const verbose = options.verbose ?? false;
3393
3671
  const quiet = options.quiet ?? false;
3672
+ const logger = options.logger ? options.logger : quiet ? createSilentLogger() : createLogger({ verbose });
3394
3673
  rootDir = path12.resolve(rootDir);
3395
3674
  const location = getIndexLocation(rootDir);
3396
- if (!quiet) {
3397
- console.log(`Indexing directory: ${rootDir}`);
3398
- console.log(`Index location: ${location.indexDir}`);
3399
- }
3675
+ logger.info(`Indexing directory: ${rootDir}`);
3676
+ logger.info(`Index location: ${location.indexDir}`);
3400
3677
  const config = await loadConfig(rootDir);
3401
3678
  const introspection = new IntrospectionIndex(rootDir);
3402
3679
  await introspection.initialize();
3403
- if (verbose) {
3404
- const structure = introspection.getStructure();
3405
- if (structure?.isMonorepo) {
3406
- console.log(`Detected monorepo with ${structure.projects.length} projects`);
3407
- }
3680
+ const structure = introspection.getStructure();
3681
+ if (structure?.isMonorepo) {
3682
+ logger.debug(`Detected monorepo with ${structure.projects.length} projects`);
3408
3683
  }
3409
3684
  await registerBuiltInModules();
3410
3685
  const enabledModules = registry.getEnabled(config);
3411
3686
  if (enabledModules.length === 0) {
3412
- if (!quiet) {
3413
- console.log("No modules enabled. Check your configuration.");
3414
- }
3687
+ logger.info("No modules enabled. Check your configuration.");
3415
3688
  return [];
3416
3689
  }
3417
- if (!quiet) {
3418
- console.log(`Enabled modules: ${enabledModules.map((m) => m.id).join(", ")}`);
3419
- }
3690
+ logger.info(`Enabled modules: ${enabledModules.map((m) => m.id).join(", ")}`);
3420
3691
  const files = await findFiles(rootDir, config);
3421
- if (!quiet) {
3422
- console.log(`Found ${files.length} files to index`);
3423
- }
3692
+ logger.info(`Found ${files.length} files to index`);
3424
3693
  const results = [];
3425
3694
  for (const module of enabledModules) {
3426
- if (!quiet) {
3427
- console.log(`
3695
+ logger.info(`
3428
3696
  [${module.name}] Starting indexing...`);
3429
- }
3430
3697
  const moduleConfig = getModuleConfig(config, module.id);
3431
3698
  if (module.initialize && moduleConfig) {
3432
3699
  const configWithOverrides = { ...moduleConfig };
@@ -3436,14 +3703,16 @@ async function indexDirectory(rootDir, options = {}) {
3436
3703
  embeddingModel: options.model
3437
3704
  };
3438
3705
  }
3706
+ configWithOverrides.options = {
3707
+ ...configWithOverrides.options,
3708
+ logger
3709
+ };
3439
3710
  await module.initialize(configWithOverrides);
3440
3711
  }
3441
- const result = await indexWithModule(rootDir, files, module, config, verbose, introspection);
3712
+ const result = await indexWithModule(rootDir, files, module, config, verbose, introspection, logger);
3442
3713
  results.push(result);
3443
3714
  if (module.finalize) {
3444
- if (!quiet) {
3445
- console.log(`[${module.name}] Building secondary indexes...`);
3446
- }
3715
+ logger.info(`[${module.name}] Building secondary indexes...`);
3447
3716
  const ctx = {
3448
3717
  rootDir,
3449
3718
  config,
@@ -3459,9 +3728,7 @@ async function indexDirectory(rootDir, options = {}) {
3459
3728
  };
3460
3729
  await module.finalize(ctx);
3461
3730
  }
3462
- if (!quiet) {
3463
- console.log(`[${module.name}] Complete: ${result.indexed} indexed, ${result.skipped} skipped, ${result.errors} errors`);
3464
- }
3731
+ logger.info(`[${module.name}] Complete: ${result.indexed} indexed, ${result.skipped} skipped, ${result.errors} errors`);
3465
3732
  }
3466
3733
  await introspection.save(config);
3467
3734
  await updateGlobalManifest(rootDir, enabledModules, config);
@@ -3484,28 +3751,37 @@ async function deleteIndex(rootDir) {
3484
3751
  await fs6.rm(indexDir, { recursive: true, force: true });
3485
3752
  } catch {}
3486
3753
  }
3754
+ async function resetIndex(rootDir) {
3755
+ rootDir = path12.resolve(rootDir);
3756
+ const status = await getIndexStatus(rootDir);
3757
+ if (!status.exists) {
3758
+ throw new Error(`No index found for ${rootDir}`);
3759
+ }
3760
+ await deleteIndex(rootDir);
3761
+ return {
3762
+ success: true,
3763
+ indexDir: status.indexDir
3764
+ };
3765
+ }
3487
3766
  async function ensureIndexFresh(rootDir, options = {}) {
3488
3767
  const verbose = options.verbose ?? false;
3489
3768
  const quiet = options.quiet ?? false;
3769
+ const logger = options.logger ? options.logger : quiet ? createSilentLogger() : createLogger({ verbose });
3490
3770
  rootDir = path12.resolve(rootDir);
3491
3771
  const status = await getIndexStatus(rootDir);
3492
3772
  if (!status.exists) {
3493
- if (!quiet) {
3494
- console.log(`No index found. Creating index...
3773
+ logger.info(`No index found. Creating index...
3495
3774
  `);
3496
- }
3497
- const results = await indexDirectory(rootDir, { ...options, quiet });
3775
+ const results = await indexDirectory(rootDir, { ...options, logger });
3498
3776
  const totalIndexed2 = results.reduce((sum, r) => sum + r.indexed, 0);
3499
3777
  return { indexed: totalIndexed2, removed: 0, unchanged: 0 };
3500
3778
  }
3501
3779
  const versionCompatible = await isIndexVersionCompatible(rootDir);
3502
3780
  if (!versionCompatible) {
3503
- if (!quiet) {
3504
- console.log(`Index version incompatible. Rebuilding...
3781
+ logger.info(`Index version incompatible. Rebuilding...
3505
3782
  `);
3506
- }
3507
3783
  await deleteIndex(rootDir);
3508
- const results = await indexDirectory(rootDir, { ...options, quiet });
3784
+ const results = await indexDirectory(rootDir, { ...options, logger });
3509
3785
  const totalIndexed2 = results.reduce((sum, r) => sum + r.indexed, 0);
3510
3786
  return { indexed: totalIndexed2, removed: 0, unchanged: 0 };
3511
3787
  }
@@ -3532,6 +3808,10 @@ async function ensureIndexFresh(rootDir, options = {}) {
3532
3808
  embeddingModel: options.model
3533
3809
  };
3534
3810
  }
3811
+ configWithOverrides.options = {
3812
+ ...configWithOverrides.options,
3813
+ logger
3814
+ };
3535
3815
  await module.initialize(configWithOverrides);
3536
3816
  }
3537
3817
  const manifest = await loadModuleManifest(rootDir, module.id, config);
@@ -3543,9 +3823,7 @@ async function ensureIndexFresh(rootDir, options = {}) {
3543
3823
  }
3544
3824
  }
3545
3825
  for (const filepath of filesToRemove) {
3546
- if (verbose) {
3547
- console.log(` Removing stale: ${filepath}`);
3548
- }
3826
+ logger.debug(` Removing stale: ${filepath}`);
3549
3827
  const indexFilePath = path12.join(indexPath, filepath.replace(/\.[^.]+$/, ".json"));
3550
3828
  try {
3551
3829
  await fs6.unlink(indexFilePath);
@@ -3571,8 +3849,11 @@ async function ensureIndexFresh(rootDir, options = {}) {
3571
3849
  },
3572
3850
  getIntrospection: (filepath) => introspection.getFile(filepath)
3573
3851
  };
3574
- for (const filepath of currentFiles) {
3852
+ const totalFiles = currentFiles.length;
3853
+ for (let i = 0;i < currentFiles.length; i++) {
3854
+ const filepath = currentFiles[i];
3575
3855
  const relativePath = path12.relative(rootDir, filepath);
3856
+ const progress = `[${i + 1}/${totalFiles}]`;
3576
3857
  try {
3577
3858
  const stats = await fs6.stat(filepath);
3578
3859
  const lastModified = stats.mtime.toISOString();
@@ -3581,9 +3862,7 @@ async function ensureIndexFresh(rootDir, options = {}) {
3581
3862
  totalUnchanged++;
3582
3863
  continue;
3583
3864
  }
3584
- if (verbose) {
3585
- console.log(` Indexing: ${relativePath}`);
3586
- }
3865
+ logger.progress(` ${progress} Indexing: ${relativePath}`);
3587
3866
  const content = await fs6.readFile(filepath, "utf-8");
3588
3867
  introspection.addFile(relativePath, content);
3589
3868
  const fileIndex = await module.indexFile(relativePath, content, ctx);
@@ -3596,11 +3875,11 @@ async function ensureIndexFresh(rootDir, options = {}) {
3596
3875
  totalIndexed++;
3597
3876
  }
3598
3877
  } catch (error) {
3599
- if (verbose) {
3600
- console.error(` Error indexing ${relativePath}:`, error);
3601
- }
3878
+ logger.clearProgress();
3879
+ logger.error(` ${progress} Error indexing ${relativePath}: ${error}`);
3602
3880
  }
3603
3881
  }
3882
+ logger.clearProgress();
3604
3883
  if (totalIndexed > 0 || totalRemoved > 0) {
3605
3884
  manifest.lastUpdated = new Date().toISOString();
3606
3885
  await writeModuleManifest(rootDir, module.id, manifest, config);
@@ -3624,7 +3903,7 @@ async function ensureIndexFresh(rootDir, options = {}) {
3624
3903
  unchanged: totalUnchanged
3625
3904
  };
3626
3905
  }
3627
- async function indexWithModule(rootDir, files, module, config, verbose, introspection) {
3906
+ async function indexWithModule(rootDir, files, module, config, verbose, introspection, logger) {
3628
3907
  const result = {
3629
3908
  moduleId: module.id,
3630
3909
  indexed: 0,
@@ -3632,6 +3911,30 @@ async function indexWithModule(rootDir, files, module, config, verbose, introspe
3632
3911
  errors: 0
3633
3912
  };
3634
3913
  const manifest = await loadModuleManifest(rootDir, module.id, config);
3914
+ const indexPath = getModuleIndexPath(rootDir, module.id, config);
3915
+ const currentFileSet = new Set(files.map((f) => path12.relative(rootDir, f)));
3916
+ const filesToRemove = [];
3917
+ for (const filepath of Object.keys(manifest.files)) {
3918
+ if (!currentFileSet.has(filepath)) {
3919
+ filesToRemove.push(filepath);
3920
+ }
3921
+ }
3922
+ if (filesToRemove.length > 0) {
3923
+ logger.info(` Removing ${filesToRemove.length} stale entries...`);
3924
+ for (const filepath of filesToRemove) {
3925
+ logger.debug(` Removing: ${filepath}`);
3926
+ const indexFilePath = path12.join(indexPath, filepath.replace(/\.[^.]+$/, ".json"));
3927
+ try {
3928
+ await fs6.unlink(indexFilePath);
3929
+ } catch {}
3930
+ const symbolicFilePath = path12.join(indexPath, "symbolic", filepath.replace(/\.[^.]+$/, ".json"));
3931
+ try {
3932
+ await fs6.unlink(symbolicFilePath);
3933
+ } catch {}
3934
+ delete manifest.files[filepath];
3935
+ }
3936
+ await cleanupEmptyDirectories(indexPath);
3937
+ }
3635
3938
  const ctx = {
3636
3939
  rootDir,
3637
3940
  config,
@@ -3646,29 +3949,26 @@ async function indexWithModule(rootDir, files, module, config, verbose, introspe
3646
3949
  },
3647
3950
  getIntrospection: (filepath) => introspection.getFile(filepath)
3648
3951
  };
3649
- for (const filepath of files) {
3952
+ const totalFiles = files.length;
3953
+ for (let i = 0;i < files.length; i++) {
3954
+ const filepath = files[i];
3650
3955
  const relativePath = path12.relative(rootDir, filepath);
3956
+ const progress = `[${i + 1}/${totalFiles}]`;
3651
3957
  try {
3652
3958
  const stats = await fs6.stat(filepath);
3653
3959
  const lastModified = stats.mtime.toISOString();
3654
3960
  const existingEntry = manifest.files[relativePath];
3655
3961
  if (existingEntry && existingEntry.lastModified === lastModified) {
3656
- if (verbose) {
3657
- console.log(` Skipped ${relativePath} (unchanged)`);
3658
- }
3962
+ logger.debug(` ${progress} Skipped ${relativePath} (unchanged)`);
3659
3963
  result.skipped++;
3660
3964
  continue;
3661
3965
  }
3662
3966
  const content = await fs6.readFile(filepath, "utf-8");
3663
3967
  introspection.addFile(relativePath, content);
3664
- if (verbose) {
3665
- console.log(` Processing ${relativePath}...`);
3666
- }
3968
+ logger.progress(` ${progress} Processing: ${relativePath}`);
3667
3969
  const fileIndex = await module.indexFile(relativePath, content, ctx);
3668
3970
  if (!fileIndex) {
3669
- if (verbose) {
3670
- console.log(` Skipped ${relativePath} (no chunks)`);
3671
- }
3971
+ logger.debug(` ${progress} Skipped ${relativePath} (no chunks)`);
3672
3972
  result.skipped++;
3673
3973
  continue;
3674
3974
  }
@@ -3679,10 +3979,12 @@ async function indexWithModule(rootDir, files, module, config, verbose, introspe
3679
3979
  };
3680
3980
  result.indexed++;
3681
3981
  } catch (error) {
3682
- console.error(` Error indexing ${relativePath}:`, error);
3982
+ logger.clearProgress();
3983
+ logger.error(` ${progress} Error indexing ${relativePath}: ${error}`);
3683
3984
  result.errors++;
3684
3985
  }
3685
3986
  }
3987
+ logger.clearProgress();
3686
3988
  manifest.lastUpdated = new Date().toISOString();
3687
3989
  await writeModuleManifest(rootDir, module.id, manifest, config);
3688
3990
  return result;
@@ -3738,26 +4040,27 @@ async function updateGlobalManifest(rootDir, modules, config) {
3738
4040
  }
3739
4041
  async function cleanupIndex(rootDir, options = {}) {
3740
4042
  const verbose = options.verbose ?? false;
4043
+ const logger = options.logger ?? createLogger({ verbose });
3741
4044
  rootDir = path12.resolve(rootDir);
3742
- console.log(`Cleaning up index in: ${rootDir}`);
4045
+ logger.info(`Cleaning up index in: ${rootDir}`);
3743
4046
  const config = await loadConfig(rootDir);
3744
4047
  await registerBuiltInModules();
3745
4048
  const enabledModules = registry.getEnabled(config);
3746
4049
  if (enabledModules.length === 0) {
3747
- console.log("No modules enabled.");
4050
+ logger.info("No modules enabled.");
3748
4051
  return [];
3749
4052
  }
3750
4053
  const results = [];
3751
4054
  for (const module of enabledModules) {
3752
- console.log(`
4055
+ logger.info(`
3753
4056
  [${module.name}] Checking for stale entries...`);
3754
- const result = await cleanupModuleIndex(rootDir, module.id, config, verbose);
4057
+ const result = await cleanupModuleIndex(rootDir, module.id, config, logger);
3755
4058
  results.push(result);
3756
- console.log(`[${module.name}] Removed ${result.removed} stale entries, kept ${result.kept} valid entries`);
4059
+ logger.info(`[${module.name}] Removed ${result.removed} stale entries, kept ${result.kept} valid entries`);
3757
4060
  }
3758
4061
  return results;
3759
4062
  }
3760
- async function cleanupModuleIndex(rootDir, moduleId, config, verbose) {
4063
+ async function cleanupModuleIndex(rootDir, moduleId, config, logger) {
3761
4064
  const result = {
3762
4065
  moduleId,
3763
4066
  removed: 0,
@@ -3776,9 +4079,7 @@ async function cleanupModuleIndex(rootDir, moduleId, config, verbose) {
3776
4079
  } catch {
3777
4080
  filesToRemove.push(filepath);
3778
4081
  result.removed++;
3779
- if (verbose) {
3780
- console.log(` Removing stale entry: ${filepath}`);
3781
- }
4082
+ logger.debug(` Removing stale entry: ${filepath}`);
3782
4083
  }
3783
4084
  }
3784
4085
  for (const filepath of filesToRemove) {
@@ -3874,9 +4175,15 @@ var init_indexer = __esm(() => {
3874
4175
  init_config2();
3875
4176
  init_registry();
3876
4177
  init_introspection2();
4178
+ init_logger();
3877
4179
  init_watcher();
3878
4180
  });
3879
4181
 
4182
+ // src/types.ts
4183
+ var init_types = __esm(() => {
4184
+ init_entities();
4185
+ });
4186
+
3880
4187
  // src/app/search/index.ts
3881
4188
  var exports_search = {};
3882
4189
  __export(exports_search, {
@@ -3887,12 +4194,16 @@ import * as fs7 from "fs/promises";
3887
4194
  import * as path13 from "path";
3888
4195
  async function search(rootDir, query, options = {}) {
3889
4196
  rootDir = path13.resolve(rootDir);
4197
+ const ensureFresh = options.ensureFresh ?? DEFAULT_SEARCH_OPTIONS.ensureFresh;
4198
+ if (ensureFresh) {
4199
+ await ensureIndexFresh(rootDir, { quiet: true });
4200
+ }
3890
4201
  console.log(`Searching for: "${query}"`);
3891
4202
  const config = await loadConfig(rootDir);
3892
4203
  await registerBuiltInModules();
3893
4204
  const globalManifest = await loadGlobalManifest(rootDir, config);
3894
4205
  if (!globalManifest || globalManifest.modules.length === 0) {
3895
- console.log('No index found. Run "bun run index" first.');
4206
+ console.log('No index found. Run "raggrep index" first.');
3896
4207
  return [];
3897
4208
  }
3898
4209
  const modulesToSearch = [];
@@ -4015,16 +4326,19 @@ function formatSearchResults(results) {
4015
4326
  return output;
4016
4327
  }
4017
4328
  var init_search = __esm(() => {
4329
+ init_types();
4018
4330
  init_config2();
4019
4331
  init_registry();
4332
+ init_indexer();
4020
4333
  });
4021
4334
 
4022
4335
  // src/app/cli/main.ts
4023
4336
  init_embeddings();
4337
+ init_logger();
4024
4338
  // package.json
4025
4339
  var package_default = {
4026
4340
  name: "raggrep",
4027
- version: "0.2.3",
4341
+ version: "0.4.0",
4028
4342
  description: "Local filesystem-based RAG system for codebases - semantic search using local embeddings",
4029
4343
  type: "module",
4030
4344
  main: "./dist/index.js",
@@ -4198,13 +4512,15 @@ Examples:
4198
4512
  process.exit(0);
4199
4513
  }
4200
4514
  const { indexDirectory: indexDirectory2, watchDirectory: watchDirectory2 } = await Promise.resolve().then(() => (init_indexer(), exports_indexer));
4515
+ const logger = createInlineLogger({ verbose: flags.verbose });
4201
4516
  console.log("RAGgrep Indexer");
4202
4517
  console.log(`================
4203
4518
  `);
4204
4519
  try {
4205
4520
  const results = await indexDirectory2(process.cwd(), {
4206
4521
  model: flags.model,
4207
- verbose: flags.verbose
4522
+ verbose: flags.verbose,
4523
+ logger
4208
4524
  });
4209
4525
  console.log(`
4210
4526
  ================`);
@@ -4289,9 +4605,11 @@ Examples:
4289
4605
  process.exit(1);
4290
4606
  }
4291
4607
  try {
4608
+ const silentLogger = createSilentLogger();
4292
4609
  const freshStats = await ensureIndexFresh2(process.cwd(), {
4293
4610
  model: flags.model,
4294
- quiet: true
4611
+ quiet: true,
4612
+ logger: silentLogger
4295
4613
  });
4296
4614
  console.log("RAGgrep Search");
4297
4615
  console.log(`==============
@@ -4314,7 +4632,8 @@ Examples:
4314
4632
  const results = await search2(process.cwd(), query, {
4315
4633
  topK: flags.topK ?? 10,
4316
4634
  minScore: flags.minScore,
4317
- filePatterns
4635
+ filePatterns,
4636
+ ensureFresh: false
4318
4637
  });
4319
4638
  console.log(formatSearchResults2(results));
4320
4639
  } catch (error) {
@@ -4323,44 +4642,37 @@ Examples:
4323
4642
  }
4324
4643
  break;
4325
4644
  }
4326
- case "cleanup": {
4645
+ case "reset": {
4327
4646
  if (flags.help) {
4328
4647
  console.log(`
4329
- raggrep cleanup - Remove stale index entries for deleted files
4648
+ raggrep reset - Clear the index for the current directory
4330
4649
 
4331
4650
  Usage:
4332
- raggrep cleanup [options]
4651
+ raggrep reset [options]
4333
4652
 
4334
4653
  Options:
4335
- -v, --verbose Show detailed progress
4336
4654
  -h, --help Show this help message
4337
4655
 
4338
4656
  Description:
4339
- Scans the index and removes entries for files that no longer exist.
4340
- Run this command after deleting files to clean up the index.
4657
+ Completely removes the index for the current directory.
4658
+ The next 'raggrep index' or 'raggrep query' will rebuild from scratch.
4341
4659
 
4342
4660
  Examples:
4343
- raggrep cleanup
4344
- raggrep cleanup --verbose
4661
+ raggrep reset
4345
4662
  `);
4346
4663
  process.exit(0);
4347
4664
  }
4348
- const { cleanupIndex: cleanupIndex2 } = await Promise.resolve().then(() => (init_indexer(), exports_indexer));
4349
- console.log("RAGgrep Cleanup");
4350
- console.log(`===============
4351
- `);
4665
+ const { resetIndex: resetIndex2 } = await Promise.resolve().then(() => (init_indexer(), exports_indexer));
4352
4666
  try {
4353
- const results = await cleanupIndex2(process.cwd(), {
4354
- verbose: flags.verbose
4355
- });
4356
- console.log(`
4357
- ===============`);
4358
- console.log("Summary:");
4359
- for (const result of results) {
4360
- console.log(` ${result.moduleId}: ${result.removed} removed, ${result.kept} kept`);
4361
- }
4667
+ const result = await resetIndex2(process.cwd());
4668
+ console.log("Index cleared successfully.");
4669
+ console.log(` Removed: ${result.indexDir}`);
4362
4670
  } catch (error) {
4363
- console.error("Error during cleanup:", error);
4671
+ if (error instanceof Error && error.message.includes("No index found")) {
4672
+ console.error("Error: No index found for this directory.");
4673
+ process.exit(1);
4674
+ }
4675
+ console.error("Error during reset:", error);
4364
4676
  process.exit(1);
4365
4677
  }
4366
4678
  break;
@@ -4439,7 +4751,7 @@ Commands:
4439
4751
  index Index the current directory
4440
4752
  query Search the indexed codebase
4441
4753
  status Show the current state of the index
4442
- cleanup Remove stale index entries for deleted files
4754
+ reset Clear the index for the current directory
4443
4755
 
4444
4756
  Options:
4445
4757
  -h, --help Show help for a command
@@ -4449,7 +4761,7 @@ Examples:
4449
4761
  raggrep index
4450
4762
  raggrep query "user login"
4451
4763
  raggrep status
4452
- raggrep cleanup
4764
+ raggrep reset
4453
4765
 
4454
4766
  Run 'raggrep <command> --help' for more information.
4455
4767
  `);
@@ -4461,4 +4773,4 @@ Run 'raggrep <command> --help' for more information.
4461
4773
  }
4462
4774
  main();
4463
4775
 
4464
- //# debugId=DB928D21A583DAC064756E2164756E21
4776
+ //# debugId=B729BEE1B814E8D564756E2164756E21