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.
- mcp_vector_search/__init__.py +10 -0
- mcp_vector_search/cli/__init__.py +1 -0
- mcp_vector_search/cli/commands/__init__.py +1 -0
- mcp_vector_search/cli/commands/auto_index.py +397 -0
- mcp_vector_search/cli/commands/chat.py +534 -0
- mcp_vector_search/cli/commands/config.py +393 -0
- mcp_vector_search/cli/commands/demo.py +358 -0
- mcp_vector_search/cli/commands/index.py +762 -0
- mcp_vector_search/cli/commands/init.py +658 -0
- mcp_vector_search/cli/commands/install.py +869 -0
- mcp_vector_search/cli/commands/install_old.py +700 -0
- mcp_vector_search/cli/commands/mcp.py +1254 -0
- mcp_vector_search/cli/commands/reset.py +393 -0
- mcp_vector_search/cli/commands/search.py +796 -0
- mcp_vector_search/cli/commands/setup.py +1133 -0
- mcp_vector_search/cli/commands/status.py +584 -0
- mcp_vector_search/cli/commands/uninstall.py +404 -0
- mcp_vector_search/cli/commands/visualize/__init__.py +39 -0
- mcp_vector_search/cli/commands/visualize/cli.py +265 -0
- mcp_vector_search/cli/commands/visualize/exporters/__init__.py +12 -0
- mcp_vector_search/cli/commands/visualize/exporters/html_exporter.py +33 -0
- mcp_vector_search/cli/commands/visualize/exporters/json_exporter.py +29 -0
- mcp_vector_search/cli/commands/visualize/graph_builder.py +709 -0
- mcp_vector_search/cli/commands/visualize/layout_engine.py +469 -0
- mcp_vector_search/cli/commands/visualize/server.py +201 -0
- mcp_vector_search/cli/commands/visualize/state_manager.py +428 -0
- mcp_vector_search/cli/commands/visualize/templates/__init__.py +16 -0
- mcp_vector_search/cli/commands/visualize/templates/base.py +218 -0
- mcp_vector_search/cli/commands/visualize/templates/scripts.py +3670 -0
- mcp_vector_search/cli/commands/visualize/templates/styles.py +779 -0
- mcp_vector_search/cli/commands/visualize.py.original +2536 -0
- mcp_vector_search/cli/commands/watch.py +287 -0
- mcp_vector_search/cli/didyoumean.py +520 -0
- mcp_vector_search/cli/export.py +320 -0
- mcp_vector_search/cli/history.py +295 -0
- mcp_vector_search/cli/interactive.py +342 -0
- mcp_vector_search/cli/main.py +484 -0
- mcp_vector_search/cli/output.py +414 -0
- mcp_vector_search/cli/suggestions.py +375 -0
- mcp_vector_search/config/__init__.py +1 -0
- mcp_vector_search/config/constants.py +24 -0
- mcp_vector_search/config/defaults.py +200 -0
- mcp_vector_search/config/settings.py +146 -0
- mcp_vector_search/core/__init__.py +1 -0
- mcp_vector_search/core/auto_indexer.py +298 -0
- mcp_vector_search/core/config_utils.py +394 -0
- mcp_vector_search/core/connection_pool.py +360 -0
- mcp_vector_search/core/database.py +1237 -0
- mcp_vector_search/core/directory_index.py +318 -0
- mcp_vector_search/core/embeddings.py +294 -0
- mcp_vector_search/core/exceptions.py +89 -0
- mcp_vector_search/core/factory.py +318 -0
- mcp_vector_search/core/git_hooks.py +345 -0
- mcp_vector_search/core/indexer.py +1002 -0
- mcp_vector_search/core/llm_client.py +453 -0
- mcp_vector_search/core/models.py +294 -0
- mcp_vector_search/core/project.py +350 -0
- mcp_vector_search/core/scheduler.py +330 -0
- mcp_vector_search/core/search.py +952 -0
- mcp_vector_search/core/watcher.py +322 -0
- mcp_vector_search/mcp/__init__.py +5 -0
- mcp_vector_search/mcp/__main__.py +25 -0
- mcp_vector_search/mcp/server.py +752 -0
- mcp_vector_search/parsers/__init__.py +8 -0
- mcp_vector_search/parsers/base.py +296 -0
- mcp_vector_search/parsers/dart.py +605 -0
- mcp_vector_search/parsers/html.py +413 -0
- mcp_vector_search/parsers/javascript.py +643 -0
- mcp_vector_search/parsers/php.py +694 -0
- mcp_vector_search/parsers/python.py +502 -0
- mcp_vector_search/parsers/registry.py +223 -0
- mcp_vector_search/parsers/ruby.py +678 -0
- mcp_vector_search/parsers/text.py +186 -0
- mcp_vector_search/parsers/utils.py +265 -0
- mcp_vector_search/py.typed +1 -0
- mcp_vector_search/utils/__init__.py +42 -0
- mcp_vector_search/utils/gitignore.py +250 -0
- mcp_vector_search/utils/gitignore_updater.py +212 -0
- mcp_vector_search/utils/monorepo.py +339 -0
- mcp_vector_search/utils/timing.py +338 -0
- mcp_vector_search/utils/version.py +47 -0
- mcp_vector_search-0.15.7.dist-info/METADATA +884 -0
- mcp_vector_search-0.15.7.dist-info/RECORD +86 -0
- mcp_vector_search-0.15.7.dist-info/WHEEL +4 -0
- mcp_vector_search-0.15.7.dist-info/entry_points.txt +3 -0
- mcp_vector_search-0.15.7.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
"""Uninstall commands for MCP Vector Search CLI.
|
|
2
|
+
|
|
3
|
+
This module provides commands to remove MCP integrations from various platforms
|
|
4
|
+
using the py-mcp-installer library.
|
|
5
|
+
|
|
6
|
+
Examples:
|
|
7
|
+
# Remove from auto-detected platform
|
|
8
|
+
$ mcp-vector-search uninstall mcp
|
|
9
|
+
|
|
10
|
+
# Remove from specific platform
|
|
11
|
+
$ mcp-vector-search uninstall mcp --platform cursor
|
|
12
|
+
|
|
13
|
+
# Remove from all platforms
|
|
14
|
+
$ mcp-vector-search uninstall mcp --all
|
|
15
|
+
|
|
16
|
+
# Use alias
|
|
17
|
+
$ mcp-vector-search remove mcp
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
|
|
22
|
+
import typer
|
|
23
|
+
from loguru import logger
|
|
24
|
+
|
|
25
|
+
# Import from py-mcp-installer library
|
|
26
|
+
from py_mcp_installer import MCPInstaller, Platform, PlatformDetector, PlatformInfo
|
|
27
|
+
from rich.console import Console
|
|
28
|
+
from rich.panel import Panel
|
|
29
|
+
from rich.table import Table
|
|
30
|
+
|
|
31
|
+
from ..didyoumean import create_enhanced_typer
|
|
32
|
+
from ..output import (
|
|
33
|
+
confirm_action,
|
|
34
|
+
print_error,
|
|
35
|
+
print_info,
|
|
36
|
+
print_success,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
# Create console for rich output
|
|
40
|
+
console = Console()
|
|
41
|
+
|
|
42
|
+
# Create uninstall app with subcommands
|
|
43
|
+
uninstall_app = create_enhanced_typer(
|
|
44
|
+
help="""🗑️ Remove MCP integrations from platforms
|
|
45
|
+
|
|
46
|
+
[bold cyan]Usage Patterns:[/bold cyan]
|
|
47
|
+
|
|
48
|
+
[green]1. Remove from Auto-Detected Platform[/green]
|
|
49
|
+
Remove MCP integration from highest confidence platform:
|
|
50
|
+
[code]$ mcp-vector-search uninstall mcp[/code]
|
|
51
|
+
|
|
52
|
+
[green]2. Remove from Specific Platform[/green]
|
|
53
|
+
Remove from a specific platform:
|
|
54
|
+
[code]$ mcp-vector-search uninstall mcp --platform cursor[/code]
|
|
55
|
+
|
|
56
|
+
[green]3. Remove from All Platforms[/green]
|
|
57
|
+
Remove from all configured platforms:
|
|
58
|
+
[code]$ mcp-vector-search uninstall mcp --all[/code]
|
|
59
|
+
|
|
60
|
+
[green]4. List Current Installations[/green]
|
|
61
|
+
See what's currently configured:
|
|
62
|
+
[code]$ mcp-vector-search uninstall list[/code]
|
|
63
|
+
|
|
64
|
+
[bold cyan]Supported Platforms:[/bold cyan]
|
|
65
|
+
• [green]claude-code[/green] - Claude Code
|
|
66
|
+
• [green]claude-desktop[/green] - Claude Desktop
|
|
67
|
+
• [green]cursor[/green] - Cursor IDE
|
|
68
|
+
• [green]auggie[/green] - Auggie
|
|
69
|
+
• [green]codex[/green] - Codex
|
|
70
|
+
• [green]windsurf[/green] - Windsurf IDE
|
|
71
|
+
• [green]gemini-cli[/green] - Gemini CLI
|
|
72
|
+
|
|
73
|
+
[dim]💡 Alias: 'mcp-vector-search remove' works the same way[/dim]
|
|
74
|
+
""",
|
|
75
|
+
invoke_without_command=True,
|
|
76
|
+
no_args_is_help=True,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
# ==============================================================================
|
|
81
|
+
# Helper Functions
|
|
82
|
+
# ==============================================================================
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def detect_all_platforms() -> list[PlatformInfo]:
|
|
86
|
+
"""Detect all available platforms on the system.
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
List of detected platforms with confidence scores
|
|
90
|
+
"""
|
|
91
|
+
detector = PlatformDetector()
|
|
92
|
+
detected_platforms = []
|
|
93
|
+
|
|
94
|
+
# Try to detect each platform
|
|
95
|
+
platform_detectors = {
|
|
96
|
+
Platform.CLAUDE_CODE: detector.detect_claude_code,
|
|
97
|
+
Platform.CLAUDE_DESKTOP: detector.detect_claude_desktop,
|
|
98
|
+
Platform.CURSOR: detector.detect_cursor,
|
|
99
|
+
Platform.AUGGIE: detector.detect_auggie,
|
|
100
|
+
Platform.CODEX: detector.detect_codex,
|
|
101
|
+
Platform.WINDSURF: detector.detect_windsurf,
|
|
102
|
+
Platform.GEMINI_CLI: detector.detect_gemini_cli,
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
for platform_enum, detector_func in platform_detectors.items():
|
|
106
|
+
try:
|
|
107
|
+
confidence, config_path = detector_func()
|
|
108
|
+
if confidence > 0.0 and config_path:
|
|
109
|
+
# Determine CLI availability
|
|
110
|
+
cli_available = False
|
|
111
|
+
from py_mcp_installer.utils import resolve_command_path
|
|
112
|
+
|
|
113
|
+
if platform_enum in (Platform.CLAUDE_CODE, Platform.CLAUDE_DESKTOP):
|
|
114
|
+
cli_available = resolve_command_path("claude") is not None
|
|
115
|
+
elif platform_enum == Platform.CURSOR:
|
|
116
|
+
cli_available = resolve_command_path("cursor") is not None
|
|
117
|
+
|
|
118
|
+
platform_info = PlatformInfo(
|
|
119
|
+
platform=platform_enum,
|
|
120
|
+
confidence=confidence,
|
|
121
|
+
config_path=config_path,
|
|
122
|
+
cli_available=cli_available,
|
|
123
|
+
)
|
|
124
|
+
detected_platforms.append(platform_info)
|
|
125
|
+
except Exception as e:
|
|
126
|
+
logger.debug(f"Failed to detect {platform_enum.value}: {e}")
|
|
127
|
+
continue
|
|
128
|
+
|
|
129
|
+
return detected_platforms
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def platform_name_to_enum(name: str) -> Platform | None:
|
|
133
|
+
"""Convert platform name to enum.
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
name: Platform name (e.g., "cursor", "claude-code")
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
Platform enum or None if not found
|
|
140
|
+
"""
|
|
141
|
+
name_map = {
|
|
142
|
+
"claude-code": Platform.CLAUDE_CODE,
|
|
143
|
+
"claude-desktop": Platform.CLAUDE_DESKTOP,
|
|
144
|
+
"cursor": Platform.CURSOR,
|
|
145
|
+
"auggie": Platform.AUGGIE,
|
|
146
|
+
"codex": Platform.CODEX,
|
|
147
|
+
"windsurf": Platform.WINDSURF,
|
|
148
|
+
"gemini-cli": Platform.GEMINI_CLI,
|
|
149
|
+
}
|
|
150
|
+
return name_map.get(name.lower())
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def find_configured_platforms() -> list[PlatformInfo]:
|
|
154
|
+
"""Find all platforms that have mcp-vector-search configured.
|
|
155
|
+
|
|
156
|
+
Returns:
|
|
157
|
+
List of platforms with mcp-vector-search installed
|
|
158
|
+
"""
|
|
159
|
+
detected = detect_all_platforms()
|
|
160
|
+
configured = []
|
|
161
|
+
|
|
162
|
+
for platform_info in detected:
|
|
163
|
+
try:
|
|
164
|
+
installer = MCPInstaller(platform=platform_info.platform)
|
|
165
|
+
server = installer.get_server("mcp-vector-search")
|
|
166
|
+
if server:
|
|
167
|
+
configured.append(platform_info)
|
|
168
|
+
except Exception as e:
|
|
169
|
+
logger.debug(
|
|
170
|
+
f"Failed to check {platform_info.platform.value} configuration: {e}"
|
|
171
|
+
)
|
|
172
|
+
continue
|
|
173
|
+
|
|
174
|
+
return configured
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def uninstall_from_platform(platform_info: PlatformInfo) -> bool:
|
|
178
|
+
"""Uninstall from a specific platform.
|
|
179
|
+
|
|
180
|
+
Args:
|
|
181
|
+
platform_info: Platform information
|
|
182
|
+
|
|
183
|
+
Returns:
|
|
184
|
+
True if uninstallation succeeded
|
|
185
|
+
"""
|
|
186
|
+
try:
|
|
187
|
+
installer = MCPInstaller(platform=platform_info.platform)
|
|
188
|
+
|
|
189
|
+
# Uninstall server
|
|
190
|
+
result = installer.uninstall_server("mcp-vector-search")
|
|
191
|
+
|
|
192
|
+
if result.success:
|
|
193
|
+
print_success(f" ✅ Removed from {platform_info.platform.value}")
|
|
194
|
+
return True
|
|
195
|
+
else:
|
|
196
|
+
print_error(
|
|
197
|
+
f" ❌ Failed to remove from {platform_info.platform.value}: {result.message}"
|
|
198
|
+
)
|
|
199
|
+
return False
|
|
200
|
+
|
|
201
|
+
except Exception as e:
|
|
202
|
+
logger.exception(f"Uninstallation from {platform_info.platform.value} failed")
|
|
203
|
+
print_error(f" ❌ Uninstallation failed: {e}")
|
|
204
|
+
return False
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
# ==============================================================================
|
|
208
|
+
# Main Uninstall Command
|
|
209
|
+
# ==============================================================================
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
@uninstall_app.command(name="mcp")
|
|
213
|
+
def uninstall_mcp(
|
|
214
|
+
ctx: typer.Context,
|
|
215
|
+
platform: str | None = typer.Option(
|
|
216
|
+
None,
|
|
217
|
+
"--platform",
|
|
218
|
+
"-p",
|
|
219
|
+
help="Specific platform to uninstall from (e.g., cursor, claude-code)",
|
|
220
|
+
),
|
|
221
|
+
all_platforms: bool = typer.Option(
|
|
222
|
+
False,
|
|
223
|
+
"--all",
|
|
224
|
+
"-a",
|
|
225
|
+
help="Uninstall from all configured platforms",
|
|
226
|
+
),
|
|
227
|
+
) -> None:
|
|
228
|
+
"""Remove MCP integration from platforms.
|
|
229
|
+
|
|
230
|
+
By default, uninstalls from the highest confidence platform. Use --all to
|
|
231
|
+
remove from all configured platforms.
|
|
232
|
+
|
|
233
|
+
[bold cyan]Examples:[/bold cyan]
|
|
234
|
+
|
|
235
|
+
[green]Remove from auto-detected platform:[/green]
|
|
236
|
+
$ mcp-vector-search uninstall mcp
|
|
237
|
+
|
|
238
|
+
[green]Remove from specific platform:[/green]
|
|
239
|
+
$ mcp-vector-search uninstall mcp --platform cursor
|
|
240
|
+
|
|
241
|
+
[green]Remove from all platforms:[/green]
|
|
242
|
+
$ mcp-vector-search uninstall mcp --all
|
|
243
|
+
|
|
244
|
+
[dim]💡 Use 'mcp-vector-search uninstall list' to see configured platforms[/dim]
|
|
245
|
+
"""
|
|
246
|
+
project_root = ctx.obj.get("project_root") or Path.cwd()
|
|
247
|
+
|
|
248
|
+
console.print(
|
|
249
|
+
Panel.fit(
|
|
250
|
+
"[bold yellow]Removing MCP Integration[/bold yellow]\n"
|
|
251
|
+
f"📁 Project: {project_root}",
|
|
252
|
+
border_style="yellow",
|
|
253
|
+
)
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
try:
|
|
257
|
+
# Find configured platforms
|
|
258
|
+
print_info("🔍 Finding configured platforms...")
|
|
259
|
+
configured = find_configured_platforms()
|
|
260
|
+
|
|
261
|
+
if not configured:
|
|
262
|
+
print_info("No MCP integrations found to remove")
|
|
263
|
+
return
|
|
264
|
+
|
|
265
|
+
# Display configured platforms
|
|
266
|
+
table = Table(title="Configured MCP Platforms")
|
|
267
|
+
table.add_column("Platform", style="cyan")
|
|
268
|
+
table.add_column("Config Path", style="green")
|
|
269
|
+
table.add_column("Confidence", style="yellow")
|
|
270
|
+
|
|
271
|
+
for p in configured:
|
|
272
|
+
table.add_row(
|
|
273
|
+
p.platform.value,
|
|
274
|
+
str(p.config_path) if p.config_path else "N/A",
|
|
275
|
+
f"{p.confidence:.2f}",
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
console.print(table)
|
|
279
|
+
|
|
280
|
+
# Filter platforms
|
|
281
|
+
target_platforms = configured
|
|
282
|
+
|
|
283
|
+
if platform:
|
|
284
|
+
# Uninstall from specific platform
|
|
285
|
+
platform_enum = platform_name_to_enum(platform)
|
|
286
|
+
if not platform_enum:
|
|
287
|
+
print_error(f"Unknown platform: {platform}")
|
|
288
|
+
print_info(
|
|
289
|
+
"Supported: claude-code, claude-desktop, cursor, auggie, codex, windsurf, gemini-cli"
|
|
290
|
+
)
|
|
291
|
+
raise typer.Exit(1)
|
|
292
|
+
|
|
293
|
+
target_platforms = [p for p in configured if p.platform == platform_enum]
|
|
294
|
+
|
|
295
|
+
if not target_platforms:
|
|
296
|
+
print_error(
|
|
297
|
+
f"Platform '{platform}' does not have mcp-vector-search configured"
|
|
298
|
+
)
|
|
299
|
+
raise typer.Exit(1)
|
|
300
|
+
|
|
301
|
+
elif not all_platforms:
|
|
302
|
+
# By default, uninstall from highest confidence platform only
|
|
303
|
+
if configured:
|
|
304
|
+
max_confidence_platform = max(configured, key=lambda p: p.confidence)
|
|
305
|
+
target_platforms = [max_confidence_platform]
|
|
306
|
+
print_info(
|
|
307
|
+
f"Removing from highest confidence platform: {max_confidence_platform.platform.value}"
|
|
308
|
+
)
|
|
309
|
+
print_info("Use --all to remove from all configured platforms")
|
|
310
|
+
|
|
311
|
+
# Show what will be removed
|
|
312
|
+
console.print("\n[bold]Target platforms:[/bold]")
|
|
313
|
+
for p in target_platforms:
|
|
314
|
+
console.print(f" • {p.platform.value}")
|
|
315
|
+
|
|
316
|
+
# Confirm removal if multiple platforms
|
|
317
|
+
if len(target_platforms) > 1:
|
|
318
|
+
if not confirm_action("\nRemove from all these platforms?", default=False):
|
|
319
|
+
print_info("Cancelled")
|
|
320
|
+
raise typer.Exit(0)
|
|
321
|
+
|
|
322
|
+
# Uninstall from each platform
|
|
323
|
+
console.print("\n[bold]Removing integrations...[/bold]")
|
|
324
|
+
successful = 0
|
|
325
|
+
failed = 0
|
|
326
|
+
|
|
327
|
+
for platform_info in target_platforms:
|
|
328
|
+
if uninstall_from_platform(platform_info):
|
|
329
|
+
successful += 1
|
|
330
|
+
else:
|
|
331
|
+
failed += 1
|
|
332
|
+
|
|
333
|
+
# Summary
|
|
334
|
+
console.print("\n[bold green]✨ Removal Summary[/bold green]")
|
|
335
|
+
console.print(f" ✅ Successful: {successful}")
|
|
336
|
+
if failed > 0:
|
|
337
|
+
console.print(f" ❌ Failed: {failed}")
|
|
338
|
+
|
|
339
|
+
console.print("\n[dim]💡 Restart your AI coding tool to apply changes[/dim]")
|
|
340
|
+
|
|
341
|
+
except typer.Exit:
|
|
342
|
+
raise
|
|
343
|
+
except Exception as e:
|
|
344
|
+
logger.exception("MCP uninstallation failed")
|
|
345
|
+
print_error(f"Uninstallation failed: {e}")
|
|
346
|
+
raise typer.Exit(1)
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
# ==============================================================================
|
|
350
|
+
# List Configured Platforms Command
|
|
351
|
+
# ==============================================================================
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
@uninstall_app.command("list")
|
|
355
|
+
def list_integrations(ctx: typer.Context) -> None:
|
|
356
|
+
"""List all currently configured MCP integrations."""
|
|
357
|
+
console.print(
|
|
358
|
+
Panel.fit(
|
|
359
|
+
"[bold cyan]Configured MCP Integrations[/bold cyan]", border_style="cyan"
|
|
360
|
+
)
|
|
361
|
+
)
|
|
362
|
+
|
|
363
|
+
try:
|
|
364
|
+
configured = find_configured_platforms()
|
|
365
|
+
|
|
366
|
+
if not configured:
|
|
367
|
+
console.print("\n[yellow]No MCP integrations configured[/yellow]")
|
|
368
|
+
console.print(
|
|
369
|
+
"\n[dim]Use 'mcp-vector-search install mcp' to add integrations[/dim]"
|
|
370
|
+
)
|
|
371
|
+
return
|
|
372
|
+
|
|
373
|
+
table = Table(show_header=True, header_style="bold cyan")
|
|
374
|
+
table.add_column("Platform", style="cyan")
|
|
375
|
+
table.add_column("Config Path")
|
|
376
|
+
table.add_column("Confidence", style="yellow")
|
|
377
|
+
table.add_column("Removal Command", style="dim")
|
|
378
|
+
|
|
379
|
+
for platform_info in configured:
|
|
380
|
+
table.add_row(
|
|
381
|
+
platform_info.platform.value,
|
|
382
|
+
str(platform_info.config_path) if platform_info.config_path else "N/A",
|
|
383
|
+
f"{platform_info.confidence:.2f}",
|
|
384
|
+
f"mcp-vector-search uninstall mcp --platform {platform_info.platform.value}",
|
|
385
|
+
)
|
|
386
|
+
|
|
387
|
+
console.print(table)
|
|
388
|
+
|
|
389
|
+
console.print("\n[bold blue]Removal Options:[/bold blue]")
|
|
390
|
+
console.print(
|
|
391
|
+
" • Remove specific: [code]mcp-vector-search uninstall mcp --platform <name>[/code]"
|
|
392
|
+
)
|
|
393
|
+
console.print(
|
|
394
|
+
" • Remove all: [code]mcp-vector-search uninstall mcp --all[/code]"
|
|
395
|
+
)
|
|
396
|
+
|
|
397
|
+
except Exception as e:
|
|
398
|
+
logger.exception("Failed to list configured platforms")
|
|
399
|
+
print_error(f"Failed to list configured platforms: {e}")
|
|
400
|
+
raise typer.Exit(1)
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
if __name__ == "__main__":
|
|
404
|
+
uninstall_app()
|
|
@@ -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,265 @@
|
|
|
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
|
+
no_args_is_help=True,
|
|
29
|
+
)
|
|
30
|
+
console = Console()
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@app.command()
|
|
34
|
+
def export(
|
|
35
|
+
output: Path = typer.Option(
|
|
36
|
+
Path("chunk-graph.json"),
|
|
37
|
+
"--output",
|
|
38
|
+
"-o",
|
|
39
|
+
help="Output file for chunk relationship data",
|
|
40
|
+
),
|
|
41
|
+
file_path: str | None = typer.Option(
|
|
42
|
+
None,
|
|
43
|
+
"--file",
|
|
44
|
+
"-f",
|
|
45
|
+
help="Export only chunks from specific file (supports wildcards)",
|
|
46
|
+
),
|
|
47
|
+
code_only: bool = typer.Option(
|
|
48
|
+
False,
|
|
49
|
+
"--code-only",
|
|
50
|
+
help="Exclude documentation chunks (text, comment, docstring)",
|
|
51
|
+
),
|
|
52
|
+
) -> None:
|
|
53
|
+
"""Export chunk relationships as JSON for D3.js visualization.
|
|
54
|
+
|
|
55
|
+
Examples:
|
|
56
|
+
# Export all chunks
|
|
57
|
+
mcp-vector-search visualize export
|
|
58
|
+
|
|
59
|
+
# Export from specific file
|
|
60
|
+
mcp-vector-search visualize export --file src/main.py
|
|
61
|
+
|
|
62
|
+
# Custom output location
|
|
63
|
+
mcp-vector-search visualize export -o graph.json
|
|
64
|
+
|
|
65
|
+
# Export only code chunks (exclude documentation)
|
|
66
|
+
mcp-vector-search visualize export --code-only
|
|
67
|
+
"""
|
|
68
|
+
asyncio.run(_export_chunks(output, file_path, code_only))
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
async def _export_chunks(
|
|
72
|
+
output: Path, file_filter: str | None, code_only: bool = False
|
|
73
|
+
) -> None:
|
|
74
|
+
"""Export chunk relationship data.
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
output: Path to output JSON file
|
|
78
|
+
file_filter: Optional file pattern to filter chunks
|
|
79
|
+
code_only: If True, exclude documentation chunks (text, comment, docstring)
|
|
80
|
+
"""
|
|
81
|
+
try:
|
|
82
|
+
# Load project
|
|
83
|
+
project_manager = ProjectManager(Path.cwd())
|
|
84
|
+
|
|
85
|
+
if not project_manager.is_initialized():
|
|
86
|
+
console.print(
|
|
87
|
+
"[red]Project not initialized. Run 'mcp-vector-search init' first.[/red]"
|
|
88
|
+
)
|
|
89
|
+
raise typer.Exit(1)
|
|
90
|
+
|
|
91
|
+
config = project_manager.load_config()
|
|
92
|
+
|
|
93
|
+
# Get database
|
|
94
|
+
embedding_function, _ = create_embedding_function(config.embedding_model)
|
|
95
|
+
database = ChromaVectorDatabase(
|
|
96
|
+
persist_directory=config.index_path,
|
|
97
|
+
embedding_function=embedding_function,
|
|
98
|
+
)
|
|
99
|
+
await database.initialize()
|
|
100
|
+
|
|
101
|
+
# Get all chunks with metadata
|
|
102
|
+
console.print("[cyan]Fetching chunks from database...[/cyan]")
|
|
103
|
+
chunks = await database.get_all_chunks()
|
|
104
|
+
|
|
105
|
+
if len(chunks) == 0:
|
|
106
|
+
console.print(
|
|
107
|
+
"[yellow]No chunks found in index. Run 'mcp-vector-search index' first.[/yellow]"
|
|
108
|
+
)
|
|
109
|
+
raise typer.Exit(1)
|
|
110
|
+
|
|
111
|
+
console.print(f"[green]✓[/green] Retrieved {len(chunks)} chunks")
|
|
112
|
+
|
|
113
|
+
# Apply file filter if specified
|
|
114
|
+
if file_filter:
|
|
115
|
+
chunks = [c for c in chunks if fnmatch(str(c.file_path), file_filter)]
|
|
116
|
+
console.print(
|
|
117
|
+
f"[cyan]Filtered to {len(chunks)} chunks matching '{file_filter}'[/cyan]"
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
# Apply code-only filter if requested
|
|
121
|
+
if code_only:
|
|
122
|
+
original_count = len(chunks)
|
|
123
|
+
chunks = [
|
|
124
|
+
c
|
|
125
|
+
for c in chunks
|
|
126
|
+
if c.chunk_type not in ["text", "comment", "docstring"]
|
|
127
|
+
]
|
|
128
|
+
filtered_count = len(chunks)
|
|
129
|
+
console.print(
|
|
130
|
+
f"[dim]Filtered out {original_count - filtered_count} documentation chunks "
|
|
131
|
+
f"({original_count} → {filtered_count} chunks)[/dim]"
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
# Build graph data using refactored module
|
|
135
|
+
graph_data = await build_graph_data(
|
|
136
|
+
chunks=chunks,
|
|
137
|
+
database=database,
|
|
138
|
+
project_manager=project_manager,
|
|
139
|
+
code_only=code_only,
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
# Export to JSON using refactored module
|
|
143
|
+
export_to_json(graph_data, output)
|
|
144
|
+
|
|
145
|
+
await database.close()
|
|
146
|
+
|
|
147
|
+
console.print()
|
|
148
|
+
# Count cycles from graph_data links
|
|
149
|
+
cycles = [link for link in graph_data["links"] if link.get("is_cycle", False)]
|
|
150
|
+
cycle_warning = f"[yellow]Cycles: {len(cycles)} ⚠️[/yellow]\n" if cycles else ""
|
|
151
|
+
|
|
152
|
+
# Count subprojects
|
|
153
|
+
subprojects_count = len(graph_data["metadata"].get("subprojects", []))
|
|
154
|
+
|
|
155
|
+
console.print(
|
|
156
|
+
Panel.fit(
|
|
157
|
+
f"[green]✓[/green] Exported graph data to [cyan]{output}[/cyan]\n\n"
|
|
158
|
+
f"Nodes: {len(graph_data['nodes'])}\n"
|
|
159
|
+
f"Links: {len(graph_data['links'])}\n"
|
|
160
|
+
f"{cycle_warning}"
|
|
161
|
+
f"{'Subprojects: ' + str(subprojects_count) if subprojects_count else ''}\n\n"
|
|
162
|
+
f"[dim]Next: Run 'mcp-vector-search visualize serve' to view[/dim]",
|
|
163
|
+
title="Export Complete",
|
|
164
|
+
border_style="green",
|
|
165
|
+
)
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
except Exception as e:
|
|
169
|
+
logger.error(f"Export failed: {e}")
|
|
170
|
+
console.print(f"[red]✗ Export failed: {e}[/red]")
|
|
171
|
+
raise typer.Exit(1)
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
@app.command()
|
|
175
|
+
def serve(
|
|
176
|
+
port: int = typer.Option(
|
|
177
|
+
8080, "--port", "-p", help="Port for visualization server"
|
|
178
|
+
),
|
|
179
|
+
graph_file: Path = typer.Option(
|
|
180
|
+
Path("chunk-graph.json"),
|
|
181
|
+
"--graph",
|
|
182
|
+
"-g",
|
|
183
|
+
help="Graph JSON file to visualize",
|
|
184
|
+
),
|
|
185
|
+
code_only: bool = typer.Option(
|
|
186
|
+
False,
|
|
187
|
+
"--code-only",
|
|
188
|
+
help="Exclude documentation chunks (text, comment, docstring)",
|
|
189
|
+
),
|
|
190
|
+
) -> None:
|
|
191
|
+
"""Start local HTTP server for D3.js visualization.
|
|
192
|
+
|
|
193
|
+
Examples:
|
|
194
|
+
# Start server on default port 8080
|
|
195
|
+
mcp-vector-search visualize serve
|
|
196
|
+
|
|
197
|
+
# Custom port
|
|
198
|
+
mcp-vector-search visualize serve --port 3000
|
|
199
|
+
|
|
200
|
+
# Custom graph file
|
|
201
|
+
mcp-vector-search visualize serve --graph my-graph.json
|
|
202
|
+
|
|
203
|
+
# Serve with code-only filter
|
|
204
|
+
mcp-vector-search visualize serve --code-only
|
|
205
|
+
"""
|
|
206
|
+
# Use specified port or find free one
|
|
207
|
+
if port == 8080: # Default port, try to find free one
|
|
208
|
+
try:
|
|
209
|
+
port = find_free_port(8080, 8099)
|
|
210
|
+
except OSError as e:
|
|
211
|
+
console.print(f"[red]✗ {e}[/red]")
|
|
212
|
+
raise typer.Exit(1)
|
|
213
|
+
|
|
214
|
+
# Get visualization directory - use project-local storage
|
|
215
|
+
project_manager = ProjectManager(Path.cwd())
|
|
216
|
+
if not project_manager.is_initialized():
|
|
217
|
+
console.print(
|
|
218
|
+
"[red]Project not initialized. Run 'mcp-vector-search init' first.[/red]"
|
|
219
|
+
)
|
|
220
|
+
raise typer.Exit(1)
|
|
221
|
+
|
|
222
|
+
viz_dir = project_manager.project_root / ".mcp-vector-search" / "visualization"
|
|
223
|
+
|
|
224
|
+
if not viz_dir.exists():
|
|
225
|
+
console.print(
|
|
226
|
+
f"[yellow]Visualization directory not found. Creating at {viz_dir}...[/yellow]"
|
|
227
|
+
)
|
|
228
|
+
viz_dir.mkdir(parents=True, exist_ok=True)
|
|
229
|
+
|
|
230
|
+
# Always ensure index.html exists (regenerate if missing)
|
|
231
|
+
html_file = viz_dir / "index.html"
|
|
232
|
+
if not html_file.exists():
|
|
233
|
+
console.print("[yellow]Creating visualization HTML file...[/yellow]")
|
|
234
|
+
export_to_html(html_file)
|
|
235
|
+
|
|
236
|
+
# Check if we need to regenerate the graph file
|
|
237
|
+
needs_regeneration = not graph_file.exists() or code_only
|
|
238
|
+
|
|
239
|
+
if graph_file.exists() and not needs_regeneration:
|
|
240
|
+
# Use existing unfiltered file
|
|
241
|
+
dest = viz_dir / "chunk-graph.json"
|
|
242
|
+
shutil.copy(graph_file, dest)
|
|
243
|
+
console.print(f"[green]✓[/green] Copied graph data to {dest}")
|
|
244
|
+
else:
|
|
245
|
+
# Generate new file (with filter if requested)
|
|
246
|
+
if graph_file.exists() and code_only:
|
|
247
|
+
console.print(
|
|
248
|
+
"[yellow]Regenerating filtered graph data (--code-only)...[/yellow]"
|
|
249
|
+
)
|
|
250
|
+
elif not graph_file.exists():
|
|
251
|
+
console.print(
|
|
252
|
+
f"[yellow]Graph file {graph_file} not found. Generating it now...[/yellow]"
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
asyncio.run(_export_chunks(graph_file, None, code_only))
|
|
256
|
+
console.print()
|
|
257
|
+
|
|
258
|
+
# Copy the newly generated graph to visualization directory
|
|
259
|
+
if graph_file.exists():
|
|
260
|
+
dest = viz_dir / "chunk-graph.json"
|
|
261
|
+
shutil.copy(graph_file, dest)
|
|
262
|
+
console.print(f"[green]✓[/green] Copied graph data to {dest}")
|
|
263
|
+
|
|
264
|
+
# Start server using refactored module
|
|
265
|
+
start_visualization_server(port, viz_dir, auto_open=True)
|