raggrep 0.12.1 → 0.12.3

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
@@ -290,11 +290,13 @@ class InlineProgressLogger {
290
290
  }
291
291
  }
292
292
  progress(message) {
293
- process.stdout.write(`\r${message}`);
294
- const padding = Math.max(0, this.lastProgressLength - message.length);
293
+ const maxCols = 120;
294
+ process.stdout.write("\r" + message);
295
+ const padding = Math.max(0, maxCols - message.length);
295
296
  if (padding > 0) {
296
297
  process.stdout.write(" ".repeat(padding));
297
298
  }
299
+ process.stdout.write("\r");
298
300
  this.lastProgressLength = message.length;
299
301
  this.hasProgress = true;
300
302
  }
@@ -325,6 +327,116 @@ function createSilentLogger() {
325
327
  return new SilentLogger;
326
328
  }
327
329
 
330
+ // src/infrastructure/logger/progressManager.ts
331
+ class ProgressManager {
332
+ logger;
333
+ state = {
334
+ completed: 0,
335
+ total: 0,
336
+ message: "",
337
+ timestamp: 0
338
+ };
339
+ intervalId = null;
340
+ constructor(logger) {
341
+ this.logger = logger;
342
+ }
343
+ start() {
344
+ if (this.intervalId) {
345
+ return;
346
+ }
347
+ this.intervalId = setInterval(() => {
348
+ this.writeProgress();
349
+ }, PROGRESS_UPDATE_INTERVAL_MS);
350
+ }
351
+ stop() {
352
+ if (this.intervalId) {
353
+ clearInterval(this.intervalId);
354
+ this.intervalId = null;
355
+ }
356
+ this.logger.clearProgress();
357
+ }
358
+ reportProgress(completed, total, message) {
359
+ this.state = {
360
+ completed,
361
+ total,
362
+ message,
363
+ timestamp: Date.now()
364
+ };
365
+ }
366
+ writeProgress() {
367
+ const progressMessage = ` [${this.state.completed}/${this.state.total}] ${this.state.message}`;
368
+ this.logger.progress(progressMessage);
369
+ }
370
+ }
371
+ var PROGRESS_UPDATE_INTERVAL_MS = 50;
372
+
373
+ // src/infrastructure/logger/multiModuleProgressManager.ts
374
+ class MultiModuleProgressManager {
375
+ logger;
376
+ modules = new Map;
377
+ intervalId = null;
378
+ constructor(logger) {
379
+ this.logger = logger;
380
+ }
381
+ start() {
382
+ if (this.intervalId) {
383
+ return;
384
+ }
385
+ this.intervalId = setInterval(() => {
386
+ this.writeProgress();
387
+ }, PROGRESS_UPDATE_INTERVAL_MS2);
388
+ }
389
+ stop() {
390
+ if (this.intervalId) {
391
+ clearInterval(this.intervalId);
392
+ this.intervalId = null;
393
+ }
394
+ this.logger.clearProgress();
395
+ }
396
+ registerModule(moduleId, moduleName, totalFiles) {
397
+ this.modules.set(moduleId, {
398
+ moduleName,
399
+ completed: 0,
400
+ total: totalFiles,
401
+ currentFile: "",
402
+ active: true
403
+ });
404
+ }
405
+ unregisterModule(moduleId) {
406
+ const module2 = this.modules.get(moduleId);
407
+ if (module2) {
408
+ module2.active = false;
409
+ }
410
+ }
411
+ reportProgress(moduleId, completed, currentFile) {
412
+ const module2 = this.modules.get(moduleId);
413
+ if (!module2) {
414
+ return;
415
+ }
416
+ module2.completed = completed;
417
+ module2.currentFile = currentFile;
418
+ }
419
+ writeProgress() {
420
+ const activeModules = Array.from(this.modules.values()).filter((m) => m.active);
421
+ if (activeModules.length === 0) {
422
+ return;
423
+ }
424
+ if (activeModules.length === 1) {
425
+ const m = activeModules[0];
426
+ const progressMessage = `[${m.moduleName}] ${m.completed}/${m.total}: ${m.currentFile}`;
427
+ this.logger.progress(progressMessage);
428
+ } else {
429
+ const parts2 = activeModules.map((m) => {
430
+ const percent = m.total > 0 ? Math.round(m.completed / m.total * 100) : 100;
431
+ return `[${m.moduleName} ${m.completed}/${m.total} ${percent}%]`;
432
+ });
433
+ const progressMessage = parts2.join(" ");
434
+ this.logger.progress(progressMessage);
435
+ }
436
+ }
437
+ }
438
+ var PROGRESS_UPDATE_INTERVAL_MS2 = 50;
439
+
328
440
  // src/infrastructure/logger/index.ts
