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
@@ -0,0 +1,39 @@
1
+ """Modular visualization package for code graphs.
2
+
3
+ This package provides D3.js-based interactive visualization of code relationships,
4
+ organized into modular components for maintainability.
5
+
6
+ Structure:
7
+ - graph_builder.py: Graph data construction logic
8
+ - server.py: HTTP server for serving visualization
9
+ - templates/: HTML, CSS, and JavaScript generation
10
+ - exporters/: Export functionality (JSON, HTML)
11
+ - cli.py: Typer CLI commands (imported for backwards compatibility)
12
+ """
13
+
14
+ from .cli import app
15
+ from .exporters import export_to_html, export_to_json
16
+ from .graph_builder import (
17
+ build_graph_data,
18
+ get_subproject_color,
19
+ parse_project_dependencies,
20
+ )
21
+ from .server import find_free_port, start_visualization_server
22
+ from .templates import generate_html_template
23
+
24
+ __all__ = [
25
+ # CLI
26
+ "app",
27
+ # Graph building
28
+ "build_graph_data",
29
+ "get_subproject_color",
30
+ "parse_project_dependencies",
31
+ # Server
32
+ "find_free_port",
33
+ "start_visualization_server",
34
+ # Templates
35
+ "generate_html_template",
36
+ # Exporters
37
+ "export_to_html",
38
+ "export_to_json",
39
+ ]
@@ -0,0 +1,276 @@
1
+ """Visualization commands for MCP Vector Search.
2
+
3
+ This module provides a backwards-compatible interface to the refactored
4
+ modular visualization components.
5
+ """
6
+
7
+ import asyncio
8
+ import shutil
9
+ from fnmatch import fnmatch
10
+ from pathlib import Path
11
+
12
+ import typer
13
+ from loguru import logger
14
+ from rich.console import Console
15
+ from rich.panel import Panel
16
+
17
+ from ....core.database import ChromaVectorDatabase
18
+ from ....core.embeddings import create_embedding_function
19
+ from ....core.project import ProjectManager
20
+
21
+ # Import from refactored modules (same directory)
22
+ from .exporters import export_to_html, export_to_json
23
+ from .graph_builder import build_graph_data
24
+ from .server import find_free_port, start_visualization_server
25
+
26
+ app = typer.Typer(
27
+ help="Visualize code chunk relationships",
28
+ )
29
+ console = Console()
30
+
31
+
32
+ @app.callback(invoke_without_command=True)
33
+ def visualize_callback(ctx: typer.Context) -> None:
34
+ """Visualize code chunk relationships.
35
+
36
+ When called without a subcommand, automatically starts the visualization server.
37
+ """
38
+ # If no subcommand was invoked, run serve with defaults
39
+ if ctx.invoked_subcommand is None:
40
+ # Call serve directly with default parameters
41
+ serve(port=8080, graph_file=Path("chunk-graph.json"), code_only=False)
42
+
43
+
44
+ @app.command()
45
+ def export(
46
+ output: Path = typer.Option(
47
+ Path("chunk-graph.json"),
48
+ "--output",
49
+ "-o",
50
+ help="Output file for chunk relationship data",
51
+ ),
52
+ file_path: str | None = typer.Option(
53
+ None,
54
+ "--file",
55
+ "-f",
56
+ help="Export only chunks from specific file (supports wildcards)",
57
+ ),
58
+ code_only: bool = typer.Option(
59
+ False,
60
+ "--code-only",
61
+ help="Exclude documentation chunks (text, comment, docstring)",
62
+ ),
63
+ ) -> None:
64
+ """Export chunk relationships as JSON for D3.js visualization.
65
+
66
+ Examples:
67
+ # Export all chunks
68
+ mcp-vector-search visualize export
69
+
70
+ # Export from specific file
71
+ mcp-vector-search visualize export --file src/main.py
72
+
73
+ # Custom output location
74
+ mcp-vector-search visualize export -o graph.json
75
+
76
+ # Export only code chunks (exclude documentation)
77
+ mcp-vector-search visualize export --code-only
78
+ """
79
+ asyncio.run(_export_chunks(output, file_path, code_only))
80
+
81
+
82
+ async def _export_chunks(
83
+ output: Path, file_filter: str | None, code_only: bool = False
84
+ ) -> None:
85
+ """Export chunk relationship data.
86
+
87
+ Args:
88
+ output: Path to output JSON file
89
+ file_filter: Optional file pattern to filter chunks
90
+ code_only: If True, exclude documentation chunks (text, comment, docstring)
91
+ """
92
+ try:
93
+ # Load project
94
+ project_manager = ProjectManager(Path.cwd())
95
+
96
+ if not project_manager.is_initialized():
97
+ console.print(
98
+ "[red]Project not initialized. Run 'mcp-vector-search init' first.[/red]"
99
+ )
100
+ raise typer.Exit(1)
101
+
102
+ config = project_manager.load_config()
103
+
104
+ # Get database
105
+ embedding_function, _ = create_embedding_function(config.embedding_model)
106
+ database = ChromaVectorDatabase(
107
+ persist_directory=config.index_path,
108
+ embedding_function=embedding_function,
109
+ )
110
+ await database.initialize()
111
+
112
+ # Get all chunks with metadata
113
+ console.print("[cyan]Fetching chunks from database...[/cyan]")
114
+ chunks = await database.get_all_chunks()
115
+
116
+ if len(chunks) == 0:
117
+ console.print(
118
+ "[yellow]No chunks found in index. Run 'mcp-vector-search index' first.[/yellow]"
119
+ )
120
+ raise typer.Exit(1)
121
+
122
+ console.print(f"[green]✓[/green] Retrieved {len(chunks)} chunks")
123
+
124
+ # Apply file filter if specified
125
+ if file_filter:
126
+ chunks = [c for c in chunks if fnmatch(str(c.file_path), file_filter)]
127
+ console.print(
128
+ f"[cyan]Filtered to {len(chunks)} chunks matching '{file_filter}'[/cyan]"
129
+ )
130
+
131
+ # Apply code-only filter if requested
132
+ if code_only:
133
+ original_count = len(chunks)
134
+ chunks = [
135
+ c
136
+ for c in chunks
137
+ if c.chunk_type not in ["text", "comment", "docstring"]
138
+ ]
139
+ filtered_count = len(chunks)
140
+ console.print(
141
+ f"[dim]Filtered out {original_count - filtered_count} documentation chunks "
142
+ f"({original_count} → {filtered_count} chunks)[/dim]"
143
+ )
144
+
145
+ # Build graph data using refactored module
146
+ graph_data = await build_graph_data(
147
+ chunks=chunks,
148
+ database=database,
149
+ project_manager=project_manager,
150
+ code_only=code_only,
151
+ )
152
+
153
+ # Export to JSON using refactored module
154
+ export_to_json(graph_data, output)
155
+
156
+ await database.close()
157
+
158
+ console.print()
159
+ # Count cycles from graph_data links
160
+ cycles = [link for link in graph_data["links"] if link.get("is_cycle", False)]
161
+ cycle_warning = f"[yellow]Cycles: {len(cycles)} ⚠️[/yellow]\n" if cycles else ""
162
+
163
+ # Count subprojects
164
+ subprojects_count = len(graph_data["metadata"].get("subprojects", []))
165
+
166
+ console.print(
167
+ Panel.fit(
168
+ f"[green]✓[/green] Exported graph data to [cyan]{output}[/cyan]\n\n"
169
+ f"Nodes: {len(graph_data['nodes'])}\n"
170
+ f"Links: {len(graph_data['links'])}\n"
171
+ f"{cycle_warning}"
172
+ f"{'Subprojects: ' + str(subprojects_count) if subprojects_count else ''}\n\n"
173
+ f"[dim]Next: Run 'mcp-vector-search visualize serve' to view[/dim]",
174
+ title="Export Complete",
175
+ border_style="green",
176
+ )
177
+ )
178
+
179
+ except Exception as e:
180
+ logger.error(f"Export failed: {e}")
181
+ console.print(f"[red]✗ Export failed: {e}[/red]")
182
+ raise typer.Exit(1)
183
+
184
+
185
+ @app.command()
186
+ def serve(
187
+ port: int = typer.Option(
188
+ 8080, "--port", "-p", help="Port for visualization server"
189
+ ),
190
+ graph_file: Path = typer.Option(
191
+ Path("chunk-graph.json"),
192
+ "--graph",
193
+ "-g",
194
+ help="Graph JSON file to visualize",
195
+ ),
196
+ code_only: bool = typer.Option(
197
+ False,
198
+ "--code-only",
199
+ help="Exclude documentation chunks (text, comment, docstring)",
200
+ ),
201
+ ) -> None:
202
+ """Start local HTTP server for D3.js visualization.
203
+
204
+ Examples:
205
+ # Start server on default port 8080
206
+ mcp-vector-search visualize serve
207
+
208
+ # Custom port
209
+ mcp-vector-search visualize serve --port 3000
210
+
211
+ # Custom graph file
212
+ mcp-vector-search visualize serve --graph my-graph.json
213
+
214
+ # Serve with code-only filter
215
+ mcp-vector-search visualize serve --code-only
216
+ """
217
+ # Use specified port or find free one
218
+ if port == 8080: # Default port, try to find free one
219
+ try:
220
+ port = find_free_port(8080, 8099)
221
+ except OSError as e:
222
+ console.print(f"[red]✗ {e}[/red]")
223
+ raise typer.Exit(1)
224
+
225
+ # Get visualization directory - use project-local storage
226
+ project_manager = ProjectManager(Path.cwd())
227
+ if not project_manager.is_initialized():
228
+ console.print(
229
+ "[red]Project not initialized. Run 'mcp-vector-search init' first.[/red]"
230
+ )
231
+ raise typer.Exit(1)
232
+
233
+ viz_dir = project_manager.project_root / ".mcp-vector-search" / "visualization"
234
+
235
+ if not viz_dir.exists():
236
+ console.print(
237
+ f"[yellow]Visualization directory not found. Creating at {viz_dir}...[/yellow]"
238
+ )
239
+ viz_dir.mkdir(parents=True, exist_ok=True)
240
+
241
+ # Always ensure index.html exists (regenerate if missing)
242
+ html_file = viz_dir / "index.html"
243
+ if not html_file.exists():
244
+ console.print("[yellow]Creating visualization HTML file...[/yellow]")
245
+ export_to_html(html_file)
246
+
247
+ # Check if we need to regenerate the graph file
248
+ needs_regeneration = not graph_file.exists() or code_only
249
+
250
+ if graph_file.exists() and not needs_regeneration:
251
+ # Use existing unfiltered file
252
+ dest = viz_dir / "chunk-graph.json"
253
+ shutil.copy(graph_file, dest)
254
+ console.print(f"[green]✓[/green] Copied graph data to {dest}")
255
+ else:
256
+ # Generate new file (with filter if requested)
257
+ if graph_file.exists() and code_only:
258
+ console.print(
259
+ "[yellow]Regenerating filtered graph data (--code-only)...[/yellow]"
260
+ )
261
+ elif not graph_file.exists():
262
+ console.print(
263
+ f"[yellow]Graph file {graph_file} not found. Generating it now...[/yellow]"
264
+ )
265
+
266
+ asyncio.run(_export_chunks(graph_file, None, code_only))
267
+ console.print()
268
+
269
+ # Copy the newly generated graph to visualization directory
270
+ if graph_file.exists():
271
+ dest = viz_dir / "chunk-graph.json"
272
+ shutil.copy(graph_file, dest)
273
+ console.print(f"[green]✓[/green] Copied graph data to {dest}")
274
+
275
+ # Start server using refactored module
276
+ start_visualization_server(port, viz_dir, auto_open=True)
@@ -0,0 +1,12 @@
1
+ """Export functionality for graph visualization data.
2
+
3
+ This package contains modules for exporting graph data to various formats.
4
+ """
5
+
6
+ from .html_exporter import export_to_html
7
+ from .json_exporter import export_to_json
8
+
9
+ __all__ = [
10
+ "export_to_html",
11
+ "export_to_json",
12
+ ]
@@ -0,0 +1,33 @@
1
+ """HTML export functionality for visualization.
2
+
3
+ This module handles creating standalone HTML files for the visualization.
4
+ """
5
+
6
+ from pathlib import Path
7
+
8
+ from rich.console import Console
9
+
10
+ from ..templates.base import generate_html_template
11
+
12
+ console = Console()
13
+
14
+
15
+ def export_to_html(output_path: Path) -> None:
16
+ """Export visualization to standalone HTML file.
17
+
18
+ Args:
19
+ output_path: Path to output HTML file
20
+ """
21
+ # Generate HTML template
22
+ html_content = generate_html_template()
23
+
24
+ # Ensure output directory exists
25
+ output_path.parent.mkdir(parents=True, exist_ok=True)
26
+
27
+ # Write to file
28
+ with open(output_path, "w") as f:
29
+ f.write(html_content)
30
+
31
+ console.print(
32
+ f"[green]✓[/green] Created visualization HTML at [cyan]{output_path}[/cyan]"
33
+ )
@@ -0,0 +1,29 @@
1
+ """JSON export functionality for graph data.
2
+
3
+ This module handles exporting graph data to JSON format.
4
+ """
5
+
6
+ import json
7
+ from pathlib import Path
8
+ from typing import Any
9
+
10
+ from rich.console import Console
11
+
12
+ console = Console()
13
+
14
+
15
+ def export_to_json(graph_data: dict[str, Any], output_path: Path) -> None:
16
+ """Export graph data to JSON file.
17
+
18
+ Args:
19
+ graph_data: Graph data dictionary containing nodes, links, and metadata
20
+ output_path: Path to output JSON file
21
+ """
22
+ # Ensure output directory exists
23
+ output_path.parent.mkdir(parents=True, exist_ok=True)
24
+
25
+ # Write to file
26
+ with open(output_path, "w") as f:
27
+ json.dump(graph_data, f, indent=2)
28
+
29
+ console.print(f"[green]✓[/green] Exported graph data to [cyan]{output_path}[/cyan]")