raggrep 0.1.7 → 0.2.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/README.md CHANGED
@@ -1,160 +1,127 @@
1
1
  # RAGgrep
2
2
 
3
- **Local filesystem-based RAG system for codebases** — semantic search using local embeddings.
3
+ **Local semantic search for codebases** — find code using natural language queries.
4
4
 
5
- RAGgrep indexes your code and allows semantic search using natural language queries. Everything runs locally on your machine — no external API calls required.
5
+ RAGgrep indexes your code and lets you search it using natural language. Everything runs locally — no external API calls required.
6
6
 
7
7
  ## Features
8
8
 
9
- - **🏠 Local-first** — All indexing and search happens locally. No cloud dependencies.
10
- - **📁 Filesystem-based** — Index stored as readable JSON files in system temp directory.
11
- - **⚡ Tiered search** — Fast keyword filtering + semantic search for efficiency.
12
- - **🔍 Hybrid scoring** — Combines semantic similarity with BM25 keyword matching.
13
- - **🔄 Incremental** — Only re-indexes files that have changed.
14
- - **📝 TypeScript-optimized** — AST-based parsing extracts functions, classes, interfaces, types.
15
- - **🎯 Zero config** — Works out of the box with sensible defaults.
9
+ - **Zero-config search** — Just run `raggrep query` and it works. Index is created and updated automatically.
10
+ - **Local-first** — All indexing and search happens on your machine. No cloud dependencies.
11
+ - **Incremental**Only re-indexes files that have changed. Instant search when nothing changed.
12
+ - **Watch mode** — Keep the index fresh in real-time as you code.
13
+ - **Hybrid search** — Combines semantic similarity with keyword matching for best results.
16
14
 
17
15
  ## Installation
18
16
 
19
17
  ```bash
20
- # Install globally with npm
18
+ # Install globally
21
19
  npm install -g raggrep
22
20
 
23
- # Or with Bun (recommended)
24
- bun install -g raggrep
25
-
26
21
  # Or use without installing
27
- npx raggrep --help
22
+ npx raggrep query "your search"
28
23
  ```
29
24
 
30
- ## Quick Start
25
+ ## Usage
26
+
27
+ ### Search Your Code
31
28
 
32
29
  ```bash
33
- # Index your project
34
30
  cd your-project
35
- raggrep index
36
-
37
- # Search your codebase
38
31
  raggrep query "user authentication"
39
32
  ```
40
33
 
34
+ That's it. The first query creates the index automatically. Subsequent queries are instant if files haven't changed. Modified files are re-indexed on the fly.
35
+
41
36
  ### Example Output
42
37
 
43
38
  ```
39
+ Index updated: 42 indexed
40
+
41
+ RAGgrep Search
42
+ ==============
43
+
44
+ Searching for: "user authentication"
45
+
44
46
  Found 3 results:
45
47
 
46
48
  1. src/auth/authService.ts:24-55 (login)
47
- Score: 34.4% | Type: function | exported
48
- export async function login(credentials: LoginCredentials): Promise<AuthResult> ...
49
+ Score: 34.4% | Type: function | via TypeScript | exported
50
+ export async function login(credentials: LoginCredentials): Promise<AuthResult> {
51
+ const { email, password } = credentials;
49
52
 
50
- 2. src/auth/authService.ts:60-62 (logout)
51
- Score: 27.5% | Type: function | exported
52
- export async function logout(token: string): Promise<void> {
53
+ 2. src/auth/session.ts:10-25 (createSession)
54
+ Score: 28.2% | Type: function | via TypeScript | exported
55
+ export function createSession(user: User): Session {
53
56
 
54
57
  3. src/users/types.ts:3-12 (User)
55
- Score: 26.0% | Type: interface | exported
58
+ Score: 26.0% | Type: interface | via TypeScript | exported
56
59
  export interface User {
57
60
  id: string;
58
61
  ```
59
62
 
