mcp-vector-search 0.12.6__py3-none-any.whl → 1.0.3__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.
Files changed (65) hide show
  1. mcp_vector_search/__init__.py +2 -2
  2. mcp_vector_search/analysis/__init__.py +64 -0
  3. mcp_vector_search/analysis/collectors/__init__.py +39 -0
  4. mcp_vector_search/analysis/collectors/base.py +164 -0
  5. mcp_vector_search/analysis/collectors/complexity.py +743 -0
  6. mcp_vector_search/analysis/metrics.py +341 -0
  7. mcp_vector_search/analysis/reporters/__init__.py +5 -0
  8. mcp_vector_search/analysis/reporters/console.py +222 -0
  9. mcp_vector_search/cli/commands/analyze.py +408 -0
  10. mcp_vector_search/cli/commands/chat.py +1262 -0
  11. mcp_vector_search/cli/commands/index.py +21 -3
  12. mcp_vector_search/cli/commands/init.py +13 -0
  13. mcp_vector_search/cli/commands/install.py +597 -335
  14. mcp_vector_search/cli/commands/install_old.py +8 -4
  15. mcp_vector_search/cli/commands/mcp.py +78 -6
  16. mcp_vector_search/cli/commands/reset.py +68 -26
  17. mcp_vector_search/cli/commands/search.py +30 -7
  18. mcp_vector_search/cli/commands/setup.py +1133 -0
  19. mcp_vector_search/cli/commands/status.py +37 -2
  20. mcp_vector_search/cli/commands/uninstall.py +276 -357
  21. mcp_vector_search/cli/commands/visualize/__init__.py +39 -0
  22. mcp_vector_search/cli/commands/visualize/cli.py +276 -0
  23. mcp_vector_search/cli/commands/visualize/exporters/__init__.py +12 -0
  24. mcp_vector_search/cli/commands/visualize/exporters/html_exporter.py +33 -0
  25. mcp_vector_search/cli/commands/visualize/exporters/json_exporter.py +29 -0
  26. mcp_vector_search/cli/commands/visualize/graph_builder.py +714 -0
  27. mcp_vector_search/cli/commands/visualize/layout_engine.py +469 -0
  28. mcp_vector_search/cli/commands/visualize/server.py +311 -0
  29. mcp_vector_search/cli/commands/visualize/state_manager.py +428 -0
  30. mcp_vector_search/cli/commands/visualize/templates/__init__.py +16 -0
  31. mcp_vector_search/cli/commands/visualize/templates/base.py +180 -0
  32. mcp_vector_search/cli/commands/visualize/templates/scripts.py +2507 -0
  33. mcp_vector_search/cli/commands/visualize/templates/styles.py +1313 -0
  34. mcp_vector_search/cli/commands/visualize.py.original +2536 -0
  35. mcp_vector_search/cli/didyoumean.py +22 -2
  36. mcp_vector_search/cli/main.py +115 -159
  37. mcp_vector_search/cli/output.py +24 -8
  38. mcp_vector_search/config/__init__.py +4 -0
  39. mcp_vector_search/config/default_thresholds.yaml +52 -0
  40. mcp_vector_search/config/settings.py +12 -0
  41. mcp_vector_search/config/thresholds.py +185 -0
  42. mcp_vector_search/core/auto_indexer.py +3 -3
  43. mcp_vector_search/core/boilerplate.py +186 -0
  44. mcp_vector_search/core/config_utils.py +394 -0
  45. mcp_vector_search/core/database.py +369 -94
  46. mcp_vector_search/core/exceptions.py +11 -0
  47. mcp_vector_search/core/git_hooks.py +4 -4
  48. mcp_vector_search/core/indexer.py +221 -4
  49. mcp_vector_search/core/llm_client.py +751 -0
  50. mcp_vector_search/core/models.py +3 -0
  51. mcp_vector_search/core/project.py +17 -0
  52. mcp_vector_search/core/scheduler.py +11 -11
  53. mcp_vector_search/core/search.py +179 -29
  54. mcp_vector_search/mcp/server.py +24 -5
  55. mcp_vector_search/utils/__init__.py +2 -0
  56. mcp_vector_search/utils/gitignore_updater.py +212 -0
  57. mcp_vector_search/utils/monorepo.py +66 -4
  58. mcp_vector_search/utils/timing.py +10 -6
  59. {mcp_vector_search-0.12.6.dist-info → mcp_vector_search-1.0.3.dist-info}/METADATA +182 -52
  60. mcp_vector_search-1.0.3.dist-info/RECORD +97 -0
  61. {mcp_vector_search-0.12.6.dist-info → mcp_vector_search-1.0.3.dist-info}/WHEEL +1 -1
  62. {mcp_vector_search-0.12.6.dist-info → mcp_vector_search-1.0.3.dist-info}/entry_points.txt +1 -0
  63. mcp_vector_search/cli/commands/visualize.py +0 -1467
  64. mcp_vector_search-0.12.6.dist-info/RECORD +0 -68
  65. {mcp_vector_search-0.12.6.dist-info → mcp_vector_search-1.0.3.dist-info}/licenses/LICENSE +0 -0
