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