mcp-vector-search 0.12.6__py3-none-any.whl

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.
Files changed (68) hide show
  1. mcp_vector_search/__init__.py +10 -0
  2. mcp_vector_search/cli/__init__.py +1 -0
  3. mcp_vector_search/cli/commands/__init__.py +1 -0
  4. mcp_vector_search/cli/commands/auto_index.py +397 -0
  5. mcp_vector_search/cli/commands/config.py +393 -0
  6. mcp_vector_search/cli/commands/demo.py +358 -0
  7. mcp_vector_search/cli/commands/index.py +744 -0
  8. mcp_vector_search/cli/commands/init.py +645 -0
  9. mcp_vector_search/cli/commands/install.py +675 -0
  10. mcp_vector_search/cli/commands/install_old.py +696 -0
  11. mcp_vector_search/cli/commands/mcp.py +1182 -0
  12. mcp_vector_search/cli/commands/reset.py +393 -0
  13. mcp_vector_search/cli/commands/search.py +773 -0
  14. mcp_vector_search/cli/commands/status.py +549 -0
  15. mcp_vector_search/cli/commands/uninstall.py +485 -0
  16. mcp_vector_search/cli/commands/visualize.py +1467 -0
  17. mcp_vector_search/cli/commands/watch.py +287 -0
  18. mcp_vector_search/cli/didyoumean.py +500 -0
  19. mcp_vector_search/cli/export.py +320 -0
  20. mcp_vector_search/cli/history.py +295 -0
  21. mcp_vector_search/cli/interactive.py +342 -0
  22. mcp_vector_search/cli/main.py +461 -0
  23. mcp_vector_search/cli/output.py +412 -0
  24. mcp_vector_search/cli/suggestions.py +375 -0
  25. mcp_vector_search/config/__init__.py +1 -0
  26. mcp_vector_search/config/constants.py +24 -0
  27. mcp_vector_search/config/defaults.py +200 -0
  28. mcp_vector_search/config/settings.py +134 -0
  29. mcp_vector_search/core/__init__.py +1 -0
  30. mcp_vector_search/core/auto_indexer.py +298 -0
  31. mcp_vector_search/core/connection_pool.py +360 -0
  32. mcp_vector_search/core/database.py +1214 -0
  33. mcp_vector_search/core/directory_index.py +318 -0
  34. mcp_vector_search/core/embeddings.py +294 -0
  35. mcp_vector_search/core/exceptions.py +89 -0
  36. mcp_vector_search/core/factory.py +318 -0
  37. mcp_vector_search/core/git_hooks.py +345 -0
  38. mcp_vector_search/core/indexer.py +1002 -0
  39. mcp_vector_search/core/models.py +294 -0
  40. mcp_vector_search/core/project.py +333 -0
  41. mcp_vector_search/core/scheduler.py +330 -0
  42. mcp_vector_search/core/search.py +952 -0
  43. mcp_vector_search/core/watcher.py +322 -0
  44. mcp_vector_search/mcp/__init__.py +5 -0
  45. mcp_vector_search/mcp/__main__.py +25 -0
  46. mcp_vector_search/mcp/server.py +733 -0
  47. mcp_vector_search/parsers/__init__.py +8 -0
  48. mcp_vector_search/parsers/base.py +296 -0
  49. mcp_vector_search/parsers/dart.py +605 -0
  50. mcp_vector_search/parsers/html.py +413 -0
  51. mcp_vector_search/parsers/javascript.py +643 -0
  52. mcp_vector_search/parsers/php.py +694 -0
  53. mcp_vector_search/parsers/python.py +502 -0
  54. mcp_vector_search/parsers/registry.py +223 -0
  55. mcp_vector_search/parsers/ruby.py +678 -0
  56. mcp_vector_search/parsers/text.py +186 -0
  57. mcp_vector_search/parsers/utils.py +265 -0
  58. mcp_vector_search/py.typed +1 -0
  59. mcp_vector_search/utils/__init__.py +40 -0
  60. mcp_vector_search/utils/gitignore.py +250 -0
  61. mcp_vector_search/utils/monorepo.py +277 -0
  62. mcp_vector_search/utils/timing.py +334 -0
  63. mcp_vector_search/utils/version.py +47 -0
  64. mcp_vector_search-0.12.6.dist-info/METADATA +754 -0
  65. mcp_vector_search-0.12.6.dist-info/RECORD +68 -0
  66. mcp_vector_search-0.12.6.dist-info/WHEEL +4 -0
  67. mcp_vector_search-0.12.6.dist-info/entry_points.txt +2 -0
  68. mcp_vector_search-0.12.6.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,500 @@
