mcp-vector-search 0.15.7__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.
Potentially problematic release.
This version of mcp-vector-search might be problematic. Click here for more details.
- mcp_vector_search/__init__.py +10 -0
- mcp_vector_search/cli/__init__.py +1 -0
- mcp_vector_search/cli/commands/__init__.py +1 -0
- mcp_vector_search/cli/commands/auto_index.py +397 -0
- mcp_vector_search/cli/commands/chat.py +534 -0
- mcp_vector_search/cli/commands/config.py +393 -0
- mcp_vector_search/cli/commands/demo.py +358 -0
- mcp_vector_search/cli/commands/index.py +762 -0
- mcp_vector_search/cli/commands/init.py +658 -0
- mcp_vector_search/cli/commands/install.py +869 -0
- mcp_vector_search/cli/commands/install_old.py +700 -0
- mcp_vector_search/cli/commands/mcp.py +1254 -0
- mcp_vector_search/cli/commands/reset.py +393 -0
- mcp_vector_search/cli/commands/search.py +796 -0
- mcp_vector_search/cli/commands/setup.py +1133 -0
- mcp_vector_search/cli/commands/status.py +584 -0
- mcp_vector_search/cli/commands/uninstall.py +404 -0
- mcp_vector_search/cli/commands/visualize/__init__.py +39 -0
- mcp_vector_search/cli/commands/visualize/cli.py +265 -0
- mcp_vector_search/cli/commands/visualize/exporters/__init__.py +12 -0
- mcp_vector_search/cli/commands/visualize/exporters/html_exporter.py +33 -0
- mcp_vector_search/cli/commands/visualize/exporters/json_exporter.py +29 -0
- mcp_vector_search/cli/commands/visualize/graph_builder.py +709 -0
- mcp_vector_search/cli/commands/visualize/layout_engine.py +469 -0
- mcp_vector_search/cli/commands/visualize/server.py +201 -0
- mcp_vector_search/cli/commands/visualize/state_manager.py +428 -0
- mcp_vector_search/cli/commands/visualize/templates/__init__.py +16 -0
- mcp_vector_search/cli/commands/visualize/templates/base.py +218 -0
- mcp_vector_search/cli/commands/visualize/templates/scripts.py +3670 -0
- mcp_vector_search/cli/commands/visualize/templates/styles.py +779 -0
- mcp_vector_search/cli/commands/visualize.py.original +2536 -0
- mcp_vector_search/cli/commands/watch.py +287 -0
- mcp_vector_search/cli/didyoumean.py +520 -0
- mcp_vector_search/cli/export.py +320 -0
- mcp_vector_search/cli/history.py +295 -0
- mcp_vector_search/cli/interactive.py +342 -0
- mcp_vector_search/cli/main.py +484 -0
- mcp_vector_search/cli/output.py +414 -0
- mcp_vector_search/cli/suggestions.py +375 -0
- mcp_vector_search/config/__init__.py +1 -0
- mcp_vector_search/config/constants.py +24 -0
- mcp_vector_search/config/defaults.py +200 -0
- mcp_vector_search/config/settings.py +146 -0
- mcp_vector_search/core/__init__.py +1 -0
- mcp_vector_search/core/auto_indexer.py +298 -0
- mcp_vector_search/core/config_utils.py +394 -0
- mcp_vector_search/core/connection_pool.py +360 -0
- mcp_vector_search/core/database.py +1237 -0
- mcp_vector_search/core/directory_index.py +318 -0
- mcp_vector_search/core/embeddings.py +294 -0
- mcp_vector_search/core/exceptions.py +89 -0
- mcp_vector_search/core/factory.py +318 -0
- mcp_vector_search/core/git_hooks.py +345 -0
- mcp_vector_search/core/indexer.py +1002 -0
- mcp_vector_search/core/llm_client.py +453 -0
- mcp_vector_search/core/models.py +294 -0
- mcp_vector_search/core/project.py +350 -0
- mcp_vector_search/core/scheduler.py +330 -0
- mcp_vector_search/core/search.py +952 -0
- mcp_vector_search/core/watcher.py +322 -0
- mcp_vector_search/mcp/__init__.py +5 -0
- mcp_vector_search/mcp/__main__.py +25 -0
- mcp_vector_search/mcp/server.py +752 -0
- mcp_vector_search/parsers/__init__.py +8 -0
- mcp_vector_search/parsers/base.py +296 -0
- mcp_vector_search/parsers/dart.py +605 -0
- mcp_vector_search/parsers/html.py +413 -0
- mcp_vector_search/parsers/javascript.py +643 -0
- mcp_vector_search/parsers/php.py +694 -0
- mcp_vector_search/parsers/python.py +502 -0
- mcp_vector_search/parsers/registry.py +223 -0
- mcp_vector_search/parsers/ruby.py +678 -0
- mcp_vector_search/parsers/text.py +186 -0
- mcp_vector_search/parsers/utils.py +265 -0
- mcp_vector_search/py.typed +1 -0
- mcp_vector_search/utils/__init__.py +42 -0
- mcp_vector_search/utils/gitignore.py +250 -0
- mcp_vector_search/utils/gitignore_updater.py +212 -0
- mcp_vector_search/utils/monorepo.py +339 -0
- mcp_vector_search/utils/timing.py +338 -0
- mcp_vector_search/utils/version.py +47 -0
- mcp_vector_search-0.15.7.dist-info/METADATA +884 -0
- mcp_vector_search-0.15.7.dist-info/RECORD +86 -0
- mcp_vector_search-0.15.7.dist-info/WHEEL +4 -0
- mcp_vector_search-0.15.7.dist-info/entry_points.txt +3 -0
- mcp_vector_search-0.15.7.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,520 @@
|
|
|
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
|
+
# Chat command variations
|
|
216
|
+
"cht": "chat",
|
|
217
|
+
"caht": "chat",
|
|
218
|
+
"chta": "chat",
|
|
219
|
+
"ask": "chat",
|
|
220
|
+
"question": "chat",
|
|
221
|
+
"qa": "chat",
|
|
222
|
+
"llm": "chat",
|
|
223
|
+
"gpt": "chat",
|
|
224
|
+
"explain": "chat",
|
|
225
|
+
"answer": "chat",
|
|
226
|
+
# Index command variations
|
|
227
|
+
"indx": "index",
|
|
228
|
+
"idx": "index",
|
|
229
|
+
"indexx": "index",
|
|
230
|
+
"indez": "index",
|
|
231
|
+
"inedx": "index",
|
|
232
|
+
"reindex": "index --force",
|
|
233
|
+
"rebuild": "index --force",
|
|
234
|
+
"refresh": "index --force",
|
|
235
|
+
"scan": "index",
|
|
236
|
+
"build": "index",
|
|
237
|
+
"i": "index", # Single letter shortcut
|
|
238
|
+
"b": "index", # Alternative shortcut for build
|
|
239
|
+
# Status command variations
|
|
240
|
+
"stat": "status",
|
|
241
|
+
"stats": "status",
|
|
242
|
+
"info": "status",
|
|
243
|
+
"information": "status",
|
|
244
|
+
"details": "status",
|
|
245
|
+
"summary": "status",
|
|
246
|
+
"overview": "status",
|
|
247
|
+
"st": "status", # Common abbreviation
|
|
248
|
+
"status": "status",
|
|
249
|
+
# Config command variations
|
|
250
|
+
"conf": "config",
|
|
251
|
+
"cfg": "config",
|
|
252
|
+
"configure": "config",
|
|
253
|
+
"configuration": "config",
|
|
254
|
+
"setting": "config",
|
|
255
|
+
"settings": "config",
|
|
256
|
+
"preferences": "config",
|
|
257
|
+
"prefs": "config",
|
|
258
|
+
"c": "config", # Single letter shortcut
|
|
259
|
+
# Init command variations
|
|
260
|
+
"initialize": "init",
|
|
261
|
+
"setup": "init",
|
|
262
|
+
"start": "init",
|
|
263
|
+
"create": "init",
|
|
264
|
+
"new": "init",
|
|
265
|
+
"begin": "init",
|
|
266
|
+
"initalize": "init", # Common misspelling
|
|
267
|
+
"initalise": "init",
|
|
268
|
+
"initialise": "init",
|
|
269
|
+
# Watch command variations
|
|
270
|
+
"monitor": "watch",
|
|
271
|
+
"observe": "watch",
|
|
272
|
+
"track": "watch",
|
|
273
|
+
"listen": "watch",
|
|
274
|
+
"follow": "watch",
|
|
275
|
+
"w": "watch", # Single letter shortcut
|
|
276
|
+
# Auto-index command variations
|
|
277
|
+
"auto": "auto-index",
|
|
278
|
+
"automatic": "auto-index",
|
|
279
|
+
"autoindex": "auto-index",
|
|
280
|
+
"auto_index": "auto-index",
|
|
281
|
+
"ai": "auto-index", # Abbreviation
|
|
282
|
+
# MCP command variations
|
|
283
|
+
"claude": "mcp",
|
|
284
|
+
"server": "mcp",
|
|
285
|
+
"protocol": "mcp",
|
|
286
|
+
"model-context": "mcp",
|
|
287
|
+
"context": "mcp",
|
|
288
|
+
"m": "mcp", # Single letter shortcut
|
|
289
|
+
# Install command variations
|
|
290
|
+
"deploy": "install",
|
|
291
|
+
"add": "install",
|
|
292
|
+
"instal": "install", # Common typo
|
|
293
|
+
"install": "install",
|
|
294
|
+
# Demo command variations
|
|
295
|
+
"example": "demo",
|
|
296
|
+
"sample": "demo",
|
|
297
|
+
"test": "demo",
|
|
298
|
+
"try": "demo",
|
|
299
|
+
"d": "demo", # Single letter shortcut
|
|
300
|
+
# Health/Doctor command variations
|
|
301
|
+
"check": "doctor",
|
|
302
|
+
"health": "doctor",
|
|
303
|
+
"diagnose": "doctor",
|
|
304
|
+
"verify": "doctor",
|
|
305
|
+
"validate": "doctor",
|
|
306
|
+
"repair": "doctor",
|
|
307
|
+
"fix": "doctor",
|
|
308
|
+
"dr": "doctor", # Common abbreviation
|
|
309
|
+
# Version command variations
|
|
310
|
+
"ver": "version",
|
|
311
|
+
"v": "version",
|
|
312
|
+
"--version": "version",
|
|
313
|
+
"-v": "version",
|
|
314
|
+
# Help command variations
|
|
315
|
+
"help": "--help",
|
|
316
|
+
"h": "--help",
|
|
317
|
+
"--help": "--help",
|
|
318
|
+
"-h": "--help",
|
|
319
|
+
"?": "--help",
|
|
320
|
+
# History command variations
|
|
321
|
+
"hist": "history",
|
|
322
|
+
"log": "history",
|
|
323
|
+
"logs": "history",
|
|
324
|
+
"recent": "history",
|
|
325
|
+
# Reset command variations
|
|
326
|
+
"clear": "reset",
|
|
327
|
+
"clean": "reset",
|
|
328
|
+
"purge": "reset",
|
|
329
|
+
"wipe": "reset",
|
|
330
|
+
"remove": "reset",
|
|
331
|
+
"delete": "reset",
|
|
332
|
+
# Interactive command variations
|
|
333
|
+
"interact": "interactive",
|
|
334
|
+
"session": "interactive",
|
|
335
|
+
"repl": "interactive",
|
|
336
|
+
"console": "interactive",
|
|
337
|
+
"ui": "interactive",
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
# Command descriptions and examples for better error messages
|
|
341
|
+
COMMAND_INFO = {
|
|
342
|
+
"search": {
|
|
343
|
+
"description": "Search for code patterns semantically",
|
|
344
|
+
"examples": [
|
|
345
|
+
'mcp-vector-search search "authentication function"',
|
|
346
|
+
'mcp-vector-search search "error handling" --limit 5',
|
|
347
|
+
'mcp-vector-search search --files "*.ts" "query"',
|
|
348
|
+
],
|
|
349
|
+
"related": ["chat", "index", "status"],
|
|
350
|
+
},
|
|
351
|
+
"chat": {
|
|
352
|
+
"description": "Ask AI questions about your code (requires API key)",
|
|
353
|
+
"examples": [
|
|
354
|
+
'mcp-vector-search chat "where is the database configured?"',
|
|
355
|
+
'mcp-vector-search chat "how does authentication work?"',
|
|
356
|
+
'mcp-vector-search chat --limit 3 "explain error handling"',
|
|
357
|
+
],
|
|
358
|
+
"related": ["search", "status", "index"],
|
|
359
|
+
},
|
|
360
|
+
"index": {
|
|
361
|
+
"description": "Index codebase for semantic search",
|
|
362
|
+
"examples": [
|
|
363
|
+
"mcp-vector-search index",
|
|
364
|
+
"mcp-vector-search index --force",
|
|
365
|
+
'mcp-vector-search index --include "*.py,*.js"',
|
|
366
|
+
],
|
|
367
|
+
"related": ["auto-index", "watch", "reset"],
|
|
368
|
+
},
|
|
369
|
+
"status": {
|
|
370
|
+
"description": "Show project status and statistics",
|
|
371
|
+
"examples": ["mcp-vector-search status", "mcp-vector-search status --verbose"],
|
|
372
|
+
"related": ["doctor", "history", "version"],
|
|
373
|
+
},
|
|
374
|
+
"config": {
|
|
375
|
+
"description": "Manage project configuration",
|
|
376
|
+
"examples": [
|
|
377
|
+
"mcp-vector-search config show",
|
|
378
|
+
"mcp-vector-search config set model all-MiniLM-L6-v2",
|
|
379
|
+
],
|
|
380
|
+
"related": ["init", "status"],
|
|
381
|
+
},
|
|
382
|
+
"init": {
|
|
383
|
+
"description": "Initialize project for semantic search",
|
|
384
|
+
"examples": [
|
|
385
|
+
"mcp-vector-search init",
|
|
386
|
+
"mcp-vector-search init --model sentence-transformers/all-MiniLM-L6-v2",
|
|
387
|
+
],
|
|
388
|
+
"related": ["config", "install", "index"],
|
|
389
|
+
},
|
|
390
|
+
"mcp": {
|
|
391
|
+
"description": "Manage Claude Code MCP integration",
|
|
392
|
+
"examples": ["mcp-vector-search mcp", "mcp-vector-search mcp test"],
|
|
393
|
+
"related": ["init-mcp", "install"],
|
|
394
|
+
},
|
|
395
|
+
"doctor": {
|
|
396
|
+
"description": "Check system dependencies and configuration",
|
|
397
|
+
"examples": [
|
|
398
|
+
"mcp-vector-search doctor",
|
|
399
|
+
],
|
|
400
|
+
"related": ["status", "health"],
|
|
401
|
+
},
|
|
402
|
+
"version": {
|
|
403
|
+
"description": "Show version information",
|
|
404
|
+
"examples": ["mcp-vector-search version", "mcp-vector-search --version"],
|
|
405
|
+
"related": ["status", "doctor"],
|
|
406
|
+
},
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
def get_fuzzy_matches(
|
|
411
|
+
command: str, available_commands: list[str], cutoff: float = 0.6
|
|
412
|
+
) -> list[tuple[str, float]]:
|
|
413
|
+
"""Get fuzzy matches for a command using difflib.
|
|
414
|
+
|
|
415
|
+
Args:
|
|
416
|
+
command: The command to match
|
|
417
|
+
available_commands: List of available commands
|
|
418
|
+
cutoff: Minimum similarity ratio (0.0 to 1.0)
|
|
419
|
+
|
|
420
|
+
Returns:
|
|
421
|
+
List of tuples (command, similarity_ratio) sorted by similarity
|
|
422
|
+
"""
|
|
423
|
+
matches = []
|
|
424
|
+
for cmd in available_commands:
|
|
425
|
+
ratio = difflib.SequenceMatcher(None, command.lower(), cmd.lower()).ratio()
|
|
426
|
+
if ratio >= cutoff:
|
|
427
|
+
matches.append((cmd, ratio))
|
|
428
|
+
|
|
429
|
+
# Sort by similarity ratio (highest first)
|
|
430
|
+
return sorted(matches, key=lambda x: x[1], reverse=True)
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
def format_command_suggestion(command: str, show_examples: bool = True) -> str:
|
|
434
|
+
"""Format a command suggestion with description and examples.
|
|
435
|
+
|
|
436
|
+
Args:
|
|
437
|
+
command: The command to format
|
|
438
|
+
show_examples: Whether to include usage examples
|
|
439
|
+
|
|
440
|
+
Returns:
|
|
441
|
+
Formatted suggestion string
|
|
442
|
+
"""
|
|
443
|
+
if command in COMMAND_INFO:
|
|
444
|
+
info = COMMAND_INFO[command]
|
|
445
|
+
suggestion = f" [bold cyan]{command}[/bold cyan] - {info['description']}"
|
|
446
|
+
|
|
447
|
+
if show_examples and info["examples"]:
|
|
448
|
+
suggestion += f"\n Example: [dim]{info['examples'][0]}[/dim]"
|
|
449
|
+
|
|
450
|
+
return suggestion
|
|
451
|
+
else:
|
|
452
|
+
return f" [bold cyan]{command}[/bold cyan]"
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
def add_common_suggestions(ctx: click.Context, command_name: str) -> None:
|
|
456
|
+
"""Add enhanced command suggestions to error messages.
|
|
457
|
+
|
|
458
|
+
Args:
|
|
459
|
+
ctx: Click context
|
|
460
|
+
command_name: The invalid command name that was entered
|
|
461
|
+
"""
|
|
462
|
+
from rich.console import Console
|
|
463
|
+
|
|
464
|
+
console = Console(stderr=True)
|
|
465
|
+
|
|
466
|
+
# First, check for exact typo matches
|
|
467
|
+
direct_suggestion = COMMON_TYPOS.get(command_name.lower())
|
|
468
|
+
if direct_suggestion:
|
|
469
|
+
console.print("\n[yellow]Did you mean:[/yellow]")
|
|
470
|
+
console.print(format_command_suggestion(direct_suggestion.split()[0]))
|
|
471
|
+
|
|
472
|
+
if "--" not in direct_suggestion: # Don't show examples for flags
|
|
473
|
+
console.print(
|
|
474
|
+
f"\n[dim]Try: [bold]mcp-vector-search {direct_suggestion}[/bold][/dim]"
|
|
475
|
+
)
|
|
476
|
+
return
|
|
477
|
+
|
|
478
|
+
# Get available commands from the context
|
|
479
|
+
available_commands = []
|
|
480
|
+
if hasattr(ctx, "command") and hasattr(ctx.command, "commands"):
|
|
481
|
+
available_commands = list(ctx.command.commands.keys())
|
|
482
|
+
|
|
483
|
+
if not available_commands:
|
|
484
|
+
# Fallback to common commands
|
|
485
|
+
available_commands = [
|
|
486
|
+
"search",
|
|
487
|
+
"index",
|
|
488
|
+
"status",
|
|
489
|
+
"config",
|
|
490
|
+
"init",
|
|
491
|
+
"mcp",
|
|
492
|
+
"doctor",
|
|
493
|
+
"version",
|
|
494
|
+
]
|
|
495
|
+
|
|
496
|
+
# Get fuzzy matches
|
|
497
|
+
fuzzy_matches = get_fuzzy_matches(command_name, available_commands, cutoff=0.4)
|
|
498
|
+
|
|
499
|
+
if fuzzy_matches:
|
|
500
|
+
console.print("\n[yellow]Did you mean one of these?[/yellow]")
|
|
501
|
+
|
|
502
|
+
# Show up to 3 best matches
|
|
503
|
+
for cmd, _ratio in fuzzy_matches[:3]:
|
|
504
|
+
console.print(format_command_suggestion(cmd, show_examples=False))
|
|
505
|
+
|
|
506
|
+
# Show example for the best match
|
|
507
|
+
if fuzzy_matches:
|
|
508
|
+
best_match = fuzzy_matches[0][0]
|
|
509
|
+
if best_match in COMMAND_INFO and COMMAND_INFO[best_match]["examples"]:
|
|
510
|
+
console.print(
|
|
511
|
+
f"\n[dim]Example: [bold]{COMMAND_INFO[best_match]['examples'][0]}[/bold][/dim]"
|
|
512
|
+
)
|
|
513
|
+
|
|
514
|
+
# Show related commands for context
|
|
515
|
+
console.print(
|
|
516
|
+
f"\n[dim]Available commands: {', '.join(sorted(available_commands))}[/dim]"
|
|
517
|
+
)
|
|
518
|
+
console.print(
|
|
519
|
+
"[dim]Use [bold]mcp-vector-search --help[/bold] for more information[/dim]"
|
|
520
|
+
)
|