60
- ## Programmatic API
61
-
62
- ```typescript
63
- import raggrep from "raggrep";
64
-
65
- // Index a directory
66
- await raggrep.index("./my-project");
63
+ ### Watch Mode
67
64
 
68
- // Search
69
- const results = await raggrep.search("./my-project", "user authentication");
70
- console.log(raggrep.formatSearchResults(results));
65
+ Keep your index fresh in real-time while you code:
71
66
 
72
- // Cleanup stale entries
73
- await raggrep.cleanup("./my-project");
67
+ ```bash
68
+ raggrep index --watch
74
69
  ```
75
70
 
76
- ## CLI Reference
71
+ This monitors file changes and re-indexes automatically. Useful during active development when you want instant search results.
77
72
 
78
- ```bash
79
- # Index commands
80
- raggrep index # Index current directory
81
- raggrep index --watch # Watch mode: re-index on file changes
82
- raggrep index --model bge-small-en-v1.5 # Use different embedding model
83
- raggrep index --verbose # Show detailed progress
84
-
85
- # Search commands
86
- raggrep query "user login" # Basic search
87
- raggrep query "error handling" --top 5 # Limit results
88
- raggrep query "database" --min-score 0.1 # Lower threshold (more results)
89
- raggrep query "interface" --type ts # Filter by file type
90
-
91
- # Maintenance
92
- raggrep cleanup # Remove stale index entries
93
- raggrep status # Show index status
94
73
  ```
74
+ ┌─────────────────────────────────────────┐
75
+ │ Watching for changes... (Ctrl+C to stop) │
76
+ └─────────────────────────────────────────┘
95
77
 
96
- ## How It Works
78
+ [Watch] language/typescript: 2 indexed, 0 errors
79
+ ```
97
80
 
98
- RAGgrep uses a **dual-module architecture** with two complementary index types:
81
+ ## CLI Quick Reference
99
82
 
100
- ### Core Module
83
+ ```bash
84
+ # Search (auto-indexes if needed)
85
+ raggrep query "user login"
86
+ raggrep query "error handling" --top 5
87
+ raggrep query "database" --type ts
101
88
 
102
- - **Language-agnostic** regex-based symbol extraction
103
- - **BM25 keyword matching** for fast, deterministic search
104
- - Works on any text file
89
+ # Watch mode
90
+ raggrep index --watch
105
91
 
106
- ### TypeScript Module
92
+ # Check index status
93
+ raggrep status
94
+ ```
107
95
 
108
- - **AST-based parsing** via TypeScript Compiler API
109
- - **Semantic embeddings** for natural language understanding
110
- - **Symbolic index** for fast BM25 candidate filtering
96
+ ## How It Works
111
97
 
112
- Search combines results from both modules:
98
+ 1. **First query** Creates the index (takes 1-2 min for ~1000 files)
99
+ 2. **Subsequent queries** — Uses cached index (instant if no changes)
100
+ 3. **Files changed** — Re-indexes only modified files automatically
101
+ 4. **Files deleted** — Stale entries cleaned up automatically
113
102
 
114
- ```
115
- Query → Core (symbol/BM25) ─┐
116
- ├→ Merge & rank → Results
117
- Query → TypeScript (BM25 filter → semantic) ─┘
118
- ```
103
+ The index is stored in a system temp directory, keeping your project clean.
119
104
 
120
105
  ## What Gets Indexed
121
106
 
122
- **File types:** `.ts`, `.tsx`, `.js`, `.jsx`, `.py`, `.go`, `.rs`, `.java`, `.md`
123
-
124
- **Code structures:**
125
-
126
- - Functions (regular, async, arrow)
127
- - Classes (including abstract)
128
- - Interfaces
129
- - Type aliases
130
- - Enums
131
- - Exported variables
107
+ **File types:** `.ts`, `.tsx`, `.js`, `.jsx`, `.py`, `.go`, `.rs`, `.java`, `.md`, `.txt`
132
108
 
