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.

Files changed (86) hide show
  1. mcp_vector_search/__init__.py +10 -0
  2. mcp_vector_search/cli/__init__.py +1 -0
  3. mcp_vector_search/cli/commands/__init__.py +1 -0
  4. mcp_vector_search/cli/commands/auto_index.py +397 -0
  5. mcp_vector_search/cli/commands/chat.py +534 -0
  6. mcp_vector_search/cli/commands/config.py +393 -0
  7. mcp_vector_search/cli/commands/demo.py +358 -0
  8. mcp_vector_search/cli/commands/index.py +762 -0
  9. mcp_vector_search/cli/commands/init.py +658 -0
  10. mcp_vector_search/cli/commands/install.py +869 -0
  11. mcp_vector_search/cli/commands/install_old.py +700 -0
  12. mcp_vector_search/cli/commands/mcp.py +1254 -0
  13. mcp_vector_search/cli/commands/reset.py +393 -0
  14. mcp_vector_search/cli/commands/search.py +796 -0
  15. mcp_vector_search/cli/commands/setup.py +1133 -0
  16. mcp_vector_search/cli/commands/status.py +584 -0
  17. mcp_vector_search/cli/commands/uninstall.py +404 -0
  18. mcp_vector_search/cli/commands/visualize/__init__.py +39 -0
  19. mcp_vector_search/cli/commands/visualize/cli.py +265 -0
  20. mcp_vector_search/cli/commands/visualize/exporters/__init__.py +12 -0
  21. mcp_vector_search/cli/commands/visualize/exporters/html_exporter.py +33 -0
  22. mcp_vector_search/cli/commands/visualize/exporters/json_exporter.py +29 -0
  23. mcp_vector_search/cli/commands/visualize/graph_builder.py +709 -0
  24. mcp_vector_search/cli/commands/visualize/layout_engine.py +469 -0
  25. mcp_vector_search/cli/commands/visualize/server.py +201 -0
  26. mcp_vector_search/cli/commands/visualize/state_manager.py +428 -0
  27. mcp_vector_search/cli/commands/visualize/templates/__init__.py +16 -0
  28. mcp_vector_search/cli/commands/visualize/templates/base.py +218 -0
  29. mcp_vector_search/cli/commands/visualize/templates/scripts.py +3670 -0
  30. mcp_vector_search/cli/commands/visualize/templates/styles.py +779 -0
  31. mcp_vector_search/cli/commands/visualize.py.original +2536 -0
  32. mcp_vector_search/cli/commands/watch.py +287 -0
  33. mcp_vector_search/cli/didyoumean.py +520 -0
  34. mcp_vector_search/cli/export.py +320 -0
  35. mcp_vector_search/cli/history.py +295 -0
  36. mcp_vector_search/cli/interactive.py +342 -0
  37. mcp_vector_search/cli/main.py +484 -0
  38. mcp_vector_search/cli/output.py +414 -0
  39. mcp_vector_search/cli/suggestions.py +375 -0
  40. mcp_vector_search/config/__init__.py +1 -0
  41. mcp_vector_search/config/constants.py +24 -0
  42. mcp_vector_search/config/defaults.py +200 -0
  43. mcp_vector_search/config/settings.py +146 -0
  44. mcp_vector_search/core/__init__.py +1 -0
  45. mcp_vector_search/core/auto_indexer.py +298 -0
  46. mcp_vector_search/core/config_utils.py +394 -0
  47. mcp_vector_search/core/connection_pool.py +360 -0
  48. mcp_vector_search/core/database.py +1237 -0
  49. mcp_vector_search/core/directory_index.py +318 -0
  50. mcp_vector_search/core/embeddings.py +294 -0
  51. mcp_vector_search/core/exceptions.py +89 -0
  52. mcp_vector_search/core/factory.py +318 -0
  53. mcp_vector_search/core/git_hooks.py +345 -0
  54. mcp_vector_search/core/indexer.py +1002 -0
  55. mcp_vector_search/core/llm_client.py +453 -0
  56. mcp_vector_search/core/models.py +294 -0
  57. mcp_vector_search/core/project.py +350 -0
  58. mcp_vector_search/core/scheduler.py +330 -0
  59. mcp_vector_search/core/search.py +952 -0
  60. mcp_vector_search/core/watcher.py +322 -0
  61. mcp_vector_search/mcp/__init__.py +5 -0
  62. mcp_vector_search/mcp/__main__.py +25 -0
  63. mcp_vector_search/mcp/server.py +752 -0
  64. mcp_vector_search/parsers/__init__.py +8 -0
  65. mcp_vector_search/parsers/base.py +296 -0
  66. mcp_vector_search/parsers/dart.py +605 -0
  67. mcp_vector_search/parsers/html.py +413 -0
  68. mcp_vector_search/parsers/javascript.py +643 -0
  69. mcp_vector_search/parsers/php.py +694 -0
  70. mcp_vector_search/parsers/python.py +502 -0
  71. mcp_vector_search/parsers/registry.py +223 -0
  72. mcp_vector_search/parsers/ruby.py +678 -0
  73. mcp_vector_search/parsers/text.py +186 -0
  74. mcp_vector_search/parsers/utils.py +265 -0
  75. mcp_vector_search/py.typed +1 -0
  76. mcp_vector_search/utils/__init__.py +42 -0
  77. mcp_vector_search/utils/gitignore.py +250 -0
  78. mcp_vector_search/utils/gitignore_updater.py +212 -0
  79. mcp_vector_search/utils/monorepo.py +339 -0
  80. mcp_vector_search/utils/timing.py +338 -0
  81. mcp_vector_search/utils/version.py +47 -0
  82. mcp_vector_search-0.15.7.dist-info/METADATA +884 -0
  83. mcp_vector_search-0.15.7.dist-info/RECORD +86 -0
  84. mcp_vector_search-0.15.7.dist-info/WHEEL +4 -0
  85. mcp_vector_search-0.15.7.dist-info/entry_points.txt +3 -0
  86. mcp_vector_search-0.15.7.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,330 @@
