crackerjack 0.33.0__py3-none-any.whl → 0.33.2__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/__main__.py +1350 -34
- crackerjack/adapters/__init__.py +17 -0
- crackerjack/adapters/lsp_client.py +358 -0
- crackerjack/adapters/rust_tool_adapter.py +194 -0
- crackerjack/adapters/rust_tool_manager.py +193 -0
- crackerjack/adapters/skylos_adapter.py +231 -0
- crackerjack/adapters/zuban_adapter.py +560 -0
- crackerjack/agents/base.py +7 -3
- crackerjack/agents/coordinator.py +271 -33
- crackerjack/agents/documentation_agent.py +9 -15
- crackerjack/agents/dry_agent.py +3 -15
- crackerjack/agents/formatting_agent.py +1 -1
- crackerjack/agents/import_optimization_agent.py +36 -180
- crackerjack/agents/performance_agent.py +17 -98
- crackerjack/agents/performance_helpers.py +7 -31
- crackerjack/agents/proactive_agent.py +1 -3
- crackerjack/agents/refactoring_agent.py +16 -85
- crackerjack/agents/refactoring_helpers.py +7 -42
- crackerjack/agents/security_agent.py +9 -48
- crackerjack/agents/test_creation_agent.py +356 -513
- crackerjack/agents/test_specialist_agent.py +0 -4
- crackerjack/api.py +6 -25
- crackerjack/cli/cache_handlers.py +204 -0
- crackerjack/cli/cache_handlers_enhanced.py +683 -0
- crackerjack/cli/facade.py +100 -0
- crackerjack/cli/handlers.py +224 -9
- crackerjack/cli/interactive.py +6 -4
- crackerjack/cli/options.py +642 -55
- crackerjack/cli/utils.py +2 -1
- crackerjack/code_cleaner.py +58 -117
- crackerjack/config/global_lock_config.py +8 -48
- crackerjack/config/hooks.py +53 -62
- crackerjack/core/async_workflow_orchestrator.py +24 -34
- crackerjack/core/autofix_coordinator.py +3 -17
- crackerjack/core/enhanced_container.py +4 -13
- crackerjack/core/file_lifecycle.py +12 -89
- crackerjack/core/performance.py +2 -2
- crackerjack/core/performance_monitor.py +15 -55
- crackerjack/core/phase_coordinator.py +104 -204
- crackerjack/core/resource_manager.py +14 -90
- crackerjack/core/service_watchdog.py +62 -95
- crackerjack/core/session_coordinator.py +149 -0
- crackerjack/core/timeout_manager.py +14 -72
- crackerjack/core/websocket_lifecycle.py +13 -78
- crackerjack/core/workflow_orchestrator.py +171 -174
- crackerjack/docs/INDEX.md +11 -0
- crackerjack/docs/generated/api/API_REFERENCE.md +10895 -0
- crackerjack/docs/generated/api/CLI_REFERENCE.md +109 -0
- crackerjack/docs/generated/api/CROSS_REFERENCES.md +1755 -0
- crackerjack/docs/generated/api/PROTOCOLS.md +3 -0
- crackerjack/docs/generated/api/SERVICES.md +1252 -0
- crackerjack/documentation/__init__.py +31 -0
- crackerjack/documentation/ai_templates.py +756 -0
- crackerjack/documentation/dual_output_generator.py +765 -0
- crackerjack/documentation/mkdocs_integration.py +518 -0
- crackerjack/documentation/reference_generator.py +977 -0
- crackerjack/dynamic_config.py +55 -50
- crackerjack/executors/async_hook_executor.py +10 -15
- crackerjack/executors/cached_hook_executor.py +117 -43
- crackerjack/executors/hook_executor.py +8 -34
- crackerjack/executors/hook_lock_manager.py +26 -183
- crackerjack/executors/individual_hook_executor.py +13 -11
- crackerjack/executors/lsp_aware_hook_executor.py +270 -0
- crackerjack/executors/tool_proxy.py +417 -0
- crackerjack/hooks/lsp_hook.py +79 -0
- crackerjack/intelligence/adaptive_learning.py +25 -10
- crackerjack/intelligence/agent_orchestrator.py +2 -5
- crackerjack/intelligence/agent_registry.py +34 -24
- crackerjack/intelligence/agent_selector.py +5 -7
- crackerjack/interactive.py +17 -6
- crackerjack/managers/async_hook_manager.py +0 -1
- crackerjack/managers/hook_manager.py +79 -1
- crackerjack/managers/publish_manager.py +44 -8
- crackerjack/managers/test_command_builder.py +1 -15
- crackerjack/managers/test_executor.py +1 -3
- crackerjack/managers/test_manager.py +98 -7
- crackerjack/managers/test_manager_backup.py +10 -9
- crackerjack/mcp/cache.py +2 -2
- crackerjack/mcp/client_runner.py +1 -1
- crackerjack/mcp/context.py +191 -68
- crackerjack/mcp/dashboard.py +7 -5
- crackerjack/mcp/enhanced_progress_monitor.py +31 -28
- crackerjack/mcp/file_monitor.py +30 -23
- crackerjack/mcp/progress_components.py +31 -21
- crackerjack/mcp/progress_monitor.py +50 -53
- crackerjack/mcp/rate_limiter.py +6 -6
- crackerjack/mcp/server_core.py +17 -16
- crackerjack/mcp/service_watchdog.py +2 -1
- crackerjack/mcp/state.py +4 -7
- crackerjack/mcp/task_manager.py +11 -9
- crackerjack/mcp/tools/core_tools.py +173 -32
- crackerjack/mcp/tools/error_analyzer.py +3 -2
- crackerjack/mcp/tools/execution_tools.py +8 -10
- crackerjack/mcp/tools/execution_tools_backup.py +42 -30
- crackerjack/mcp/tools/intelligence_tool_registry.py +7 -5
- crackerjack/mcp/tools/intelligence_tools.py +5 -2
- crackerjack/mcp/tools/monitoring_tools.py +33 -70
- crackerjack/mcp/tools/proactive_tools.py +24 -11
- crackerjack/mcp/tools/progress_tools.py +5 -8
- crackerjack/mcp/tools/utility_tools.py +20 -14
- crackerjack/mcp/tools/workflow_executor.py +62 -40
- crackerjack/mcp/websocket/app.py +8 -0
- crackerjack/mcp/websocket/endpoints.py +352 -357
- crackerjack/mcp/websocket/jobs.py +40 -57
- crackerjack/mcp/websocket/monitoring_endpoints.py +2935 -0
- crackerjack/mcp/websocket/server.py +7 -25
- crackerjack/mcp/websocket/websocket_handler.py +6 -17
- crackerjack/mixins/__init__.py +0 -2
- crackerjack/mixins/error_handling.py +1 -70
- crackerjack/models/config.py +12 -1
- crackerjack/models/config_adapter.py +49 -1
- crackerjack/models/protocols.py +122 -122
- crackerjack/models/resource_protocols.py +55 -210
- crackerjack/monitoring/ai_agent_watchdog.py +13 -13
- crackerjack/monitoring/metrics_collector.py +426 -0
- crackerjack/monitoring/regression_prevention.py +8 -8
- crackerjack/monitoring/websocket_server.py +643 -0
- crackerjack/orchestration/advanced_orchestrator.py +11 -6
- crackerjack/orchestration/coverage_improvement.py +3 -3
- crackerjack/orchestration/execution_strategies.py +26 -6
- crackerjack/orchestration/test_progress_streamer.py +8 -5
- crackerjack/plugins/base.py +2 -2
- crackerjack/plugins/hooks.py +7 -0
- crackerjack/plugins/managers.py +11 -8
- crackerjack/security/__init__.py +0 -1
- crackerjack/security/audit.py +6 -35
- crackerjack/services/anomaly_detector.py +392 -0
- crackerjack/services/api_extractor.py +615 -0
- crackerjack/services/backup_service.py +2 -2
- crackerjack/services/bounded_status_operations.py +15 -152
- crackerjack/services/cache.py +127 -1
- crackerjack/services/changelog_automation.py +395 -0
- crackerjack/services/config.py +15 -9
- crackerjack/services/config_merge.py +19 -80
- crackerjack/services/config_template.py +506 -0
- crackerjack/services/contextual_ai_assistant.py +48 -22
- crackerjack/services/coverage_badge_service.py +171 -0
- crackerjack/services/coverage_ratchet.py +27 -25
- crackerjack/services/debug.py +3 -3
- crackerjack/services/dependency_analyzer.py +460 -0
- crackerjack/services/dependency_monitor.py +14 -11
- crackerjack/services/documentation_generator.py +491 -0
- crackerjack/services/documentation_service.py +675 -0
- crackerjack/services/enhanced_filesystem.py +6 -5
- crackerjack/services/enterprise_optimizer.py +865 -0
- crackerjack/services/error_pattern_analyzer.py +676 -0
- crackerjack/services/file_hasher.py +1 -1
- crackerjack/services/git.py +8 -25
- crackerjack/services/health_metrics.py +10 -8
- crackerjack/services/heatmap_generator.py +735 -0
- crackerjack/services/initialization.py +11 -30
- crackerjack/services/input_validator.py +5 -97
- crackerjack/services/intelligent_commit.py +327 -0
- crackerjack/services/log_manager.py +15 -12
- crackerjack/services/logging.py +4 -3
- crackerjack/services/lsp_client.py +628 -0
- crackerjack/services/memory_optimizer.py +19 -87
- crackerjack/services/metrics.py +42 -33
- crackerjack/services/parallel_executor.py +9 -67
- crackerjack/services/pattern_cache.py +1 -1
- crackerjack/services/pattern_detector.py +6 -6
- crackerjack/services/performance_benchmarks.py +18 -59
- crackerjack/services/performance_cache.py +20 -81
- crackerjack/services/performance_monitor.py +27 -95
- crackerjack/services/predictive_analytics.py +510 -0
- crackerjack/services/quality_baseline.py +234 -0
- crackerjack/services/quality_baseline_enhanced.py +646 -0
- crackerjack/services/quality_intelligence.py +785 -0
- crackerjack/services/regex_patterns.py +618 -524
- crackerjack/services/regex_utils.py +43 -123
- crackerjack/services/secure_path_utils.py +5 -164
- crackerjack/services/secure_status_formatter.py +30 -141
- crackerjack/services/secure_subprocess.py +11 -92
- crackerjack/services/security.py +9 -41
- crackerjack/services/security_logger.py +12 -24
- crackerjack/services/server_manager.py +124 -16
- crackerjack/services/status_authentication.py +16 -159
- crackerjack/services/status_security_manager.py +4 -131
- crackerjack/services/thread_safe_status_collector.py +19 -125
- crackerjack/services/unified_config.py +21 -13
- crackerjack/services/validation_rate_limiter.py +5 -54
- crackerjack/services/version_analyzer.py +459 -0
- crackerjack/services/version_checker.py +1 -1
- crackerjack/services/websocket_resource_limiter.py +10 -144
- crackerjack/services/zuban_lsp_service.py +390 -0
- crackerjack/slash_commands/__init__.py +2 -7
- crackerjack/slash_commands/run.md +2 -2
- crackerjack/tools/validate_input_validator_patterns.py +14 -40
- crackerjack/tools/validate_regex_patterns.py +19 -48
- {crackerjack-0.33.0.dist-info → crackerjack-0.33.2.dist-info}/METADATA +196 -25
- crackerjack-0.33.2.dist-info/RECORD +229 -0
- crackerjack/CLAUDE.md +0 -207
- crackerjack/RULES.md +0 -380
- crackerjack/py313.py +0 -234
- crackerjack-0.33.0.dist-info/RECORD +0 -187
- {crackerjack-0.33.0.dist-info → crackerjack-0.33.2.dist-info}/WHEEL +0 -0
- {crackerjack-0.33.0.dist-info → crackerjack-0.33.2.dist-info}/entry_points.txt +0 -0
- {crackerjack-0.33.0.dist-info → crackerjack-0.33.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -19,7 +19,7 @@ def register_utility_tools(mcp_app: t.Any) -> None:
|
|
|
19
19
|
|
|
20
20
|
def _clean_file_if_old(
|
|
21
21
|
file_path: Path, cutoff_time: float, dry_run: bool, file_type: str
|
|
22
|
-
) -> dict | None:
|
|
22
|
+
) -> dict[str, t.Any] | None:
|
|
23
23
|
with suppress(OSError):
|
|
24
24
|
if file_path.stat().st_mtime < cutoff_time:
|
|
25
25
|
file_size = file_path.stat().st_size
|
|
@@ -29,7 +29,9 @@ def _clean_file_if_old(
|
|
|
29
29
|
return None
|
|
30
30
|
|
|
31
31
|
|
|
32
|
-
def _clean_temp_files(
|
|
32
|
+
def _clean_temp_files(
|
|
33
|
+
cutoff_time: float, dry_run: bool
|
|
34
|
+
) -> tuple[list[dict[str, t.Any]], int]:
|
|
33
35
|
import tempfile
|
|
34
36
|
|
|
35
37
|
cleaned_files = []
|
|
@@ -49,7 +51,7 @@ def _clean_temp_files(cutoff_time: float, dry_run: bool) -> tuple[list[dict], in
|
|
|
49
51
|
|
|
50
52
|
def _clean_progress_files(
|
|
51
53
|
context: t.Any, cutoff_time: float, dry_run: bool
|
|
52
|
-
) -> tuple[list[dict], int]:
|
|
54
|
+
) -> tuple[list[dict[str, t.Any]], int]:
|
|
53
55
|
cleaned_files = []
|
|
54
56
|
total_size = 0
|
|
55
57
|
|
|
@@ -65,9 +67,9 @@ def _clean_progress_files(
|
|
|
65
67
|
return cleaned_files, total_size
|
|
66
68
|
|
|
67
69
|
|
|
68
|
-
def _parse_cleanup_options(kwargs: str) -> tuple[dict, str | None]:
|
|
70
|
+
def _parse_cleanup_options(kwargs: str) -> tuple[dict[str, t.Any], str | None]:
|
|
69
71
|
try:
|
|
70
|
-
extra_kwargs = json.loads(kwargs) if kwargs.strip() else {}
|
|
72
|
+
extra_kwargs: dict[str, t.Any] = json.loads(kwargs) if kwargs.strip() else {}
|
|
71
73
|
return extra_kwargs, None
|
|
72
74
|
except json.JSONDecodeError as e:
|
|
73
75
|
return {}, f"Invalid JSON in kwargs: {e}"
|
|
@@ -91,7 +93,7 @@ def _register_clean_tool(mcp_app: t.Any) -> None:
|
|
|
91
93
|
return _create_error_response(f"Cleanup failed: {e}")
|
|
92
94
|
|
|
93
95
|
|
|
94
|
-
def _parse_clean_configuration(args: str, kwargs: str) -> dict:
|
|
96
|
+
def _parse_clean_configuration(args: str, kwargs: str) -> dict[str, t.Any]:
|
|
95
97
|
extra_kwargs, parse_error = _parse_cleanup_options(kwargs)
|
|
96
98
|
if parse_error:
|
|
97
99
|
return {"error": parse_error}
|
|
@@ -103,7 +105,9 @@ def _parse_clean_configuration(args: str, kwargs: str) -> dict:
|
|
|
103
105
|
}
|
|
104
106
|
|
|
105
107
|
|
|
106
|
-
def _execute_cleanup_operations(
|
|
108
|
+
def _execute_cleanup_operations(
|
|
109
|
+
context: t.Any, clean_config: dict[str, t.Any]
|
|
110
|
+
) -> dict[str, t.Any]:
|
|
107
111
|
from datetime import datetime, timedelta
|
|
108
112
|
|
|
109
113
|
cutoff_time = (
|
|
@@ -130,7 +134,9 @@ def _execute_cleanup_operations(context: t.Any, clean_config: dict) -> dict:
|
|
|
130
134
|
return {"all_cleaned_files": all_cleaned_files, "total_size": total_size}
|
|
131
135
|
|
|
132
136
|
|
|
133
|
-
def _create_cleanup_response(
|
|
137
|
+
def _create_cleanup_response(
|
|
138
|
+
clean_config: dict[str, t.Any], cleanup_results: dict[str, t.Any]
|
|
139
|
+
) -> str:
|
|
134
140
|
all_cleaned_files = cleanup_results["all_cleaned_files"]
|
|
135
141
|
|
|
136
142
|
return json.dumps(
|
|
@@ -208,16 +214,16 @@ def _register_config_tool(mcp_app: t.Any) -> None:
|
|
|
208
214
|
if parse_error:
|
|
209
215
|
return _create_error_response(parse_error)
|
|
210
216
|
|
|
211
|
-
args_parts = args.strip().split() if args.strip() else ["list"]
|
|
217
|
+
args_parts = args.strip().split() if args.strip() else ["list[t.Any]"]
|
|
212
218
|
action = args_parts[0].lower()
|
|
213
219
|
|
|
214
220
|
try:
|
|
215
|
-
if action == "list":
|
|
221
|
+
if action == "list[t.Any]":
|
|
216
222
|
config_info = _handle_config_list(context)
|
|
217
223
|
result = {
|
|
218
224
|
"success": True,
|
|
219
225
|
"command": "config_crackerjack",
|
|
220
|
-
"action": "list",
|
|
226
|
+
"action": "list[t.Any]",
|
|
221
227
|
"configuration": config_info,
|
|
222
228
|
}
|
|
223
229
|
elif action == "get" and len(args_parts) > 1:
|
|
@@ -226,7 +232,7 @@ def _register_config_tool(mcp_app: t.Any) -> None:
|
|
|
226
232
|
result = _handle_config_validate(context)
|
|
227
233
|
else:
|
|
228
234
|
return _create_error_response(
|
|
229
|
-
f"Invalid action '{action}'. Valid actions: list, get < key >, validate"
|
|
235
|
+
f"Invalid action '{action}'. Valid actions: list[t.Any], get < key >, validate"
|
|
230
236
|
)
|
|
231
237
|
|
|
232
238
|
return json.dumps(result, indent=2)
|
|
@@ -235,7 +241,7 @@ def _register_config_tool(mcp_app: t.Any) -> None:
|
|
|
235
241
|
return _create_error_response(f"Config operation failed: {e}")
|
|
236
242
|
|
|
237
243
|
|
|
238
|
-
def _run_hooks_analysis(orchestrator: t.Any, options: t.Any) -> dict:
|
|
244
|
+
def _run_hooks_analysis(orchestrator: t.Any, options: t.Any) -> dict[str, t.Any]:
|
|
239
245
|
fast_result = orchestrator.run_fast_hooks_only(options)
|
|
240
246
|
comprehensive_result = orchestrator.run_comprehensive_hooks_only(options)
|
|
241
247
|
|
|
@@ -245,7 +251,7 @@ def _run_hooks_analysis(orchestrator: t.Any, options: t.Any) -> dict:
|
|
|
245
251
|
}
|
|
246
252
|
|
|
247
253
|
|
|
248
|
-
def _run_tests_analysis(orchestrator: t.Any, options: t.Any) -> dict:
|
|
254
|
+
def _run_tests_analysis(orchestrator: t.Any, options: t.Any) -> dict[str, t.Any]:
|
|
249
255
|
test_result = orchestrator.run_testing_phase(options)
|
|
250
256
|
return {"status": "passed" if test_result else "failed"}
|
|
251
257
|
|
|
@@ -13,35 +13,65 @@ async def execute_crackerjack_workflow(
|
|
|
13
13
|
) -> dict[str, t.Any]:
|
|
14
14
|
job_id = str(uuid.uuid4())[:8]
|
|
15
15
|
|
|
16
|
-
#
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
# Initialize progress immediately
|
|
17
|
+
await _update_progress(
|
|
18
|
+
job_id,
|
|
19
|
+
{"status": "started", "args": args, "timestamp": time.time()},
|
|
20
|
+
0,
|
|
21
|
+
message="Crackerjack execution started",
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
# Start execution in background - no timeout!
|
|
25
|
+
context = get_context()
|
|
26
|
+
asyncio.create_task(_execute_crackerjack_background(job_id, args, kwargs, context))
|
|
27
|
+
|
|
28
|
+
# Return job_id immediately for progress monitoring
|
|
29
|
+
return {
|
|
30
|
+
"job_id": job_id,
|
|
31
|
+
"status": "running",
|
|
32
|
+
"message": "Execution started. Use get_job_progress(job_id) to monitor progress.",
|
|
33
|
+
"timestamp": time.time(),
|
|
34
|
+
}
|
|
35
|
+
|
|
20
36
|
|
|
37
|
+
async def _execute_crackerjack_background(
|
|
38
|
+
job_id: str,
|
|
39
|
+
args: str,
|
|
40
|
+
kwargs: dict[str, t.Any],
|
|
41
|
+
context: t.Any,
|
|
42
|
+
) -> None:
|
|
43
|
+
"""Execute crackerjack workflow in background with progress updates."""
|
|
21
44
|
try:
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
45
|
+
result = await _execute_crackerjack_sync(job_id, args, kwargs, context)
|
|
46
|
+
|
|
47
|
+
# Update final progress with result
|
|
48
|
+
await _update_progress(
|
|
49
|
+
job_id,
|
|
50
|
+
{
|
|
51
|
+
"status": result.get("status", "completed"),
|
|
52
|
+
"result": result,
|
|
53
|
+
"timestamp": time.time(),
|
|
54
|
+
"final": True,
|
|
55
|
+
},
|
|
56
|
+
100,
|
|
57
|
+
message=f"Execution {result.get('status', 'completed')}",
|
|
26
58
|
)
|
|
27
|
-
except TimeoutError:
|
|
28
|
-
return {
|
|
29
|
-
"job_id": job_id,
|
|
30
|
-
"status": "timeout",
|
|
31
|
-
"error": f"Execution timed out after {execution_timeout} seconds",
|
|
32
|
-
"timestamp": time.time(),
|
|
33
|
-
}
|
|
34
59
|
except Exception as e:
|
|
35
60
|
import traceback
|
|
36
61
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
62
|
+
# Update progress with error
|
|
63
|
+
await _update_progress(
|
|
64
|
+
job_id,
|
|
65
|
+
{
|
|
66
|
+
"status": "failed",
|
|
67
|
+
"error": str(e),
|
|
68
|
+
"traceback": traceback.format_exc(),
|
|
69
|
+
"timestamp": time.time(),
|
|
70
|
+
"final": True,
|
|
71
|
+
},
|
|
72
|
+
-1,
|
|
73
|
+
message=f"Execution failed: {e}",
|
|
74
|
+
)
|
|
45
75
|
|
|
46
76
|
|
|
47
77
|
async def _execute_crackerjack_sync(
|
|
@@ -81,7 +111,6 @@ async def _initialize_execution(
|
|
|
81
111
|
context,
|
|
82
112
|
)
|
|
83
113
|
|
|
84
|
-
# Ensure WebSocket server is running for progress tracking
|
|
85
114
|
await _ensure_websocket_server_running(job_id, context)
|
|
86
115
|
|
|
87
116
|
working_dir = kwargs.get("working_directory", ".")
|
|
@@ -228,9 +257,8 @@ async def _run_workflow_iterations(
|
|
|
228
257
|
context: t.Any,
|
|
229
258
|
) -> dict[str, t.Any]:
|
|
230
259
|
options = _create_workflow_options(kwargs)
|
|
231
|
-
max_iterations = kwargs.get("max_iterations",
|
|
260
|
+
max_iterations = kwargs.get("max_iterations", 5)
|
|
232
261
|
|
|
233
|
-
# Start keep-alive task to prevent TCP timeouts
|
|
234
262
|
keep_alive_task = asyncio.create_task(_keep_alive_heartbeat(job_id, context))
|
|
235
263
|
|
|
236
264
|
try:
|
|
@@ -250,7 +278,6 @@ async def _execute_iterations_loop(
|
|
|
250
278
|
max_iterations: int,
|
|
251
279
|
context: t.Any,
|
|
252
280
|
) -> dict[str, t.Any]:
|
|
253
|
-
"""Execute the main iterations loop."""
|
|
254
281
|
for iteration in range(max_iterations):
|
|
255
282
|
_update_iteration_progress(job_id, iteration, max_iterations, context)
|
|
256
283
|
|
|
@@ -276,7 +303,6 @@ async def _execute_iterations_loop(
|
|
|
276
303
|
def _update_iteration_progress(
|
|
277
304
|
job_id: str, iteration: int, max_iterations: int, context: t.Any
|
|
278
305
|
) -> None:
|
|
279
|
-
"""Update progress for current iteration."""
|
|
280
306
|
_update_progress(
|
|
281
307
|
job_id,
|
|
282
308
|
{
|
|
@@ -296,7 +322,6 @@ async def _handle_iteration_success(
|
|
|
296
322
|
kwargs: dict[str, t.Any],
|
|
297
323
|
context: t.Any,
|
|
298
324
|
) -> dict[str, t.Any]:
|
|
299
|
-
"""Handle successful iteration."""
|
|
300
325
|
coverage_result = None
|
|
301
326
|
if kwargs.get("boost_coverage", False):
|
|
302
327
|
coverage_result = await _attempt_coverage_improvement(
|
|
@@ -306,7 +331,6 @@ async def _handle_iteration_success(
|
|
|
306
331
|
|
|
307
332
|
|
|
308
333
|
async def _cleanup_keep_alive_task(keep_alive_task: asyncio.Task[t.Any]) -> None:
|
|
309
|
-
"""Clean up the keep-alive task."""
|
|
310
334
|
if not keep_alive_task.cancelled():
|
|
311
335
|
keep_alive_task.cancel()
|
|
312
336
|
try:
|
|
@@ -316,10 +340,8 @@ async def _cleanup_keep_alive_task(keep_alive_task: asyncio.Task[t.Any]) -> None
|
|
|
316
340
|
|
|
317
341
|
|
|
318
342
|
async def _keep_alive_heartbeat(job_id: str, context: t.Any) -> None:
|
|
319
|
-
"""Send periodic keep-alive messages to prevent TCP timeouts."""
|
|
320
343
|
try:
|
|
321
344
|
while True:
|
|
322
|
-
# Send heartbeat every 60 seconds (well under 2-minute TCP timeout)
|
|
323
345
|
await asyncio.sleep(60)
|
|
324
346
|
_update_progress(
|
|
325
347
|
job_id,
|
|
@@ -332,7 +354,6 @@ async def _keep_alive_heartbeat(job_id: str, context: t.Any) -> None:
|
|
|
332
354
|
context,
|
|
333
355
|
)
|
|
334
356
|
except asyncio.CancelledError:
|
|
335
|
-
# Task was cancelled, cleanup
|
|
336
357
|
_update_progress(
|
|
337
358
|
job_id,
|
|
338
359
|
{
|
|
@@ -404,23 +425,27 @@ async def _execute_single_iteration(
|
|
|
404
425
|
raise ValueError(
|
|
405
426
|
"Method run_complete_workflow_async returned None instead of awaitable"
|
|
406
427
|
)
|
|
407
|
-
|
|
428
|
+
workflow_result: bool = await result
|
|
429
|
+
return workflow_result
|
|
408
430
|
elif hasattr(orchestrator, "run_complete_workflow"):
|
|
409
431
|
result = orchestrator.run_complete_workflow(options)
|
|
410
432
|
if result is None:
|
|
411
433
|
raise ValueError(
|
|
412
434
|
"Method run_complete_workflow returned None instead of awaitable"
|
|
413
435
|
)
|
|
414
|
-
|
|
436
|
+
workflow_result: bool = await result
|
|
437
|
+
return workflow_result
|
|
415
438
|
elif hasattr(orchestrator, "execute_workflow"):
|
|
416
439
|
result = orchestrator.execute_workflow(options)
|
|
417
440
|
if result is None:
|
|
418
441
|
raise ValueError(
|
|
419
442
|
"Method execute_workflow returned None instead of awaitable"
|
|
420
443
|
)
|
|
421
|
-
|
|
444
|
+
workflow_result: bool = await result
|
|
445
|
+
return workflow_result
|
|
422
446
|
elif hasattr(orchestrator, "run"):
|
|
423
|
-
|
|
447
|
+
run_result: bool = orchestrator.run(options)
|
|
448
|
+
return run_result
|
|
424
449
|
else:
|
|
425
450
|
raise ValueError(
|
|
426
451
|
f"Orchestrator {type(orchestrator)} has no recognized workflow execution method"
|
|
@@ -606,11 +631,9 @@ def _create_failure_result(
|
|
|
606
631
|
|
|
607
632
|
|
|
608
633
|
async def _ensure_websocket_server_running(job_id: str, context: t.Any) -> None:
|
|
609
|
-
"""Ensure WebSocket server is running for progress tracking during crackerjack:run."""
|
|
610
634
|
try:
|
|
611
635
|
from crackerjack.mcp.progress_components import ServiceManager
|
|
612
636
|
|
|
613
|
-
# Initialize and start services if needed
|
|
614
637
|
service_manager = ServiceManager()
|
|
615
638
|
await service_manager.ensure_services_running()
|
|
616
639
|
|
|
@@ -624,7 +647,6 @@ async def _ensure_websocket_server_running(job_id: str, context: t.Any) -> None:
|
|
|
624
647
|
context,
|
|
625
648
|
)
|
|
626
649
|
except Exception as e:
|
|
627
|
-
# Don't fail the whole workflow if WebSocket server fails to start
|
|
628
650
|
_update_progress(
|
|
629
651
|
job_id,
|
|
630
652
|
{
|
crackerjack/mcp/websocket/app.py
CHANGED
|
@@ -5,6 +5,10 @@ from fastapi import FastAPI
|
|
|
5
5
|
|
|
6
6
|
from .endpoints import register_endpoints
|
|
7
7
|
from .jobs import JobManager
|
|
8
|
+
from .monitoring_endpoints import (
|
|
9
|
+
MonitoringWebSocketManager,
|
|
10
|
+
create_monitoring_endpoints,
|
|
11
|
+
)
|
|
8
12
|
from .websocket_handler import register_websocket_routes
|
|
9
13
|
|
|
10
14
|
|
|
@@ -33,4 +37,8 @@ def create_websocket_app(job_manager: JobManager, progress_dir: Path) -> FastAPI
|
|
|
33
37
|
|
|
34
38
|
register_websocket_routes(app, job_manager, progress_dir)
|
|
35
39
|
|
|
40
|
+
# Register monitoring endpoints
|
|
41
|
+
monitoring_ws_manager = MonitoringWebSocketManager()
|
|
42
|
+
create_monitoring_endpoints(app, job_manager, progress_dir, monitoring_ws_manager)
|
|
43
|
+
|
|
36
44
|
return app
|