@@ -212,6 +212,17 @@ COMMON_TYPOS = {
212
212
  "grep": "search",
213
213
  "s": "search", # Single letter shortcut
214
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",
215
226
  # Index command variations
216
227
  "indx": "index",
217
228
  "idx": "index",
@@ -333,9 +344,18 @@ COMMAND_INFO = {
333
344
  "examples": [
334
345
  'mcp-vector-search search "authentication function"',
335
346
  'mcp-vector-search search "error handling" --limit 5',
336
- 'mcp-vector-search find "database connection"',
347
+ 'mcp-vector-search search --files "*.ts" "query"',
337
348
  ],
338
- "related": ["search-similar", "search-context", "find", "interactive"],
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"],
339
359
  },
340
360
  "index": {
341
361
  "description": "Index codebase for semantic search",
@@ -1,5 +1,8 @@
1
1
  """Main CLI application for MCP Vector Search."""
2
2
 
3
+ import faulthandler
4
+ import signal
5
+ import sys
3
6
  from pathlib import Path
4
7
 
5
8
  import typer
@@ -9,9 +12,52 @@ from rich.traceback import install
9
12
 
10
13
  from .. import __build__, __version__
11
14
  from .didyoumean import add_common_suggestions, create_enhanced_typer
12
- from .output import print_warning, setup_logging
15
+ from .output import setup_logging
13
16
  from .suggestions import get_contextual_suggestions
14
17
 
18
+
19
+ # ============================================================================
20
+ # SIGNAL HANDLERS - Register early for crash diagnostics
21
+ # ============================================================================
22
+ def _handle_segfault(signum: int, frame) -> None:
23
+ """Handle segmentation faults with helpful error message.
24
+
25
+ Segmentation faults typically occur due to corrupted ChromaDB index data
26
+ or issues with native libraries (sentence-transformers, tree-sitter).
27
+
28
+ Args:
29
+ signum: Signal number (SIGSEGV = 11)
30
+ frame: Current stack frame (unused)
31
+ """
32
+ error_message = """
33
+ ╭─────────────────────────────────────────────────────────────────╮
34
+ │ ⚠️ Segmentation Fault Detected │
35
+ ├─────────────────────────────────────────────────────────────────┤
36
+ │ This usually indicates corrupted index data or a crash in │
37
+ │ native libraries (ChromaDB, sentence-transformers, tree-sitter).│
38
+ │ │
39
+ │ To fix this, please run: │
40
+ │ 1. mcp-vector-search reset index --force │
41
+ │ 2. mcp-vector-search index │
42
+ │ │
43
+ │ This will rebuild your search index from scratch. │
44
+ │ │
45
+ │ If the problem persists: │
46
+ │ - Try updating dependencies: pip install -U mcp-vector-search │
47
+ │ - Check GitHub issues: github.com/bobmatnyc/mcp-vector-search │
48
+ ╰─────────────────────────────────────────────────────────────────╯
49
+ """
50
+ print(error_message, file=sys.stderr)
51
+ sys.exit(139) # Standard segfault exit code (128 + 11)
52
+
53
+
54
+ # Register signal handler for segmentation faults
55
+ signal.signal(signal.SIGSEGV, _handle_segfault)
56
+
57
+ # Enable faulthandler for better crash diagnostics
58
+ # This prints Python traceback on segfaults before signal handler runs
59
+ faulthandler.enable()
60
+
15
61
  # Install rich traceback handler
16
62
  install(show_locals=True)
17
63
 
@@ -22,45 +68,65 @@ console = Console()
22
68
  app = create_enhanced_typer(
23
69
  name="mcp-vector-search",
24
70
  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]
71
+ 🔍 [bold]MCP Vector Search - Semantic Code Search CLI[/bold]
72
+
73
+ Search your codebase by meaning, not just keywords. Find similar code patterns,
74
+ explore unfamiliar projects, and integrate with AI coding tools via MCP.
75
+
76
+ [bold cyan]QUICK START:[/bold cyan]
77
+ mcp-vector-search setup # One-time setup (recommended)
78
+ mcp-vector-search search "query" # Search by meaning
79
+ mcp-vector-search chat "question" # Ask AI about your code
80
+
81
+ [bold cyan]MAIN COMMANDS:[/bold cyan]
82
+ setup 🚀 Zero-config setup (indexes + configures MCP)
83
+ search 🔍 Semantic search (finds code by meaning)
84
+ chat 🤖 LLM-powered Q&A about your code (needs API key)
85
+ status 📊 Show project status
86
+ visualize 📊 Interactive code graph
87
+
88
+ [bold cyan]AI CHAT SETUP:[/bold cyan]
89
+ The 'chat' command requires an OpenRouter API key:
90
+ 1. Get key: [cyan]https://openrouter.ai/keys[/cyan]
91
+ 2. Set: [yellow]export OPENROUTER_API_KEY='your-key'[/yellow]
92
+
93
+ [bold cyan]EXAMPLES:[/bold cyan]
94
+ mcp-vector-search search "error handling"
95
+ mcp-vector-search search --files "*.ts" "authentication"
96
+ mcp-vector-search chat "where is the database configured?"
97
+ mcp-vector-search chat "how does auth work in this project?"
98
+
99
+ [bold cyan]MORE COMMANDS:[/bold cyan]
36
100
  install 📦 Install project and MCP integrations
37
101
  uninstall 🗑️ Remove MCP integrations
38
- init 🔧 Initialize project (simple)
102
+ init 🔧 Initialize project (advanced)
39
103
  demo 🎬 Run interactive demo
40
104
  doctor 🩺 Check system health
41
- status 📊 Show project status
42
- search 🔍 Search code semantically
43
105
  index 📇 Index codebase
106
+ reset 🔄 Reset and recovery operations
44
107
  mcp 🔌 MCP server operations
45
108
  config ⚙️ Configure settings
46
- visualize 📊 Visualize code relationships
47
109
  help ❓ Get help
48
110
  version ℹ️ Show version
49
111
 
50
- [dim]For detailed help: [cyan]mcp-vector-search COMMAND --help[/cyan][/dim]
112
+ [dim]For more: [cyan]mcp-vector-search COMMAND --help[/cyan][/dim]
51
113
  """,
52
114
  add_completion=False,
53
115
  rich_markup_mode="rich",
54
116
  )
55
117
 
56
118
  # Import command modules
119
+ from .commands.analyze import analyze_app # noqa: E402
120
+ from .commands.chat import chat_app # noqa: E402
57
121
  from .commands.config import config_app # noqa: E402
58
122
  from .commands.demo import demo_app # noqa: E402
59
123
  from .commands.index import index_app # noqa: E402
60
124
  from .commands.init import init_app # noqa: E402
61
125
  from .commands.install import install_app # noqa: E402
62
126
  from .commands.mcp import mcp_app # noqa: E402
127
+ from .commands.reset import reset_app # noqa: E402
63
128
  from .commands.search import search_app, search_main # noqa: E402, F401
129
+ from .commands.setup import setup_app # noqa: E402
64
130
  from .commands.status import main as status_main # noqa: E402
65
131
  from .commands.uninstall import uninstall_app # noqa: E402
66
132
  from .commands.visualize import app as visualize_app # noqa: E402
@@ -69,6 +135,9 @@ from .commands.visualize import app as visualize_app # noqa: E402
69
135
  # MAIN COMMANDS - Clean hierarchy
70
136
  # ============================================================================
71
137
 
138
+ # 0. SETUP - Smart zero-config setup (RECOMMENDED!)
139
+ app.add_typer(setup_app, name="setup", help="🚀 Smart zero-config setup (recommended)")
140
+
72
141
  # 1. INSTALL - Install project and MCP integrations (NEW!)
73
142
  app.add_typer(
74
143
  install_app, name="install", help="📦 Install project and MCP integrations"
@@ -95,6 +164,9 @@ app.command("status", help="📊 Show project status and statistics")(status_mai
95
164
  # Register search as both a command and a typer group
96
165
  app.add_typer(search_app, name="search", help="🔍 Search code semantically")
97
166
 
167
+ # 7.5. CHAT - LLM-powered intelligent search
168
+ app.add_typer(chat_app, name="chat", help="🤖 Ask questions about code with LLM")
169
+
98
170
  # 8. INDEX - Index codebase
99
171
  app.add_typer(index_app, name="index", help="📇 Index codebase for semantic search")
100
172
 
@@ -104,152 +176,26 @@ app.add_typer(mcp_app, name="mcp", help="🔌 MCP server operations")
104
176
  # 10. CONFIG - Configuration
105
177
  app.add_typer(config_app, name="config", help="⚙️ Manage project configuration")
106
178
 
107
- # 11. VISUALIZE - Code graph visualization
179
+ # 10.5. RESET - Reset and recovery operations
180
+ app.add_typer(reset_app, name="reset", help="🔄 Reset and recovery operations")
181
+
182
+ # 11. ANALYZE - Code complexity analysis
183
+ app.add_typer(
184
+ analyze_app, name="analyze", help="📈 Analyze code complexity and quality"
185
+ )
186
+
187
+ # 12. VISUALIZE - Code graph visualization
108
188
  app.add_typer(
109
189
  visualize_app, name="visualize", help="📊 Visualize code chunk relationships"
110
190
  )
111
191
 
112
- # 12. HELP - Enhanced help
192
+ # 13. HELP - Enhanced help
113
193
  # (defined below inline)
114
194
 
115
- # 13. VERSION - Version info
195
+ # 14. VERSION - Version info
116
196
  # (defined below inline)
117
197
 
118
198
 
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
199
  # ============================================================================
254
200
  # MAIN INLINE COMMANDS
255
201
  # ============================================================================
@@ -329,6 +275,15 @@ def version_command() -> None:
329
275
  console.print("[dim]Built with ChromaDB, Tree-sitter, and modern Python[/dim]")
330
276
 
331
277
 
278
+ def _version_callback(value: bool) -> None:
279
+ """Handle --version flag eagerly before command parsing."""
280
+ if value:
281
+ console.print(
282
+ f"[bold blue]mcp-vector-search[/bold blue] version [green]{__version__}[/green] [dim](build {__build__})[/dim]"
283
+ )
284
+ raise typer.Exit()
285
+
286
+
332
287
  @app.callback()
333
288
  def main(
334
289
  ctx: typer.Context,
@@ -338,6 +293,8 @@ def main(
338
293
  "-v",
339
294
  help="Show version and exit",
340
295
  rich_help_panel="ℹ️ Information",
296
+ is_eager=True,
297
+ callback=lambda v: _version_callback(v),
341
298
  ),
342
299
  verbose: bool = typer.Option(
343
300
  False,
@@ -368,9 +325,8 @@ def main(
368
325
  A modern, lightweight tool for semantic code search using ChromaDB and Tree-sitter.
369
326
  Designed for local development with optional MCP server integration.
370
327
  """
371
- if version:
372
- console.print(f"mcp-vector-search version {__version__} (build {__build__})")
373
- raise typer.Exit()
328
+ # Note: --version is handled by _version_callback with is_eager=True
329
+ # This ensures it runs before no_args_is_help check
374
330
 
375
331
  # Setup logging
376
332
  log_level = "DEBUG" if verbose else "ERROR" if quiet else "WARNING"
@@ -439,8 +395,8 @@ def cli_with_suggestions():
439
395
  except click.Abort:
440
396
  # User interrupted (Ctrl+C)
441
397
  sys.exit(1)
442
- except SystemExit:
443
- # Re-raise system exits
398
+ except (SystemExit, click.exceptions.Exit):
399
+ # Re-raise system exits and typer.Exit
444
400
  raise
445
401
  except Exception as e:
446
402
  # For other exceptions, show error and exit if verbose logging is enabled
@@ -97,9 +97,11 @@ def print_project_info(project_info: ProjectInfo) -> None:
97
97
  table.add_row("Initialized", "✓" if project_info.is_initialized else "✗")
98
98
  table.add_row(
99
99
  "Languages",
100
- ", ".join(project_info.languages)
101
- if project_info.languages
102
- else "None detected",
100
+ (
101
+ ", ".join(project_info.languages)
102
+ if project_info.languages
103
+ else "None detected"
104
+ ),
103
105
  )
104
106
  table.add_row("Indexable Files", str(project_info.file_count))
105
107
 
@@ -248,16 +250,30 @@ def print_dependency_status(
248
250
 
249
251
 
250
252
  def print_json(data: Any, title: str | None = None) -> None:
251
- """Print data as formatted JSON."""
252
- import json
253
+ """Print data as formatted JSON.
254
+
255
+ When title is None (typical for --json flag), outputs raw JSON to stdout
256
+ for machine consumption (e.g., piping to json.tool).
257
+ When title is provided, uses Rich formatting for human-readable display.
253
258
 
254
- json_str = json.dumps(data, indent=2, default=str)
255
- syntax = Syntax(json_str, "json", theme="monokai")
259
+ Args:
260
+ data: Data to serialize as JSON
261
+ title: Optional title for Rich panel display
262
+ """
263
+ import json
256
264
 
257
265
  if title:
266
+ # Human-readable display with Rich formatting
267
+ json_str = json.dumps(data, indent=2, default=str)
268
+ syntax = Syntax(json_str, "json", theme="monokai")
258
269
  console.print(Panel(syntax, title=title, border_style="blue"))
259
270
  else:
260
- console.print(syntax)
271
+ # Machine-readable output: raw JSON to stdout
272
+ # Use sys.stdout.write to bypass Rich console formatting
273
+ json_str = json.dumps(data, indent=2, default=str, ensure_ascii=False)
274
+ sys.stdout.write(json_str)
275
+ sys.stdout.write("\n")
276
+ sys.stdout.flush()
261
277
 
262
278
 
263
279
  def print_panel(
@@ -1 +1,5 @@
1
1
  """Configuration management for MCP Vector Search."""
2
+
3
+ from .thresholds import ComplexityThresholds, SmellThresholds, ThresholdConfig
4
+
5
+ __all__ = ["ComplexityThresholds", "SmellThresholds", "ThresholdConfig"]
@@ -0,0 +1,52 @@
1
+ # Code Quality Threshold Configuration
2
+ # Customize these values to match your project's standards
3
+
4
+ complexity:
5
+ # Cognitive complexity grade thresholds
6
+ cognitive_a: 5 # Grade A: 0-5 (excellent)
7
+ cognitive_b: 10 # Grade B: 6-10 (good)
8
+ cognitive_c: 20 # Grade C: 11-20 (acceptable)
9
+ cognitive_d: 30 # Grade D: 21-30 (needs improvement)
10
+ # Grade F: 31+ (refactor recommended)
11
+
12
+ # Cyclomatic complexity thresholds
13
+ cyclomatic_low: 4 # Low: 1-4
14
+ cyclomatic_moderate: 10 # Moderate: 5-10
15
+ cyclomatic_high: 20 # High: 11-20
16
+ # Very high: 21+
17
+
18
+ # Nesting depth thresholds
19
+ nesting_warning: 3 # Warning level
20
+ nesting_error: 5 # Error level
21
+
22
+ # Parameter count thresholds
23
+ parameters_warning: 4 # Warning level
24
+ parameters_error: 7 # Error level
25
+
26
+ # Method count thresholds (per class)
27
+ methods_warning: 10 # Warning level
28
+ methods_error: 20 # Error level
29
+
30
+ smells:
31
+ # Long method (lines of code)
32
+ long_method_lines: 50
33
+
34
+ # Too many parameters
35
+ too_many_parameters: 5
36
+
37
+ # Deep nesting
38
+ deep_nesting_depth: 4
39
+
40
+ # High complexity
41
+ high_complexity: 15
42
+
43
+ # God class (too many methods)
44
+ god_class_methods: 20
45
+
46
+ # Feature envy (external calls)
47
+ feature_envy_external_calls: 5
48
+
49
+ # Quality gate settings
50
+ fail_on_f_grade: true # Fail quality gate on F grade
51
+ fail_on_smell_count: 10 # Fail if more than N smells total
52
+ warn_on_d_grade: true # Warn on D grade
@@ -49,6 +49,18 @@ class ProjectConfig(BaseSettings):
49
49
  default=True,
50
50
  description="Respect .gitignore patterns when indexing files",
51
51
  )
52
+ openrouter_api_key: str | None = Field(
53
+ default=None,
54
+ description="OpenRouter API key for chat command (optional, can also use env var)",
55
+ )
56
+ openai_api_key: str | None = Field(
57
+ default=None,
58
+ description="OpenAI API key for chat command (optional, can also use env var)",
59
+ )
60
+ preferred_llm_provider: str | None = Field(
61
+ default=None,
62
+ description="Preferred LLM provider: 'openai' or 'openrouter' (auto-detect if not set)",
63
+ )
52
64
 
53
65
  @field_validator("project_root", "index_path", mode="before")
54
66
  @classmethod