133
- **Automatically ignored:**
109
+ **Code structures:** Functions, classes, interfaces, types, enums, exports
134
110
 
135
- - `node_modules`, `dist`, `build`, `.git`
136
- - `.next`, `.nuxt`, `__pycache__`, `venv`
137
- - See [Configuration](./docs/configuration.md) for full list
111
+ **Automatically ignored:** `node_modules`, `dist`, `build`, `.git`, and other common directories
138
112
 
139
113
  ## Documentation
140
114
 
141
- - [Getting Started](./docs/getting-started.md) — Installation and first steps
115
+ - [Getting Started](./docs/getting-started.md) — Installation options and first steps
142
116
  - [CLI Reference](./docs/cli-reference.md) — All commands and options
143
- - [Configuration](./docs/configuration.md) — Customize indexing behavior
117
+ - [SDK Reference](./docs/sdk.md) — Programmatic API for Node.js/Bun
118
+ - [Advanced](./docs/advanced.md) — Configuration, maintenance commands
144
119
  - [Architecture](./docs/architecture.md) — How RAGgrep works internally
145
120
 
146
- ## Performance
147
-
148
- | Operation | Time | Notes |
149
- | ------------------------ | ---------- | -------------------------------------- |
150
- | Initial index (1k files) | 1-2 min | Embedding generation is the bottleneck |
151
- | Incremental update | <2s | Only changed files |
152
- | Search | ~100-500ms | Depends on codebase size |
153
-
154
121
  ## Requirements
155
122
 
156
123
  - Node.js 18+ or Bun 1.0+
157
- - ~50MB disk space for models (cached globally at `~/.cache/raggrep/models/`)
124
+ - ~50MB disk space for models (cached at `~/.cache/raggrep/models/`)
158
125
 
159
126
  ## License
160
127
 
@@ -10,6 +10,16 @@ export interface IndexOptions {
10
10
  model?: EmbeddingModelName;
11
11
  /** Show detailed progress */
12
12
  verbose?: boolean;
13
+ /** Suppress most output (for use during query) */
14
+ quiet?: boolean;
15
+ }
16
+ export interface EnsureFreshResult {
17
+ /** Number of files indexed (new or modified) */
18
+ indexed: number;
19
+ /** Number of stale entries removed (deleted files) */
20
+ removed: number;
21
+ /** Number of files unchanged (used cache) */
22
+ unchanged: number;
13
23
  }