1
+ """Scheduling utilities for automatic reindexing."""
2
+
3
+ import platform
4
+ import subprocess
5
+ import sys
6
+ from pathlib import Path
7
+
8
+ from loguru import logger
9
+
10
+
11
+ class SchedulerManager:
12
+ """Manages scheduled tasks for automatic reindexing."""
13
+
14
+ def __init__(self, project_root: Path):
15
+ """Initialize scheduler manager.
16
+
17
+ Args:
18
+ project_root: Project root directory
19
+ """
20
+ self.project_root = project_root
21
+ self.system = platform.system().lower()
22
+
23
+ def install_scheduled_task(
24
+ self, interval_minutes: int = 60, task_name: str | None = None
25
+ ) -> bool:
26
+ """Install a scheduled task for automatic reindexing.
27
+
28
+ Args:
29
+ interval_minutes: Interval between reindex checks in minutes
30
+ task_name: Custom task name (auto-generated if None)
31
+
32
+ Returns:
33
+ True if task was installed successfully
34
+ """
35
+ if task_name is None:
36
+ safe_path = str(self.project_root).replace("/", "_").replace("\\", "_")
37
+ task_name = f"mcp_vector_search_reindex_{safe_path}"
38
+
39
+ if self.system == "linux" or self.system == "darwin":
40
+ return self._install_cron_job(interval_minutes, task_name)
41
+ elif self.system == "windows":
42
+ return self._install_windows_task(interval_minutes, task_name)
43
+ else:
44
+ logger.error(f"Unsupported system: {self.system}")
45
+ return False
46
+
47
+ def uninstall_scheduled_task(self, task_name: str | None = None) -> bool:
48
+ """Uninstall scheduled task.
49
+
50
+ Args:
51
+ task_name: Task name to uninstall (auto-generated if None)
52
+
53
+ Returns:
54
+ True if task was uninstalled successfully
55
+ """
56
+ if task_name is None:
57
+ safe_path = str(self.project_root).replace("/", "_").replace("\\", "_")
58
+ task_name = f"mcp_vector_search_reindex_{safe_path}"
59
+
60
+ if self.system == "linux" or self.system == "darwin":
61
+ return self._uninstall_cron_job(task_name)
62
+ elif self.system == "windows":
63
+ return self._uninstall_windows_task(task_name)
64
+ else:
65
+ logger.error(f"Unsupported system: {self.system}")
66
+ return False
67
+
68
+ def _install_cron_job(self, interval_minutes: int, task_name: str) -> bool:
69
+ """Install cron job on Linux/macOS."""
70
+ try:
71
+ # Generate cron command
72
+ python_path = sys.executable
73
+ project_root = str(self.project_root)
74
+
75
+ # Create wrapper script
76
+ script_content = f"""#!/bin/bash
77
+ # MCP Vector Search Auto-Reindex - {task_name}
78
+ cd "{project_root}" || exit 1
79
+
80
+ # Check if mcp-vector-search is available
81
+ if command -v mcp-vector-search &> /dev/null; then
82
+ mcp-vector-search auto-index check --auto-reindex --max-files 10
83
+ elif [ -f "{python_path}" ]; then
84
+ "{python_path}" -m mcp_vector_search auto-index check --auto-reindex --max-files 10
85
+ else
86
+ python3 -m mcp_vector_search auto-index check --auto-reindex --max-files 10
87
+ fi
88
+ """
89
+
90
+ # Write script to temp file
91
+ script_dir = Path.home() / ".mcp-vector-search" / "scripts"
92
+ script_dir.mkdir(parents=True, exist_ok=True)
93
+ script_file = script_dir / f"{task_name}.sh"
94
+
95
+ script_file.write_text(script_content)
96
+ script_file.chmod(0o755)
97
+
98
+ # Calculate cron schedule
99
+ if interval_minutes >= 60:
100
+ # Hourly or less frequent
101
+ hours = interval_minutes // 60
102
+ cron_schedule = f"0 */{hours} * * *"
103
+ else:
104
+ # More frequent than hourly
105
+ cron_schedule = f"*/{interval_minutes} * * * *"
106
+
107
+ # Add to crontab
108
+ cron_entry = f"{cron_schedule} {script_file} # {task_name}\n"
109
+
110
+ # Get current crontab
111
+ try:
112
+ result = subprocess.run( # nosec B607
113
+ ["crontab", "-l"], capture_output=True, text=True, check=True
114
+ )
115
+ current_crontab = result.stdout
116
+ except subprocess.CalledProcessError:
117
+ current_crontab = ""
118
+
119
+ # Check if entry already exists
120
+ if task_name in current_crontab:
121
+ logger.info(f"Cron job {task_name} already exists")
122
+ return True
123
+
124
+ # Add new entry
125
+ new_crontab = current_crontab + cron_entry
126
+
127
+ # Install new crontab
128
+ process = subprocess.Popen( # nosec B607
129
+ ["crontab", "-"], stdin=subprocess.PIPE, text=True
130
+ )
131
+ process.communicate(input=new_crontab)
132
+
133
+ if process.returncode == 0:
134
+ logger.info(f"Installed cron job: {task_name}")
135
+ logger.info(f"Schedule: every {interval_minutes} minutes")
136
+ logger.info(f"Script: {script_file}")
137
+ return True
138
+ else:
139
+ logger.error("Failed to install cron job")
140
+ return False
141
+
142
+ except Exception as e:
143
+ logger.error(f"Failed to install cron job: {e}")
144
+ return False
145
+
146
+ def _uninstall_cron_job(self, task_name: str) -> bool:
147
+ """Uninstall cron job on Linux/macOS."""
148
+ try:
149
+ # Get current crontab
150
+ try:
151
+ result = subprocess.run( # nosec B607
152
+ ["crontab", "-l"], capture_output=True, text=True, check=True
153
+ )
154
+ current_crontab = result.stdout
155
+ except subprocess.CalledProcessError:
156
+ logger.info("No crontab found")
157
+ return True
158
+
159
+ # Remove lines containing task name
160
+ lines = current_crontab.split("\n")
161
+ new_lines = [line for line in lines if task_name not in line]
162
+ new_crontab = "\n".join(new_lines)
163
+
164
+ # Install new crontab
165
+ if new_crontab.strip():
166
+ process = subprocess.Popen( # nosec B607
167
+ ["crontab", "-"], stdin=subprocess.PIPE, text=True
168
+ )
169
+ process.communicate(input=new_crontab)
170
+ else:
171
+ # Remove crontab entirely if empty
172
+ subprocess.run(["crontab", "-r"], check=False) # nosec B607
173
+
174
+ # Remove script file
175
+ script_dir = Path.home() / ".mcp-vector-search" / "scripts"
176
+ script_file = script_dir / f"{task_name}.sh"
177
+ if script_file.exists():
178
+ script_file.unlink()
179
+
180
+ logger.info(f"Uninstalled cron job: {task_name}")
181
+ return True
182
+
183
+ except Exception as e:
184
+ logger.error(f"Failed to uninstall cron job: {e}")
185
+ return False
186
+
187
+ def _install_windows_task(self, interval_minutes: int, task_name: str) -> bool:
188
+ """Install Windows scheduled task."""
189
+ try:
190
+ python_path = sys.executable
191
+ project_root = str(self.project_root)
192
+
193
+ # Create PowerShell script
194
+ script_content = f"""# MCP Vector Search Auto-Reindex - {task_name}
195
+ Set-Location "{project_root}"
196
+
197
+ try {{
198
+ if (Get-Command "mcp-vector-search" -ErrorAction SilentlyContinue) {{
199
+ mcp-vector-search auto-index check --auto-reindex --max-files 10
200
+ }} elseif (Test-Path "{python_path}") {{
201
+ & "{python_path}" -m mcp_vector_search auto-index check --auto-reindex --max-files 10
202
+ }} else {{
203
+ python -m mcp_vector_search auto-index check --auto-reindex --max-files 10
204
+ }}
205
+ }} catch {{
206
+ # Silently ignore errors
207
+ }}
208
+ """
209
+
210
+ # Write script
211
+ script_dir = Path.home() / ".mcp-vector-search" / "scripts"
212
+ script_dir.mkdir(parents=True, exist_ok=True)
213
+ script_file = script_dir / f"{task_name}.ps1"
214
+
215
+ script_file.write_text(script_content)
216
+
217
+ # Create scheduled task using schtasks
218
+ cmd = [
219
+ "schtasks",
220
+ "/create",
221
+ "/tn",
222
+ task_name,
223
+ "/tr",
224
+ f'powershell.exe -ExecutionPolicy Bypass -File "{script_file}"',
225
+ "/sc",
226
+ "minute",
227
+ "/mo",
228
+ str(interval_minutes),
229
+ "/f", # Force overwrite if exists
230
+ ]
231
+
232
+ result = subprocess.run(cmd, capture_output=True, text=True)
233
+
234
+ if result.returncode == 0:
235
+ logger.info(f"Installed Windows task: {task_name}")
236
+ logger.info(f"Schedule: every {interval_minutes} minutes")
237
+ return True
238
+ else:
239
+ logger.error(f"Failed to install Windows task: {result.stderr}")
240
+ return False
241
+
242
+ except Exception as e:
243
+ logger.error(f"Failed to install Windows task: {e}")
244
+ return False
245
+
246
+ def _uninstall_windows_task(self, task_name: str) -> bool:
247
+ """Uninstall Windows scheduled task."""
248
+ try:
249
+ # Delete scheduled task
250
+ cmd = ["schtasks", "/delete", "/tn", task_name, "/f"]
251
+ result = subprocess.run(cmd, capture_output=True, text=True)
252
+
253
+ # Remove script file
254
+ script_dir = Path.home() / ".mcp-vector-search" / "scripts"
255
+ script_file = script_dir / f"{task_name}.ps1"
256
+ if script_file.exists():
257
+ script_file.unlink()
258
+
259
+ if result.returncode == 0:
260
+ logger.info(f"Uninstalled Windows task: {task_name}")
261
+ return True
262
+ else:
263
+ # Task might not exist, which is fine
264
+ logger.info(
265
+ f"Windows task {task_name} was not found (already uninstalled)"
266
+ )
267
+ return True
268
+
269
+ except Exception as e:
270
+ logger.error(f"Failed to uninstall Windows task: {e}")
271
+ return False
272
+
273
+ def get_scheduled_task_status(self, task_name: str | None = None) -> dict:
274
+ """Get status of scheduled tasks.
275
+
276
+ Args:
277
+ task_name: Task name to check (auto-generated if None)
278
+
279
+ Returns:
280
+ Dictionary with task status information
281
+ """
282
+ if task_name is None:
283
+ safe_path = str(self.project_root).replace("/", "_").replace("\\", "_")
284
+ task_name = f"mcp_vector_search_reindex_{safe_path}"
285
+
286
+ status = {
287
+ "system": self.system,
288
+ "task_name": task_name,
289
+ "exists": False,
290
+ "enabled": False,
291
+ "last_run": None,
292
+ "next_run": None,
293
+ }
294
+
295
+ if self.system == "linux" or self.system == "darwin":
296
+ status.update(self._get_cron_status(task_name))
297
+ elif self.system == "windows":
298
+ status.update(self._get_windows_task_status(task_name))
299
+
300
+ return status
301
+
302
+ def _get_cron_status(self, task_name: str) -> dict:
303
+ """Get cron job status."""
304
+ try:
305
+ result = subprocess.run( # nosec B607
306
+ ["crontab", "-l"], capture_output=True, text=True, check=True
307
+ )
308
+
309
+ exists = task_name in result.stdout
310
+ return {"exists": exists, "enabled": exists}
311
+
312
+ except subprocess.CalledProcessError:
313
+ return {"exists": False, "enabled": False}
314
+
315
+ def _get_windows_task_status(self, task_name: str) -> dict:
316
+ """Get Windows task status."""
317
+ try:
318
+ result = subprocess.run( # nosec B607
319
+ ["schtasks", "/query", "/tn", task_name], capture_output=True, text=True
320
+ )
321
+
322
+ if result.returncode == 0:
323
+ # Parse output for status
324
+ enabled = "Ready" in result.stdout or "Running" in result.stdout
325
+ return {"exists": True, "enabled": enabled}
326
+ else:
327
+ return {"exists": False, "enabled": False}
328
+
329
+ except Exception:
330
+ return {"exists": False, "enabled": False}