329
441
  var init_logger = () => {};
330
442
 
@@ -932,7 +1044,24 @@ var init_config = __esm(() => {
932
1044
  ".pytest_cache",
933
1045
  "*.egg-info",
934
1046
  ".idea",
935
- ".raggrep"
1047
+ ".raggrep",
1048
+ ".DS_Store",
1049
+ "Thumbs.db",
1050
+ ".env",
1051
+ ".env.local",
1052
+ ".env.development.local",
1053
+ ".env.test.local",
1054
+ ".env.production.local",
1055
+ "*.lock",
1056
+ "package-lock.json",
1057
+ "yarn.lock",
1058
+ "pnpm-lock.yaml",
1059
+ "Cargo.lock",
1060
+ "poetry.lock",
1061
+ "Gemfile.lock",
1062
+ "go.sum",
1063
+ "*.min.js",
1064
+ "*.min.css"
936
1065
  ];
937
1066
  DEFAULT_EXTENSIONS = [
938
1067
  ".ts",
@@ -12215,8 +12344,15 @@ async function ensureIndexFresh(rootDir, options = {}) {
12215
12344
  }
12216
12345
  let completedCount = 0;
12217
12346
  const totalToProcess = filesToProcess.length;
12347
+ const progressManager = new ProgressManager(logger);
12348
+ progressManager.start();
12218
12349
  const processChangedFile = async (fileToProcess) => {
12219
12350
  const { filepath, relativePath, lastModified, isNew, existingContentHash } = fileToProcess;
12351
+ if (isLikelyBinary(filepath)) {
12352
+ completedCount++;
12353
+ logger.debug(` Skipping ${relativePath} (binary file)`);
12354
+ return { relativePath, status: "unchanged" };
12355
+ }
12220
12356
  try {
12221
12357
  const content = await fs8.readFile(filepath, "utf-8");
12222
12358
  const contentHash = computeContentHash(content);
@@ -12230,7 +12366,7 @@ async function ensureIndexFresh(rootDir, options = {}) {
12230
12366
  };
12231
12367
  }
12232
12368
  completedCount++;
12233
- logger.progress(` [${completedCount}/${totalToProcess}] Indexing: ${relativePath}`);
12369
+ progressManager.reportProgress(completedCount, totalToProcess, `Indexing: ${relativePath}`);
12234
12370
  introspection.addFile(relativePath, content);
12235
12371
  const fileIndex = await module2.indexFile(relativePath, content, ctx);
12236
12372
  if (!fileIndex) {
@@ -12253,6 +12389,7 @@ async function ensureIndexFresh(rootDir, options = {}) {
12253
12389
  const concurrency = options.concurrency ?? DEFAULT_CONCURRENCY;
12254
12390
  const results = await parallelMap(filesToProcess, processChangedFile, concurrency);
12255
12391
  indexingMs += Date.now() - indexingStart;
12392
+ progressManager.stop();
12256
12393
  totalUnchanged += unchangedCount;
12257
12394
  logger.clearProgress();
12258
12395
  let mtimeUpdates = 0;
@@ -12387,9 +12524,16 @@ async function indexWithModule(rootDir, files, module2, config, verbose, introsp
12387
12524
  getIntrospection: (filepath) => introspection.getFile(filepath)
12388
12525
  };
12389
12526
  const totalFiles = files.length;
12527
+ const progressManager = new ProgressManager(logger);
12528
+ progressManager.start();
12390
12529
  let completedCount = 0;
12391
12530
  const processFile = async (filepath, _index) => {
12392
12531
  const relativePath = path22.relative(rootDir, filepath);
12532
+ if (isLikelyBinary(filepath)) {
12533
+ completedCount++;
12534
+ logger.debug(` [${completedCount}/${totalFiles}] Skipped ${relativePath} (binary file)`);
12535
+ return { relativePath, status: "skipped" };
12536
+ }
12393
12537
  try {
12394
12538
  const stats = await fs8.stat(filepath);
12395
12539
  const lastModified = stats.mtime.toISOString();
@@ -12413,7 +12557,7 @@ async function indexWithModule(rootDir, files, module2, config, verbose, introsp
12413
12557
  }
12414
12558
  introspection.addFile(relativePath, content);
12415
12559
  completedCount++;
12416
- logger.progress(` [${completedCount}/${totalFiles}] Processing: ${relativePath}`);
12560
+ progressManager.reportProgress(completedCount, totalFiles, `Processing: ${relativePath}`);
12417
12561
  const fileIndex = await module2.indexFile(relativePath, content, ctx);
12418
12562
  if (!fileIndex) {
12419
12563
  logger.debug(` [${completedCount}/${totalFiles}] Skipped ${relativePath} (no chunks)`);
@@ -12434,6 +12578,7 @@ async function indexWithModule(rootDir, files, module2, config, verbose, introsp
12434
12578
  };
12435
12579
  logger.debug(` Using concurrency: ${concurrency}`);
12436
12580
  const results = await parallelMap(files, processFile, concurrency);
12581
+ progressManager.stop();
12437
12582
  logger.clearProgress();
12438
12583
  for (const item of results) {
12439
12584
  if (!item.success) {
@@ -12473,6 +12618,79 @@ async function indexWithModule(rootDir, files, module2, config, verbose, introsp
12473
12618
  await writeModuleManifest(rootDir, module2.id, manifest, config);
12474
12619
  return result;
12475
12620
  }
12621
+ function isLikelyBinary(filepath) {
12622
+ const ext = path22.extname(filepath).toLowerCase();
12623
+ const basename15 = path22.basename(filepath).toLowerCase();
12624
+ const binaryExtensions = new Set([
12625
+ ".png",
12626
+ ".jpg",
12627
+ ".jpeg",
12628
+ ".gif",
12629
+ ".ico",
12630
+ ".svg",
12631
+ ".webp",
12632
+ ".bmp",
12633
+ ".tiff",
12634
+ ".pdf",
12635
+ ".doc",
12636
+ ".docx",
12637
+ ".xls",
12638
+ ".xlsx",
12639
+ ".ppt",
12640
+ ".pptx",
12641
+ ".zip",
12642
+ ".tar",
12643
+ ".gz",
12644
+ ".7z",
12645
+ ".rar",
12646
+ ".bz2",
12647
+ ".exe",
12648
+ ".dll",
12649
+ ".so",
12650
+ ".dylib",
12651
+ ".bin",
12652
+ ".dat",
12653
+ ".obj",
12654
+ ".o",
12655
+ ".mp3",
12656
+ ".mp4",
12657
+ ".wav",
12658
+ ".avi",
12659
+ ".mov",
12660
+ ".flac",
12661
+ ".ogg",
12662
+ ".woff",
12663
+ ".woff2",
12664
+ ".ttf",
12665
+ ".eot",
12666
+ ".otf"
12667
+ ]);
12668
+ if (binaryExtensions.has(ext)) {
12669
+ return true;
12670
+ }
12671
+ const minifiedPatterns = [
12672
+ ".min.js",
12673
+ ".min.css",
12674
+ ".bundle.js",
12675
+ ".bundle.css",
12676
+ ".prod.js",
12677
+ ".prod.css",
12678
+ ".chunk.js",
12679
+ ".chunk.css"
12680
+ ];
12681
+ if (minifiedPatterns.some((pattern) => filepath.includes(pattern))) {
12682
+ return true;
12683
+ }
12684
+ const systemFiles = [
12685
+ ".ds_store",
12686
+ "thumbs.db",
12687
+ "desktop.ini"
12688
+ ];
12689
+ if (systemFiles.includes(basename15)) {
12690
+ return true;
12691
+ }
12692
+ return false;
12693
+ }
12476
12694
  async function findFilesWithStats(rootDir, config, lastIndexStarted) {
12477
12695
  const validExtensions = new Set(config.extensions);
12478
12696
  const ignoreDirs = new Set(config.ignorePaths);
@@ -14276,7 +14494,7 @@ init_logger();
14276
14494
  // package.json
14277
14495
  var package_default = {
14278
14496
  name: "raggrep",
14279
- version: "0.12.1",
14497
+ version: "0.12.3",
14280
14498
  description: "Local filesystem-based RAG system for codebases - semantic search using local embeddings",
14281
14499
  type: "module",
14282
14500
  main: "./dist/index.js",
@@ -14778,6 +14996,34 @@ Examples:
14778
14996
  const toolPath = path25.join(toolDir, "raggrep.ts");
14779
14997
  const toolContent = `import { tool } from "@opencode-ai/plugin";
14780
14998
 
14999
+ /**
15000
+ * Get the package executor command (pnpx if available, otherwise npx)
15001
+ */
15002
+ async function getExecutor(): Promise<string> {
15003
+ try {
15004
+ // Try to find pnpm first (faster)
15005
+ await Bun.spawn(['pnpm', '--version'], { stdout: 'pipe', stderr: 'pipe' }).exited;
15006
+ return 'pnpx';
15007
+ } catch {
15008
+ // Fall back to npx
15009
+ return 'npx';
15010
+ }
15011
+ }
15012
+
15013
+ /**
15014
+ * Get the installed raggrep version
15015
+ */
15016
+ async function getRagrepVersion(executor: string): Promise<string | null> {
15017
+ try {
15018
+ const proc = Bun.spawn([executor, 'raggrep', '--version'], { stdout: 'pipe', stderr: 'pipe' });
15019
+ const output = await new Response(proc.stdout).text();
15020
+ const match = output.match(/v([\\d.]+)/);
15021
+ return match ? match[1] : null;
15022
+ } catch {
15023
+ return null;
15024
+ }
15025
+ }
15026
+
14781
15027
  export default tool({
14782
15028
  description:
14783
15029
  "Semantic code search powered by RAG - understands INTENT, not just literal text. Parses code using AST to extract functions, classes, and symbols with full context. Finds relevant code even when exact keywords don't match. Superior to grep for exploratory searches like 'authentication logic', 'error handling patterns', or 'configuration loading'.\\n\\n\uD83C\uDFAF USE THIS TOOL FIRST when you need to:\\n• Find WHERE code is located (functions, components, services)\\n• Understand HOW code is structured\\n• Discover RELATED code across multiple files\\n• Get a QUICK overview of a topic\\n\\n❌ DON'T read multiple files manually when you can:\\n raggrep(\\"user authentication\\", { filter: [\\"src/\\"] })\\n\\n✅ INSTEAD of reading files one-by-one, search semantically:\\n • \\"Find the auth middleware\\" vs read: auth.ts, middleware.ts, index.ts...\\n • \\"Where are React components?\\" vs read: App.tsx, components/*, pages/*...\\n • \\"Database connection logic?\\" vs read: db.ts, config.ts, models/*...\\n • \\"Error handling patterns\\" vs read: error.ts, middleware.ts, handlers/*...\\n\\nThis saves ~10x tool calls and provides BETTER context by showing related code across the entire codebase.",
@@ -14808,6 +15054,13 @@ export default tool({
14808
15054
  ),
14809
15055
  },
14810
15056
  async execute(args) {
15057
+ const executor = await getExecutor();
15058
+ const version = await getRagrepVersion(executor);
15059
+
15060
+ if (!version) {
15061
+ return \`Error: raggrep not found. Install it with: \${executor} install -g raggrep\`;
15062
+ }
15063
+
14811
15064
  const cmdArgs = [args.query];
14812
15065
 
14813
15066
  if (args.top !== undefined) {
@@ -14825,7 +15078,7 @@ export default tool({
14825
15078
  }
14826
15079
  }
14827
15080
 
14828
- const proc = Bun.spawn(['raggrep', 'query', ...cmdArgs], { stdout: 'pipe' });
15081
+ const proc = Bun.spawn([executor, 'raggrep', 'query', ...cmdArgs], { stdout: 'pipe' });
14829
15082
  const result = await new Response(proc.stdout).text();
14830
15083
  return result.trim();
14831
15084
  },
@@ -14833,19 +15086,9 @@ export default tool({
14833
15086
  `;
14834
15087
  try {
14835
15088
  await fs10.mkdir(toolDir, { recursive: true });
14836
- let action = "Installed";
14837
- const backupPath = toolPath + ".backup";
14838
- try {
14839
- await fs10.access(toolPath);
14840
- await fs10.copyFile(toolPath, backupPath);
14841
- action = "Updated";
14842
- } catch {}
14843
15089
  await fs10.writeFile(toolPath, toolContent, "utf-8");
14844
- console.log(`${action} raggrep tool for opencode.`);
15090
+ console.log(`Installed raggrep tool for opencode.`);
14845
15091
  console.log(` Location: ${toolPath}`);
14846
- if (action === "Updated") {
14847
- console.log(` Backup: ${backupPath}`);
14848
- }
14849
15092
  console.log(`
14850
15093
  The raggrep tool is now available in opencode.`);
14851
15094
  } catch (error) {
@@ -14894,4 +15137,4 @@ Run 'raggrep <command> --help' for more information.
14894
15137
  }
14895
15138
  main();
14896
15139
 
14897
- //# debugId=7C2BD8137F58966D64756E2164756E21
15140
+ //# debugId=0D7443A2D252636E64756E2164756E21