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.

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