1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
//! # TurboProp - Fast Semantic Code Search and Indexing
//!
//! TurboProp is a Rust library and CLI tool that enables fast semantic search across codebases
//! using machine learning embeddings. It indexes your code files and allows you to search for
//! functionality using natural language queries.
//!
//! Now includes MCP server support for real-time integration with coding agents.
//!
//! ## Features
//!
//! - **Semantic Search**: Find code by meaning, not just keywords
//! - **Git Integration**: Automatically respects `.gitignore` and only indexes tracked files
//! - **Watch Mode**: Monitor file changes and automatically update the index
//! - **File Filtering**: Filter by file type, size, and custom patterns
//! - **Multiple Output Formats**: JSON for tools, human-readable text for reading
//! - **Performance Optimized**: Handles codebases with 50-10,000+ files efficiently
//! - **Configurable Models**: Use any HuggingFace sentence-transformer model
//! - **MCP Server**: Real-time integration with coding agents via Model Context Protocol
//!
//! ## Quick Start
//!
//! ### CLI Usage
//!
//! ```bash
//! # Index your codebase
//! tp index --repo . --max-filesize 2mb
//!
//! # Search for code
//! tp search "jwt authentication" --repo .
//!
//! # Filter by file type
//! tp search --filetype .js "error handling" --repo .
//!
//! # Get human-readable output
//! tp search "database queries" --repo . --output text
//! ```
//!
//! ### Library Usage
//!
//! The library provides both high-level convenience functions and low-level components
//! for building custom search solutions.
//!
//! #### Basic Indexing and Search
//!
//! ```no_run
//! use turboprop::{config::TurboPropConfig, build_persistent_index, search_with_config};
//! use std::path::Path;
//!
//! # tokio::runtime::Runtime::new().unwrap().block_on(async {
//! // Build an index with default settings
//! let config = TurboPropConfig::default();
//! let index = build_persistent_index(Path::new("./src"), &config).await?;
//!
//! // Search the index
//! let results = search_with_config(
//! "error handling patterns",
//! Path::new("./src"),
//! Some(10), // limit results
//! Some(0.7) // similarity threshold
//! ).await?;
//!
//! for result in results {
//! println!("{}: {}", result.location_display(), result.content_preview(80));
//! }
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! # });
//! ```
//!
//! #### Custom Configuration
//!
//! ```no_run
//! use turboprop::{
//! config::TurboPropConfig,
//! embeddings::EmbeddingConfig,
//! types::FileDiscoveryConfig,
//! build_persistent_index
//! };
//! use std::path::Path;
//!
//! # tokio::runtime::Runtime::new().unwrap().block_on(async {
//! // Configure embedding model
//! let embedding_config = EmbeddingConfig::with_model("sentence-transformers/all-mpnet-base-v2")
//! .with_batch_size(16);
//!
//! // Configure file discovery
//! let file_config = FileDiscoveryConfig::default()
//! .with_max_filesize(5_000_000) // 5MB limit
//! .with_gitignore_respect(true)
//! .with_untracked(false);
//!
//! // Create complete configuration
//! let config = TurboPropConfig {
//! embedding: embedding_config,
//! file_discovery: file_config,
//! ..Default::default()
//! };
//!
//! // Build index with custom configuration
//! let index = build_persistent_index(Path::new("./project"), &config).await?;
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! # });
//! ```
//!
//! #### Incremental Updates
//!
//! ```no_run
//! use turboprop::{config::TurboPropConfig, update_persistent_index, index_exists};
//! use std::path::Path;
//!
//! # tokio::runtime::Runtime::new().unwrap().block_on(async {
//! let path = Path::new("./src");
//! let config = TurboPropConfig::default();
//!
//! if index_exists(path) {
//! // Update existing index incrementally
//! let (updated_index, update_result) = update_persistent_index(path, &config).await?;
//!
//! println!("Index updated: {} files added, {} files modified, {} files removed",
//! update_result.added_files,
//! update_result.updated_files,
//! update_result.removed_files);
//! } else {
//! println!("No existing index found, create one first");
//! }
//! # Ok::<(), Box<dyn std::error::Error>>(())
//! # });
//! ```
//!
//! ## Architecture
//!
//! TurboProp uses a multi-stage pipeline for indexing:
//!
//! 1. **File Discovery**: Finds files to index based on git status and filters
//! 2. **Content Processing**: Reads and preprocesses file content
//! 3. **Chunking**: Breaks large files into smaller, searchable chunks
//! 4. **Embedding Generation**: Creates vector embeddings using ML models
//! 5. **Index Storage**: Stores embeddings and metadata for fast retrieval
//!
//! For searching, it:
//!
//! 1. **Query Embedding**: Converts the search query to a vector
//! 2. **Similarity Search**: Finds the most similar code chunks using cosine similarity
//! 3. **Result Ranking**: Sorts results by relevance score
//! 4. **Output Formatting**: Presents results in the requested format
//!
//! ## Performance Characteristics
//!
//! - **Indexing Speed**: ~100-500 files/second (varies by file size and hardware)
//! - **Search Speed**: ~10-50ms per query (after model loading)
//! - **Memory Usage**: ~50-200MB (varies with model and index size)
//! - **Index Size**: Typically 10-30% of source code size
//!
//! ## Supported Models
//!
//! TurboProp supports any HuggingFace sentence-transformer model:
//!
//! - `sentence-transformers/all-MiniLM-L6-v2` (default, 384 dims, ~90MB)
//! - `sentence-transformers/all-MiniLM-L12-v2` (384 dims, ~130MB)
//! - `sentence-transformers/all-mpnet-base-v2` (768 dims, ~420MB, highest quality)
//! - `sentence-transformers/paraphrase-MiniLM-L6-v2` (384 dims, ~90MB)
//!
//! ## Error Handling
//!
//! All functions return `anyhow::Result<T>` for comprehensive error handling.
//! Common error types include:
//!
//! - **I/O Errors**: File access, permission issues
//! - **Model Errors**: Download failures, model loading issues
//! - **Configuration Errors**: Invalid settings, malformed config files
//! - **Index Errors**: Corrupted index, version mismatches
//!
//! ## Thread Safety
//!
//! Most operations are thread-safe and designed for concurrent use:
//!
//! - Index building uses multiple worker threads for parallel processing
//! - Search operations are read-only and fully concurrent
//! - File watching runs in a separate background thread
//!
//! ## Module Organization
//!
//! - [`cli`]: Command-line interface definitions
//! - [`commands`]: CLI command implementations
//! - [`config`]: Configuration structures and loading
//! - [`embeddings`]: ML embedding generation
//! - [`files`]: File discovery and git integration
//! - [`index`]: Core indexing and storage functionality
//! - [`search`]: Search algorithms and result processing
//! - [`types`]: Common data structures and utilities
use crateChunkingStrategy;
use crateTurboPropConfig;
use crateEmbeddingGenerator;
use crateFileDiscovery;
use cratePersistentChunkIndex;
use crateIndexStorage;
use crate;
use Result;
use Path;
use ;
// Re-export MCP server for library usage
pub use McpServer;
/// Default path for indexing when no path is specified
pub const DEFAULT_INDEX_PATH: &str = ".";
/// Index files in the specified path for fast searching.
///
/// # Arguments
///
/// * `path` - The file system path to index
/// * `max_filesize` - Optional maximum file size filter (e.g., "2mb", "100kb")
///
/// # Returns
///
/// * `Result<()>` - Ok(()) if successful, error otherwise
///
/// # Examples
///
/// Index current directory without size limit:
/// ```
/// use std::path::Path;
/// use turboprop::index_files;
///
/// let result = index_files(Path::new("."), None);
/// assert!(result.is_ok());
/// ```
///
/// Index with maximum file size filter:
/// ```
/// use std::path::Path;
/// use turboprop::index_files;
///
/// // Index files up to 2MB in size
/// # std::fs::create_dir_all("test_dir").unwrap();
/// let result = index_files(Path::new("test_dir"), Some("2mb"));
/// assert!(result.is_ok());
///
/// // Index files up to 500KB in size
/// let result = index_files(Path::new("test_dir"), Some("500kb"));
/// assert!(result.is_ok());
/// ```
/// Index files with embedding generation using the provided configuration.
///
/// This is the enhanced version that generates embeddings for the discovered text chunks
/// and stores them in a searchable index.
///
/// # Arguments
///
/// * `path` - The file system path to index
/// * `config` - Complete configuration including embedding and file discovery settings
///
/// # Returns
///
/// * `Result<ChunkIndex>` - The populated chunk index with embeddings
///
/// # Examples
///
/// Basic usage with default configuration:
/// ```no_run
/// use std::path::Path;
/// use turboprop::{config::TurboPropConfig, index_files_with_config};
///
/// # tokio::runtime::Runtime::new().unwrap().block_on(async {
/// let config = TurboPropConfig::default();
/// let result = index_files_with_config(Path::new("./src"), &config).await;
/// assert!(result.is_ok());
///
/// let index = result.unwrap();
/// println!("Indexed {} chunks", index.len());
/// # });
/// ```
///
/// Advanced usage with custom embedding model and batch size:
/// ```no_run
/// use std::path::Path;
/// use turboprop::{config::TurboPropConfig, embeddings::EmbeddingConfig, index_files_with_config};
///
/// # tokio::runtime::Runtime::new().unwrap().block_on(async {
/// let embedding_config = EmbeddingConfig::with_model("sentence-transformers/all-MiniLM-L12-v2")
/// .with_batch_size(16);
///
/// let config = TurboPropConfig {
/// embedding: embedding_config,
/// ..Default::default()
/// };
///
/// let result = index_files_with_config(Path::new("./project"), &config).await;
/// assert!(result.is_ok());
///
/// let index = result.unwrap();
/// // The index can now be used for similarity search
/// println!("Created index with {} chunks using {}-dimensional embeddings",
/// index.len(), config.embedding.embedding_dimensions);
/// # });
/// ```
pub async
/// Search through indexed files using the specified query.
///
/// # Arguments
///
/// * `query` - The search query string
///
/// # Returns
///
/// * `Result<()>` - Ok(()) if successful, error otherwise
///
/// # Examples
///
/// Simple text search:
/// ```
/// use turboprop::search_files;
///
/// let result = search_files("function main");
/// assert!(result.is_ok());
/// ```
///
/// Search for specific patterns or keywords:
/// ```
/// use turboprop::search_files;
///
/// // Search for function definitions
/// let result = search_files("fn calculate_total");
/// assert!(result.is_ok());
///
/// // Search for error handling patterns
/// let result = search_files("Result<Vec<String>>");
/// assert!(result.is_ok());
///
/// // Search for imports and modules
/// let result = search_files("use serde::");
/// assert!(result.is_ok());
/// ```
/// Advanced search function with configurable parameters.
///
/// This is the enhanced search functionality that supports similarity thresholds,
/// result limits, and returns detailed results with similarity scores.
///
/// # Arguments
///
/// * `query` - The search query string
/// * `repo_path` - Path to the repository/directory to search in
/// * `limit` - Maximum number of results to return (default: 10)
/// * `threshold` - Minimum similarity threshold (0.0 to 1.0, optional)
///
/// # Returns
///
/// * `Result<Vec<SearchResult>>` - Vector of search results with similarity scores
///
/// # Examples
///
/// Basic search with default parameters:
/// ```no_run
/// use std::path::Path;
/// use turboprop::search_with_config;
///
/// # tokio::runtime::Runtime::new().unwrap().block_on(async {
/// let results = search_with_config("jwt authentication", Path::new("."), None, None).await;
/// if let Ok(results) = results {
/// for result in results {
/// println!("{} ({:.3}): {}",
/// result.location_display(),
/// result.similarity,
/// result.content_preview(50));
/// }
/// }
/// # });
/// ```
///
/// Search with custom limit and threshold:
/// ```no_run
/// use std::path::Path;
/// use turboprop::search_with_config;
///
/// # tokio::runtime::Runtime::new().unwrap().block_on(async {
/// let results = search_with_config(
/// "error handling",
/// Path::new("./src"),
/// Some(5), // limit: 5 results
/// Some(0.7) // threshold: minimum 70% similarity
/// ).await;
/// # });
/// ```
pub async
/// Build a persistent vector index for the specified path.
///
/// This creates a complete index with embeddings that is stored to disk
/// and can be loaded later for fast similarity search.
///
/// # Arguments
///
/// * `path` - The file system path to index
/// * `config` - Complete configuration for indexing and embedding generation
///
/// # Returns
///
/// * `Result<PersistentChunkIndex>` - The built index ready for searching
///
/// # Examples
///
/// Build an index with default configuration:
/// ```no_run
/// use std::path::Path;
/// use turboprop::{config::TurboPropConfig, build_persistent_index};
///
/// # tokio::runtime::Runtime::new().unwrap().block_on(async {
/// let config = TurboPropConfig::default();
/// let result = build_persistent_index(Path::new("./src"), &config).await;
/// assert!(result.is_ok());
///
/// let index = result.unwrap();
/// println!("Built index with {} chunks", index.len());
/// # });
/// ```
pub async
/// Load an existing persistent vector index from disk.
///
/// # Arguments
///
/// * `path` - The path where the index was originally built
///
/// # Returns
///
/// * `Result<PersistentChunkIndex>` - The loaded index ready for searching
///
/// # Examples
///
/// Load an existing index:
/// ```no_run
/// use std::path::Path;
/// use turboprop::load_persistent_index;
///
/// let result = load_persistent_index(Path::new("./src"));
/// if let Ok(index) = result {
/// println!("Loaded index with {} chunks", index.len());
/// }
/// ```
/// Check if a persistent index exists at the specified path.
///
/// # Arguments
///
/// * `path` - The path to check for an existing index
///
/// # Returns
///
/// * `bool` - true if an index exists, false otherwise
///
/// # Examples
///
/// ```no_run
/// use std::path::Path;
/// use turboprop::index_exists;
///
/// if index_exists(Path::new("./src")) {
/// println!("Index found, can load it");
/// } else {
/// println!("No index found, need to build one");
/// }
/// ```
/// Update an existing persistent index incrementally based on file changes.
///
/// This is more efficient than rebuilding the entire index when only some
/// files have changed.
///
/// # Arguments
///
/// * `path` - The path of the existing index
/// * `config` - Configuration for the update process
///
/// # Returns
///
/// * `Result<(PersistentChunkIndex, crate::index::UpdateResult)>` - The updated index and update statistics
///
/// # Examples
///
/// Update an existing index:
/// ```no_run
/// use std::path::Path;
/// use turboprop::{config::TurboPropConfig, update_persistent_index};
///
/// # tokio::runtime::Runtime::new().unwrap().block_on(async {
/// let config = TurboPropConfig::default();
/// let result = update_persistent_index(Path::new("./src"), &config).await;
///
/// if let Ok((index, update_result)) = result {
/// println!("Updated index: {} files added, {} files updated, {} files removed",
/// update_result.added_files,
/// update_result.updated_files,
/// update_result.removed_files);
/// }
/// # });
/// ```
pub async