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.
- 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/config.py +393 -0
- mcp_vector_search/cli/commands/demo.py +358 -0
- mcp_vector_search/cli/commands/index.py +744 -0
- mcp_vector_search/cli/commands/init.py +645 -0
- mcp_vector_search/cli/commands/install.py +675 -0
- mcp_vector_search/cli/commands/install_old.py +696 -0
- mcp_vector_search/cli/commands/mcp.py +1182 -0
- mcp_vector_search/cli/commands/reset.py +393 -0
- mcp_vector_search/cli/commands/search.py +773 -0
- mcp_vector_search/cli/commands/status.py +549 -0
- mcp_vector_search/cli/commands/uninstall.py +485 -0
- mcp_vector_search/cli/commands/visualize.py +1467 -0
- mcp_vector_search/cli/commands/watch.py +287 -0
- mcp_vector_search/cli/didyoumean.py +500 -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 +461 -0
- mcp_vector_search/cli/output.py +412 -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 +134 -0
- mcp_vector_search/core/__init__.py +1 -0
- mcp_vector_search/core/auto_indexer.py +298 -0
- mcp_vector_search/core/connection_pool.py +360 -0
- mcp_vector_search/core/database.py +1214 -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/models.py +294 -0
- mcp_vector_search/core/project.py +333 -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 +733 -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 +40 -0
- mcp_vector_search/utils/gitignore.py +250 -0
- mcp_vector_search/utils/monorepo.py +277 -0
- mcp_vector_search/utils/timing.py +334 -0
- mcp_vector_search/utils/version.py +47 -0
- mcp_vector_search-0.12.6.dist-info/METADATA +754 -0
- mcp_vector_search-0.12.6.dist-info/RECORD +68 -0
- mcp_vector_search-0.12.6.dist-info/WHEEL +4 -0
- mcp_vector_search-0.12.6.dist-info/entry_points.txt +2 -0
- mcp_vector_search-0.12.6.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,461 @@
|
|
|
1
|
+
"""Main CLI application for MCP Vector Search."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
from loguru import logger
|
|
7
|
+
from rich.console import Console
|
|
8
|
+
from rich.traceback import install
|
|
9
|
+
|
|
10
|
+
from .. import __build__, __version__
|
|
11
|
+
from .didyoumean import add_common_suggestions, create_enhanced_typer
|
|
12
|
+
from .output import print_warning, setup_logging
|
|
13
|
+
from .suggestions import get_contextual_suggestions
|
|
14
|
+
|
|
15
|
+
# Install rich traceback handler
|
|
16
|
+
install(show_locals=True)
|
|
17
|
+
|
|
18
|
+
# Create console for rich output
|
|
19
|
+
console = Console()
|
|
20
|
+
|
|
21
|
+
# Create main Typer app with "did you mean" functionality
|
|
22
|
+
app = create_enhanced_typer(
|
|
23
|
+
name="mcp-vector-search",
|
|
24
|
+
help="""
|
|
25
|
+
đ [bold]CLI-first semantic code search with MCP integration[/bold]
|
|
26
|
+
|
|
27
|
+
Semantic search finds code by meaning, not just keywords. Perfect for exploring
|
|
28
|
+
unfamiliar codebases, finding similar patterns, and integrating with AI tools.
|
|
29
|
+
|
|
30
|
+
[bold cyan]Quick Start:[/bold cyan]
|
|
31
|
+
1. Initialize: [green]mcp-vector-search init[/green]
|
|
32
|
+
2. Search code: [green]mcp-vector-search search "your query"[/green]
|
|
33
|
+
3. Check status: [green]mcp-vector-search status[/green]
|
|
34
|
+
|
|
35
|
+
[bold cyan]Main Commands:[/bold cyan]
|
|
36
|
+
install đĻ Install project and MCP integrations
|
|
37
|
+
uninstall đī¸ Remove MCP integrations
|
|
38
|
+
init đ§ Initialize project (simple)
|
|
39
|
+
demo đŦ Run interactive demo
|
|
40
|
+
doctor đŠē Check system health
|
|
41
|
+
status đ Show project status
|
|
42
|
+
search đ Search code semantically
|
|
43
|
+
index đ Index codebase
|
|
44
|
+
mcp đ MCP server operations
|
|
45
|
+
config âī¸ Configure settings
|
|
46
|
+
visualize đ Visualize code relationships
|
|
47
|
+
help â Get help
|
|
48
|
+
version âšī¸ Show version
|
|
49
|
+
|
|
50
|
+
[dim]For detailed help: [cyan]mcp-vector-search COMMAND --help[/cyan][/dim]
|
|
51
|
+
""",
|
|
52
|
+
add_completion=False,
|
|
53
|
+
rich_markup_mode="rich",
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
# Import command modules
|
|
57
|
+
from .commands.config import config_app # noqa: E402
|
|
58
|
+
from .commands.demo import demo_app # noqa: E402
|
|
59
|
+
from .commands.index import index_app # noqa: E402
|
|
60
|
+
from .commands.init import init_app # noqa: E402
|
|
61
|
+
from .commands.install import install_app # noqa: E402
|
|
62
|
+
from .commands.mcp import mcp_app # noqa: E402
|
|
63
|
+
from .commands.search import search_app, search_main # noqa: E402, F401
|
|
64
|
+
from .commands.status import main as status_main # noqa: E402
|
|
65
|
+
from .commands.uninstall import uninstall_app # noqa: E402
|
|
66
|
+
from .commands.visualize import app as visualize_app # noqa: E402
|
|
67
|
+
|
|
68
|
+
# ============================================================================
|
|
69
|
+
# MAIN COMMANDS - Clean hierarchy
|
|
70
|
+
# ============================================================================
|
|
71
|
+
|
|
72
|
+
# 1. INSTALL - Install project and MCP integrations (NEW!)
|
|
73
|
+
app.add_typer(
|
|
74
|
+
install_app, name="install", help="đĻ Install project and MCP integrations"
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
# 2. UNINSTALL - Remove MCP integrations (NEW!)
|
|
78
|
+
app.add_typer(uninstall_app, name="uninstall", help="đī¸ Remove MCP integrations")
|
|
79
|
+
app.add_typer(uninstall_app, name="remove", help="đī¸ Remove MCP integrations (alias)")
|
|
80
|
+
|
|
81
|
+
# 3. INIT - Initialize project (simplified)
|
|
82
|
+
# Use Typer group for init to support both direct call and subcommands
|
|
83
|
+
app.add_typer(init_app, name="init", help="đ§ Initialize project for semantic search")
|
|
84
|
+
|
|
85
|
+
# 4. DEMO - Interactive demo
|
|
86
|
+
app.add_typer(demo_app, name="demo", help="đŦ Run interactive demo with sample project")
|
|
87
|
+
|
|
88
|
+
# 5. DOCTOR - System health check
|
|
89
|
+
# (defined below inline)
|
|
90
|
+
|
|
91
|
+
# 6. STATUS - Project status
|
|
92
|
+
app.command("status", help="đ Show project status and statistics")(status_main)
|
|
93
|
+
|
|
94
|
+
# 7. SEARCH - Search code
|
|
95
|
+
# Register search as both a command and a typer group
|
|
96
|
+
app.add_typer(search_app, name="search", help="đ Search code semantically")
|
|
97
|
+
|
|
98
|
+
# 8. INDEX - Index codebase
|
|
99
|
+
app.add_typer(index_app, name="index", help="đ Index codebase for semantic search")
|
|
100
|
+
|
|
101
|
+
# 9. MCP - MCP server operations (RESERVED for server ops only!)
|
|
102
|
+
app.add_typer(mcp_app, name="mcp", help="đ MCP server operations")
|
|
103
|
+
|
|
104
|
+
# 10. CONFIG - Configuration
|
|
105
|
+
app.add_typer(config_app, name="config", help="âī¸ Manage project configuration")
|
|
106
|
+
|
|
107
|
+
# 11. VISUALIZE - Code graph visualization
|
|
108
|
+
app.add_typer(
|
|
109
|
+
visualize_app, name="visualize", help="đ Visualize code chunk relationships"
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
# 12. HELP - Enhanced help
|
|
113
|
+
# (defined below inline)
|
|
114
|
+
|
|
115
|
+
# 13. VERSION - Version info
|
|
116
|
+
# (defined below inline)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
# ============================================================================
|
|
120
|
+
# DEPRECATED COMMANDS - With helpful suggestions
|
|
121
|
+
# ============================================================================
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def _deprecated_command(old_cmd: str, new_cmd: str):
|
|
125
|
+
"""Helper to create deprecated command with suggestion."""
|
|
126
|
+
|
|
127
|
+
def wrapper(*args, **kwargs):
|
|
128
|
+
print_warning(
|
|
129
|
+
f"â ī¸ The command '{old_cmd}' is deprecated.\n"
|
|
130
|
+
f" Please use '{new_cmd}' instead.\n"
|
|
131
|
+
f" Run: [cyan]mcp-vector-search {new_cmd} --help[/cyan] for details."
|
|
132
|
+
)
|
|
133
|
+
raise typer.Exit(1)
|
|
134
|
+
|
|
135
|
+
return wrapper
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
# NOTE: 'install' command is now the primary command for project installation
|
|
139
|
+
# Old 'install' was deprecated in favor of 'init' in v0.7.0
|
|
140
|
+
# Now 'install' is back as the hierarchical installation command in v0.13.0
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
# Deprecated: find -> search
|
|
144
|
+
@app.command("find", hidden=True)
|
|
145
|
+
def deprecated_find():
|
|
146
|
+
"""[DEPRECATED] Use 'search' instead."""
|
|
147
|
+
_deprecated_command("find", "search")()
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
# Deprecated: search-similar -> search --similar
|
|
151
|
+
@app.command("search-similar", hidden=True)
|
|
152
|
+
def deprecated_search_similar():
|
|
153
|
+
"""[DEPRECATED] Use 'search --similar' instead."""
|
|
154
|
+
_deprecated_command("search-similar", "search --similar")()
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
# Deprecated: search-context -> search --context
|
|
158
|
+
@app.command("search-context", hidden=True)
|
|
159
|
+
def deprecated_search_context():
|
|
160
|
+
"""[DEPRECATED] Use 'search --context' instead."""
|
|
161
|
+
_deprecated_command("search-context", "search --context")()
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
# Deprecated: interactive -> search interactive
|
|
165
|
+
@app.command("interactive", hidden=True)
|
|
166
|
+
def deprecated_interactive():
|
|
167
|
+
"""[DEPRECATED] Use 'search interactive' instead."""
|
|
168
|
+
_deprecated_command("interactive", "search interactive")()
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
# Deprecated: history -> search history
|
|
172
|
+
@app.command("history", hidden=True)
|
|
173
|
+
def deprecated_history():
|
|
174
|
+
"""[DEPRECATED] Use 'search history' instead."""
|
|
175
|
+
_deprecated_command("history", "search history")()
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
# Deprecated: favorites -> search favorites
|
|
179
|
+
@app.command("favorites", hidden=True)
|
|
180
|
+
def deprecated_favorites():
|
|
181
|
+
"""[DEPRECATED] Use 'search favorites' instead."""
|
|
182
|
+
_deprecated_command("favorites", "search favorites")()
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
# Deprecated: add-favorite -> search favorites add
|
|
186
|
+
@app.command("add-favorite", hidden=True)
|
|
187
|
+
def deprecated_add_favorite():
|
|
188
|
+
"""[DEPRECATED] Use 'search favorites add' instead."""
|
|
189
|
+
_deprecated_command("add-favorite", "search favorites add")()
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
# Deprecated: remove-favorite -> search favorites remove
|
|
193
|
+
@app.command("remove-favorite", hidden=True)
|
|
194
|
+
def deprecated_remove_favorite():
|
|
195
|
+
"""[DEPRECATED] Use 'search favorites remove' instead."""
|
|
196
|
+
_deprecated_command("remove-favorite", "search favorites remove")()
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
# Deprecated: health -> index health
|
|
200
|
+
@app.command("health", hidden=True)
|
|
201
|
+
def deprecated_health():
|
|
202
|
+
"""[DEPRECATED] Use 'index health' instead."""
|
|
203
|
+
_deprecated_command("health", "index health")()
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
# Deprecated: watch -> index watch
|
|
207
|
+
@app.command("watch", hidden=True)
|
|
208
|
+
def deprecated_watch():
|
|
209
|
+
"""[DEPRECATED] Use 'index watch' instead."""
|
|
210
|
+
_deprecated_command("watch", "index watch")()
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
# Deprecated: auto-index -> index auto
|
|
214
|
+
@app.command("auto-index", hidden=True)
|
|
215
|
+
def deprecated_auto_index():
|
|
216
|
+
"""[DEPRECATED] Use 'index auto' instead."""
|
|
217
|
+
_deprecated_command("auto-index", "index auto")()
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
# Deprecated: reset -> mcp reset or config reset
|
|
221
|
+
@app.command("reset", hidden=True)
|
|
222
|
+
def deprecated_reset():
|
|
223
|
+
"""[DEPRECATED] Use 'mcp reset' or 'config reset' instead."""
|
|
224
|
+
print_warning(
|
|
225
|
+
"â ī¸ The 'reset' command is deprecated.\n"
|
|
226
|
+
" Use [cyan]mcp-vector-search mcp reset[/cyan] for MCP reset\n"
|
|
227
|
+
" Use [cyan]mcp-vector-search config reset[/cyan] for config reset"
|
|
228
|
+
)
|
|
229
|
+
raise typer.Exit(1)
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
# Deprecated: init-check -> init check
|
|
233
|
+
@app.command("init-check", hidden=True)
|
|
234
|
+
def deprecated_init_check():
|
|
235
|
+
"""[DEPRECATED] Use 'init check' instead."""
|
|
236
|
+
_deprecated_command("init-check", "init check")()
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
# Deprecated: init-mcp -> mcp install
|
|
240
|
+
@app.command("init-mcp", hidden=True)
|
|
241
|
+
def deprecated_init_mcp():
|
|
242
|
+
"""[DEPRECATED] Use 'mcp install' instead."""
|
|
243
|
+
_deprecated_command("init-mcp", "mcp install")()
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
# Deprecated: init-models -> config models
|
|
247
|
+
@app.command("init-models", hidden=True)
|
|
248
|
+
def deprecated_init_models():
|
|
249
|
+
"""[DEPRECATED] Use 'config models' instead."""
|
|
250
|
+
_deprecated_command("init-models", "config models")()
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
# ============================================================================
|
|
254
|
+
# MAIN INLINE COMMANDS
|
|
255
|
+
# ============================================================================
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
@app.command("doctor")
|
|
259
|
+
def doctor_command() -> None:
|
|
260
|
+
"""đŠē Check system dependencies and configuration.
|
|
261
|
+
|
|
262
|
+
Runs diagnostic checks to ensure all required dependencies are installed
|
|
263
|
+
and properly configured. Use this to troubleshoot installation issues.
|
|
264
|
+
|
|
265
|
+
Examples:
|
|
266
|
+
mcp-vector-search doctor
|
|
267
|
+
"""
|
|
268
|
+
from .commands.status import check_dependencies
|
|
269
|
+
|
|
270
|
+
console.print("[bold blue]đŠē MCP Vector Search - System Check[/bold blue]\n")
|
|
271
|
+
|
|
272
|
+
# Check dependencies
|
|
273
|
+
deps_ok = check_dependencies()
|
|
274
|
+
|
|
275
|
+
if deps_ok:
|
|
276
|
+
console.print("\n[green]â All dependencies are available[/green]")
|
|
277
|
+
else:
|
|
278
|
+
console.print("\n[red]â Some dependencies are missing[/red]")
|
|
279
|
+
console.print(
|
|
280
|
+
"Run [code]pip install mcp-vector-search[/code] to install missing dependencies"
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
@app.command("help")
|
|
285
|
+
def help_command(
|
|
286
|
+
command: str | None = typer.Argument(
|
|
287
|
+
None, help="Command to get help for (optional)"
|
|
288
|
+
),
|
|
289
|
+
) -> None:
|
|
290
|
+
"""â Show contextual help and suggestions.
|
|
291
|
+
|
|
292
|
+
Get detailed help about specific commands or general usage guidance
|
|
293
|
+
based on your project state.
|
|
294
|
+
|
|
295
|
+
Examples:
|
|
296
|
+
mcp-vector-search help # General help
|
|
297
|
+
mcp-vector-search help search # Help for search command
|
|
298
|
+
mcp-vector-search help init # Help for init command
|
|
299
|
+
"""
|
|
300
|
+
try:
|
|
301
|
+
project_root = Path.cwd()
|
|
302
|
+
console.print(
|
|
303
|
+
f"[bold blue]mcp-vector-search[/bold blue] version [green]{__version__}[/green]"
|
|
304
|
+
)
|
|
305
|
+
console.print("[dim]CLI-first semantic code search with MCP integration[/dim]")
|
|
306
|
+
|
|
307
|
+
if command:
|
|
308
|
+
# Show help for specific command
|
|
309
|
+
console.print(
|
|
310
|
+
f"\n[dim]Run: [bold]mcp-vector-search {command} --help[/bold] for detailed help[/dim]"
|
|
311
|
+
)
|
|
312
|
+
else:
|
|
313
|
+
# Show general contextual suggestions
|
|
314
|
+
get_contextual_suggestions(project_root)
|
|
315
|
+
except Exception as e:
|
|
316
|
+
logger.debug(f"Failed to show contextual help: {e}")
|
|
317
|
+
console.print(
|
|
318
|
+
"\n[dim]Use [bold]mcp-vector-search --help[/bold] for more information.[/dim]"
|
|
319
|
+
)
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
@app.command("version")
|
|
323
|
+
def version_command() -> None:
|
|
324
|
+
"""âšī¸ Show version information."""
|
|
325
|
+
console.print(
|
|
326
|
+
f"[bold blue]mcp-vector-search[/bold blue] version [green]{__version__}[/green] [dim](build {__build__})[/dim]"
|
|
327
|
+
)
|
|
328
|
+
console.print("\n[dim]CLI-first semantic code search with MCP integration[/dim]")
|
|
329
|
+
console.print("[dim]Built with ChromaDB, Tree-sitter, and modern Python[/dim]")
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
@app.callback()
|
|
333
|
+
def main(
|
|
334
|
+
ctx: typer.Context,
|
|
335
|
+
version: bool = typer.Option(
|
|
336
|
+
False,
|
|
337
|
+
"--version",
|
|
338
|
+
"-v",
|
|
339
|
+
help="Show version and exit",
|
|
340
|
+
rich_help_panel="âšī¸ Information",
|
|
341
|
+
),
|
|
342
|
+
verbose: bool = typer.Option(
|
|
343
|
+
False,
|
|
344
|
+
"--verbose",
|
|
345
|
+
help="Enable verbose logging",
|
|
346
|
+
rich_help_panel="đ§ Global Options",
|
|
347
|
+
),
|
|
348
|
+
quiet: bool = typer.Option(
|
|
349
|
+
False,
|
|
350
|
+
"--quiet",
|
|
351
|
+
help="Suppress non-error output",
|
|
352
|
+
rich_help_panel="đ§ Global Options",
|
|
353
|
+
),
|
|
354
|
+
project_root: Path | None = typer.Option(
|
|
355
|
+
None,
|
|
356
|
+
"--project-root",
|
|
357
|
+
"-p",
|
|
358
|
+
help="Project root directory (auto-detected if not specified)",
|
|
359
|
+
exists=True,
|
|
360
|
+
file_okay=False,
|
|
361
|
+
dir_okay=True,
|
|
362
|
+
readable=True,
|
|
363
|
+
rich_help_panel="đ§ Global Options",
|
|
364
|
+
),
|
|
365
|
+
) -> None:
|
|
366
|
+
"""MCP Vector Search - CLI-first semantic code search with MCP integration.
|
|
367
|
+
|
|
368
|
+
A modern, lightweight tool for semantic code search using ChromaDB and Tree-sitter.
|
|
369
|
+
Designed for local development with optional MCP server integration.
|
|
370
|
+
"""
|
|
371
|
+
if version:
|
|
372
|
+
console.print(f"mcp-vector-search version {__version__} (build {__build__})")
|
|
373
|
+
raise typer.Exit()
|
|
374
|
+
|
|
375
|
+
# Setup logging
|
|
376
|
+
log_level = "DEBUG" if verbose else "ERROR" if quiet else "WARNING"
|
|
377
|
+
setup_logging(log_level)
|
|
378
|
+
|
|
379
|
+
# Store global options in context
|
|
380
|
+
ctx.ensure_object(dict)
|
|
381
|
+
ctx.obj["verbose"] = verbose
|
|
382
|
+
ctx.obj["quiet"] = quiet
|
|
383
|
+
ctx.obj["project_root"] = project_root
|
|
384
|
+
|
|
385
|
+
if verbose:
|
|
386
|
+
logger.info(f"MCP Vector Search v{__version__} (build {__build__})")
|
|
387
|
+
if project_root:
|
|
388
|
+
logger.info(f"Using project root: {project_root}")
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
# ============================================================================
|
|
392
|
+
# CLI ENTRY POINT WITH ERROR HANDLING
|
|
393
|
+
# ============================================================================
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
def cli_with_suggestions():
|
|
397
|
+
"""CLI wrapper that catches errors and provides suggestions."""
|
|
398
|
+
import sys
|
|
399
|
+
|
|
400
|
+
import click
|
|
401
|
+
|
|
402
|
+
try:
|
|
403
|
+
# Call the app with standalone_mode=False to get exceptions instead of sys.exit
|
|
404
|
+
app(standalone_mode=False)
|
|
405
|
+
except click.UsageError as e:
|
|
406
|
+
# Check if it's a "No such command" error
|
|
407
|
+
if "No such command" in str(e):
|
|
408
|
+
# Extract the command name from the error
|
|
409
|
+
import re
|
|
410
|
+
|
|
411
|
+
match = re.search(r"No such command '([^']+)'", str(e))
|
|
412
|
+
if match:
|
|
413
|
+
command_name = match.group(1)
|
|
414
|
+
|
|
415
|
+
# Show enhanced suggestions
|
|
416
|
+
from rich.console import Console
|
|
417
|
+
|
|
418
|
+
console = Console(stderr=True)
|
|
419
|
+
console.print(f"\\n[red]Error:[/red] {e}")
|
|
420
|
+
|
|
421
|
+
# Show enhanced suggestions
|
|
422
|
+
add_common_suggestions(None, command_name)
|
|
423
|
+
|
|
424
|
+
# Show contextual suggestions too
|
|
425
|
+
try:
|
|
426
|
+
project_root = Path.cwd()
|
|
427
|
+
get_contextual_suggestions(project_root, command_name)
|
|
428
|
+
except Exception as e:
|
|
429
|
+
logger.debug(
|
|
430
|
+
f"Failed to get contextual suggestions for error handling: {e}"
|
|
431
|
+
)
|
|
432
|
+
pass
|
|
433
|
+
|
|
434
|
+
sys.exit(2) # Exit with error code
|
|
435
|
+
|
|
436
|
+
# For other usage errors, show the default message and exit
|
|
437
|
+
click.echo(f"Error: {e}", err=True)
|
|
438
|
+
sys.exit(2)
|
|
439
|
+
except click.Abort:
|
|
440
|
+
# User interrupted (Ctrl+C)
|
|
441
|
+
sys.exit(1)
|
|
442
|
+
except SystemExit:
|
|
443
|
+
# Re-raise system exits
|
|
444
|
+
raise
|
|
445
|
+
except Exception as e:
|
|
446
|
+
# For other exceptions, show error and exit if verbose logging is enabled
|
|
447
|
+
# Suppress internal framework errors in normal operation
|
|
448
|
+
|
|
449
|
+
# Suppress harmless didyoumean framework AttributeError (known issue)
|
|
450
|
+
# This occurs during Click/Typer cleanup after successful command completion
|
|
451
|
+
if isinstance(e, AttributeError) and "attribute" in str(e) and "name" in str(e):
|
|
452
|
+
pass # Ignore - this is a harmless framework cleanup error
|
|
453
|
+
elif "--verbose" in sys.argv or "-v" in sys.argv:
|
|
454
|
+
click.echo(f"Unexpected error: {e}", err=True)
|
|
455
|
+
sys.exit(1)
|
|
456
|
+
# Otherwise, just exit silently to avoid confusing error messages
|
|
457
|
+
pass
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
if __name__ == "__main__":
|
|
461
|
+
cli_with_suggestions()
|