mcp-vector-search 0.12.6__py3-none-any.whl → 1.1.22__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 (92) hide show
  1. mcp_vector_search/__init__.py +3 -3
  2. mcp_vector_search/analysis/__init__.py +111 -0
  3. mcp_vector_search/analysis/baseline/__init__.py +68 -0
  4. mcp_vector_search/analysis/baseline/comparator.py +462 -0
  5. mcp_vector_search/analysis/baseline/manager.py +621 -0
  6. mcp_vector_search/analysis/collectors/__init__.py +74 -0
  7. mcp_vector_search/analysis/collectors/base.py +164 -0
  8. mcp_vector_search/analysis/collectors/cohesion.py +463 -0
  9. mcp_vector_search/analysis/collectors/complexity.py +743 -0
  10. mcp_vector_search/analysis/collectors/coupling.py +1162 -0
  11. mcp_vector_search/analysis/collectors/halstead.py +514 -0
  12. mcp_vector_search/analysis/collectors/smells.py +325 -0
  13. mcp_vector_search/analysis/debt.py +516 -0
  14. mcp_vector_search/analysis/interpretation.py +685 -0
  15. mcp_vector_search/analysis/metrics.py +414 -0
  16. mcp_vector_search/analysis/reporters/__init__.py +7 -0
  17. mcp_vector_search/analysis/reporters/console.py +646 -0
  18. mcp_vector_search/analysis/reporters/markdown.py +480 -0
  19. mcp_vector_search/analysis/reporters/sarif.py +377 -0
  20. mcp_vector_search/analysis/storage/__init__.py +93 -0
  21. mcp_vector_search/analysis/storage/metrics_store.py +762 -0
  22. mcp_vector_search/analysis/storage/schema.py +245 -0
  23. mcp_vector_search/analysis/storage/trend_tracker.py +560 -0
  24. mcp_vector_search/analysis/trends.py +308 -0
  25. mcp_vector_search/analysis/visualizer/__init__.py +90 -0
  26. mcp_vector_search/analysis/visualizer/d3_data.py +534 -0
  27. mcp_vector_search/analysis/visualizer/exporter.py +484 -0
  28. mcp_vector_search/analysis/visualizer/html_report.py +2895 -0
  29. mcp_vector_search/analysis/visualizer/schemas.py +525 -0
  30. mcp_vector_search/cli/commands/analyze.py +1062 -0
  31. mcp_vector_search/cli/commands/chat.py +1455 -0
  32. mcp_vector_search/cli/commands/index.py +621 -5
  33. mcp_vector_search/cli/commands/index_background.py +467 -0
  34. mcp_vector_search/cli/commands/init.py +13 -0
  35. mcp_vector_search/cli/commands/install.py +597 -335
  36. mcp_vector_search/cli/commands/install_old.py +8 -4
  37. mcp_vector_search/cli/commands/mcp.py +78 -6
  38. mcp_vector_search/cli/commands/reset.py +68 -26
  39. mcp_vector_search/cli/commands/search.py +224 -8
  40. mcp_vector_search/cli/commands/setup.py +1184 -0
  41. mcp_vector_search/cli/commands/status.py +339 -5
  42. mcp_vector_search/cli/commands/uninstall.py +276 -357
  43. mcp_vector_search/cli/commands/visualize/__init__.py +39 -0
  44. mcp_vector_search/cli/commands/visualize/cli.py +292 -0
  45. mcp_vector_search/cli/commands/visualize/exporters/__init__.py +12 -0
  46. mcp_vector_search/cli/commands/visualize/exporters/html_exporter.py +33 -0
  47. mcp_vector_search/cli/commands/visualize/exporters/json_exporter.py +33 -0
  48. mcp_vector_search/cli/commands/visualize/graph_builder.py +647 -0
  49. mcp_vector_search/cli/commands/visualize/layout_engine.py +469 -0
  50. mcp_vector_search/cli/commands/visualize/server.py +600 -0
  51. mcp_vector_search/cli/commands/visualize/state_manager.py +428 -0
  52. mcp_vector_search/cli/commands/visualize/templates/__init__.py +16 -0
  53. mcp_vector_search/cli/commands/visualize/templates/base.py +234 -0
  54. mcp_vector_search/cli/commands/visualize/templates/scripts.py +4542 -0
  55. mcp_vector_search/cli/commands/visualize/templates/styles.py +2522 -0
  56. mcp_vector_search/cli/didyoumean.py +27 -2
  57. mcp_vector_search/cli/main.py +127 -160
  58. mcp_vector_search/cli/output.py +158 -13
  59. mcp_vector_search/config/__init__.py +4 -0
  60. mcp_vector_search/config/default_thresholds.yaml +52 -0
  61. mcp_vector_search/config/settings.py +12 -0
  62. mcp_vector_search/config/thresholds.py +273 -0
  63. mcp_vector_search/core/__init__.py +16 -0
  64. mcp_vector_search/core/auto_indexer.py +3 -3
  65. mcp_vector_search/core/boilerplate.py +186 -0
  66. mcp_vector_search/core/config_utils.py +394 -0
  67. mcp_vector_search/core/database.py +406 -94
  68. mcp_vector_search/core/embeddings.py +24 -0
  69. mcp_vector_search/core/exceptions.py +11 -0
  70. mcp_vector_search/core/git.py +380 -0
  71. mcp_vector_search/core/git_hooks.py +4 -4
  72. mcp_vector_search/core/indexer.py +632 -54
  73. mcp_vector_search/core/llm_client.py +756 -0
  74. mcp_vector_search/core/models.py +91 -1
  75. mcp_vector_search/core/project.py +17 -0
  76. mcp_vector_search/core/relationships.py +473 -0
  77. mcp_vector_search/core/scheduler.py +11 -11
  78. mcp_vector_search/core/search.py +179 -29
  79. mcp_vector_search/mcp/server.py +819 -9
  80. mcp_vector_search/parsers/python.py +285 -5
  81. mcp_vector_search/utils/__init__.py +2 -0
  82. mcp_vector_search/utils/gitignore.py +0 -3
  83. mcp_vector_search/utils/gitignore_updater.py +212 -0
  84. mcp_vector_search/utils/monorepo.py +66 -4
  85. mcp_vector_search/utils/timing.py +10 -6
  86. {mcp_vector_search-0.12.6.dist-info → mcp_vector_search-1.1.22.dist-info}/METADATA +184 -53
  87. mcp_vector_search-1.1.22.dist-info/RECORD +120 -0
  88. {mcp_vector_search-0.12.6.dist-info → mcp_vector_search-1.1.22.dist-info}/WHEEL +1 -1
  89. {mcp_vector_search-0.12.6.dist-info → mcp_vector_search-1.1.22.dist-info}/entry_points.txt +1 -0
  90. mcp_vector_search/cli/commands/visualize.py +0 -1467
  91. mcp_vector_search-0.12.6.dist-info/RECORD +0 -68
  92. {mcp_vector_search-0.12.6.dist-info → mcp_vector_search-1.1.22.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,292 @@
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
+ invoke_without_command=True,
29
+ )
30
+ console = Console()
31
+
32
+
33
+ @app.callback()
34
+ def visualize_callback(ctx: typer.Context) -> None:
35
+ """Visualize code chunk relationships.
36
+
37
+ If no subcommand is provided, defaults to starting the visualization server.
38
+ """
39
+ if ctx.invoked_subcommand is None:
40
+ # Default to serve when no subcommand given
41
+ # Must pass explicit defaults since typer.Option doesn't work when called directly
42
+ serve(port=8501, graph_file=Path("chunk-graph.json"), code_only=False)
43
+
44
+
45
+ @app.command()
46
+ def export(
47
+ output: Path = typer.Option(
48
+ Path("chunk-graph.json"),
49
+ "--output",
50
+ "-o",
51
+ help="Output file for chunk relationship data",
52
+ ),
53
+ file_path: str | None = typer.Option(
54
+ None,
55
+ "--file",
56
+ "-f",
57
+ help="Export only chunks from specific file (supports wildcards)",
58
+ ),
59
+ code_only: bool = typer.Option(
60
+ False,
61
+ "--code-only",
62
+ help="Exclude documentation chunks (text, comment, docstring)",
63
+ ),
64
+ ) -> None:
65
+ """Export chunk relationships as JSON for D3.js visualization.
66
+
67
+ Examples:
68
+ # Export all chunks
69
+ mcp-vector-search visualize export
70
+
71
+ # Export from specific file
72
+ mcp-vector-search visualize export --file src/main.py
73
+
74
+ # Custom output location
75
+ mcp-vector-search visualize export -o graph.json
76
+
77
+ # Export only code chunks (exclude documentation)
78
+ mcp-vector-search visualize export --code-only
79
+ """
80
+ asyncio.run(_export_chunks(output, file_path, code_only))
81
+
82
+
83
+ async def _export_chunks(
84
+ output: Path, file_filter: str | None, code_only: bool = False
85
+ ) -> None:
86
+ """Export chunk relationship data.
87
+
88
+ Args:
89
+ output: Path to output JSON file
90
+ file_filter: Optional file pattern to filter chunks
91
+ code_only: If True, exclude documentation chunks (text, comment, docstring)
92
+ """
93
+ try:
94
+ # Load project
95
+ project_manager = ProjectManager(Path.cwd())
96
+
97
+ if not project_manager.is_initialized():
98
+ console.print(
99
+ "[red]Project not initialized. Run 'mcp-vector-search init' first.[/red]"
100
+ )
101
+ raise typer.Exit(1)
102
+
103
+ config = project_manager.load_config()
104
+
105
+ # Get database
106
+ embedding_function, _ = create_embedding_function(config.embedding_model)
107
+ database = ChromaVectorDatabase(
108
+ persist_directory=config.index_path,
109
+ embedding_function=embedding_function,
110
+ )
111
+ await database.initialize()
112
+
113
+ # Get all chunks with metadata
114
+ console.print("[cyan]Fetching chunks from database...[/cyan]")
115
+ chunks = await database.get_all_chunks()
116
+
117
+ if len(chunks) == 0:
118
+ console.print(
119
+ "[yellow]No chunks found in index. Run 'mcp-vector-search index' first.[/yellow]"
120
+ )
121
+ raise typer.Exit(1)
122
+
123
+ console.print(f"[green]✓[/green] Retrieved {len(chunks)} chunks")
124
+
125
+ # Apply file filter if specified
126
+ if file_filter:
127
+ chunks = [c for c in chunks if fnmatch(str(c.file_path), file_filter)]
128
+ console.print(
129
+ f"[cyan]Filtered to {len(chunks)} chunks matching '{file_filter}'[/cyan]"
130
+ )
131
+
132
+ # Apply code-only filter if requested
133
+ if code_only:
134
+ original_count = len(chunks)
135
+ chunks = [
136
+ c
137
+ for c in chunks
138
+ if c.chunk_type not in ["text", "comment", "docstring"]
139
+ ]
140
+ filtered_count = len(chunks)
141
+ console.print(
142
+ f"[dim]Filtered out {original_count - filtered_count} documentation chunks "
143
+ f"({original_count} → {filtered_count} chunks)[/dim]"
144
+ )
145
+
146
+ # Build graph data using refactored module
147
+ graph_data = await build_graph_data(
148
+ chunks=chunks,
149
+ database=database,
150
+ project_manager=project_manager,
151
+ code_only=code_only,
152
+ )
153
+
154
+ # Export to JSON using refactored module
155
+ export_to_json(graph_data, output)
156
+
157
+ await database.close()
158
+
159
+ console.print()
160
+ # Count cycles from graph_data links
161
+ cycles = [link for link in graph_data["links"] if link.get("is_cycle", False)]
162
+ cycle_warning = f"[yellow]Cycles: {len(cycles)} ⚠️[/yellow]\n" if cycles else ""
163
+
164
+ # Count subprojects
165
+ subprojects_count = len(graph_data["metadata"].get("subprojects", []))
166
+
167
+ console.print(
168
+ Panel.fit(
169
+ f"[green]✓[/green] Exported graph data to [cyan]{output}[/cyan]\n\n"
170
+ f"Nodes: {len(graph_data['nodes'])}\n"
171
+ f"Links: {len(graph_data['links'])}\n"
172
+ f"{cycle_warning}"
173
+ f"{'Subprojects: ' + str(subprojects_count) if subprojects_count else ''}\n\n"
174
+ f"[dim]Next: Run 'mcp-vector-search visualize serve' to view[/dim]",
175
+ title="Export Complete",
176
+ border_style="green",
177
+ )
178
+ )
179
+
180
+ except Exception as e:
181
+ logger.error(f"Export failed: {e}")
182
+ console.print(f"[red]✗ Export failed: {e}[/red]")
183
+ raise typer.Exit(1)
184
+
185
+
186
+ @app.command()
187
+ def serve(
188
+ port: int = typer.Option(
189
+ 8501, "--port", "-p", help="Port for visualization server"
190
+ ),
191
+ graph_file: Path = typer.Option(
192
+ Path("chunk-graph.json"),
193
+ "--graph",
194
+ "-g",
195
+ help="Graph JSON file to visualize",
196
+ ),
197
+ code_only: bool = typer.Option(
198
+ False,
199
+ "--code-only",
200
+ help="Exclude documentation chunks (text, comment, docstring)",
201
+ ),
202
+ ) -> None:
203
+ """Start local HTTP server for D3.js visualization.
204
+
205
+ Examples:
206
+ # Start server on default port 8501
207
+ mcp-vector-search visualize serve
208
+
209
+ # Custom port
210
+ mcp-vector-search visualize serve --port 3000
211
+
212
+ # Custom graph file
213
+ mcp-vector-search visualize serve --graph my-graph.json
214
+
215
+ # Serve with code-only filter
216
+ mcp-vector-search visualize serve --code-only
217
+ """
218
+ # Use specified port or find free one
219
+ if port == 8501: # Default port, try to find free one
220
+ try:
221
+ port = find_free_port(8501, 8599)
222
+ except OSError as e:
223
+ console.print(f"[red]✗ {e}[/red]")
224
+ raise typer.Exit(1)
225
+
226
+ # Get visualization directory - use project-local storage
227
+ project_manager = ProjectManager(Path.cwd())
228
+ if not project_manager.is_initialized():
229
+ console.print(
230
+ "[red]Project not initialized. Run 'mcp-vector-search init' first.[/red]"
231
+ )
232
+ raise typer.Exit(1)
233
+
234
+ viz_dir = project_manager.project_root / ".mcp-vector-search" / "visualization"
235
+
236
+ if not viz_dir.exists():
237
+ console.print(
238
+ f"[yellow]Visualization directory not found. Creating at {viz_dir}...[/yellow]"
239
+ )
240
+ viz_dir.mkdir(parents=True, exist_ok=True)
241
+
242
+ # Always ensure index.html exists (regenerate if missing)
243
+ html_file = viz_dir / "index.html"
244
+ if not html_file.exists():
245
+ console.print("[yellow]Creating visualization HTML file...[/yellow]")
246
+ export_to_html(html_file)
247
+
248
+ # Check if we need to regenerate the graph file
249
+ # Regenerate if: graph doesn't exist, code_only filter, or index is newer than graph
250
+ needs_regeneration = not graph_file.exists() or code_only
251
+
252
+ # Check if index database is newer than graph (stale graph detection)
253
+ if graph_file.exists() and not needs_regeneration:
254
+ index_db = (
255
+ project_manager.project_root / ".mcp-vector-search" / "chroma.sqlite3"
256
+ )
257
+ if index_db.exists():
258
+ graph_mtime = graph_file.stat().st_mtime
259
+ index_mtime = index_db.stat().st_mtime
260
+ if index_mtime > graph_mtime:
261
+ console.print(
262
+ "[yellow]Index has changed since graph was generated. Regenerating...[/yellow]"
263
+ )
264
+ needs_regeneration = True
265
+
266
+ if graph_file.exists() and not needs_regeneration:
267
+ # Use existing unfiltered file
268
+ dest = viz_dir / "chunk-graph.json"
269
+ shutil.copy(graph_file, dest)
270
+ console.print(f"[green]✓[/green] Copied graph data to {dest}")
271
+ else:
272
+ # Generate new file (with filter if requested)
273
+ if graph_file.exists() and code_only:
274
+ console.print(
275
+ "[yellow]Regenerating filtered graph data (--code-only)...[/yellow]"
276
+ )
277
+ elif not graph_file.exists():
278
+ console.print(
279
+ f"[yellow]Graph file {graph_file} not found. Generating it now...[/yellow]"
280
+ )
281
+
282
+ asyncio.run(_export_chunks(graph_file, None, code_only))
283
+ console.print()
284
+
285
+ # Copy the newly generated graph to visualization directory
286
+ if graph_file.exists():
287
+ dest = viz_dir / "chunk-graph.json"
288
+ shutil.copy(graph_file, dest)
289
+ console.print(f"[green]✓[/green] Copied graph data to {dest}")
290
+
291
+ # Start server using refactored module
292
+ 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,33 @@
1
+ """JSON export functionality for graph data.
2
+
3
+ This module handles exporting graph data to JSON format.
4
+ Uses orjson for 5-10x faster serialization performance.
5
+ """
6
+
7
+ from pathlib import Path
8
+ from typing import Any
9
+
10
+ import orjson
11
+ from rich.console import Console
12
+
13
+ console = Console()
14
+
15
+
16
+ def export_to_json(graph_data: dict[str, Any], output_path: Path) -> None:
17
+ """Export graph data to JSON file.
18
+
19
+ Uses orjson for fast serialization (5-10x faster than stdlib json).
20
+
21
+ Args:
22
+ graph_data: Graph data dictionary containing nodes, links, and metadata
23
+ output_path: Path to output JSON file
24
+ """
25
+ # Ensure output directory exists
26
+ output_path.parent.mkdir(parents=True, exist_ok=True)
27
+
28
+ # Write to file using orjson for fast serialization
29
+ # OPT_INDENT_2 gives readable output, OPT_SORT_KEYS for consistency
30
+ with open(output_path, "wb") as f:
31
+ f.write(orjson.dumps(graph_data, option=orjson.OPT_INDENT_2))
32
+
33
+ console.print(f"[green]✓[/green] Exported graph data to [cyan]{output_path}[/cyan]")