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