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,584 @@
|
|
|
1
|
+
"""Status command for MCP Vector Search CLI."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import json
|
|
5
|
+
import subprocess
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
import typer
|
|
10
|
+
from loguru import logger
|
|
11
|
+
|
|
12
|
+
from ... import __version__
|
|
13
|
+
from ...core.database import ChromaVectorDatabase
|
|
14
|
+
from ...core.embeddings import create_embedding_function
|
|
15
|
+
from ...core.exceptions import ProjectNotFoundError
|
|
16
|
+
from ...core.indexer import SemanticIndexer
|
|
17
|
+
from ...core.project import ProjectManager
|
|
18
|
+
from ..output import (
|
|
19
|
+
console,
|
|
20
|
+
print_dependency_status,
|
|
21
|
+
print_error,
|
|
22
|
+
print_info,
|
|
23
|
+
print_json,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
# Create status subcommand app
|
|
27
|
+
status_app = typer.Typer(help="Show project status and statistics")
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@status_app.command()
|
|
31
|
+
def main(
|
|
32
|
+
ctx: typer.Context,
|
|
33
|
+
project_root: Path | None = typer.Option(
|
|
34
|
+
None,
|
|
35
|
+
"--project-root",
|
|
36
|
+
"-p",
|
|
37
|
+
help="Project root directory (auto-detected if not specified)",
|
|
38
|
+
exists=True,
|
|
39
|
+
file_okay=False,
|
|
40
|
+
dir_okay=True,
|
|
41
|
+
readable=True,
|
|
42
|
+
rich_help_panel="🔧 Global Options",
|
|
43
|
+
),
|
|
44
|
+
verbose: bool = typer.Option(
|
|
45
|
+
False,
|
|
46
|
+
"--verbose",
|
|
47
|
+
"-v",
|
|
48
|
+
help="Show detailed information including paths and patterns",
|
|
49
|
+
rich_help_panel="📊 Display Options",
|
|
50
|
+
),
|
|
51
|
+
health_check: bool = typer.Option(
|
|
52
|
+
False,
|
|
53
|
+
"--health-check",
|
|
54
|
+
help="Perform comprehensive health check of all components",
|
|
55
|
+
rich_help_panel="🔍 Diagnostics",
|
|
56
|
+
),
|
|
57
|
+
mcp: bool = typer.Option(
|
|
58
|
+
False,
|
|
59
|
+
"--mcp",
|
|
60
|
+
help="Check Claude Code MCP integration status",
|
|
61
|
+
rich_help_panel="🔍 Diagnostics",
|
|
62
|
+
),
|
|
63
|
+
json_output: bool = typer.Option(
|
|
64
|
+
False,
|
|
65
|
+
"--json",
|
|
66
|
+
help="Output status in JSON format",
|
|
67
|
+
rich_help_panel="📊 Display Options",
|
|
68
|
+
),
|
|
69
|
+
) -> None:
|
|
70
|
+
"""📊 Show project status and indexing statistics.
|
|
71
|
+
|
|
72
|
+
Displays comprehensive information about your project including configuration,
|
|
73
|
+
indexing statistics, and system health. Use this to verify setup and monitor
|
|
74
|
+
indexing progress.
|
|
75
|
+
|
|
76
|
+
[bold cyan]Basic Examples:[/bold cyan]
|
|
77
|
+
|
|
78
|
+
[green]Quick status check:[/green]
|
|
79
|
+
$ mcp-vector-search status
|
|
80
|
+
|
|
81
|
+
[green]Detailed status with all information:[/green]
|
|
82
|
+
$ mcp-vector-search status --verbose
|
|
83
|
+
|
|
84
|
+
[green]Check MCP integration:[/green]
|
|
85
|
+
$ mcp-vector-search status --mcp
|
|
86
|
+
|
|
87
|
+
[bold cyan]Diagnostics:[/bold cyan]
|
|
88
|
+
|
|
89
|
+
[green]Full health check:[/green]
|
|
90
|
+
$ mcp-vector-search status --health-check
|
|
91
|
+
|
|
92
|
+
[green]Export status to JSON:[/green]
|
|
93
|
+
$ mcp-vector-search status --json > status.json
|
|
94
|
+
|
|
95
|
+
[green]Combined diagnostics:[/green]
|
|
96
|
+
$ mcp-vector-search status --verbose --health-check --mcp
|
|
97
|
+
|
|
98
|
+
[dim]💡 Tip: Use --health-check to diagnose issues with dependencies or database.[/dim]
|
|
99
|
+
"""
|
|
100
|
+
try:
|
|
101
|
+
# Use provided project_root or current working directory
|
|
102
|
+
if project_root is None:
|
|
103
|
+
project_root = Path.cwd()
|
|
104
|
+
|
|
105
|
+
async def run_status_with_timeout():
|
|
106
|
+
"""Run status command with timeout protection."""
|
|
107
|
+
try:
|
|
108
|
+
await asyncio.wait_for(
|
|
109
|
+
show_status(
|
|
110
|
+
project_root=project_root,
|
|
111
|
+
verbose=verbose,
|
|
112
|
+
health_check=health_check,
|
|
113
|
+
mcp=mcp,
|
|
114
|
+
json_output=json_output,
|
|
115
|
+
),
|
|
116
|
+
timeout=30.0, # 30 second timeout
|
|
117
|
+
)
|
|
118
|
+
except TimeoutError:
|
|
119
|
+
logger.error("Status check timed out after 30 seconds")
|
|
120
|
+
print_error(
|
|
121
|
+
"Status check timed out after 30 seconds. "
|
|
122
|
+
"Try running with --verbose for more details."
|
|
123
|
+
)
|
|
124
|
+
raise typer.Exit(1)
|
|
125
|
+
|
|
126
|
+
asyncio.run(run_status_with_timeout())
|
|
127
|
+
|
|
128
|
+
except Exception as e:
|
|
129
|
+
logger.error(f"Status check failed: {e}")
|
|
130
|
+
print_error(f"Status check failed: {e}")
|
|
131
|
+
raise typer.Exit(1)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
async def show_status(
|
|
135
|
+
project_root: Path,
|
|
136
|
+
verbose: bool = False,
|
|
137
|
+
health_check: bool = False,
|
|
138
|
+
mcp: bool = False,
|
|
139
|
+
json_output: bool = False,
|
|
140
|
+
) -> None:
|
|
141
|
+
"""Show comprehensive project status."""
|
|
142
|
+
status_data = {}
|
|
143
|
+
|
|
144
|
+
try:
|
|
145
|
+
# Check if project is initialized - use the specified project root
|
|
146
|
+
project_manager = ProjectManager(project_root)
|
|
147
|
+
|
|
148
|
+
if not project_manager.is_initialized():
|
|
149
|
+
if json_output:
|
|
150
|
+
status_data = {
|
|
151
|
+
"initialized": False,
|
|
152
|
+
"project_root": str(project_root),
|
|
153
|
+
"error": "Project not initialized",
|
|
154
|
+
}
|
|
155
|
+
print_json(status_data)
|
|
156
|
+
else:
|
|
157
|
+
print_error(f"Project not initialized at {project_root}")
|
|
158
|
+
print_info("Run 'mcp-vector-search init' to initialize the project")
|
|
159
|
+
return
|
|
160
|
+
|
|
161
|
+
# Get configuration first
|
|
162
|
+
config = project_manager.load_config()
|
|
163
|
+
|
|
164
|
+
# Get indexing statistics from database (fast, no filesystem scan)
|
|
165
|
+
embedding_function, _ = create_embedding_function(config.embedding_model)
|
|
166
|
+
database = ChromaVectorDatabase(
|
|
167
|
+
persist_directory=config.index_path,
|
|
168
|
+
embedding_function=embedding_function,
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
indexer = SemanticIndexer(
|
|
172
|
+
database=database,
|
|
173
|
+
project_root=project_root,
|
|
174
|
+
config=config,
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
# Get indexing stats (using database stats only, no filesystem scan)
|
|
178
|
+
async with database:
|
|
179
|
+
db_stats = await database.get_stats()
|
|
180
|
+
index_stats = await indexer.get_indexing_stats(db_stats=db_stats)
|
|
181
|
+
|
|
182
|
+
# Get project information with pre-computed file count (avoids filesystem scan)
|
|
183
|
+
project_info = project_manager.get_project_info(file_count=db_stats.total_files)
|
|
184
|
+
|
|
185
|
+
# Get version information
|
|
186
|
+
index_version = indexer.get_index_version()
|
|
187
|
+
needs_reindex = indexer.needs_reindex_for_version()
|
|
188
|
+
|
|
189
|
+
# Compile status data
|
|
190
|
+
status_data = {
|
|
191
|
+
"project": {
|
|
192
|
+
"name": project_info.name,
|
|
193
|
+
"root_path": str(project_info.root_path),
|
|
194
|
+
"initialized": project_info.is_initialized,
|
|
195
|
+
"languages": project_info.languages,
|
|
196
|
+
"file_count": project_info.file_count,
|
|
197
|
+
},
|
|
198
|
+
"configuration": {
|
|
199
|
+
"embedding_model": config.embedding_model,
|
|
200
|
+
"similarity_threshold": config.similarity_threshold,
|
|
201
|
+
"file_extensions": config.file_extensions,
|
|
202
|
+
"max_chunk_size": config.max_chunk_size,
|
|
203
|
+
"cache_embeddings": config.cache_embeddings,
|
|
204
|
+
"watch_files": config.watch_files,
|
|
205
|
+
"auto_reindex_on_upgrade": config.auto_reindex_on_upgrade,
|
|
206
|
+
},
|
|
207
|
+
"index": {
|
|
208
|
+
"total_files": index_stats.get("total_indexable_files", 0),
|
|
209
|
+
"indexed_files": index_stats.get("indexed_files", 0),
|
|
210
|
+
"total_chunks": index_stats.get("total_chunks", 0),
|
|
211
|
+
"languages": index_stats.get("languages", {}),
|
|
212
|
+
"index_size_mb": db_stats.index_size_mb,
|
|
213
|
+
"last_updated": db_stats.last_updated,
|
|
214
|
+
"index_version": index_version,
|
|
215
|
+
"current_version": __version__,
|
|
216
|
+
"needs_reindex": needs_reindex,
|
|
217
|
+
},
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
# Add health check if requested
|
|
221
|
+
if health_check:
|
|
222
|
+
health_status = await perform_health_check(project_root, config)
|
|
223
|
+
status_data["health"] = health_status
|
|
224
|
+
|
|
225
|
+
# Add MCP integration check if requested
|
|
226
|
+
if mcp:
|
|
227
|
+
mcp_status = await check_mcp_integration(project_root)
|
|
228
|
+
status_data["mcp"] = mcp_status
|
|
229
|
+
|
|
230
|
+
# Add verbose information
|
|
231
|
+
if verbose:
|
|
232
|
+
status_data["verbose"] = {
|
|
233
|
+
"config_path": str(project_info.config_path),
|
|
234
|
+
"index_path": str(project_info.index_path),
|
|
235
|
+
"ignore_patterns": list(indexer.get_ignore_patterns()),
|
|
236
|
+
"parser_info": index_stats.get("parser_info", {}),
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
# Output results
|
|
240
|
+
if json_output:
|
|
241
|
+
print_json(status_data)
|
|
242
|
+
else:
|
|
243
|
+
_display_status(status_data, verbose, mcp)
|
|
244
|
+
|
|
245
|
+
except ProjectNotFoundError:
|
|
246
|
+
if json_output:
|
|
247
|
+
print_json({"initialized": False, "error": "Project not initialized"})
|
|
248
|
+
else:
|
|
249
|
+
print_error("Project not initialized")
|
|
250
|
+
print_info("Run 'mcp-vector-search init' to initialize the project")
|
|
251
|
+
except Exception as e:
|
|
252
|
+
if json_output:
|
|
253
|
+
print_json({"error": str(e)})
|
|
254
|
+
else:
|
|
255
|
+
print_error(f"Failed to get status: {e}")
|
|
256
|
+
raise
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def _display_status(
|
|
260
|
+
status_data: dict[str, Any], verbose: bool, mcp: bool = False
|
|
261
|
+
) -> None:
|
|
262
|
+
"""Display status in human-readable format."""
|
|
263
|
+
project_data = status_data["project"]
|
|
264
|
+
config_data = status_data["configuration"]
|
|
265
|
+
index_data = status_data["index"]
|
|
266
|
+
|
|
267
|
+
# Project information
|
|
268
|
+
console.print("[bold blue]Project Information[/bold blue]")
|
|
269
|
+
console.print(f" Name: {project_data['name']}")
|
|
270
|
+
console.print(f" Root: {project_data['root_path']}")
|
|
271
|
+
console.print(
|
|
272
|
+
f" Languages: {', '.join(project_data['languages']) if project_data['languages'] else 'None detected'}"
|
|
273
|
+
)
|
|
274
|
+
console.print(f" Indexable Files: {project_data['file_count']}")
|
|
275
|
+
console.print()
|
|
276
|
+
|
|
277
|
+
# Configuration
|
|
278
|
+
console.print("[bold blue]Configuration[/bold blue]")
|
|
279
|
+
console.print(f" Embedding Model: {config_data['embedding_model']}")
|
|
280
|
+
console.print(f" Similarity Threshold: {config_data['similarity_threshold']}")
|
|
281
|
+
console.print(f" File Extensions: {', '.join(config_data['file_extensions'])}")
|
|
282
|
+
console.print(
|
|
283
|
+
f" Cache Embeddings: {'✓' if config_data['cache_embeddings'] else '✗'}"
|
|
284
|
+
)
|
|
285
|
+
console.print()
|
|
286
|
+
|
|
287
|
+
# Index statistics
|
|
288
|
+
console.print("[bold blue]Index Statistics[/bold blue]")
|
|
289
|
+
console.print(
|
|
290
|
+
f" Indexed Files: {index_data['indexed_files']}/{index_data['total_files']}"
|
|
291
|
+
)
|
|
292
|
+
console.print(f" Total Chunks: {index_data['total_chunks']}")
|
|
293
|
+
console.print(f" Index Size: {index_data['index_size_mb']:.2f} MB")
|
|
294
|
+
|
|
295
|
+
# Version information
|
|
296
|
+
index_version = index_data.get("index_version")
|
|
297
|
+
current_version = index_data.get("current_version", __version__)
|
|
298
|
+
needs_reindex = index_data.get("needs_reindex", False)
|
|
299
|
+
|
|
300
|
+
if index_version:
|
|
301
|
+
if needs_reindex:
|
|
302
|
+
console.print(
|
|
303
|
+
f" Version: [yellow]{index_version}[/yellow] (current: {current_version}) [yellow]⚠️ Reindex recommended[/yellow]"
|
|
304
|
+
)
|
|
305
|
+
else:
|
|
306
|
+
console.print(f" Version: [green]{index_version}[/green] (up to date)")
|
|
307
|
+
else:
|
|
308
|
+
console.print(
|
|
309
|
+
f" Version: [yellow]Not tracked[/yellow] (current: {current_version}) [yellow]⚠️ Reindex recommended[/yellow]"
|
|
310
|
+
)
|
|
311
|
+
|
|
312
|
+
if index_data["languages"]:
|
|
313
|
+
console.print(" Language Distribution:")
|
|
314
|
+
for lang, count in index_data["languages"].items():
|
|
315
|
+
console.print(f" {lang}: {count} chunks")
|
|
316
|
+
console.print()
|
|
317
|
+
|
|
318
|
+
# Show reindex recommendation if needed
|
|
319
|
+
if needs_reindex:
|
|
320
|
+
console.print(
|
|
321
|
+
"[yellow]💡 Tip: Run 'mcp-vector-search index' to reindex with the latest improvements[/yellow]"
|
|
322
|
+
)
|
|
323
|
+
console.print()
|
|
324
|
+
|
|
325
|
+
# Health check results
|
|
326
|
+
if "health" in status_data:
|
|
327
|
+
health_data = status_data["health"]
|
|
328
|
+
console.print("[bold blue]Health Check[/bold blue]")
|
|
329
|
+
|
|
330
|
+
overall_health = health_data.get("overall", "unknown")
|
|
331
|
+
if overall_health == "healthy":
|
|
332
|
+
console.print("[green]✓ System is healthy[/green]")
|
|
333
|
+
elif overall_health == "warning":
|
|
334
|
+
console.print("[yellow]⚠ System has warnings[/yellow]")
|
|
335
|
+
else:
|
|
336
|
+
console.print("[red]✗ System has issues[/red]")
|
|
337
|
+
|
|
338
|
+
for component, status in health_data.get("components", {}).items():
|
|
339
|
+
if status == "ok":
|
|
340
|
+
console.print(f" [green]✓[/green] {component}")
|
|
341
|
+
elif status == "warning":
|
|
342
|
+
console.print(f" [yellow]⚠[/yellow] {component}")
|
|
343
|
+
else:
|
|
344
|
+
console.print(f" [red]✗[/red] {component}")
|
|
345
|
+
console.print()
|
|
346
|
+
|
|
347
|
+
# MCP integration status
|
|
348
|
+
if "mcp" in status_data:
|
|
349
|
+
mcp_data = status_data["mcp"]
|
|
350
|
+
console.print("[bold blue]MCP Integration[/bold blue]")
|
|
351
|
+
|
|
352
|
+
if mcp_data.get("claude_available"):
|
|
353
|
+
console.print("[green]✓[/green] Claude Code: Available")
|
|
354
|
+
else:
|
|
355
|
+
console.print("[red]✗[/red] Claude Code: Not available")
|
|
356
|
+
|
|
357
|
+
server_status = mcp_data.get("server_status", "unknown")
|
|
358
|
+
server_name = mcp_data.get("server_name", "mcp-vector-search")
|
|
359
|
+
|
|
360
|
+
if server_status == "installed":
|
|
361
|
+
console.print(f"[green]✓[/green] MCP Server '{server_name}': Installed")
|
|
362
|
+
elif server_status == "not_installed":
|
|
363
|
+
console.print(f"[red]✗[/red] MCP Server '{server_name}': Not installed")
|
|
364
|
+
else:
|
|
365
|
+
console.print(
|
|
366
|
+
f"[yellow]⚠[/yellow] MCP Server '{server_name}': {server_status}"
|
|
367
|
+
)
|
|
368
|
+
|
|
369
|
+
if mcp_data.get("project_config"):
|
|
370
|
+
console.print("[green]✓[/green] Project Configuration: Found")
|
|
371
|
+
else:
|
|
372
|
+
console.print("[red]✗[/red] Project Configuration: Missing")
|
|
373
|
+
|
|
374
|
+
console.print()
|
|
375
|
+
|
|
376
|
+
# Verbose information
|
|
377
|
+
if verbose and "verbose" in status_data:
|
|
378
|
+
verbose_data = status_data["verbose"]
|
|
379
|
+
console.print("[bold blue]Detailed Information[/bold blue]")
|
|
380
|
+
console.print(f" Config Path: {verbose_data['config_path']}")
|
|
381
|
+
console.print(f" Index Path: {verbose_data['index_path']}")
|
|
382
|
+
console.print(
|
|
383
|
+
f" Ignore Patterns: {', '.join(verbose_data['ignore_patterns'])}"
|
|
384
|
+
)
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
async def perform_health_check(project_root: Path, config) -> dict[str, Any]:
|
|
388
|
+
"""Perform comprehensive health check."""
|
|
389
|
+
health_status = {
|
|
390
|
+
"overall": "healthy",
|
|
391
|
+
"components": {},
|
|
392
|
+
"issues": [],
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
try:
|
|
396
|
+
# Check dependencies
|
|
397
|
+
deps_ok = check_dependencies()
|
|
398
|
+
health_status["components"]["dependencies"] = "ok" if deps_ok else "error"
|
|
399
|
+
if not deps_ok:
|
|
400
|
+
health_status["issues"].append("Missing dependencies")
|
|
401
|
+
|
|
402
|
+
# Check configuration
|
|
403
|
+
try:
|
|
404
|
+
# Validate embedding model
|
|
405
|
+
embedding_function, _ = create_embedding_function(config.embedding_model)
|
|
406
|
+
health_status["components"]["embedding_model"] = "ok"
|
|
407
|
+
except Exception as e:
|
|
408
|
+
health_status["components"]["embedding_model"] = "error"
|
|
409
|
+
health_status["issues"].append(f"Embedding model error: {e}")
|
|
410
|
+
|
|
411
|
+
# Check database
|
|
412
|
+
try:
|
|
413
|
+
database = ChromaVectorDatabase(
|
|
414
|
+
persist_directory=config.index_path,
|
|
415
|
+
embedding_function=embedding_function,
|
|
416
|
+
)
|
|
417
|
+
async with database:
|
|
418
|
+
await database.get_stats()
|
|
419
|
+
health_status["components"]["database"] = "ok"
|
|
420
|
+
except Exception as e:
|
|
421
|
+
health_status["components"]["database"] = "error"
|
|
422
|
+
health_status["issues"].append(f"Database error: {e}")
|
|
423
|
+
|
|
424
|
+
# Check file system permissions
|
|
425
|
+
try:
|
|
426
|
+
config.index_path.mkdir(parents=True, exist_ok=True)
|
|
427
|
+
test_file = config.index_path / ".test_write"
|
|
428
|
+
test_file.write_text("test")
|
|
429
|
+
test_file.unlink()
|
|
430
|
+
health_status["components"]["file_permissions"] = "ok"
|
|
431
|
+
except Exception as e:
|
|
432
|
+
health_status["components"]["file_permissions"] = "error"
|
|
433
|
+
health_status["issues"].append(f"File permission error: {e}")
|
|
434
|
+
|
|
435
|
+
# Determine overall health
|
|
436
|
+
if any(status == "error" for status in health_status["components"].values()):
|
|
437
|
+
health_status["overall"] = "error"
|
|
438
|
+
elif any(
|
|
439
|
+
status == "warning" for status in health_status["components"].values()
|
|
440
|
+
):
|
|
441
|
+
health_status["overall"] = "warning"
|
|
442
|
+
|
|
443
|
+
except Exception as e:
|
|
444
|
+
health_status["overall"] = "error"
|
|
445
|
+
health_status["issues"].append(f"Health check failed: {e}")
|
|
446
|
+
|
|
447
|
+
return health_status
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
async def check_mcp_integration(
|
|
451
|
+
project_root: Path, server_name: str = "mcp-vector-search"
|
|
452
|
+
) -> dict[str, Any]:
|
|
453
|
+
"""Check MCP integration status."""
|
|
454
|
+
mcp_status = {
|
|
455
|
+
"claude_available": False,
|
|
456
|
+
"server_status": "unknown",
|
|
457
|
+
"server_name": server_name,
|
|
458
|
+
"project_config": False,
|
|
459
|
+
"issues": [],
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
try:
|
|
463
|
+
# Import MCP functions from the mcp command module
|
|
464
|
+
from .mcp import check_claude_code_available, get_claude_command
|
|
465
|
+
|
|
466
|
+
# Check if Claude Code is available
|
|
467
|
+
mcp_status["claude_available"] = check_claude_code_available()
|
|
468
|
+
|
|
469
|
+
if mcp_status["claude_available"]:
|
|
470
|
+
claude_cmd = get_claude_command()
|
|
471
|
+
|
|
472
|
+
# Check if MCP server is installed
|
|
473
|
+
try:
|
|
474
|
+
result = subprocess.run(
|
|
475
|
+
[claude_cmd, "mcp", "get", server_name],
|
|
476
|
+
capture_output=True,
|
|
477
|
+
text=True,
|
|
478
|
+
timeout=10,
|
|
479
|
+
)
|
|
480
|
+
|
|
481
|
+
if result.returncode == 0:
|
|
482
|
+
mcp_status["server_status"] = "installed"
|
|
483
|
+
else:
|
|
484
|
+
mcp_status["server_status"] = "not_installed"
|
|
485
|
+
mcp_status["issues"].append(
|
|
486
|
+
f"MCP server '{server_name}' not found in Claude Code"
|
|
487
|
+
)
|
|
488
|
+
|
|
489
|
+
except subprocess.TimeoutExpired:
|
|
490
|
+
mcp_status["server_status"] = "timeout"
|
|
491
|
+
mcp_status["issues"].append("Timeout checking MCP server status")
|
|
492
|
+
except Exception as e:
|
|
493
|
+
mcp_status["server_status"] = "error"
|
|
494
|
+
mcp_status["issues"].append(f"Error checking MCP server: {e}")
|
|
495
|
+
else:
|
|
496
|
+
mcp_status["issues"].append("Claude Code not available")
|
|
497
|
+
|
|
498
|
+
# Check for project-level .claude.json configuration
|
|
499
|
+
claude_json_path = project_root / ".claude.json"
|
|
500
|
+
if claude_json_path.exists():
|
|
501
|
+
try:
|
|
502
|
+
with open(claude_json_path) as f:
|
|
503
|
+
config = json.load(f)
|
|
504
|
+
if config.get("mcpServers", {}).get(server_name):
|
|
505
|
+
mcp_status["project_config"] = True
|
|
506
|
+
else:
|
|
507
|
+
mcp_status["issues"].append(
|
|
508
|
+
f"MCP server '{server_name}' not found in project .claude.json"
|
|
509
|
+
)
|
|
510
|
+
except Exception as e:
|
|
511
|
+
mcp_status["issues"].append(f"Error reading project .claude.json: {e}")
|
|
512
|
+
else:
|
|
513
|
+
mcp_status["issues"].append("Project .claude.json not found")
|
|
514
|
+
|
|
515
|
+
except Exception as e:
|
|
516
|
+
mcp_status["issues"].append(f"MCP integration check failed: {e}")
|
|
517
|
+
|
|
518
|
+
return mcp_status
|
|
519
|
+
|
|
520
|
+
|
|
521
|
+
def check_dependencies() -> bool:
|
|
522
|
+
"""Check if all required dependencies are available.
|
|
523
|
+
|
|
524
|
+
Returns:
|
|
525
|
+
bool: True if all dependencies are available, False otherwise.
|
|
526
|
+
"""
|
|
527
|
+
dependencies = [
|
|
528
|
+
("chromadb", "ChromaDB"),
|
|
529
|
+
("sentence_transformers", "Sentence Transformers"),
|
|
530
|
+
("tree_sitter", "Tree-sitter"),
|
|
531
|
+
("tree_sitter_language_pack", "Tree-sitter Languages"),
|
|
532
|
+
("typer", "Typer"),
|
|
533
|
+
("rich", "Rich"),
|
|
534
|
+
("pydantic", "Pydantic"),
|
|
535
|
+
("watchdog", "Watchdog"),
|
|
536
|
+
("loguru", "Loguru"),
|
|
537
|
+
]
|
|
538
|
+
|
|
539
|
+
all_available = True
|
|
540
|
+
missing_deps = []
|
|
541
|
+
|
|
542
|
+
for module_name, display_name in dependencies:
|
|
543
|
+
try:
|
|
544
|
+
__import__(module_name)
|
|
545
|
+
print_dependency_status(display_name, True)
|
|
546
|
+
except ImportError:
|
|
547
|
+
print_dependency_status(display_name, False)
|
|
548
|
+
all_available = False
|
|
549
|
+
missing_deps.append(module_name)
|
|
550
|
+
|
|
551
|
+
# Print helpful installation instructions if dependencies are missing
|
|
552
|
+
if not all_available:
|
|
553
|
+
console.print()
|
|
554
|
+
console.print("[yellow]💡 Installation Help:[/yellow]")
|
|
555
|
+
console.print()
|
|
556
|
+
console.print("[bold]To install missing dependencies:[/bold]")
|
|
557
|
+
console.print()
|
|
558
|
+
console.print(" [cyan]# Using pip (recommended):[/cyan]")
|
|
559
|
+
console.print(" pip install mcp-vector-search")
|
|
560
|
+
console.print()
|
|
561
|
+
console.print(" [cyan]# Using uv (faster):[/cyan]")
|
|
562
|
+
console.print(" uv pip install mcp-vector-search")
|
|
563
|
+
console.print()
|
|
564
|
+
console.print(" [cyan]# Install from source:[/cyan]")
|
|
565
|
+
console.print(" pip install -e .")
|
|
566
|
+
console.print()
|
|
567
|
+
|
|
568
|
+
if "tree_sitter_language_pack" in missing_deps:
|
|
569
|
+
console.print(
|
|
570
|
+
"[yellow]⚠️ Tree-sitter Language Pack Issue Detected[/yellow]"
|
|
571
|
+
)
|
|
572
|
+
console.print()
|
|
573
|
+
console.print("If you installed via Homebrew, you may need to reinstall:")
|
|
574
|
+
console.print(" brew reinstall mcp-vector-search")
|
|
575
|
+
console.print()
|
|
576
|
+
console.print("Or install the dependency manually:")
|
|
577
|
+
console.print(" pip install tree-sitter-language-pack")
|
|
578
|
+
console.print()
|
|
579
|
+
|
|
580
|
+
return all_available
|
|
581
|
+
|
|
582
|
+
|
|
583
|
+
if __name__ == "__main__":
|
|
584
|
+
status_app()
|