mcp-vector-search 0.0.3__py3-none-any.whl → 0.4.12__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 +3 -2
- mcp_vector_search/cli/commands/auto_index.py +397 -0
- mcp_vector_search/cli/commands/config.py +88 -40
- mcp_vector_search/cli/commands/index.py +198 -52
- mcp_vector_search/cli/commands/init.py +471 -58
- mcp_vector_search/cli/commands/install.py +284 -0
- mcp_vector_search/cli/commands/mcp.py +495 -0
- mcp_vector_search/cli/commands/search.py +241 -87
- mcp_vector_search/cli/commands/status.py +184 -58
- mcp_vector_search/cli/commands/watch.py +34 -35
- mcp_vector_search/cli/didyoumean.py +184 -0
- mcp_vector_search/cli/export.py +320 -0
- mcp_vector_search/cli/history.py +292 -0
- mcp_vector_search/cli/interactive.py +342 -0
- mcp_vector_search/cli/main.py +175 -27
- mcp_vector_search/cli/output.py +63 -45
- mcp_vector_search/config/defaults.py +50 -36
- mcp_vector_search/config/settings.py +49 -35
- mcp_vector_search/core/auto_indexer.py +298 -0
- mcp_vector_search/core/connection_pool.py +322 -0
- mcp_vector_search/core/database.py +335 -25
- mcp_vector_search/core/embeddings.py +73 -29
- mcp_vector_search/core/exceptions.py +19 -2
- mcp_vector_search/core/factory.py +310 -0
- mcp_vector_search/core/git_hooks.py +345 -0
- mcp_vector_search/core/indexer.py +237 -73
- mcp_vector_search/core/models.py +21 -19
- mcp_vector_search/core/project.py +73 -58
- mcp_vector_search/core/scheduler.py +330 -0
- mcp_vector_search/core/search.py +574 -86
- mcp_vector_search/core/watcher.py +48 -46
- mcp_vector_search/mcp/__init__.py +4 -0
- mcp_vector_search/mcp/__main__.py +25 -0
- mcp_vector_search/mcp/server.py +701 -0
- mcp_vector_search/parsers/base.py +30 -31
- mcp_vector_search/parsers/javascript.py +74 -48
- mcp_vector_search/parsers/python.py +57 -49
- mcp_vector_search/parsers/registry.py +47 -32
- mcp_vector_search/parsers/text.py +179 -0
- mcp_vector_search/utils/__init__.py +40 -0
- mcp_vector_search/utils/gitignore.py +229 -0
- mcp_vector_search/utils/timing.py +334 -0
- mcp_vector_search/utils/version.py +47 -0
- {mcp_vector_search-0.0.3.dist-info → mcp_vector_search-0.4.12.dist-info}/METADATA +173 -7
- mcp_vector_search-0.4.12.dist-info/RECORD +54 -0
- mcp_vector_search-0.0.3.dist-info/RECORD +0 -35
- {mcp_vector_search-0.0.3.dist-info → mcp_vector_search-0.4.12.dist-info}/WHEEL +0 -0
- {mcp_vector_search-0.0.3.dist-info → mcp_vector_search-0.4.12.dist-info}/entry_points.txt +0 -0
- {mcp_vector_search-0.0.3.dist-info → mcp_vector_search-0.4.12.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
"""Status command for MCP Vector Search CLI."""
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
|
+
import json
|
|
5
|
+
import subprocess
|
|
4
6
|
from pathlib import Path
|
|
5
|
-
from typing import
|
|
7
|
+
from typing import Any
|
|
6
8
|
|
|
7
9
|
import typer
|
|
8
10
|
from loguru import logger
|
|
@@ -14,13 +16,10 @@ from ...core.indexer import SemanticIndexer
|
|
|
14
16
|
from ...core.project import ProjectManager
|
|
15
17
|
from ..output import (
|
|
16
18
|
console,
|
|
17
|
-
print_config,
|
|
18
19
|
print_dependency_status,
|
|
19
20
|
print_error,
|
|
20
|
-
print_index_stats,
|
|
21
21
|
print_info,
|
|
22
22
|
print_json,
|
|
23
|
-
print_project_info,
|
|
24
23
|
)
|
|
25
24
|
|
|
26
25
|
# Create status subcommand app
|
|
@@ -30,6 +29,16 @@ status_app = typer.Typer(help="Show project status and statistics")
|
|
|
30
29
|
@status_app.command()
|
|
31
30
|
def main(
|
|
32
31
|
ctx: typer.Context,
|
|
32
|
+
project_root: Path | None = typer.Option(
|
|
33
|
+
None,
|
|
34
|
+
"--project-root",
|
|
35
|
+
"-p",
|
|
36
|
+
help="Project root directory (auto-detected if not specified)",
|
|
37
|
+
exists=True,
|
|
38
|
+
file_okay=False,
|
|
39
|
+
dir_okay=True,
|
|
40
|
+
readable=True,
|
|
41
|
+
),
|
|
33
42
|
verbose: bool = typer.Option(
|
|
34
43
|
False,
|
|
35
44
|
"--verbose",
|
|
@@ -41,6 +50,11 @@ def main(
|
|
|
41
50
|
"--health-check",
|
|
42
51
|
help="Perform health check of all components",
|
|
43
52
|
),
|
|
53
|
+
mcp: bool = typer.Option(
|
|
54
|
+
False,
|
|
55
|
+
"--mcp",
|
|
56
|
+
help="Check Claude Code MCP integration status",
|
|
57
|
+
),
|
|
44
58
|
json_output: bool = typer.Option(
|
|
45
59
|
False,
|
|
46
60
|
"--json",
|
|
@@ -48,25 +62,31 @@ def main(
|
|
|
48
62
|
),
|
|
49
63
|
) -> None:
|
|
50
64
|
"""Show project status and indexing statistics.
|
|
51
|
-
|
|
65
|
+
|
|
52
66
|
This command displays comprehensive information about your MCP Vector Search
|
|
53
67
|
project including configuration, indexing status, and system health.
|
|
54
|
-
|
|
68
|
+
|
|
55
69
|
Examples:
|
|
56
70
|
mcp-vector-search status
|
|
57
71
|
mcp-vector-search status --verbose
|
|
58
72
|
mcp-vector-search status --health-check --json
|
|
73
|
+
mcp-vector-search status --mcp
|
|
59
74
|
"""
|
|
60
75
|
try:
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
76
|
+
# Use provided project_root or current working directory
|
|
77
|
+
if project_root is None:
|
|
78
|
+
project_root = Path.cwd()
|
|
79
|
+
|
|
80
|
+
asyncio.run(
|
|
81
|
+
show_status(
|
|
82
|
+
project_root=project_root,
|
|
83
|
+
verbose=verbose,
|
|
84
|
+
health_check=health_check,
|
|
85
|
+
mcp=mcp,
|
|
86
|
+
json_output=json_output,
|
|
87
|
+
)
|
|
88
|
+
)
|
|
89
|
+
|
|
70
90
|
except Exception as e:
|
|
71
91
|
logger.error(f"Status check failed: {e}")
|
|
72
92
|
print_error(f"Status check failed: {e}")
|
|
@@ -77,49 +97,50 @@ async def show_status(
|
|
|
77
97
|
project_root: Path,
|
|
78
98
|
verbose: bool = False,
|
|
79
99
|
health_check: bool = False,
|
|
100
|
+
mcp: bool = False,
|
|
80
101
|
json_output: bool = False,
|
|
81
102
|
) -> None:
|
|
82
103
|
"""Show comprehensive project status."""
|
|
83
104
|
status_data = {}
|
|
84
|
-
|
|
105
|
+
|
|
85
106
|
try:
|
|
86
|
-
# Check if project is initialized
|
|
107
|
+
# Check if project is initialized - use the specified project root
|
|
87
108
|
project_manager = ProjectManager(project_root)
|
|
88
|
-
|
|
109
|
+
|
|
89
110
|
if not project_manager.is_initialized():
|
|
90
111
|
if json_output:
|
|
91
112
|
status_data = {
|
|
92
113
|
"initialized": False,
|
|
93
114
|
"project_root": str(project_root),
|
|
94
|
-
"error": "Project not initialized"
|
|
115
|
+
"error": "Project not initialized",
|
|
95
116
|
}
|
|
96
117
|
print_json(status_data)
|
|
97
118
|
else:
|
|
98
119
|
print_error(f"Project not initialized at {project_root}")
|
|
99
120
|
print_info("Run 'mcp-vector-search init' to initialize the project")
|
|
100
121
|
return
|
|
101
|
-
|
|
122
|
+
|
|
102
123
|
# Get project information
|
|
103
124
|
project_info = project_manager.get_project_info()
|
|
104
125
|
config = project_manager.load_config()
|
|
105
|
-
|
|
126
|
+
|
|
106
127
|
# Get indexing statistics
|
|
107
128
|
embedding_function, _ = create_embedding_function(config.embedding_model)
|
|
108
129
|
database = ChromaVectorDatabase(
|
|
109
130
|
persist_directory=config.index_path,
|
|
110
131
|
embedding_function=embedding_function,
|
|
111
132
|
)
|
|
112
|
-
|
|
133
|
+
|
|
113
134
|
indexer = SemanticIndexer(
|
|
114
135
|
database=database,
|
|
115
136
|
project_root=project_root,
|
|
116
137
|
file_extensions=config.file_extensions,
|
|
117
138
|
)
|
|
118
|
-
|
|
139
|
+
|
|
119
140
|
async with database:
|
|
120
141
|
index_stats = await indexer.get_indexing_stats()
|
|
121
142
|
db_stats = await database.get_stats()
|
|
122
|
-
|
|
143
|
+
|
|
123
144
|
# Compile status data
|
|
124
145
|
status_data = {
|
|
125
146
|
"project": {
|
|
@@ -146,12 +167,17 @@ async def show_status(
|
|
|
146
167
|
"last_updated": db_stats.last_updated,
|
|
147
168
|
},
|
|
148
169
|
}
|
|
149
|
-
|
|
170
|
+
|
|
150
171
|
# Add health check if requested
|
|
151
172
|
if health_check:
|
|
152
173
|
health_status = await perform_health_check(project_root, config)
|
|
153
174
|
status_data["health"] = health_status
|
|
154
|
-
|
|
175
|
+
|
|
176
|
+
# Add MCP integration check if requested
|
|
177
|
+
if mcp:
|
|
178
|
+
mcp_status = await check_mcp_integration(project_root)
|
|
179
|
+
status_data["mcp"] = mcp_status
|
|
180
|
+
|
|
155
181
|
# Add verbose information
|
|
156
182
|
if verbose:
|
|
157
183
|
status_data["verbose"] = {
|
|
@@ -160,13 +186,13 @@ async def show_status(
|
|
|
160
186
|
"ignore_patterns": list(indexer.get_ignore_patterns()),
|
|
161
187
|
"parser_info": index_stats.get("parser_info", {}),
|
|
162
188
|
}
|
|
163
|
-
|
|
189
|
+
|
|
164
190
|
# Output results
|
|
165
191
|
if json_output:
|
|
166
192
|
print_json(status_data)
|
|
167
193
|
else:
|
|
168
|
-
_display_status(status_data, verbose)
|
|
169
|
-
|
|
194
|
+
_display_status(status_data, verbose, mcp)
|
|
195
|
+
|
|
170
196
|
except ProjectNotFoundError:
|
|
171
197
|
if json_output:
|
|
172
198
|
print_json({"initialized": False, "error": "Project not initialized"})
|
|
@@ -181,45 +207,51 @@ async def show_status(
|
|
|
181
207
|
raise
|
|
182
208
|
|
|
183
209
|
|
|
184
|
-
def _display_status(status_data:
|
|
210
|
+
def _display_status(status_data: dict[str, Any], verbose: bool, mcp: bool = False) -> None:
|
|
185
211
|
"""Display status in human-readable format."""
|
|
186
212
|
project_data = status_data["project"]
|
|
187
213
|
config_data = status_data["configuration"]
|
|
188
214
|
index_data = status_data["index"]
|
|
189
|
-
|
|
215
|
+
|
|
190
216
|
# Project information
|
|
191
217
|
console.print("[bold blue]Project Information[/bold blue]")
|
|
192
218
|
console.print(f" Name: {project_data['name']}")
|
|
193
219
|
console.print(f" Root: {project_data['root_path']}")
|
|
194
|
-
console.print(
|
|
220
|
+
console.print(
|
|
221
|
+
f" Languages: {', '.join(project_data['languages']) if project_data['languages'] else 'None detected'}"
|
|
222
|
+
)
|
|
195
223
|
console.print(f" Indexable Files: {project_data['file_count']}")
|
|
196
224
|
console.print()
|
|
197
|
-
|
|
225
|
+
|
|
198
226
|
# Configuration
|
|
199
227
|
console.print("[bold blue]Configuration[/bold blue]")
|
|
200
228
|
console.print(f" Embedding Model: {config_data['embedding_model']}")
|
|
201
229
|
console.print(f" Similarity Threshold: {config_data['similarity_threshold']}")
|
|
202
230
|
console.print(f" File Extensions: {', '.join(config_data['file_extensions'])}")
|
|
203
|
-
console.print(
|
|
231
|
+
console.print(
|
|
232
|
+
f" Cache Embeddings: {'✓' if config_data['cache_embeddings'] else '✗'}"
|
|
233
|
+
)
|
|
204
234
|
console.print()
|
|
205
|
-
|
|
235
|
+
|
|
206
236
|
# Index statistics
|
|
207
237
|
console.print("[bold blue]Index Statistics[/bold blue]")
|
|
208
|
-
console.print(
|
|
238
|
+
console.print(
|
|
239
|
+
f" Indexed Files: {index_data['indexed_files']}/{index_data['total_files']}"
|
|
240
|
+
)
|
|
209
241
|
console.print(f" Total Chunks: {index_data['total_chunks']}")
|
|
210
242
|
console.print(f" Index Size: {index_data['index_size_mb']:.2f} MB")
|
|
211
|
-
|
|
212
|
-
if index_data[
|
|
243
|
+
|
|
244
|
+
if index_data["languages"]:
|
|
213
245
|
console.print(" Language Distribution:")
|
|
214
|
-
for lang, count in index_data[
|
|
246
|
+
for lang, count in index_data["languages"].items():
|
|
215
247
|
console.print(f" {lang}: {count} chunks")
|
|
216
248
|
console.print()
|
|
217
|
-
|
|
249
|
+
|
|
218
250
|
# Health check results
|
|
219
251
|
if "health" in status_data:
|
|
220
252
|
health_data = status_data["health"]
|
|
221
253
|
console.print("[bold blue]Health Check[/bold blue]")
|
|
222
|
-
|
|
254
|
+
|
|
223
255
|
overall_health = health_data.get("overall", "unknown")
|
|
224
256
|
if overall_health == "healthy":
|
|
225
257
|
console.print("[green]✓ System is healthy[/green]")
|
|
@@ -227,7 +259,7 @@ def _display_status(status_data: Dict[str, Any], verbose: bool) -> None:
|
|
|
227
259
|
console.print("[yellow]⚠ System has warnings[/yellow]")
|
|
228
260
|
else:
|
|
229
261
|
console.print("[red]✗ System has issues[/red]")
|
|
230
|
-
|
|
262
|
+
|
|
231
263
|
for component, status in health_data.get("components", {}).items():
|
|
232
264
|
if status == "ok":
|
|
233
265
|
console.print(f" [green]✓[/green] {component}")
|
|
@@ -236,42 +268,69 @@ def _display_status(status_data: Dict[str, Any], verbose: bool) -> None:
|
|
|
236
268
|
else:
|
|
237
269
|
console.print(f" [red]✗[/red] {component}")
|
|
238
270
|
console.print()
|
|
239
|
-
|
|
271
|
+
|
|
272
|
+
# MCP integration status
|
|
273
|
+
if "mcp" in status_data:
|
|
274
|
+
mcp_data = status_data["mcp"]
|
|
275
|
+
console.print("[bold blue]MCP Integration[/bold blue]")
|
|
276
|
+
|
|
277
|
+
if mcp_data.get("claude_available"):
|
|
278
|
+
console.print("[green]✓[/green] Claude Code: Available")
|
|
279
|
+
else:
|
|
280
|
+
console.print("[red]✗[/red] Claude Code: Not available")
|
|
281
|
+
|
|
282
|
+
server_status = mcp_data.get("server_status", "unknown")
|
|
283
|
+
server_name = mcp_data.get("server_name", "mcp-vector-search")
|
|
284
|
+
|
|
285
|
+
if server_status == "installed":
|
|
286
|
+
console.print(f"[green]✓[/green] MCP Server '{server_name}': Installed")
|
|
287
|
+
elif server_status == "not_installed":
|
|
288
|
+
console.print(f"[red]✗[/red] MCP Server '{server_name}': Not installed")
|
|
289
|
+
else:
|
|
290
|
+
console.print(f"[yellow]⚠[/yellow] MCP Server '{server_name}': {server_status}")
|
|
291
|
+
|
|
292
|
+
if mcp_data.get("project_config"):
|
|
293
|
+
console.print("[green]✓[/green] Project Configuration: Found")
|
|
294
|
+
else:
|
|
295
|
+
console.print("[red]✗[/red] Project Configuration: Missing")
|
|
296
|
+
|
|
297
|
+
console.print()
|
|
298
|
+
|
|
240
299
|
# Verbose information
|
|
241
300
|
if verbose and "verbose" in status_data:
|
|
242
301
|
verbose_data = status_data["verbose"]
|
|
243
302
|
console.print("[bold blue]Detailed Information[/bold blue]")
|
|
244
303
|
console.print(f" Config Path: {verbose_data['config_path']}")
|
|
245
304
|
console.print(f" Index Path: {verbose_data['index_path']}")
|
|
246
|
-
console.print(
|
|
305
|
+
console.print(
|
|
306
|
+
f" Ignore Patterns: {', '.join(verbose_data['ignore_patterns'])}"
|
|
307
|
+
)
|
|
247
308
|
|
|
248
309
|
|
|
249
|
-
async def perform_health_check(project_root: Path, config) ->
|
|
310
|
+
async def perform_health_check(project_root: Path, config) -> dict[str, Any]:
|
|
250
311
|
"""Perform comprehensive health check."""
|
|
251
312
|
health_status = {
|
|
252
313
|
"overall": "healthy",
|
|
253
314
|
"components": {},
|
|
254
315
|
"issues": [],
|
|
255
316
|
}
|
|
256
|
-
|
|
317
|
+
|
|
257
318
|
try:
|
|
258
319
|
# Check dependencies
|
|
259
320
|
deps_ok = check_dependencies()
|
|
260
321
|
health_status["components"]["dependencies"] = "ok" if deps_ok else "error"
|
|
261
322
|
if not deps_ok:
|
|
262
323
|
health_status["issues"].append("Missing dependencies")
|
|
263
|
-
|
|
324
|
+
|
|
264
325
|
# Check configuration
|
|
265
|
-
config_ok = True
|
|
266
326
|
try:
|
|
267
327
|
# Validate embedding model
|
|
268
328
|
embedding_function, _ = create_embedding_function(config.embedding_model)
|
|
269
329
|
health_status["components"]["embedding_model"] = "ok"
|
|
270
330
|
except Exception as e:
|
|
271
|
-
config_ok = False
|
|
272
331
|
health_status["components"]["embedding_model"] = "error"
|
|
273
332
|
health_status["issues"].append(f"Embedding model error: {e}")
|
|
274
|
-
|
|
333
|
+
|
|
275
334
|
# Check database
|
|
276
335
|
try:
|
|
277
336
|
database = ChromaVectorDatabase(
|
|
@@ -284,7 +343,7 @@ async def perform_health_check(project_root: Path, config) -> Dict[str, Any]:
|
|
|
284
343
|
except Exception as e:
|
|
285
344
|
health_status["components"]["database"] = "error"
|
|
286
345
|
health_status["issues"].append(f"Database error: {e}")
|
|
287
|
-
|
|
346
|
+
|
|
288
347
|
# Check file system permissions
|
|
289
348
|
try:
|
|
290
349
|
config.index_path.mkdir(parents=True, exist_ok=True)
|
|
@@ -295,20 +354,87 @@ async def perform_health_check(project_root: Path, config) -> Dict[str, Any]:
|
|
|
295
354
|
except Exception as e:
|
|
296
355
|
health_status["components"]["file_permissions"] = "error"
|
|
297
356
|
health_status["issues"].append(f"File permission error: {e}")
|
|
298
|
-
|
|
357
|
+
|
|
299
358
|
# Determine overall health
|
|
300
359
|
if any(status == "error" for status in health_status["components"].values()):
|
|
301
360
|
health_status["overall"] = "error"
|
|
302
|
-
elif any(
|
|
361
|
+
elif any(
|
|
362
|
+
status == "warning" for status in health_status["components"].values()
|
|
363
|
+
):
|
|
303
364
|
health_status["overall"] = "warning"
|
|
304
|
-
|
|
365
|
+
|
|
305
366
|
except Exception as e:
|
|
306
367
|
health_status["overall"] = "error"
|
|
307
368
|
health_status["issues"].append(f"Health check failed: {e}")
|
|
308
|
-
|
|
369
|
+
|
|
309
370
|
return health_status
|
|
310
371
|
|
|
311
372
|
|
|
373
|
+
async def check_mcp_integration(project_root: Path, server_name: str = "mcp-vector-search") -> dict[str, Any]:
|
|
374
|
+
"""Check MCP integration status."""
|
|
375
|
+
mcp_status = {
|
|
376
|
+
"claude_available": False,
|
|
377
|
+
"server_status": "unknown",
|
|
378
|
+
"server_name": server_name,
|
|
379
|
+
"project_config": False,
|
|
380
|
+
"issues": [],
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
try:
|
|
384
|
+
# Import MCP functions from the mcp command module
|
|
385
|
+
from .mcp import check_claude_code_available, get_claude_command
|
|
386
|
+
|
|
387
|
+
# Check if Claude Code is available
|
|
388
|
+
mcp_status["claude_available"] = check_claude_code_available()
|
|
389
|
+
|
|
390
|
+
if mcp_status["claude_available"]:
|
|
391
|
+
claude_cmd = get_claude_command()
|
|
392
|
+
|
|
393
|
+
# Check if MCP server is installed
|
|
394
|
+
try:
|
|
395
|
+
result = subprocess.run(
|
|
396
|
+
[claude_cmd, "mcp", "get", server_name],
|
|
397
|
+
capture_output=True,
|
|
398
|
+
text=True,
|
|
399
|
+
timeout=10
|
|
400
|
+
)
|
|
401
|
+
|
|
402
|
+
if result.returncode == 0:
|
|
403
|
+
mcp_status["server_status"] = "installed"
|
|
404
|
+
else:
|
|
405
|
+
mcp_status["server_status"] = "not_installed"
|
|
406
|
+
mcp_status["issues"].append(f"MCP server '{server_name}' not found in Claude Code")
|
|
407
|
+
|
|
408
|
+
except subprocess.TimeoutExpired:
|
|
409
|
+
mcp_status["server_status"] = "timeout"
|
|
410
|
+
mcp_status["issues"].append("Timeout checking MCP server status")
|
|
411
|
+
except Exception as e:
|
|
412
|
+
mcp_status["server_status"] = "error"
|
|
413
|
+
mcp_status["issues"].append(f"Error checking MCP server: {e}")
|
|
414
|
+
else:
|
|
415
|
+
mcp_status["issues"].append("Claude Code not available")
|
|
416
|
+
|
|
417
|
+
# Check for project-level .claude.json configuration
|
|
418
|
+
claude_json_path = project_root / ".claude.json"
|
|
419
|
+
if claude_json_path.exists():
|
|
420
|
+
try:
|
|
421
|
+
with open(claude_json_path, 'r') as f:
|
|
422
|
+
config = json.load(f)
|
|
423
|
+
if config.get("mcpServers", {}).get(server_name):
|
|
424
|
+
mcp_status["project_config"] = True
|
|
425
|
+
else:
|
|
426
|
+
mcp_status["issues"].append(f"MCP server '{server_name}' not found in project .claude.json")
|
|
427
|
+
except Exception as e:
|
|
428
|
+
mcp_status["issues"].append(f"Error reading project .claude.json: {e}")
|
|
429
|
+
else:
|
|
430
|
+
mcp_status["issues"].append("Project .claude.json not found")
|
|
431
|
+
|
|
432
|
+
except Exception as e:
|
|
433
|
+
mcp_status["issues"].append(f"MCP integration check failed: {e}")
|
|
434
|
+
|
|
435
|
+
return mcp_status
|
|
436
|
+
|
|
437
|
+
|
|
312
438
|
def check_dependencies() -> bool:
|
|
313
439
|
"""Check if all required dependencies are available."""
|
|
314
440
|
dependencies = [
|
|
@@ -322,9 +448,9 @@ def check_dependencies() -> bool:
|
|
|
322
448
|
("watchdog", "Watchdog"),
|
|
323
449
|
("loguru", "Loguru"),
|
|
324
450
|
]
|
|
325
|
-
|
|
451
|
+
|
|
326
452
|
all_available = True
|
|
327
|
-
|
|
453
|
+
|
|
328
454
|
for module_name, display_name in dependencies:
|
|
329
455
|
try:
|
|
330
456
|
__import__(module_name)
|
|
@@ -332,7 +458,7 @@ def check_dependencies() -> bool:
|
|
|
332
458
|
except ImportError:
|
|
333
459
|
print_dependency_status(display_name, False)
|
|
334
460
|
all_available = False
|
|
335
|
-
|
|
461
|
+
|
|
336
462
|
return all_available
|
|
337
463
|
|
|
338
464
|
|
|
@@ -4,7 +4,6 @@ import asyncio
|
|
|
4
4
|
import signal
|
|
5
5
|
import sys
|
|
6
6
|
from pathlib import Path
|
|
7
|
-
from typing import Optional
|
|
8
7
|
|
|
9
8
|
import typer
|
|
10
9
|
from loguru import logger
|
|
@@ -36,7 +35,7 @@ def watch_main(
|
|
|
36
35
|
dir_okay=True,
|
|
37
36
|
readable=True,
|
|
38
37
|
),
|
|
39
|
-
config:
|
|
38
|
+
config: Path | None = typer.Option(
|
|
40
39
|
None,
|
|
41
40
|
"--config",
|
|
42
41
|
"-c",
|
|
@@ -54,19 +53,19 @@ def watch_main(
|
|
|
54
53
|
),
|
|
55
54
|
) -> None:
|
|
56
55
|
"""Watch for file changes and automatically update the search index.
|
|
57
|
-
|
|
56
|
+
|
|
58
57
|
This command starts a file watcher that monitors your project directory
|
|
59
58
|
for changes to code files. When files are created, modified, or deleted,
|
|
60
59
|
the search index is automatically updated to reflect the changes.
|
|
61
|
-
|
|
60
|
+
|
|
62
61
|
The watcher will:
|
|
63
62
|
- Monitor all files with configured extensions
|
|
64
63
|
- Debounce rapid changes to avoid excessive indexing
|
|
65
64
|
- Update the index incrementally for better performance
|
|
66
65
|
- Ignore common build/cache directories
|
|
67
|
-
|
|
66
|
+
|
|
68
67
|
Press Ctrl+C to stop watching.
|
|
69
|
-
|
|
68
|
+
|
|
70
69
|
Examples:
|
|
71
70
|
mcp-vector-search watch
|
|
72
71
|
mcp-vector-search watch /path/to/project --verbose
|
|
@@ -75,7 +74,7 @@ def watch_main(
|
|
|
75
74
|
if verbose:
|
|
76
75
|
logger.remove()
|
|
77
76
|
logger.add(sys.stderr, level="DEBUG")
|
|
78
|
-
|
|
77
|
+
|
|
79
78
|
try:
|
|
80
79
|
asyncio.run(_watch_async(project_root, config))
|
|
81
80
|
except KeyboardInterrupt:
|
|
@@ -85,7 +84,7 @@ def watch_main(
|
|
|
85
84
|
raise typer.Exit(1)
|
|
86
85
|
|
|
87
86
|
|
|
88
|
-
async def _watch_async(project_root: Path, config_path:
|
|
87
|
+
async def _watch_async(project_root: Path, config_path: Path | None) -> None:
|
|
89
88
|
"""Async implementation of watch command."""
|
|
90
89
|
# Load project configuration
|
|
91
90
|
try:
|
|
@@ -96,17 +95,17 @@ async def _watch_async(project_root: Path, config_path: Optional[Path]) -> None:
|
|
|
96
95
|
"Run 'mcp-vector-search init' first."
|
|
97
96
|
)
|
|
98
97
|
raise typer.Exit(1)
|
|
99
|
-
|
|
98
|
+
|
|
100
99
|
config = project_manager.load_config()
|
|
101
100
|
print_info(f"Loaded configuration from {project_root}")
|
|
102
|
-
|
|
101
|
+
|
|
103
102
|
except ProjectNotFoundError:
|
|
104
103
|
print_error(
|
|
105
104
|
f"No MCP Vector Search project found at {project_root}. "
|
|
106
105
|
"Run 'mcp-vector-search init' to initialize."
|
|
107
106
|
)
|
|
108
107
|
raise typer.Exit(1)
|
|
109
|
-
|
|
108
|
+
|
|
110
109
|
# Setup database and indexer
|
|
111
110
|
try:
|
|
112
111
|
embedding_function, _ = create_embedding_function(config.embedding_model)
|
|
@@ -114,19 +113,19 @@ async def _watch_async(project_root: Path, config_path: Optional[Path]) -> None:
|
|
|
114
113
|
persist_directory=config.index_path,
|
|
115
114
|
embedding_function=embedding_function,
|
|
116
115
|
)
|
|
117
|
-
|
|
116
|
+
|
|
118
117
|
indexer = SemanticIndexer(
|
|
119
118
|
database=database,
|
|
120
119
|
project_root=project_root,
|
|
121
120
|
file_extensions=config.file_extensions,
|
|
122
121
|
)
|
|
123
|
-
|
|
122
|
+
|
|
124
123
|
print_info(f"Initialized database at {config.index_path}")
|
|
125
|
-
|
|
124
|
+
|
|
126
125
|
except Exception as e:
|
|
127
126
|
print_error(f"Failed to initialize database: {e}")
|
|
128
127
|
raise typer.Exit(1)
|
|
129
|
-
|
|
128
|
+
|
|
130
129
|
# Start watching
|
|
131
130
|
try:
|
|
132
131
|
async with database:
|
|
@@ -136,34 +135,34 @@ async def _watch_async(project_root: Path, config_path: Optional[Path]) -> None:
|
|
|
136
135
|
indexer=indexer,
|
|
137
136
|
database=database,
|
|
138
137
|
)
|
|
139
|
-
|
|
138
|
+
|
|
140
139
|
print_success("🔍 Starting file watcher...")
|
|
141
140
|
print_info(f"📁 Watching: {project_root}")
|
|
142
141
|
print_info(f"📄 Extensions: {', '.join(config.file_extensions)}")
|
|
143
142
|
print_info("Press Ctrl+C to stop watching")
|
|
144
|
-
|
|
143
|
+
|
|
145
144
|
async with watcher:
|
|
146
145
|
# Set up signal handlers for graceful shutdown
|
|
147
146
|
stop_event = asyncio.Event()
|
|
148
|
-
|
|
147
|
+
|
|
149
148
|
def signal_handler():
|
|
150
149
|
print_info("\n⏹️ Stopping file watcher...")
|
|
151
150
|
stop_event.set()
|
|
152
|
-
|
|
151
|
+
|
|
153
152
|
# Handle SIGINT (Ctrl+C) and SIGTERM
|
|
154
153
|
if sys.platform != "win32":
|
|
155
154
|
loop = asyncio.get_running_loop()
|
|
156
155
|
for sig in (signal.SIGINT, signal.SIGTERM):
|
|
157
156
|
loop.add_signal_handler(sig, signal_handler)
|
|
158
|
-
|
|
157
|
+
|
|
159
158
|
try:
|
|
160
159
|
# Wait for stop signal
|
|
161
160
|
await stop_event.wait()
|
|
162
161
|
except KeyboardInterrupt:
|
|
163
162
|
signal_handler()
|
|
164
|
-
|
|
163
|
+
|
|
165
164
|
print_success("✅ File watcher stopped")
|
|
166
|
-
|
|
165
|
+
|
|
167
166
|
except Exception as e:
|
|
168
167
|
print_error(f"File watching failed: {e}")
|
|
169
168
|
raise typer.Exit(1)
|
|
@@ -181,7 +180,7 @@ def watch_status(
|
|
|
181
180
|
),
|
|
182
181
|
) -> None:
|
|
183
182
|
"""Check if file watching is enabled for a project.
|
|
184
|
-
|
|
183
|
+
|
|
185
184
|
This command checks the project configuration to see if file watching
|
|
186
185
|
is enabled and provides information about the watch settings.
|
|
187
186
|
"""
|
|
@@ -190,20 +189,20 @@ def watch_status(
|
|
|
190
189
|
if not project_manager.is_initialized():
|
|
191
190
|
print_error(f"Project not initialized at {project_root}")
|
|
192
191
|
raise typer.Exit(1)
|
|
193
|
-
|
|
192
|
+
|
|
194
193
|
config = project_manager.load_config()
|
|
195
|
-
|
|
194
|
+
|
|
196
195
|
console.print("\n[bold]File Watch Status[/bold]")
|
|
197
196
|
console.print(f"Project: {project_root}")
|
|
198
197
|
console.print(f"Watch Files: {'✓' if config.watch_files else '✗'}")
|
|
199
|
-
|
|
198
|
+
|
|
200
199
|
if config.watch_files:
|
|
201
200
|
console.print(f"Extensions: {', '.join(config.file_extensions)}")
|
|
202
201
|
print_info("File watching is enabled for this project")
|
|
203
202
|
else:
|
|
204
203
|
print_warning("File watching is disabled for this project")
|
|
205
204
|
print_info("Enable with: mcp-vector-search config set watch_files true")
|
|
206
|
-
|
|
205
|
+
|
|
207
206
|
except ProjectNotFoundError:
|
|
208
207
|
print_error(f"No MCP Vector Search project found at {project_root}")
|
|
209
208
|
raise typer.Exit(1)
|
|
@@ -224,7 +223,7 @@ def watch_enable(
|
|
|
224
223
|
),
|
|
225
224
|
) -> None:
|
|
226
225
|
"""Enable file watching for a project.
|
|
227
|
-
|
|
226
|
+
|
|
228
227
|
This command enables the watch_files setting in the project configuration.
|
|
229
228
|
After enabling, you can use 'mcp-vector-search watch' to start monitoring.
|
|
230
229
|
"""
|
|
@@ -233,14 +232,14 @@ def watch_enable(
|
|
|
233
232
|
if not project_manager.is_initialized():
|
|
234
233
|
print_error(f"Project not initialized at {project_root}")
|
|
235
234
|
raise typer.Exit(1)
|
|
236
|
-
|
|
235
|
+
|
|
237
236
|
config = project_manager.load_config()
|
|
238
237
|
config.watch_files = True
|
|
239
238
|
project_manager.save_config(config)
|
|
240
|
-
|
|
239
|
+
|
|
241
240
|
print_success("✅ File watching enabled")
|
|
242
241
|
print_info("Start watching with: mcp-vector-search watch")
|
|
243
|
-
|
|
242
|
+
|
|
244
243
|
except ProjectNotFoundError:
|
|
245
244
|
print_error(f"No MCP Vector Search project found at {project_root}")
|
|
246
245
|
raise typer.Exit(1)
|
|
@@ -261,7 +260,7 @@ def watch_disable(
|
|
|
261
260
|
),
|
|
262
261
|
) -> None:
|
|
263
262
|
"""Disable file watching for a project.
|
|
264
|
-
|
|
263
|
+
|
|
265
264
|
This command disables the watch_files setting in the project configuration.
|
|
266
265
|
"""
|
|
267
266
|
try:
|
|
@@ -269,13 +268,13 @@ def watch_disable(
|
|
|
269
268
|
if not project_manager.is_initialized():
|
|
270
269
|
print_error(f"Project not initialized at {project_root}")
|
|
271
270
|
raise typer.Exit(1)
|
|
272
|
-
|
|
271
|
+
|
|
273
272
|
config = project_manager.load_config()
|
|
274
273
|
config.watch_files = False
|
|
275
274
|
project_manager.save_config(config)
|
|
276
|
-
|
|
275
|
+
|
|
277
276
|
print_success("✅ File watching disabled")
|
|
278
|
-
|
|
277
|
+
|
|
279
278
|
except ProjectNotFoundError:
|
|
280
279
|
print_error(f"No MCP Vector Search project found at {project_root}")
|
|
281
280
|
raise typer.Exit(1)
|