crackerjack 0.31.10__py3-none-any.whl → 0.31.13__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 crackerjack might be problematic. Click here for more details.
- crackerjack/CLAUDE.md +288 -705
- crackerjack/__main__.py +22 -8
- crackerjack/agents/__init__.py +0 -3
- crackerjack/agents/architect_agent.py +0 -43
- crackerjack/agents/base.py +1 -9
- crackerjack/agents/coordinator.py +2 -148
- crackerjack/agents/documentation_agent.py +109 -81
- crackerjack/agents/dry_agent.py +122 -97
- crackerjack/agents/formatting_agent.py +3 -16
- crackerjack/agents/import_optimization_agent.py +1174 -130
- crackerjack/agents/performance_agent.py +956 -188
- crackerjack/agents/performance_helpers.py +229 -0
- crackerjack/agents/proactive_agent.py +1 -48
- crackerjack/agents/refactoring_agent.py +516 -246
- crackerjack/agents/refactoring_helpers.py +282 -0
- crackerjack/agents/security_agent.py +393 -90
- crackerjack/agents/test_creation_agent.py +1776 -120
- crackerjack/agents/test_specialist_agent.py +59 -15
- crackerjack/agents/tracker.py +0 -102
- crackerjack/api.py +145 -37
- crackerjack/cli/handlers.py +48 -30
- crackerjack/cli/interactive.py +11 -11
- crackerjack/cli/options.py +66 -4
- crackerjack/code_cleaner.py +808 -148
- crackerjack/config/global_lock_config.py +110 -0
- crackerjack/config/hooks.py +43 -64
- crackerjack/core/async_workflow_orchestrator.py +247 -97
- crackerjack/core/autofix_coordinator.py +192 -109
- crackerjack/core/enhanced_container.py +46 -63
- crackerjack/core/file_lifecycle.py +549 -0
- crackerjack/core/performance.py +9 -8
- crackerjack/core/performance_monitor.py +395 -0
- crackerjack/core/phase_coordinator.py +281 -94
- crackerjack/core/proactive_workflow.py +9 -58
- crackerjack/core/resource_manager.py +501 -0
- crackerjack/core/service_watchdog.py +490 -0
- crackerjack/core/session_coordinator.py +4 -8
- crackerjack/core/timeout_manager.py +504 -0
- crackerjack/core/websocket_lifecycle.py +475 -0
- crackerjack/core/workflow_orchestrator.py +343 -209
- crackerjack/dynamic_config.py +50 -9
- crackerjack/errors.py +3 -4
- crackerjack/executors/async_hook_executor.py +63 -13
- crackerjack/executors/cached_hook_executor.py +14 -14
- crackerjack/executors/hook_executor.py +100 -37
- crackerjack/executors/hook_lock_manager.py +856 -0
- crackerjack/executors/individual_hook_executor.py +120 -86
- crackerjack/intelligence/__init__.py +0 -7
- crackerjack/intelligence/adaptive_learning.py +13 -86
- crackerjack/intelligence/agent_orchestrator.py +15 -78
- crackerjack/intelligence/agent_registry.py +12 -59
- crackerjack/intelligence/agent_selector.py +31 -92
- crackerjack/intelligence/integration.py +1 -41
- crackerjack/interactive.py +9 -9
- crackerjack/managers/async_hook_manager.py +25 -8
- crackerjack/managers/hook_manager.py +9 -9
- crackerjack/managers/publish_manager.py +57 -59
- crackerjack/managers/test_command_builder.py +6 -36
- crackerjack/managers/test_executor.py +9 -61
- crackerjack/managers/test_manager.py +17 -63
- crackerjack/managers/test_manager_backup.py +77 -127
- crackerjack/managers/test_progress.py +4 -23
- crackerjack/mcp/cache.py +5 -12
- crackerjack/mcp/client_runner.py +10 -10
- crackerjack/mcp/context.py +64 -6
- crackerjack/mcp/dashboard.py +14 -11
- crackerjack/mcp/enhanced_progress_monitor.py +55 -55
- crackerjack/mcp/file_monitor.py +72 -42
- crackerjack/mcp/progress_components.py +103 -84
- crackerjack/mcp/progress_monitor.py +122 -49
- crackerjack/mcp/rate_limiter.py +12 -12
- crackerjack/mcp/server_core.py +16 -22
- crackerjack/mcp/service_watchdog.py +26 -26
- crackerjack/mcp/state.py +15 -0
- crackerjack/mcp/tools/core_tools.py +95 -39
- crackerjack/mcp/tools/error_analyzer.py +6 -32
- crackerjack/mcp/tools/execution_tools.py +1 -56
- crackerjack/mcp/tools/execution_tools_backup.py +35 -131
- crackerjack/mcp/tools/intelligence_tool_registry.py +0 -36
- crackerjack/mcp/tools/intelligence_tools.py +2 -55
- crackerjack/mcp/tools/monitoring_tools.py +308 -145
- crackerjack/mcp/tools/proactive_tools.py +12 -42
- crackerjack/mcp/tools/progress_tools.py +23 -15
- crackerjack/mcp/tools/utility_tools.py +3 -40
- crackerjack/mcp/tools/workflow_executor.py +40 -60
- crackerjack/mcp/websocket/app.py +0 -3
- crackerjack/mcp/websocket/endpoints.py +206 -268
- crackerjack/mcp/websocket/jobs.py +213 -66
- crackerjack/mcp/websocket/server.py +84 -6
- crackerjack/mcp/websocket/websocket_handler.py +137 -29
- crackerjack/models/config_adapter.py +3 -16
- crackerjack/models/protocols.py +162 -3
- crackerjack/models/resource_protocols.py +454 -0
- crackerjack/models/task.py +3 -3
- crackerjack/monitoring/__init__.py +0 -0
- crackerjack/monitoring/ai_agent_watchdog.py +25 -71
- crackerjack/monitoring/regression_prevention.py +28 -87
- crackerjack/orchestration/advanced_orchestrator.py +44 -78
- crackerjack/orchestration/coverage_improvement.py +10 -60
- crackerjack/orchestration/execution_strategies.py +16 -16
- crackerjack/orchestration/test_progress_streamer.py +61 -53
- crackerjack/plugins/base.py +1 -1
- crackerjack/plugins/managers.py +22 -20
- crackerjack/py313.py +65 -21
- crackerjack/services/backup_service.py +467 -0
- crackerjack/services/bounded_status_operations.py +627 -0
- crackerjack/services/cache.py +7 -9
- crackerjack/services/config.py +35 -52
- crackerjack/services/config_integrity.py +5 -16
- crackerjack/services/config_merge.py +542 -0
- crackerjack/services/contextual_ai_assistant.py +17 -19
- crackerjack/services/coverage_ratchet.py +44 -73
- crackerjack/services/debug.py +25 -39
- crackerjack/services/dependency_monitor.py +52 -50
- crackerjack/services/enhanced_filesystem.py +14 -11
- crackerjack/services/file_hasher.py +1 -1
- crackerjack/services/filesystem.py +1 -12
- crackerjack/services/git.py +71 -47
- crackerjack/services/health_metrics.py +31 -27
- crackerjack/services/initialization.py +276 -428
- crackerjack/services/input_validator.py +760 -0
- crackerjack/services/log_manager.py +16 -16
- crackerjack/services/logging.py +7 -6
- crackerjack/services/metrics.py +43 -43
- crackerjack/services/pattern_cache.py +2 -31
- crackerjack/services/pattern_detector.py +26 -63
- crackerjack/services/performance_benchmarks.py +20 -45
- crackerjack/services/regex_patterns.py +2887 -0
- crackerjack/services/regex_utils.py +537 -0
- crackerjack/services/secure_path_utils.py +683 -0
- crackerjack/services/secure_status_formatter.py +534 -0
- crackerjack/services/secure_subprocess.py +605 -0
- crackerjack/services/security.py +47 -10
- crackerjack/services/security_logger.py +492 -0
- crackerjack/services/server_manager.py +109 -50
- crackerjack/services/smart_scheduling.py +8 -25
- crackerjack/services/status_authentication.py +603 -0
- crackerjack/services/status_security_manager.py +442 -0
- crackerjack/services/thread_safe_status_collector.py +546 -0
- crackerjack/services/tool_version_service.py +1 -23
- crackerjack/services/unified_config.py +36 -58
- crackerjack/services/validation_rate_limiter.py +269 -0
- crackerjack/services/version_checker.py +9 -40
- crackerjack/services/websocket_resource_limiter.py +572 -0
- crackerjack/slash_commands/__init__.py +52 -2
- crackerjack/tools/__init__.py +0 -0
- crackerjack/tools/validate_input_validator_patterns.py +262 -0
- crackerjack/tools/validate_regex_patterns.py +198 -0
- {crackerjack-0.31.10.dist-info → crackerjack-0.31.13.dist-info}/METADATA +197 -12
- crackerjack-0.31.13.dist-info/RECORD +178 -0
- crackerjack/cli/facade.py +0 -104
- crackerjack-0.31.10.dist-info/RECORD +0 -149
- {crackerjack-0.31.10.dist-info → crackerjack-0.31.13.dist-info}/WHEEL +0 -0
- {crackerjack-0.31.10.dist-info → crackerjack-0.31.13.dist-info}/entry_points.txt +0 -0
- {crackerjack-0.31.10.dist-info → crackerjack-0.31.13.dist-info}/licenses/LICENSE +0 -0
|
@@ -10,6 +10,8 @@ from typing import Any
|
|
|
10
10
|
import aiohttp
|
|
11
11
|
from rich.console import Console
|
|
12
12
|
|
|
13
|
+
from crackerjack.core.timeout_manager import get_timeout_manager
|
|
14
|
+
|
|
13
15
|
|
|
14
16
|
class JobDataCollector:
|
|
15
17
|
def __init__(self, progress_dir: Path, websocket_url: str) -> None:
|
|
@@ -48,7 +50,7 @@ class JobDataCollector:
|
|
|
48
50
|
if not self.progress_dir.exists():
|
|
49
51
|
return jobs_data
|
|
50
52
|
|
|
51
|
-
for progress_file in self.progress_dir.glob("job
|
|
53
|
+
for progress_file in self.progress_dir.glob("job-* .json"):
|
|
52
54
|
self._process_progress_file(progress_file, jobs_data)
|
|
53
55
|
|
|
54
56
|
return jobs_data
|
|
@@ -62,7 +64,7 @@ class JobDataCollector:
|
|
|
62
64
|
with progress_file.open() as f:
|
|
63
65
|
data = json.load(f)
|
|
64
66
|
|
|
65
|
-
job_id = progress_file.stem.replace("job
|
|
67
|
+
job_id = progress_file.stem.replace("job-", "")
|
|
66
68
|
self._update_job_counters(data, jobs_data)
|
|
67
69
|
self._aggregate_error_metrics(data, jobs_data)
|
|
68
70
|
self._add_individual_job(job_id, data, jobs_data)
|
|
@@ -148,56 +150,62 @@ class JobDataCollector:
|
|
|
148
150
|
"current_errors": 0,
|
|
149
151
|
}
|
|
150
152
|
|
|
151
|
-
|
|
152
|
-
websocket_base = self.websocket_url.replace("ws: // ", "http: // ").replace(
|
|
153
|
-
"wss: // ",
|
|
154
|
-
"https: // ",
|
|
155
|
-
)
|
|
153
|
+
timeout_manager = get_timeout_manager()
|
|
156
154
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
session.get(f"{websocket_base} / ") as response,
|
|
155
|
+
with suppress(Exception):
|
|
156
|
+
async with timeout_manager.timeout_context(
|
|
157
|
+
"network_operations",
|
|
158
|
+
timeout=5.0, # Short timeout for websocket discovery
|
|
162
159
|
):
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
"
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
"
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
160
|
+
websocket_base = self.websocket_url.replace("ws://", "http://").replace(
|
|
161
|
+
"wss://",
|
|
162
|
+
"https://",
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
async with (
|
|
166
|
+
aiohttp.ClientSession(
|
|
167
|
+
timeout=aiohttp.ClientTimeout(total=3),
|
|
168
|
+
) as session,
|
|
169
|
+
session.get(f"{websocket_base}/") as response,
|
|
170
|
+
):
|
|
171
|
+
if response.status == 200:
|
|
172
|
+
data = await response.json()
|
|
173
|
+
|
|
174
|
+
active_jobs = data.get("active_jobs_detailed", [])
|
|
175
|
+
|
|
176
|
+
for job in active_jobs:
|
|
177
|
+
job_id = job.get("job_id", "unknown")
|
|
178
|
+
status = job.get("status", "unknown")
|
|
179
|
+
|
|
180
|
+
if status == "running":
|
|
181
|
+
jobs_data["active"] += 1
|
|
182
|
+
elif status == "completed":
|
|
183
|
+
jobs_data["completed"] += 1
|
|
184
|
+
elif status == "failed":
|
|
185
|
+
jobs_data["failed"] += 1
|
|
186
|
+
|
|
187
|
+
jobs_data["total"] += 1
|
|
188
|
+
|
|
189
|
+
job_entry = {
|
|
190
|
+
"job_id": job_id,
|
|
191
|
+
"status": status,
|
|
192
|
+
"iteration": job.get("iteration", 1),
|
|
193
|
+
"max_iterations": job.get("max_iterations", 10),
|
|
194
|
+
"current_stage": job.get("current_stage", "unknown"),
|
|
195
|
+
"message": job.get("message", "Processing..."),
|
|
196
|
+
"project": job.get("project", "crackerjack"),
|
|
197
|
+
"total_issues": job.get("total_issues", 0),
|
|
198
|
+
"errors_fixed": job.get("errors_fixed", 0),
|
|
199
|
+
"errors_failed": job.get("errors_failed", 0),
|
|
200
|
+
"current_errors": job.get("current_errors", 0),
|
|
201
|
+
"overall_progress": job.get("overall_progress", 0.0),
|
|
202
|
+
"stage_progress": job.get("stage_progress", 0.0),
|
|
203
|
+
}
|
|
204
|
+
jobs_data["individual_jobs"].append(job_entry)
|
|
205
|
+
|
|
206
|
+
jobs_data["total_issues"] += job.get("total_issues", 0)
|
|
207
|
+
jobs_data["errors_fixed"] += job.get("errors_fixed", 0)
|
|
208
|
+
jobs_data["errors_failed"] += job.get("errors_failed", 0)
|
|
201
209
|
|
|
202
210
|
return jobs_data
|
|
203
211
|
|
|
@@ -226,23 +234,29 @@ class ServiceHealthChecker:
|
|
|
226
234
|
return services
|
|
227
235
|
|
|
228
236
|
async def _check_websocket_server(self) -> tuple[str, str, str]:
|
|
237
|
+
timeout_manager = get_timeout_manager()
|
|
238
|
+
|
|
229
239
|
try:
|
|
230
|
-
async with (
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
) as session,
|
|
234
|
-
session.get("http: // localhost: 8675 / ") as response,
|
|
240
|
+
async with timeout_manager.timeout_context(
|
|
241
|
+
"network_operations",
|
|
242
|
+
timeout=3.0, # Quick health check timeout
|
|
235
243
|
):
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
244
|
+
async with (
|
|
245
|
+
aiohttp.ClientSession(
|
|
246
|
+
timeout=aiohttp.ClientTimeout(total=2),
|
|
247
|
+
) as session,
|
|
248
|
+
session.get("http://localhost:8675/") as response,
|
|
249
|
+
):
|
|
250
|
+
if response.status == 200:
|
|
251
|
+
data = await response.json()
|
|
252
|
+
connections = data.get("total_connections", 0)
|
|
253
|
+
len(data.get("active_jobs", []))
|
|
254
|
+
return (
|
|
255
|
+
"WebSocket Server",
|
|
256
|
+
f"🟢 Active ({connections} conn)",
|
|
257
|
+
"0",
|
|
258
|
+
)
|
|
259
|
+
return ("WebSocket Server", "🔴 HTTP Error", "1")
|
|
246
260
|
except Exception:
|
|
247
261
|
return ("WebSocket Server", "🔴 Connection Failed", "1")
|
|
248
262
|
|
|
@@ -253,10 +267,13 @@ class ServiceHealthChecker:
|
|
|
253
267
|
check=False,
|
|
254
268
|
capture_output=True,
|
|
255
269
|
text=True,
|
|
270
|
+
timeout=5.0, # Add timeout protection
|
|
256
271
|
)
|
|
257
272
|
if result.returncode == 0:
|
|
258
273
|
return ("MCP Server", "🟢 Process Active", "0")
|
|
259
274
|
return ("MCP Server", "🔴 No Process", "0")
|
|
275
|
+
except subprocess.TimeoutExpired:
|
|
276
|
+
return ("MCP Server", "🔴 Process Check Timeout", "0")
|
|
260
277
|
except Exception:
|
|
261
278
|
return ("MCP Server", "🔴 Check Failed", "0")
|
|
262
279
|
|
|
@@ -267,10 +284,13 @@ class ServiceHealthChecker:
|
|
|
267
284
|
check=False,
|
|
268
285
|
capture_output=True,
|
|
269
286
|
text=True,
|
|
287
|
+
timeout=5.0, # Add timeout protection
|
|
270
288
|
)
|
|
271
289
|
if result.returncode == 0:
|
|
272
290
|
return ("Service Watchdog", "🟢 Active", "0")
|
|
273
291
|
return ("Service Watchdog", "🔴 Inactive", "0")
|
|
292
|
+
except subprocess.TimeoutExpired:
|
|
293
|
+
return ("Service Watchdog", "🔴 Process Check Timeout", "0")
|
|
274
294
|
except Exception:
|
|
275
295
|
return ("Service Watchdog", "🔴 Check Failed", "0")
|
|
276
296
|
|
|
@@ -294,13 +314,12 @@ class ErrorCollector:
|
|
|
294
314
|
"No recent errors found",
|
|
295
315
|
"Clean",
|
|
296
316
|
),
|
|
297
|
-
("
|
|
317
|
+
(" - - : - - : --", "monitor", "System monitoring active", "Status"),
|
|
298
318
|
]
|
|
299
319
|
|
|
300
320
|
return errors[-5:]
|
|
301
321
|
|
|
302
322
|
def _check_debug_logs(self) -> list[tuple[str, str, str, str]]:
|
|
303
|
-
"""Check debug logs for recent errors."""
|
|
304
323
|
errors = []
|
|
305
324
|
|
|
306
325
|
with suppress(Exception):
|
|
@@ -314,7 +333,6 @@ class ErrorCollector:
|
|
|
314
333
|
self,
|
|
315
334
|
debug_log: Path,
|
|
316
335
|
) -> list[tuple[str, str, str, str]]:
|
|
317
|
-
"""Extract error entries from debug log file."""
|
|
318
336
|
errors = []
|
|
319
337
|
|
|
320
338
|
with debug_log.open() as f:
|
|
@@ -329,11 +347,9 @@ class ErrorCollector:
|
|
|
329
347
|
return errors
|
|
330
348
|
|
|
331
349
|
def _is_debug_error_line(self, line: str) -> bool:
|
|
332
|
-
"""Check if debug log line contains error indicators."""
|
|
333
350
|
return any(indicator in line for indicator in ("ERROR", "Exception", "Failed"))
|
|
334
351
|
|
|
335
352
|
def _parse_debug_error_line(self, line: str) -> tuple[str, str, str, str] | None:
|
|
336
|
-
"""Parse debug error line into error entry tuple."""
|
|
337
353
|
parts = line.strip().split(" ", 2)
|
|
338
354
|
if len(parts) < 3:
|
|
339
355
|
return None
|
|
@@ -343,29 +359,27 @@ class ErrorCollector:
|
|
|
343
359
|
return (timestamp, "debug", error_msg, "System")
|
|
344
360
|
|
|
345
361
|
def _truncate_debug_message(self, message: str) -> str:
|
|
346
|
-
"""Truncate debug message to reasonable length."""
|
|
347
362
|
return message[:40] + "..." if len(message) > 40 else message
|
|
348
363
|
|
|
349
364
|
def _check_crackerjack_logs(self) -> list[tuple[str, str, str, str]]:
|
|
350
|
-
"""Check crackerjack debug logs for recent errors."""
|
|
351
365
|
errors = []
|
|
352
366
|
|
|
353
367
|
with suppress(Exception):
|
|
354
|
-
for log_file in Path(tempfile.gettempdir()).glob(
|
|
368
|
+
for log_file in Path(tempfile.gettempdir()).glob(
|
|
369
|
+
"crackerjack - debug-*.log"
|
|
370
|
+
):
|
|
355
371
|
if self._is_log_file_recent(log_file):
|
|
356
372
|
errors.extend(self._extract_errors_from_log_file(log_file))
|
|
357
373
|
|
|
358
374
|
return errors
|
|
359
375
|
|
|
360
376
|
def _is_log_file_recent(self, log_file: Path) -> bool:
|
|
361
|
-
"""Check if log file was modified within the last hour."""
|
|
362
377
|
return time.time() - log_file.stat().st_mtime < 3600
|
|
363
378
|
|
|
364
379
|
def _extract_errors_from_log_file(
|
|
365
380
|
self,
|
|
366
381
|
log_file: Path,
|
|
367
382
|
) -> list[tuple[str, str, str, str]]:
|
|
368
|
-
"""Extract error entries from a single log file."""
|
|
369
383
|
errors = []
|
|
370
384
|
|
|
371
385
|
with log_file.open() as f:
|
|
@@ -379,7 +393,6 @@ class ErrorCollector:
|
|
|
379
393
|
return errors
|
|
380
394
|
|
|
381
395
|
def _is_error_line(self, line: str) -> bool:
|
|
382
|
-
"""Check if a log line contains error keywords."""
|
|
383
396
|
return any(
|
|
384
397
|
keyword in line.lower() for keyword in ("error", "failed", "exception")
|
|
385
398
|
)
|
|
@@ -389,7 +402,6 @@ class ErrorCollector:
|
|
|
389
402
|
line: str,
|
|
390
403
|
log_file: Path,
|
|
391
404
|
) -> tuple[str, str, str, str]:
|
|
392
|
-
"""Create error entry tuple from log line and file."""
|
|
393
405
|
timestamp = time.strftime(
|
|
394
406
|
" % H: % M: % S",
|
|
395
407
|
time.localtime(log_file.stat().st_mtime),
|
|
@@ -398,7 +410,6 @@ class ErrorCollector:
|
|
|
398
410
|
return (timestamp, "job", error_msg, "Crackerjack")
|
|
399
411
|
|
|
400
412
|
def _truncate_error_message(self, message: str) -> str:
|
|
401
|
-
"""Truncate error message to reasonable length."""
|
|
402
413
|
return message[:50] + "..." if len(message) > 50 else message
|
|
403
414
|
|
|
404
415
|
|
|
@@ -430,12 +441,18 @@ class ServiceManager:
|
|
|
430
441
|
]
|
|
431
442
|
|
|
432
443
|
async def _check_websocket_server(self) -> bool:
|
|
444
|
+
timeout_manager = get_timeout_manager()
|
|
445
|
+
|
|
433
446
|
with suppress(Exception):
|
|
434
|
-
async with
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
447
|
+
async with timeout_manager.timeout_context(
|
|
448
|
+
"network_operations",
|
|
449
|
+
timeout=3.0, # Quick check timeout
|
|
450
|
+
):
|
|
451
|
+
async with aiohttp.ClientSession(
|
|
452
|
+
timeout=aiohttp.ClientTimeout(total=2),
|
|
453
|
+
) as session:
|
|
454
|
+
async with session.get("http://localhost:8675/") as response:
|
|
455
|
+
return response.status == 200
|
|
439
456
|
return False
|
|
440
457
|
|
|
441
458
|
def _check_mcp_server(self) -> bool:
|
|
@@ -445,6 +462,7 @@ class ServiceManager:
|
|
|
445
462
|
check=False,
|
|
446
463
|
capture_output=True,
|
|
447
464
|
text=True,
|
|
465
|
+
timeout=5.0, # Add timeout protection
|
|
448
466
|
)
|
|
449
467
|
return result.returncode == 0
|
|
450
468
|
return False
|
|
@@ -478,12 +496,13 @@ class ServiceManager:
|
|
|
478
496
|
check=False,
|
|
479
497
|
capture_output=True,
|
|
480
498
|
text=True,
|
|
499
|
+
timeout=5.0, # Add timeout protection
|
|
481
500
|
)
|
|
482
501
|
if result.returncode == 0:
|
|
483
502
|
return
|
|
484
503
|
|
|
485
504
|
process = subprocess.Popen(
|
|
486
|
-
["python", "
|
|
505
|
+
["python", "-m", "crackerjack", "--watchdog"],
|
|
487
506
|
stdout=subprocess.PIPE,
|
|
488
507
|
stderr=subprocess.PIPE,
|
|
489
508
|
start_new_session=True,
|