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,414 @@
1
+ """Rich formatting and display utilities for CLI."""
2
+
3
+ import sys
4
+ from pathlib import Path
5
+ from typing import Any
6
+
7
+ from loguru import logger
8
+ from rich.console import Console
9
+ from rich.panel import Panel
10
+ from rich.progress import (
11
+ BarColumn,
12
+ MofNCompleteColumn,
13
+ Progress,
14
+ SpinnerColumn,
15
+ TextColumn,
16
+ TimeElapsedColumn,
17
+ )
18
+ from rich.syntax import Syntax
19
+ from rich.table import Table
20
+
21
+ from ..core.models import ProjectInfo, SearchResult
22
+
23
+ # Global console instance
24
+ console = Console()
25
+
26
+
27
+ def setup_logging(level: str = "WARNING") -> None:
28
+ """Setup structured logging with rich formatting.
29
+
30
+ Args:
31
+ level: Log level (DEBUG, INFO, WARNING, ERROR)
32
+ """
33
+ # Remove all existing handlers
34
+ logger.remove()
35
+
36
+ # Only add console handler if level is DEBUG or INFO
37
+ # For WARNING and ERROR, we want minimal output
38
+ if level in ["DEBUG", "INFO"]:
39
+ logger.add(
40
+ sys.stderr,
41
+ level=level,
42
+ format="<green>{time:HH:mm:ss}</green> | <level>{level: <8}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>",
43
+ colorize=True,
44
+ )
45
+ else:
46
+ # For WARNING and ERROR, use minimal format and only show WARNING+ messages
47
+ logger.add(
48
+ sys.stderr,
49
+ level=level,
50
+ format="<level>{level}</level>: <level>{message}</level>",
51
+ colorize=True,
52
+ )
53
+
54
+
55
+ def print_success(message: str) -> None:
56
+ """Print success message."""
57
+ console.print(f"[green]āœ“[/green] {message}")
58
+
59
+
60
+ def print_error(message: str) -> None:
61
+ """Print error message."""
62
+ console.print(f"[red]āœ—[/red] {message}")
63
+
64
+
65
+ def print_warning(message: str) -> None:
66
+ """Print warning message."""
67
+ console.print(f"[yellow]⚠[/yellow] {message}")
68
+
69
+
70
+ def print_info(message: str) -> None:
71
+ """Print info message."""
72
+ console.print(f"[blue]ℹ[/blue] {message}")
73
+
74
+
75
+ def create_progress() -> Progress:
76
+ """Create a progress bar for long-running operations."""
77
+ return Progress(
78
+ SpinnerColumn(),
79
+ TextColumn("[progress.description]{task.description}"),
80
+ BarColumn(),
81
+ MofNCompleteColumn(),
82
+ TimeElapsedColumn(),
83
+ console=console,
84
+ )
85
+
86
+
87
+ def print_project_info(project_info: ProjectInfo) -> None:
88
+ """Print project information in a formatted table."""
89
+ table = Table(title="Project Information", show_header=False)
90
+ table.add_column("Property", style="cyan", no_wrap=True)
91
+ table.add_column("Value", style="white")
92
+
93
+ table.add_row("Name", project_info.name)
94
+ table.add_row("Root Path", str(project_info.root_path))
95
+ table.add_row("Config Path", str(project_info.config_path))
96
+ table.add_row("Index Path", str(project_info.index_path))
97
+ table.add_row("Initialized", "āœ“" if project_info.is_initialized else "āœ—")
98
+ table.add_row(
99
+ "Languages",
100
+ (
101
+ ", ".join(project_info.languages)
102
+ if project_info.languages
103
+ else "None detected"
104
+ ),
105
+ )
106
+ table.add_row("Indexable Files", str(project_info.file_count))
107
+
108
+ console.print(table)
109
+
110
+
111
+ def print_search_results(
112
+ results: list[SearchResult],
113
+ query: str,
114
+ show_content: bool = True,
115
+ max_content_lines: int = 10,
116
+ ) -> None:
117
+ """Print search results in a formatted display."""
118
+ if not results:
119
+ print_warning(f"No results found for query: '{query}'")
120
+ return
121
+
122
+ console.print(
123
+ f"\n[bold blue]Search Results for:[/bold blue] [green]'{query}'[/green]"
124
+ )
125
+ console.print(f"[dim]Found {len(results)} results[/dim]\n")
126
+
127
+ for i, result in enumerate(results, 1):
128
+ # Create result header
129
+ header = f"[bold]{i}. {result.file_path.name}[/bold]"
130
+ if result.function_name:
131
+ header += f" → [cyan]{result.function_name}()[/cyan]"
132
+ if result.class_name:
133
+ header += f" in [yellow]{result.class_name}[/yellow]"
134
+
135
+ # Add location and similarity
136
+ location = f"[dim]{result.location}[/dim]"
137
+ similarity = f"[green]{result.similarity_score:.2%}[/green]"
138
+
139
+ console.print(f"{header}")
140
+ console.print(f" {location} | Similarity: {similarity}")
141
+
142
+ # Show code content if requested
143
+ if show_content and result.content:
144
+ content_lines = result.content.splitlines()
145
+ if len(content_lines) > max_content_lines:
146
+ content_lines = content_lines[:max_content_lines]
147
+ content_lines.append("...")
148
+
149
+ content = "\n".join(content_lines)
150
+
151
+ # Create syntax-highlighted code block
152
+ syntax = Syntax(
153
+ content,
154
+ result.language,
155
+ theme="monokai",
156
+ line_numbers=True,
157
+ start_line=result.start_line,
158
+ word_wrap=True,
159
+ )
160
+
161
+ console.print(Panel(syntax, border_style="dim"))
162
+
163
+ console.print() # Empty line between results
164
+
165
+
166
+ def print_index_stats(stats: dict[str, Any]) -> None:
167
+ """Print indexing statistics."""
168
+ table = Table(title="Index Statistics", show_header=False)
169
+ table.add_column("Metric", style="cyan", no_wrap=True)
170
+ table.add_column("Value", style="white")
171
+
172
+ table.add_row("Total Files", str(stats.get("total_indexable_files", 0)))
173
+ table.add_row("Indexed Files", str(stats.get("indexed_files", 0)))
174
+ table.add_row("Total Chunks", str(stats.get("total_chunks", 0)))
175
+
176
+ # Language distribution
177
+ languages = stats.get("languages", {})
178
+ if languages:
179
+ lang_str = ", ".join(f"{lang}: {count}" for lang, count in languages.items())
180
+ table.add_row("Languages", lang_str)
181
+
182
+ # File extensions
183
+ extensions = stats.get("file_extensions", [])
184
+ if extensions:
185
+ table.add_row("Extensions", ", ".join(extensions))
186
+
187
+ console.print(table)
188
+
189
+
190
+ def print_config(config_dict: dict[str, Any]) -> None:
191
+ """Print configuration in a formatted table."""
192
+ table = Table(title="Configuration", show_header=False)
193
+ table.add_column("Setting", style="cyan", no_wrap=True)
194
+ table.add_column("Value", style="white")
195
+
196
+ for key, value in config_dict.items():
197
+ if isinstance(value, list | dict):
198
+ value_str = str(value)
199
+ elif isinstance(value, Path):
200
+ value_str = str(value)
201
+ else:
202
+ value_str = str(value)
203
+
204
+ table.add_row(key.replace("_", " ").title(), value_str)
205
+
206
+ console.print(table)
207
+
208
+
209
+ def confirm_action(message: str, default: bool = False) -> bool:
210
+ """Ask for user confirmation."""
211
+ default_str = "Y/n" if default else "y/N"
212
+ response = console.input(f"{message} [{default_str}]: ").strip().lower()
213
+
214
+ if not response:
215
+ return default
216
+
217
+ return response in ("y", "yes", "true", "1")
218
+
219
+
220
+ def print_banner() -> None:
221
+ """Print application banner."""
222
+ banner = """
223
+ [bold blue]MCP Vector Search[/bold blue]
224
+ [dim]CLI-first semantic code search with MCP integration[/dim]
225
+ """
226
+ console.print(Panel(banner.strip(), border_style="blue"))
227
+
228
+
229
+ def format_file_path(file_path: Path, project_root: Path | None = None) -> str:
230
+ """Format file path for display (relative to project root if possible)."""
231
+ if project_root:
232
+ try:
233
+ relative_path = file_path.relative_to(project_root)
234
+ return str(relative_path)
235
+ except ValueError:
236
+ pass
237
+
238
+ return str(file_path)
239
+
240
+
241
+ def print_dependency_status(
242
+ name: str, available: bool, version: str | None = None
243
+ ) -> None:
244
+ """Print dependency status."""
245
+ if available:
246
+ version_str = f" ({version})" if version else ""
247
+ console.print(f"[green]āœ“[/green] {name}{version_str}")
248
+ else:
249
+ console.print(f"[red]āœ—[/red] {name} - Not available")
250
+
251
+
252
+ def print_json(data: Any, title: str | None = None) -> None:
253
+ """Print data as formatted JSON."""
254
+ import json
255
+
256
+ json_str = json.dumps(data, indent=2, default=str)
257
+ syntax = Syntax(json_str, "json", theme="monokai")
258
+
259
+ if title:
260
+ console.print(Panel(syntax, title=title, border_style="blue"))
261
+ else:
262
+ console.print(syntax)
263
+
264
+
265
+ def print_panel(
266
+ content: str,
267
+ title: str | None = None,
268
+ border_style: str = "blue",
269
+ padding: tuple[int, int] = (1, 2),
270
+ ) -> None:
271
+ """Print content in a Rich panel.
272
+
273
+ Args:
274
+ content: The content to display in the panel
275
+ title: Optional title for the panel
276
+ border_style: Border color/style (default: "blue")
277
+ padding: Tuple of (vertical, horizontal) padding
278
+ """
279
+ console.print(
280
+ Panel(
281
+ content,
282
+ title=title,
283
+ border_style=border_style,
284
+ padding=padding,
285
+ )
286
+ )
287
+
288
+
289
+ def print_next_steps(steps: list[str], title: str = "Next Steps") -> None:
290
+ """Print next step hints after a command execution.
291
+
292
+ Args:
293
+ steps: List of next step descriptions
294
+ title: Panel title (default: "Next Steps")
295
+ """
296
+ content = "\n".join(f" {i}. {step}" for i, step in enumerate(steps, 1))
297
+ print_panel(content, title=f"šŸš€ {title}", border_style="blue")
298
+
299
+
300
+ def print_tip(message: str) -> None:
301
+ """Print a helpful tip message.
302
+
303
+ Args:
304
+ message: The tip message to display
305
+ """
306
+ console.print(f"[dim]šŸ’” Tip: {message}[/dim]")
307
+
308
+
309
+ def print_completion_status(
310
+ title: str,
311
+ completed_items: list[str],
312
+ pending_items: list[str] | None = None,
313
+ ) -> None:
314
+ """Print completion status with checkmarks.
315
+
316
+ Args:
317
+ title: Status title
318
+ completed_items: List of completed items
319
+ pending_items: Optional list of pending items
320
+ """
321
+ content_lines = []
322
+
323
+ if completed_items:
324
+ content_lines.append("[bold green]✨ Completed:[/bold green]")
325
+ for item in completed_items:
326
+ content_lines.append(f" āœ… {item}")
327
+
328
+ if pending_items:
329
+ content_lines.append("\n[bold yellow]šŸ“‹ Pending:[/bold yellow]")
330
+ for item in pending_items:
331
+ content_lines.append(f" ☐ {item}")
332
+
333
+ print_panel("\n".join(content_lines), title=title, border_style="green")
334
+
335
+
336
+ def print_setup_progress(
337
+ completed_steps: list[str],
338
+ all_steps: list[tuple[str, str]] | None = None,
339
+ ) -> None:
340
+ """Display setup workflow progress.
341
+
342
+ Args:
343
+ completed_steps: List of completed step IDs
344
+ all_steps: Optional list of (step_id, step_name) tuples
345
+ """
346
+ if all_steps is None:
347
+ all_steps = [
348
+ ("initialize", "Initialize project"),
349
+ ("configure", "Configure settings"),
350
+ ("index", "Index codebase"),
351
+ ("mcp_setup", "Setup MCP integration"),
352
+ ("verify", "Verify installation"),
353
+ ]
354
+
355
+ completed = len([s for s, _ in all_steps if s in completed_steps])
356
+ total = len(all_steps)
357
+ percentage = (completed / total) * 100
358
+
359
+ console.print(f"\nšŸš€ Setup Progress: {completed}/{total} ({percentage:.0f}%)")
360
+
361
+ for step_id, step_name in all_steps:
362
+ status = "āœ“" if step_id in completed_steps else "☐"
363
+ style = "green" if step_id in completed_steps else "dim"
364
+ console.print(f" {status} {step_name}", style=style)
365
+
366
+
367
+ def print_error_with_recovery(error_message: str, recovery_steps: list[str]) -> None:
368
+ """Print error message with recovery hints.
369
+
370
+ Args:
371
+ error_message: The error message
372
+ recovery_steps: List of recovery step descriptions
373
+ """
374
+ print_error(error_message)
375
+
376
+ console.print("\n[bold]How to fix:[/bold]")
377
+ for i, step in enumerate(recovery_steps, 1):
378
+ console.print(f" {i}. {step}")
379
+
380
+ console.print("\n[dim]For more help: mcp-vector-search --help[/dim]")
381
+
382
+
383
+ def print_command_examples(
384
+ command: str,
385
+ examples: list[tuple[str, str]],
386
+ ) -> None:
387
+ """Print command examples in a formatted table.
388
+
389
+ Args:
390
+ command: Base command name
391
+ examples: List of (description, example) tuples
392
+ """
393
+ table = Table(
394
+ title=f"Examples: {command}",
395
+ show_header=True,
396
+ header_style="bold cyan",
397
+ )
398
+ table.add_column("Description", style="white", no_wrap=False)
399
+ table.add_column("Command", style="green", no_wrap=False)
400
+
401
+ for description, example in examples:
402
+ table.add_row(description, example)
403
+
404
+ console.print(table)
405
+
406
+
407
+ def print_config_hint(config_type: str, config_path: str) -> None:
408
+ """Print configuration file location hint.
409
+
410
+ Args:
411
+ config_type: Type of configuration (e.g., "Claude Code", "Project")
412
+ config_path: Path to the configuration file
413
+ """
414
+ console.print(f"[dim]šŸ’” {config_type} config: {config_path}[/dim]")