14
24
  export interface CleanupResult {
15
25
  moduleId: string;
@@ -40,6 +50,21 @@ export interface IndexStatus {
40
50
  * Index a directory using all enabled modules
41
51
  */
42
52
  export declare function indexDirectory(rootDir: string, options?: IndexOptions): Promise<IndexResult[]>;
53
+ /**
54
+ * Ensure the index is fresh by checking for changes and updating incrementally.
55
+ * This function is designed to be called before search to transparently manage the index.
56
+ *
57
+ * - If no index exists, creates a full index
58
+ * - If index version is incompatible, rebuilds from scratch
59
+ * - If files have changed, re-indexes only the modified files
60
+ * - If files have been deleted, removes stale entries
61
+ * - If nothing changed, returns immediately (uses cache)
62
+ *
63
+ * @param rootDir - Root directory of the project
64
+ * @param options - Index options
65
+ * @returns Statistics about what was updated
66
+ */
67
+ export declare function ensureIndexFresh(rootDir: string, options?: IndexOptions): Promise<EnsureFreshResult>;
43
68
  /**
44
69
  * Clean up stale index entries for files that no longer exist
45
70
  * @param rootDir - Root directory of the project
package/dist/cli/main.js CHANGED
@@ -3383,6 +3383,7 @@ __export(exports_indexer, {
3383
3383
  watchDirectory: () => watchDirectory,
3384
3384
  indexDirectory: () => indexDirectory,
3385
3385
  getIndexStatus: () => getIndexStatus,
3386
+ ensureIndexFresh: () => ensureIndexFresh,
3386
3387
  cleanupIndex: () => cleanupIndex
3387
3388
  });
3388
3389
  import { glob } from "glob";
@@ -3390,10 +3391,13 @@ import * as fs6 from "fs/promises";
3390
3391
  import * as path12 from "path";
3391
3392
  async function indexDirectory(rootDir, options = {}) {
3392
3393
  const verbose = options.verbose ?? false;
3394
+ const quiet = options.quiet ?? false;
3393
3395
  rootDir = path12.resolve(rootDir);
3394
3396
  const location = getIndexLocation(rootDir);
3395
- console.log(`Indexing directory: ${rootDir}`);
3396
- console.log(`Index location: ${location.indexDir}`);
3397
+ if (!quiet) {
3398
+ console.log(`Indexing directory: ${rootDir}`);
3399
+ console.log(`Index location: ${location.indexDir}`);
3400
+ }
3397
3401
  const config = await loadConfig(rootDir);
3398
3402
  const introspection = new IntrospectionIndex(rootDir);
3399
3403
  await introspection.initialize();
@@ -3406,16 +3410,24 @@ async function indexDirectory(rootDir, options = {}) {
3406
3410
  await registerBuiltInModules();
3407
3411
  const enabledModules = registry.getEnabled(config);
3408
3412
  if (enabledModules.length === 0) {
3409
- console.log("No modules enabled. Check your configuration.");
3413
+ if (!quiet) {
3414
+ console.log("No modules enabled. Check your configuration.");
3415
+ }
3410
3416
  return [];
3411
3417
  }
3412
- console.log(`Enabled modules: ${enabledModules.map((m) => m.id).join(", ")}`);
3418
+ if (!quiet) {
3419
+ console.log(`Enabled modules: ${enabledModules.map((m) => m.id).join(", ")}`);
3420
+ }
3413
3421
  const files = await findFiles(rootDir, config);
3414
- console.log(`Found ${files.length} files to index`);
3422
+ if (!quiet) {
3423
+ console.log(`Found ${files.length} files to index`);
3424
+ }
3415
3425
  const results = [];
3416
3426
  for (const module of enabledModules) {
3417
- console.log(`
3427
+ if (!quiet) {
3428
+ console.log(`
3418
3429
  [${module.name}] Starting indexing...`);
3430
+ }
3419
3431
  const moduleConfig = getModuleConfig(config, module.id);
3420
3432
  if (module.initialize && moduleConfig) {
3421
3433
  const configWithOverrides = { ...moduleConfig };
@@ -3430,7 +3442,9 @@ async function indexDirectory(rootDir, options = {}) {
3430
3442
  const result = await indexWithModule(rootDir, files, module, config, verbose, introspection);
3431
3443
  results.push(result);
3432
3444
  if (module.finalize) {
3433
- console.log(`[${module.name}] Building secondary indexes...`);
3445
+ if (!quiet) {
3446
+ console.log(`[${module.name}] Building secondary indexes...`);
3447
+ }
3434
3448
  const ctx = {
3435
3449
  rootDir,
3436
3450
  config,
@@ -3446,12 +3460,167 @@ async function indexDirectory(rootDir, options = {}) {
3446
3460
  };
3447
3461
  await module.finalize(ctx);
3448
3462
  }
3449
- console.log(`[${module.name}] Complete: ${result.indexed} indexed, ${result.skipped} skipped, ${result.errors} errors`);
3463
+ if (!quiet) {
3464
+ console.log(`[${module.name}] Complete: ${result.indexed} indexed, ${result.skipped} skipped, ${result.errors} errors`);
3465
+ }
3450
3466
  }
3451
3467
  await introspection.save(config);
3452
3468
  await updateGlobalManifest(rootDir, enabledModules, config);
3453
3469
  return results;
3454
3470
  }
3471
+ async function isIndexVersionCompatible(rootDir) {
3472
+ const config = await loadConfig(rootDir);
3473
+ const globalManifestPath = getGlobalManifestPath(rootDir, config);
3474
+ try {
3475
+ const content = await fs6.readFile(globalManifestPath, "utf-8");
3476
+ const manifest = JSON.parse(content);
3477
+ return manifest.version === INDEX_SCHEMA_VERSION;
3478
+ } catch {
3479
+ return false;
3480
+ }
3481
+ }
3482
+ async function deleteIndex(rootDir) {
3483
+ const indexDir = getRaggrepDir(rootDir);
3484
+ try {
3485
+ await fs6.rm(indexDir, { recursive: true, force: true });
3486
+ } catch {}
3487
+ }
3488
+ async function ensureIndexFresh(rootDir, options = {}) {
3489
+ const verbose = options.verbose ?? false;
3490
+ const quiet = options.quiet ?? false;
3491
+ rootDir = path12.resolve(rootDir);
3492
+ const status = await getIndexStatus(rootDir);
3493
+ if (!status.exists) {
3494
+ if (!quiet) {
3495
+ console.log(`No index found. Creating index...
3496
+ `);
3497
+ }
3498
+ const results = await indexDirectory(rootDir, { ...options, quiet });
3499
+ const totalIndexed2 = results.reduce((sum, r) => sum + r.indexed, 0);
3500
+ return { indexed: totalIndexed2, removed: 0, unchanged: 0 };
3501
+ }
3502
+ const versionCompatible = await isIndexVersionCompatible(rootDir);
3503
+ if (!versionCompatible) {
3504
+ if (!quiet) {
3505
+ console.log(`Index version incompatible. Rebuilding...
3506
+ `);
3507
+ }
3508
+ await deleteIndex(rootDir);
3509
+ const results = await indexDirectory(rootDir, { ...options, quiet });
3510
+ const totalIndexed2 = results.reduce((sum, r) => sum + r.indexed, 0);
3511
+ return { indexed: totalIndexed2, removed: 0, unchanged: 0 };
3512
+ }
3513
+ const config = await loadConfig(rootDir);
3514
+ await registerBuiltInModules();
3515
+ const enabledModules = registry.getEnabled(config);
3516
+ if (enabledModules.length === 0) {
3517
+ return { indexed: 0, removed: 0, unchanged: 0 };
3518
+ }
3519
+ const introspection = new IntrospectionIndex(rootDir);
3520
+ await introspection.initialize();
3521
+ const currentFiles = await findFiles(rootDir, config);
3522
+ const currentFileSet = new Set(currentFiles.map((f) => path12.relative(rootDir, f)));
3523
+ let totalIndexed = 0;
3524
+ let totalRemoved = 0;
3525
+ let totalUnchanged = 0;
3526
+ for (const module of enabledModules) {
3527
+ const moduleConfig = getModuleConfig(config, module.id);
3528
+ if (module.initialize && moduleConfig) {
3529
+ const configWithOverrides = { ...moduleConfig };
3530
+ if (options.model && module.id === "language/typescript") {
3531
+ configWithOverrides.options = {
3532
+ ...configWithOverrides.options,
3533
+ embeddingModel: options.model
3534
+ };
3535
+ }
3536
+ await module.initialize(configWithOverrides);
3537
+ }
3538
+ const manifest = await loadModuleManifest(rootDir, module.id, config);
3539
+ const indexPath = getModuleIndexPath(rootDir, module.id, config);
3540
+ const filesToRemove = [];
3541
+ for (const filepath of Object.keys(manifest.files)) {
3542
+ if (!currentFileSet.has(filepath)) {
3543
+ filesToRemove.push(filepath);
3544
+ }
3545
+ }
3546
+ for (const filepath of filesToRemove) {
3547
+ if (verbose) {
3548
+ console.log(` Removing stale: ${filepath}`);
3549
+ }
3550
+ const indexFilePath = path12.join(indexPath, filepath.replace(/\.[^.]+$/, ".json"));
3551
+ try {
3552
+ await fs6.unlink(indexFilePath);
3553
+ } catch {}
3554
+ delete manifest.files[filepath];
3555
+ totalRemoved++;
3556
+ }
3557
+ const ctx = {
3558
+ rootDir,
3559
+ config,
3560
+ readFile: async (filepath) => {
3561
+ const fullPath = path12.isAbsolute(filepath) ? filepath : path12.join(rootDir, filepath);
3562
+ return fs6.readFile(fullPath, "utf-8");
3563
+ },
3564
+ getFileStats: async (filepath) => {
3565
+ const fullPath = path12.isAbsolute(filepath) ? filepath : path12.join(rootDir, filepath);
3566
+ const stats = await fs6.stat(fullPath);
3567
+ return { lastModified: stats.mtime.toISOString() };
3568
+ },
3569
+ getIntrospection: (filepath) => introspection.getFile(filepath)
3570
+ };
3571
+ for (const filepath of currentFiles) {
3572
+ const relativePath = path12.relative(rootDir, filepath);
3573
+ try {
3574
+ const stats = await fs6.stat(filepath);
3575
+ const lastModified = stats.mtime.toISOString();
3576
+ const existingEntry = manifest.files[relativePath];
3577
+ if (existingEntry && existingEntry.lastModified === lastModified) {
3578
+ totalUnchanged++;
3579
+ continue;
3580
+ }
3581
+ if (verbose) {
3582
+ console.log(` Indexing: ${relativePath}`);
3583
+ }
3584
+ const content = await fs6.readFile(filepath, "utf-8");
3585
+ introspection.addFile(relativePath, content);
3586
+ const fileIndex = await module.indexFile(relativePath, content, ctx);
3587
+ if (fileIndex) {
3588
+ await writeFileIndex(rootDir, module.id, relativePath, fileIndex, config);
3589
+ manifest.files[relativePath] = {
3590
+ lastModified,
3591
+ chunkCount: fileIndex.chunks.length
3592
+ };
3593
+ totalIndexed++;
3594
+ }
3595
+ } catch (error) {
3596
+ if (verbose) {
3597
+ console.error(` Error indexing ${relativePath}:`, error);
3598
+ }
3599
+ }
3600
+ }
3601
+ if (totalIndexed > 0 || totalRemoved > 0) {
3602
+ manifest.lastUpdated = new Date().toISOString();
3603
+ await writeModuleManifest(rootDir, module.id, manifest, config);
3604
+ if (module.finalize) {
3605
+ await module.finalize(ctx);
3606
+ }
3607
+ }
3608
+ if (totalRemoved > 0) {
3609
+ await cleanupEmptyDirectories(indexPath);
3610
+ }
3611
+ }
3612
+ if (totalIndexed > 0) {
3613
+ await introspection.save(config);
3614
+ }
3615
+ if (totalIndexed > 0 || totalRemoved > 0) {
3616
+ await updateGlobalManifest(rootDir, enabledModules, config);
3617
+ }
3618
+ return {
3619
+ indexed: totalIndexed,
3620
+ removed: totalRemoved,
3621
+ unchanged: totalUnchanged
3622
+ };
3623
+ }
3455
3624
  async function indexWithModule(rootDir, files, module, config, verbose, introspection) {
3456
3625
  const result = {
3457
3626
  moduleId: module.id,
@@ -3557,7 +3726,7 @@ async function writeFileIndex(rootDir, moduleId, filepath, fileIndex, config) {
3557
3726
  async function updateGlobalManifest(rootDir, modules, config) {
3558
3727
  const manifestPath = getGlobalManifestPath(rootDir, config);
3559
3728
  const manifest = {
3560
- version: config.version,
3729
+ version: INDEX_SCHEMA_VERSION,
3561
3730
  lastUpdated: new Date().toISOString(),
3562
3731
  modules: modules.map((m) => m.id)
3563
3732
  };
@@ -3697,6 +3866,7 @@ async function getIndexStatus(rootDir) {
3697
3866
  }
3698
3867
  return status;
3699
3868
  }
3869
+ var INDEX_SCHEMA_VERSION = "1.0.0";
3700
3870
  var init_indexer = __esm(() => {
3701
3871
  init_config2();
3702
3872
  init_registry();
@@ -3851,7 +4021,7 @@ init_embeddings();
3851
4021
  // package.json
3852
4022
  var package_default = {
3853
4023
  name: "raggrep",
3854
- version: "0.1.7",
4024
+ version: "0.2.0",
3855
4025
  description: "Local filesystem-based RAG system for codebases - semantic search using local embeddings",
3856
4026
  type: "module",
3857
4027
  main: "./dist/index.js",
@@ -4093,8 +4263,11 @@ Options:
4093
4263
  -h, --help Show this help message
4094
4264
 
4095
4265
  Note:
4096
- If the current directory has not been indexed, raggrep will
4097
- automatically index it before searching.
4266
+ The index is managed automatically like a cache:
4267
+ - First query creates the index
4268
+ - Changed files are re-indexed automatically
4269
+ - Deleted files are cleaned up automatically
4270
+ - Unchanged files use the cached index (instant)
4098
4271
 
4099
4272
  Examples:
4100
4273
  raggrep query "user authentication"
@@ -4105,7 +4278,7 @@ Examples:
4105
4278
  process.exit(0);
4106
4279
  }
4107
4280
  const { search: search2, formatSearchResults: formatSearchResults2 } = await Promise.resolve().then(() => (init_search(), exports_search));
4108
- const { getIndexStatus: getIndexStatus2, indexDirectory: indexDirectory2 } = await Promise.resolve().then(() => (init_indexer(), exports_indexer));
4281
+ const { ensureIndexFresh: ensureIndexFresh2 } = await Promise.resolve().then(() => (init_indexer(), exports_indexer));
4109
4282
  const query = flags.remaining[0];
4110
4283
  if (!query) {
4111
4284
  console.error("Usage: raggrep query <search query>");
@@ -4113,24 +4286,20 @@ Examples:
4113
4286
  process.exit(1);
4114
4287
  }
4115
4288
  try {
4116
- const status = await getIndexStatus2(process.cwd());
4117
- if (!status.exists) {
4118
- console.log(`No index found. Indexing directory first...
4119
- `);
4120
- console.log("RAGgrep Indexer");
4121
- console.log(`================
4122
- `);
4123
- const indexResults = await indexDirectory2(process.cwd(), {
4124
- model: flags.model,
4125
- verbose: false
4126
- });
4127
- console.log(`
4128
- ================`);
4129
- console.log("Summary:");
4130
- for (const result of indexResults) {
4131
- console.log(` ${result.moduleId}: ${result.indexed} indexed, ${result.skipped} skipped, ${result.errors} errors`);
4289
+ const freshStats = await ensureIndexFresh2(process.cwd(), {
4290
+ model: flags.model,
4291
+ quiet: true
4292
+ });
4293
+ if (freshStats.indexed > 0 || freshStats.removed > 0) {
4294
+ const parts = [];
4295
+ if (freshStats.indexed > 0) {
4296
+ parts.push(`${freshStats.indexed} indexed`);
4132
4297
  }
4133
- console.log("");
4298
+ if (freshStats.removed > 0) {
4299
+ parts.push(`${freshStats.removed} removed`);
4300
+ }
4301
+ console.log(`Index updated: ${parts.join(", ")}
4302
+ `);
4134
4303
  }
4135
4304
  console.log("RAGgrep Search");
4136
4305
  console.log(`==============
@@ -4286,4 +4455,4 @@ Run 'raggrep <command> --help' for more information.
4286
4455
  }
4287
4456
  main();
4288
4457
 
4289
- //# debugId=C248CB1C621D0FC764756E2164756E21
4458
+ //# debugId=4B6F0EA9EEB7164864756E2164756E21