1
+ """Enhanced CLI with 'did you mean' functionality for better user experience."""
2
+
3
+ import difflib
4
+
5
+ import click
6
+ import typer
7
+ from click_didyoumean import DYMGroup
8
+
9
+
10
+ class EnhancedDidYouMeanTyper(typer.Typer):
11
+ """Enhanced Typer class with advanced 'did you mean' functionality."""
12
+
13
+ def __init__(self, *args, **kwargs):
14
+ """Initialize with enhanced did-you-mean support."""
15
+ # Extract Typer-specific kwargs
16
+ typer_kwargs = {}
17
+ click_kwargs = {}
18
+
19
+ # Separate Typer and Click kwargs
20
+ typer_specific = {
21
+ "name",
22
+ "help",
23
+ "epilog",
24
+ "short_help",
25
+ "options_metavar",
26
+ "add_completion",
27
+ "context_settings",
28
+ "callback",
29
+ "invoke_without_command",
30
+ "no_args_is_help",
31
+ "subcommand_metavar",
32
+ "chain",
33
+ "result_callback",
34
+ "deprecated",
35
+ "rich_markup_mode",
36
+ "rich_help_panel",
37
+ "pretty_exceptions_enable",
38
+ "pretty_exceptions_show_locals",
39
+ "pretty_exceptions_short",
40
+ }
41
+
42
+ for key, value in kwargs.items():
43
+ if key in typer_specific:
44
+ typer_kwargs[key] = value
45
+ else:
46
+ click_kwargs[key] = value
47
+
48
+ # Initialize Typer with its specific kwargs
49
+ super().__init__(*args, **typer_kwargs)
50
+
51
+ # Store click kwargs for later use
52
+ self._click_kwargs = click_kwargs
53
+ self.command_aliases = {} # Store command aliases
54
+
55
+ def __call__(self, *args, **kwargs):
56
+ """Override call to use enhanced DYMGroup."""
57
+ # Get the underlying click group
58
+ click_group = super().__call__(*args, **kwargs)
59
+
60
+ # If click_group is None (command already executed), return None
61
+ # This happens after command execution completes successfully
62
+ if click_group is None:
63
+ return None
64
+
65
+ # Create enhanced DYM group with original group's properties
66
+ enhanced_group = EnhancedDidYouMeanGroup(
67
+ name=click_group.name,
68
+ commands=click_group.commands,
69
+ callback=click_group.callback,
70
+ params=click_group.params,
71
+ help=click_group.help,
72
+ epilog=click_group.epilog,
73
+ short_help=click_group.short_help,
74
+ add_help_option=click_group.add_help_option,
75
+ context_settings=click_group.context_settings,
76
+ invoke_without_command=click_group.invoke_without_command,
77
+ no_args_is_help=click_group.no_args_is_help,
78
+ subcommand_metavar=click_group.subcommand_metavar,
79
+ chain=click_group.chain,
80
+ result_callback=click_group.result_callback,
81
+ deprecated=click_group.deprecated,
82
+ **self._click_kwargs,
83
+ )
84
+
85
+ # Additional attributes that might be needed
86
+ if hasattr(click_group, "options_metavar"):
87
+ enhanced_group.options_metavar = click_group.options_metavar
88
+
89
+ return enhanced_group
90
+
91
+ def add_alias(self, command_name: str, alias: str) -> None:
92
+ """Add an alias for a command.
93
+
94
+ Args:
95
+ command_name: The original command name
96
+ alias: The alias to add
97
+ """
98
+ self.command_aliases[alias] = command_name
99
+
100
+
101
+ class EnhancedDidYouMeanGroup(DYMGroup):
102
+ """Enhanced Click group with advanced 'did you mean' functionality."""
103
+
104
+ def __init__(self, *args, **kwargs):
105
+ """Initialize with better error messages and fuzzy matching."""
106
+ super().__init__(*args, **kwargs)
107
+ self.max_suggestions = 3 # Maximum number of suggestions to show
108
+
109
+ def resolve_command(self, ctx: click.Context, args: list) -> tuple:
110
+ """Resolve command with enhanced error handling and suggestions."""
111
+ try:
112
+ return super().resolve_command(ctx, args)
113
+ except click.UsageError as e:
114
+ # Enhanced error handling with better suggestions
115
+ if "No such command" in str(e) and args:
116
+ command_name = args[0]
117
+
118
+ # Use our enhanced suggestion system
119
+ add_common_suggestions(ctx, command_name)
120
+
121
+ # Re-raise with original message (suggestions already printed)
122
+ raise click.UsageError(str(e), ctx=ctx)
123
+ raise
124
+
125
+ def get_command(self, ctx: click.Context, cmd_name: str):
126
+ """Get command with support for aliases and shortcuts."""
127
+ # First try exact match
128
+ rv = super().get_command(ctx, cmd_name)
129
+ if rv is not None:
130
+ return rv
131
+
132
+ # Try common typo mappings
133
+ suggestion = COMMON_TYPOS.get(cmd_name.lower())
134
+ if suggestion and " " not in suggestion: # Only single commands, not flags
135
+ return super().get_command(ctx, suggestion)
136
+
137
+ return None
138
+
139
+
140
+ def create_enhanced_typer(**kwargs) -> typer.Typer:
141
+ """Create a Typer instance with enhanced 'did you mean' functionality."""
142
+ # Set default values for better UX
143
+ defaults = {
144
+ "no_args_is_help": True,
145
+ "add_completion": False,
146
+ "rich_markup_mode": "rich",
147
+ }
148
+
149
+ # Merge with provided kwargs
150
+ final_kwargs = {**defaults, **kwargs}
151
+
152
+ # Create the enhanced Typer
153
+ app = EnhancedDidYouMeanTyper(**final_kwargs)
154
+
155
+ return app
156
+
157
+
158
+ def enhance_existing_typer(app: typer.Typer) -> typer.Typer:
159
+ """Enhance an existing Typer app with advanced 'did you mean' functionality."""
160
+ # This is a bit tricky since we need to modify the underlying Click group
161
+ # We'll create a wrapper that intercepts the click group creation
162
+
163
+ original_call = app.__call__
164
+
165
+ def enhanced_call(*args, **kwargs):
166
+ """Enhanced call that uses EnhancedDidYouMeanGroup."""
167
+ click_group = original_call(*args, **kwargs)
168
+
169
+ # If click_group is None (command already executed), return None
170
+ # This happens after command execution completes successfully
171
+ if click_group is None:
172
+ return None
173
+
174
+ # Create enhanced group
175
+ enhanced_group = EnhancedDidYouMeanGroup(
176
+ name=click_group.name,
177
+ commands=click_group.commands,
178
+ callback=click_group.callback,
179
+ params=click_group.params,
180
+ help=click_group.help,
181
+ epilog=click_group.epilog,
182
+ short_help=click_group.short_help,
183
+ options_metavar=click_group.options_metavar,
184
+ add_help_option=click_group.add_help_option,
185
+ context_settings=click_group.context_settings,
186
+ invoke_without_command=click_group.invoke_without_command,
187
+ no_args_is_help=click_group.no_args_is_help,
188
+ subcommand_metavar=click_group.subcommand_metavar,
189
+ chain=click_group.chain,
190
+ result_callback=click_group.result_callback,
191
+ deprecated=click_group.deprecated,
192
+ )
193
+
194
+ return enhanced_group
195
+
196
+ app.__call__ = enhanced_call
197
+ return app
198
+
199
+
200
+ # Enhanced typo mapping with comprehensive variations
201
+ COMMON_TYPOS = {
202
+ # Search command variations
203
+ "serach": "search",
204
+ "seach": "search",
205
+ "searh": "search",
206
+ "sarch": "search",
207
+ "serch": "search",
208
+ "searhc": "search",
209
+ "find": "search",
210
+ "query": "search",
211
+ "lookup": "search",
212
+ "grep": "search",
213
+ "s": "search", # Single letter shortcut
214
+ "f": "search", # Alternative shortcut for find
215
+ # Index command variations
216
+ "indx": "index",
217
+ "idx": "index",
218
+ "indexx": "index",
219
+ "indez": "index",
220
+ "inedx": "index",
221
+ "reindex": "index --force",
222
+ "rebuild": "index --force",
223
+ "refresh": "index --force",
224
+ "scan": "index",
225
+ "build": "index",
226
+ "i": "index", # Single letter shortcut
227
+ "b": "index", # Alternative shortcut for build
228
+ # Status command variations
229
+ "stat": "status",
230
+ "stats": "status",
231
+ "info": "status",
232
+ "information": "status",
233
+ "details": "status",
234
+ "summary": "status",
235
+ "overview": "status",
236
+ "st": "status", # Common abbreviation
237
+ "status": "status",
238
+ # Config command variations
239
+ "conf": "config",
240
+ "cfg": "config",
241
+ "configure": "config",
242
+ "configuration": "config",
243
+ "setting": "config",
244
+ "settings": "config",
245
+ "preferences": "config",
246
+ "prefs": "config",
247
+ "c": "config", # Single letter shortcut
248
+ # Init command variations
249
+ "initialize": "init",
250
+ "setup": "init",
251
+ "start": "init",
252
+ "create": "init",
253
+ "new": "init",
254
+ "begin": "init",
255
+ "initalize": "init", # Common misspelling
256
+ "initalise": "init",
257
+ "initialise": "init",
258
+ # Watch command variations
259
+ "monitor": "watch",
260
+ "observe": "watch",
261
+ "track": "watch",
262
+ "listen": "watch",
263
+ "follow": "watch",
264
+ "w": "watch", # Single letter shortcut
265
+ # Auto-index command variations
266
+ "auto": "auto-index",
267
+ "automatic": "auto-index",
268
+ "autoindex": "auto-index",
269
+ "auto_index": "auto-index",
270
+ "ai": "auto-index", # Abbreviation
271
+ # MCP command variations
272
+ "claude": "mcp",
273
+ "server": "mcp",
274
+ "protocol": "mcp",
275
+ "model-context": "mcp",
276
+ "context": "mcp",
277
+ "m": "mcp", # Single letter shortcut
278
+ # Install command variations
279
+ "deploy": "install",
280
+ "add": "install",
281
+ "instal": "install", # Common typo
282
+ "install": "install",
283
+ # Demo command variations
284
+ "example": "demo",
285
+ "sample": "demo",
286
+ "test": "demo",
287
+ "try": "demo",
288
+ "d": "demo", # Single letter shortcut
289
+ # Health/Doctor command variations
290
+ "check": "doctor",
291
+ "health": "doctor",
292
+ "diagnose": "doctor",
293
+ "verify": "doctor",
294
+ "validate": "doctor",
295
+ "repair": "doctor",
296
+ "fix": "doctor",
297
+ "dr": "doctor", # Common abbreviation
298
+ # Version command variations
299
+ "ver": "version",
300
+ "v": "version",
301
+ "--version": "version",
302
+ "-v": "version",
303
+ # Help command variations
304
+ "help": "--help",
305
+ "h": "--help",
306
+ "--help": "--help",
307
+ "-h": "--help",
308
+ "?": "--help",
309
+ # History command variations
310
+ "hist": "history",
311
+ "log": "history",
312
+ "logs": "history",
313
+ "recent": "history",
314
+ # Reset command variations
315
+ "clear": "reset",
316
+ "clean": "reset",
317
+ "purge": "reset",
318
+ "wipe": "reset",
319
+ "remove": "reset",
320
+ "delete": "reset",
321
+ # Interactive command variations
322
+ "interact": "interactive",
323
+ "session": "interactive",
324
+ "repl": "interactive",
325
+ "console": "interactive",
326
+ "ui": "interactive",
327
+ }
328
+
329
+ # Command descriptions and examples for better error messages
330
+ COMMAND_INFO = {
331
+ "search": {
332
+ "description": "Search for code patterns semantically",
333
+ "examples": [
334
+ 'mcp-vector-search search "authentication function"',
335
+ 'mcp-vector-search search "error handling" --limit 5',
336
+ 'mcp-vector-search find "database connection"',
337
+ ],
338
+ "related": ["search-similar", "search-context", "find", "interactive"],
339
+ },
340
+ "index": {
341
+ "description": "Index codebase for semantic search",
342
+ "examples": [
343
+ "mcp-vector-search index",
344
+ "mcp-vector-search index --force",
345
+ 'mcp-vector-search index --include "*.py,*.js"',
346
+ ],
347
+ "related": ["auto-index", "watch", "reset"],
348
+ },
349
+ "status": {
350
+ "description": "Show project status and statistics",
351
+ "examples": ["mcp-vector-search status", "mcp-vector-search status --verbose"],
352
+ "related": ["doctor", "history", "version"],
353
+ },
354
+ "config": {
355
+ "description": "Manage project configuration",
356
+ "examples": [
357
+ "mcp-vector-search config show",
358
+ "mcp-vector-search config set model all-MiniLM-L6-v2",
359
+ ],
360
+ "related": ["init", "status"],
361
+ },
362
+ "init": {
363
+ "description": "Initialize project for semantic search",
364
+ "examples": [
365
+ "mcp-vector-search init",
366
+ "mcp-vector-search init --model sentence-transformers/all-MiniLM-L6-v2",
367
+ ],
368
+ "related": ["config", "install", "index"],
369
+ },
370
+ "mcp": {
371
+ "description": "Manage Claude Code MCP integration",
372
+ "examples": ["mcp-vector-search mcp", "mcp-vector-search mcp test"],
373
+ "related": ["init-mcp", "install"],
374
+ },
375
+ "doctor": {
376
+ "description": "Check system dependencies and configuration",
377
+ "examples": [
378
+ "mcp-vector-search doctor",
379
+ ],
380
+ "related": ["status", "health"],
381
+ },
382
+ "version": {
383
+ "description": "Show version information",
384
+ "examples": ["mcp-vector-search version", "mcp-vector-search --version"],
385
+ "related": ["status", "doctor"],
386
+ },
387
+ }
388
+
389
+
390
+ def get_fuzzy_matches(
391
+ command: str, available_commands: list[str], cutoff: float = 0.6
392
+ ) -> list[tuple[str, float]]:
393
+ """Get fuzzy matches for a command using difflib.
394
+
395
+ Args:
396
+ command: The command to match
397
+ available_commands: List of available commands
398
+ cutoff: Minimum similarity ratio (0.0 to 1.0)
399
+
400
+ Returns:
401
+ List of tuples (command, similarity_ratio) sorted by similarity
402
+ """
403
+ matches = []
404
+ for cmd in available_commands:
405
+ ratio = difflib.SequenceMatcher(None, command.lower(), cmd.lower()).ratio()
406
+ if ratio >= cutoff:
407
+ matches.append((cmd, ratio))
408
+
409
+ # Sort by similarity ratio (highest first)
410
+ return sorted(matches, key=lambda x: x[1], reverse=True)
411
+
412
+
413
+ def format_command_suggestion(command: str, show_examples: bool = True) -> str:
414
+ """Format a command suggestion with description and examples.
415
+
416
+ Args:
417
+ command: The command to format
418
+ show_examples: Whether to include usage examples
419
+
420
+ Returns:
421
+ Formatted suggestion string
422
+ """
423
+ if command in COMMAND_INFO:
424
+ info = COMMAND_INFO[command]
425
+ suggestion = f" [bold cyan]{command}[/bold cyan] - {info['description']}"
426
+
427
+ if show_examples and info["examples"]:
428
+ suggestion += f"\n Example: [dim]{info['examples'][0]}[/dim]"
429
+
430
+ return suggestion
431
+ else:
432
+ return f" [bold cyan]{command}[/bold cyan]"
433
+
434
+
435
+ def add_common_suggestions(ctx: click.Context, command_name: str) -> None:
436
+ """Add enhanced command suggestions to error messages.
437
+
438
+ Args:
439
+ ctx: Click context
440
+ command_name: The invalid command name that was entered
441
+ """
442
+ from rich.console import Console
443
+
444
+ console = Console(stderr=True)
445
+
446
+ # First, check for exact typo matches
447
+ direct_suggestion = COMMON_TYPOS.get(command_name.lower())
448
+ if direct_suggestion:
449
+ console.print("\n[yellow]Did you mean:[/yellow]")
450
+ console.print(format_command_suggestion(direct_suggestion.split()[0]))
451
+
452
+ if "--" not in direct_suggestion: # Don't show examples for flags
453
+ console.print(
454
+ f"\n[dim]Try: [bold]mcp-vector-search {direct_suggestion}[/bold][/dim]"
455
+ )
456
+ return
457
+
458
+ # Get available commands from the context
459
+ available_commands = []
460
+ if hasattr(ctx, "command") and hasattr(ctx.command, "commands"):
461
+ available_commands = list(ctx.command.commands.keys())
462
+
463
+ if not available_commands:
464
+ # Fallback to common commands
465
+ available_commands = [
466
+ "search",
467
+ "index",
468
+ "status",
469
+ "config",
470
+ "init",
471
+ "mcp",
472
+ "doctor",
473
+ "version",
474
+ ]
475
+
476
+ # Get fuzzy matches
477
+ fuzzy_matches = get_fuzzy_matches(command_name, available_commands, cutoff=0.4)
478
+
479
+ if fuzzy_matches:
480
+ console.print("\n[yellow]Did you mean one of these?[/yellow]")
481
+
482
+ # Show up to 3 best matches
483
+ for cmd, _ratio in fuzzy_matches[:3]:
484
+ console.print(format_command_suggestion(cmd, show_examples=False))
485
+
486
+ # Show example for the best match
487
+ if fuzzy_matches:
488
+ best_match = fuzzy_matches[0][0]
489
+ if best_match in COMMAND_INFO and COMMAND_INFO[best_match]["examples"]:
490
+ console.print(
491
+ f"\n[dim]Example: [bold]{COMMAND_INFO[best_match]['examples'][0]}[/bold][/dim]"
492
+ )
493
+
494
+ # Show related commands for context
495
+ console.print(
496
+ f"\n[dim]Available commands: {', '.join(sorted(available_commands))}[/dim]"
497
+ )
498
+ console.print(
499
+ "[dim]Use [bold]mcp-vector-search --help[/bold] for more information[/dim]"
500
+ )