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
|
@@ -33,7 +33,6 @@ def _register_execute_crackerjack_tool(mcp_app: t.Any) -> None:
|
|
|
33
33
|
|
|
34
34
|
extra_kwargs = kwargs_result["kwargs"]
|
|
35
35
|
|
|
36
|
-
# Run the workflow directly instead of in background
|
|
37
36
|
try:
|
|
38
37
|
result = await _execute_crackerjack_sync(
|
|
39
38
|
job_id,
|
|
@@ -78,7 +77,6 @@ async def _validate_context_and_rate_limit(context: t.Any) -> str | None:
|
|
|
78
77
|
if not context:
|
|
79
78
|
return '{"error": "Server context not available"}'
|
|
80
79
|
|
|
81
|
-
# Rate limiting is optional - skip if not configured
|
|
82
80
|
if context.rate_limiter:
|
|
83
81
|
allowed, details = await context.rate_limiter.check_request_allowed("default")
|
|
84
82
|
if not allowed:
|
|
@@ -88,16 +86,14 @@ async def _validate_context_and_rate_limit(context: t.Any) -> str | None:
|
|
|
88
86
|
|
|
89
87
|
|
|
90
88
|
def _handle_task_exception(job_id: str, task: asyncio.Task) -> None:
|
|
91
|
-
"""Handle exceptions from background tasks."""
|
|
92
89
|
import tempfile
|
|
93
90
|
from pathlib import Path
|
|
94
91
|
|
|
95
92
|
try:
|
|
96
93
|
exception = task.exception()
|
|
97
94
|
if exception:
|
|
98
|
-
# Log the exception to a debug file
|
|
99
95
|
debug_file = (
|
|
100
|
-
Path(tempfile.gettempdir()) / f"crackerjack-task-error-{job_id}.log"
|
|
96
|
+
Path(tempfile.gettempdir()) / f"crackerjack - task-error -{job_id}.log"
|
|
101
97
|
)
|
|
102
98
|
with debug_file.open("w") as f:
|
|
103
99
|
f.write(
|
|
@@ -107,13 +103,13 @@ def _handle_task_exception(job_id: str, task: asyncio.Task) -> None:
|
|
|
107
103
|
import traceback
|
|
108
104
|
|
|
109
105
|
f.write(
|
|
110
|
-
f"Traceback
|
|
106
|
+
f"Traceback: \n{traceback.format_exception(type(exception), exception, exception.__traceback__)}\n",
|
|
111
107
|
)
|
|
112
108
|
except Exception as e:
|
|
113
|
-
# If we can't even log the error, at least try to create a simple file
|
|
114
109
|
with suppress(Exception):
|
|
115
110
|
debug_file = (
|
|
116
|
-
Path(tempfile.gettempdir())
|
|
111
|
+
Path(tempfile.gettempdir())
|
|
112
|
+
/ f"crackerjack - logging-error -{job_id}.log"
|
|
117
113
|
)
|
|
118
114
|
with debug_file.open("w") as f:
|
|
119
115
|
f.write(f"Failed to log task exception: {e}\n")
|
|
@@ -220,7 +216,6 @@ async def _initialize_execution(
|
|
|
220
216
|
current_iteration: int,
|
|
221
217
|
context: t.Any,
|
|
222
218
|
) -> None:
|
|
223
|
-
"""Initialize execution with status checks and service preparation."""
|
|
224
219
|
_update_progress(
|
|
225
220
|
job_id=job_id,
|
|
226
221
|
iteration=current_iteration,
|
|
@@ -229,7 +224,6 @@ async def _initialize_execution(
|
|
|
229
224
|
message="Initializing crackerjack execution",
|
|
230
225
|
)
|
|
231
226
|
|
|
232
|
-
# Check comprehensive status first to prevent conflicts and perform cleanup
|
|
233
227
|
status_result = await _check_status_and_prepare(job_id, context)
|
|
234
228
|
if status_result.get("should_abort", False):
|
|
235
229
|
msg = f"Execution aborted: {status_result['reason']}"
|
|
@@ -241,13 +235,11 @@ async def _initialize_execution(
|
|
|
241
235
|
max_iterations=max_iterations,
|
|
242
236
|
overall_progress=5,
|
|
243
237
|
current_stage="status_verified",
|
|
244
|
-
message="Status check complete
|
|
238
|
+
message="Status check complete-no conflicts detected",
|
|
245
239
|
)
|
|
246
240
|
|
|
247
|
-
# Clean up stale jobs first
|
|
248
241
|
await _cleanup_stale_jobs(context)
|
|
249
242
|
|
|
250
|
-
# Auto-start required services
|
|
251
243
|
await _ensure_services_running(job_id, context)
|
|
252
244
|
|
|
253
245
|
_update_progress(
|
|
@@ -267,13 +259,10 @@ async def _setup_orchestrator(
|
|
|
267
259
|
kwargs: dict[str, t.Any],
|
|
268
260
|
context: t.Any,
|
|
269
261
|
) -> tuple[t.Any, bool]:
|
|
270
|
-
"""Set up the appropriate orchestrator (force standard for MCP compatibility)."""
|
|
271
|
-
# Force standard orchestrator for MCP server to ensure proper progress reporting
|
|
272
262
|
context.safe_print("Using Standard WorkflowOrchestrator for MCP compatibility")
|
|
273
263
|
orchestrator = _create_standard_orchestrator(job_id, kwargs, context)
|
|
274
264
|
use_advanced_orchestrator = False
|
|
275
265
|
|
|
276
|
-
# Update progress to show orchestrator mode
|
|
277
266
|
orchestrator_type = "Standard Orchestrator (MCP Compatible)"
|
|
278
267
|
_update_progress(
|
|
279
268
|
job_id=job_id,
|
|
@@ -292,7 +281,6 @@ async def _create_advanced_orchestrator(
|
|
|
292
281
|
kwargs: dict[str, t.Any],
|
|
293
282
|
context: t.Any,
|
|
294
283
|
) -> t.Any:
|
|
295
|
-
"""Create and configure the advanced orchestrator."""
|
|
296
284
|
from crackerjack.core.session_coordinator import SessionCoordinator
|
|
297
285
|
from crackerjack.orchestration.advanced_orchestrator import (
|
|
298
286
|
AdvancedWorkflowOrchestrator,
|
|
@@ -306,28 +294,23 @@ async def _create_advanced_orchestrator(
|
|
|
306
294
|
StreamingMode,
|
|
307
295
|
)
|
|
308
296
|
|
|
309
|
-
# Create optimal orchestration configuration for maximum efficiency
|
|
310
297
|
optimal_config = OrchestrationConfig(
|
|
311
298
|
execution_strategy=ExecutionStrategy.ADAPTIVE,
|
|
312
299
|
progress_level=ProgressLevel.DETAILED,
|
|
313
300
|
streaming_mode=StreamingMode.WEBSOCKET,
|
|
314
301
|
ai_coordination_mode=AICoordinationMode.COORDINATOR,
|
|
315
302
|
ai_intelligence=AIIntelligence.ADAPTIVE,
|
|
316
|
-
# Enable advanced features
|
|
317
303
|
correlation_tracking=True,
|
|
318
304
|
failure_analysis=True,
|
|
319
305
|
intelligent_retry=True,
|
|
320
|
-
# Maximize parallelism for hook and test fixing
|
|
321
306
|
max_parallel_hooks=3,
|
|
322
307
|
max_parallel_tests=4,
|
|
323
308
|
timeout_multiplier=1.0,
|
|
324
|
-
# Enhanced debugging and monitoring
|
|
325
309
|
debug_level="standard",
|
|
326
310
|
log_individual_outputs=False,
|
|
327
311
|
preserve_temp_files=False,
|
|
328
312
|
)
|
|
329
313
|
|
|
330
|
-
# Initialize advanced orchestrator with optimal config
|
|
331
314
|
session = SessionCoordinator(
|
|
332
315
|
context.console,
|
|
333
316
|
context.config.project_path,
|
|
@@ -340,10 +323,9 @@ async def _create_advanced_orchestrator(
|
|
|
340
323
|
config=optimal_config,
|
|
341
324
|
)
|
|
342
325
|
|
|
343
|
-
# Override MCP mode if debug flag is set
|
|
344
326
|
if kwargs.get("debug", False):
|
|
345
327
|
orchestrator.individual_executor.set_mcp_mode(False)
|
|
346
|
-
context.safe_print("🐛 Debug mode enabled
|
|
328
|
+
context.safe_print("🐛 Debug mode enabled-full output mode")
|
|
347
329
|
|
|
348
330
|
return orchestrator
|
|
349
331
|
|
|
@@ -353,7 +335,6 @@ def _create_standard_orchestrator(
|
|
|
353
335
|
kwargs: dict[str, t.Any],
|
|
354
336
|
context: t.Any,
|
|
355
337
|
) -> t.Any:
|
|
356
|
-
"""Create the standard fallback orchestrator."""
|
|
357
338
|
from crackerjack.core.workflow_orchestrator import WorkflowOrchestrator
|
|
358
339
|
|
|
359
340
|
return WorkflowOrchestrator(
|
|
@@ -371,7 +352,6 @@ async def _run_workflow_iterations(
|
|
|
371
352
|
use_advanced_orchestrator: bool,
|
|
372
353
|
kwargs: dict[str, t.Any],
|
|
373
354
|
) -> dict[str, t.Any]:
|
|
374
|
-
"""Run the main workflow iteration loop."""
|
|
375
355
|
success = False
|
|
376
356
|
current_iteration = 1
|
|
377
357
|
|
|
@@ -421,14 +401,13 @@ async def _run_workflow_iterations(
|
|
|
421
401
|
|
|
422
402
|
|
|
423
403
|
def _create_workflow_options(kwargs: dict[str, t.Any]) -> t.Any:
|
|
424
|
-
"""Create WorkflowOptions from kwargs."""
|
|
425
404
|
from crackerjack.models.config import WorkflowOptions
|
|
426
405
|
|
|
427
406
|
options = WorkflowOptions()
|
|
428
407
|
options.testing.test = kwargs.get("test", True)
|
|
429
408
|
options.ai_agent = kwargs.get("ai_agent", True)
|
|
430
409
|
options.skip_hooks = kwargs.get("skip_hooks", False)
|
|
431
|
-
|
|
410
|
+
|
|
432
411
|
options.proactive_mode = kwargs.get("proactive_mode", True)
|
|
433
412
|
return options
|
|
434
413
|
|
|
@@ -438,7 +417,6 @@ async def _execute_single_iteration(
|
|
|
438
417
|
use_advanced_orchestrator: bool,
|
|
439
418
|
options: t.Any,
|
|
440
419
|
) -> bool:
|
|
441
|
-
"""Execute a single workflow iteration."""
|
|
442
420
|
if use_advanced_orchestrator:
|
|
443
421
|
return await orchestrator.execute_orchestrated_workflow(options)
|
|
444
422
|
return await orchestrator.run_complete_workflow(options)
|
|
@@ -450,7 +428,6 @@ def _create_success_result(
|
|
|
450
428
|
max_iterations: int,
|
|
451
429
|
iteration: int,
|
|
452
430
|
) -> dict[str, t.Any]:
|
|
453
|
-
"""Create success result dictionary."""
|
|
454
431
|
_update_progress(
|
|
455
432
|
job_id=job_id,
|
|
456
433
|
status="completed",
|
|
@@ -474,7 +451,6 @@ async def _handle_iteration_retry(
|
|
|
474
451
|
max_iterations: int,
|
|
475
452
|
iteration: int,
|
|
476
453
|
) -> None:
|
|
477
|
-
"""Handle iteration retry logic."""
|
|
478
454
|
_update_progress(
|
|
479
455
|
job_id=job_id,
|
|
480
456
|
iteration=current_iteration,
|
|
@@ -491,7 +467,6 @@ async def _handle_iteration_error(
|
|
|
491
467
|
max_iterations: int,
|
|
492
468
|
error: Exception,
|
|
493
469
|
) -> bool:
|
|
494
|
-
"""Handle iteration errors. Returns True to continue, False to break."""
|
|
495
470
|
if iteration >= max_iterations:
|
|
496
471
|
return False
|
|
497
472
|
await asyncio.sleep(1)
|
|
@@ -503,7 +478,6 @@ def _create_failure_result(
|
|
|
503
478
|
current_iteration: int,
|
|
504
479
|
max_iterations: int,
|
|
505
480
|
) -> dict[str, t.Any]:
|
|
506
|
-
"""Create failure result dictionary."""
|
|
507
481
|
_update_progress(
|
|
508
482
|
job_id=job_id,
|
|
509
483
|
status="failed",
|
|
@@ -522,7 +496,6 @@ def _create_failure_result(
|
|
|
522
496
|
|
|
523
497
|
|
|
524
498
|
async def _ensure_services_running(job_id: str, context: t.Any) -> None:
|
|
525
|
-
"""Ensure WebSocket server and watchdog are running before starting workflow."""
|
|
526
499
|
import subprocess
|
|
527
500
|
|
|
528
501
|
_update_progress(
|
|
@@ -531,7 +504,6 @@ async def _ensure_services_running(job_id: str, context: t.Any) -> None:
|
|
|
531
504
|
message="Checking required services...",
|
|
532
505
|
)
|
|
533
506
|
|
|
534
|
-
# Check if WebSocket server is running
|
|
535
507
|
websocket_running = False
|
|
536
508
|
with suppress(Exception):
|
|
537
509
|
from crackerjack.services.server_manager import find_websocket_server_processes
|
|
@@ -547,16 +519,14 @@ async def _ensure_services_running(job_id: str, context: t.Any) -> None:
|
|
|
547
519
|
)
|
|
548
520
|
|
|
549
521
|
try:
|
|
550
|
-
# Start WebSocket server in background
|
|
551
522
|
subprocess.Popen(
|
|
552
|
-
["python", "-m", "crackerjack", "
|
|
523
|
+
["python", "- m", "crackerjack", "- - start - websocket-server"],
|
|
553
524
|
cwd=context.config.project_path,
|
|
554
525
|
stdout=subprocess.DEVNULL,
|
|
555
526
|
stderr=subprocess.DEVNULL,
|
|
556
527
|
start_new_session=True,
|
|
557
528
|
)
|
|
558
529
|
|
|
559
|
-
# Wait for server to start
|
|
560
530
|
for _i in range(10):
|
|
561
531
|
with suppress(Exception):
|
|
562
532
|
websocket_processes = find_websocket_server_processes()
|
|
@@ -574,7 +544,6 @@ async def _ensure_services_running(job_id: str, context: t.Any) -> None:
|
|
|
574
544
|
|
|
575
545
|
|
|
576
546
|
async def _check_status_and_prepare(job_id: str, context: t.Any) -> dict[str, t.Any]:
|
|
577
|
-
"""Check comprehensive system status and prepare for execution."""
|
|
578
547
|
_update_progress(
|
|
579
548
|
job_id=job_id,
|
|
580
549
|
current_stage="status_check",
|
|
@@ -588,16 +557,13 @@ async def _check_status_and_prepare(job_id: str, context: t.Any) -> dict[str, t.
|
|
|
588
557
|
|
|
589
558
|
cleanup_performed = []
|
|
590
559
|
|
|
591
|
-
# Check for conflicting jobs
|
|
592
560
|
_check_active_jobs(status_info, context)
|
|
593
561
|
|
|
594
|
-
# Check and flag resource cleanup needs
|
|
595
562
|
cleanup_performed.extend(_check_resource_cleanup(status_info, context))
|
|
596
563
|
|
|
597
|
-
# Check service health
|
|
598
564
|
_check_service_health(status_info, context)
|
|
599
565
|
|
|
600
|
-
context.safe_print("✅ Status check complete
|
|
566
|
+
context.safe_print("✅ Status check complete-ready to proceed")
|
|
601
567
|
|
|
602
568
|
return {
|
|
603
569
|
"should_abort": False,
|
|
@@ -611,7 +577,6 @@ async def _check_status_and_prepare(job_id: str, context: t.Any) -> dict[str, t.
|
|
|
611
577
|
|
|
612
578
|
|
|
613
579
|
async def _get_status_info() -> dict[str, t.Any]:
|
|
614
|
-
"""Get comprehensive system status."""
|
|
615
580
|
from .monitoring_tools import _get_comprehensive_status
|
|
616
581
|
|
|
617
582
|
return await _get_comprehensive_status()
|
|
@@ -621,7 +586,6 @@ def _handle_status_error(
|
|
|
621
586
|
status_info: dict[str, t.Any],
|
|
622
587
|
context: t.Any,
|
|
623
588
|
) -> dict[str, t.Any]:
|
|
624
|
-
"""Handle status check failure."""
|
|
625
589
|
context.safe_print(f"⚠️ Status check failed: {status_info['error']}")
|
|
626
590
|
return {
|
|
627
591
|
"should_abort": False,
|
|
@@ -632,7 +596,6 @@ def _handle_status_error(
|
|
|
632
596
|
|
|
633
597
|
|
|
634
598
|
def _check_active_jobs(status_info: dict[str, t.Any], context: t.Any) -> None:
|
|
635
|
-
"""Check for active jobs that might conflict."""
|
|
636
599
|
active_jobs = [
|
|
637
600
|
j
|
|
638
601
|
for j in status_info.get("jobs", {}).get("details", [])
|
|
@@ -642,15 +605,13 @@ def _check_active_jobs(status_info: dict[str, t.Any], context: t.Any) -> None:
|
|
|
642
605
|
if active_jobs:
|
|
643
606
|
_handle_conflicting_jobs(active_jobs, context)
|
|
644
607
|
else:
|
|
645
|
-
context.safe_print("✅ No active jobs detected
|
|
608
|
+
context.safe_print("✅ No active jobs detected-safe to proceed")
|
|
646
609
|
|
|
647
610
|
|
|
648
611
|
def _handle_conflicting_jobs(
|
|
649
612
|
active_jobs: list[dict[str, t.Any]],
|
|
650
613
|
context: t.Any,
|
|
651
614
|
) -> None:
|
|
652
|
-
"""Handle conflicting active jobs."""
|
|
653
|
-
# For now, assume all jobs could conflict (future: check project paths)
|
|
654
615
|
conflicting_jobs = active_jobs
|
|
655
616
|
|
|
656
617
|
if conflicting_jobs:
|
|
@@ -659,13 +620,12 @@ def _handle_conflicting_jobs(
|
|
|
659
620
|
f"⚠️ Found {len(conflicting_jobs)} active job(s): {', '.join(job_ids[:3])}",
|
|
660
621
|
)
|
|
661
622
|
context.safe_print(
|
|
662
|
-
"
|
|
623
|
+
" Running concurrent crackerjack instances may cause file conflicts",
|
|
663
624
|
)
|
|
664
|
-
context.safe_print("
|
|
625
|
+
context.safe_print(" Proceeding with caution...")
|
|
665
626
|
|
|
666
627
|
|
|
667
628
|
def _check_resource_cleanup(status_info: dict[str, t.Any], context: t.Any) -> list[str]:
|
|
668
|
-
"""Check if resource cleanup is needed."""
|
|
669
629
|
cleanup_performed = []
|
|
670
630
|
|
|
671
631
|
temp_files_count = (
|
|
@@ -676,7 +636,7 @@ def _check_resource_cleanup(status_info: dict[str, t.Any], context: t.Any) -> li
|
|
|
676
636
|
|
|
677
637
|
if temp_files_count > 50:
|
|
678
638
|
context.safe_print(
|
|
679
|
-
f"🗑️ Found {temp_files_count} temporary files
|
|
639
|
+
f"🗑️ Found {temp_files_count} temporary files-cleanup recommended",
|
|
680
640
|
)
|
|
681
641
|
cleanup_performed.append("temp_files_flagged")
|
|
682
642
|
|
|
@@ -684,7 +644,6 @@ def _check_resource_cleanup(status_info: dict[str, t.Any], context: t.Any) -> li
|
|
|
684
644
|
|
|
685
645
|
|
|
686
646
|
def _check_service_health(status_info: dict[str, t.Any], context: t.Any) -> None:
|
|
687
|
-
"""Check health of required services."""
|
|
688
647
|
services = status_info.get("services", {})
|
|
689
648
|
mcp_running = services.get("mcp_server", {}).get("running", False)
|
|
690
649
|
websocket_running = services.get("websocket_server", {}).get("running", False)
|
|
@@ -697,7 +656,6 @@ def _check_service_health(status_info: dict[str, t.Any], context: t.Any) -> None
|
|
|
697
656
|
|
|
698
657
|
|
|
699
658
|
def _handle_status_exception(error: Exception, context: t.Any) -> dict[str, t.Any]:
|
|
700
|
-
"""Handle status check exceptions."""
|
|
701
659
|
context.safe_print(f"⚠️ Status check encountered error: {error}")
|
|
702
660
|
return {
|
|
703
661
|
"should_abort": False,
|
|
@@ -708,7 +666,6 @@ def _handle_status_exception(error: Exception, context: t.Any) -> dict[str, t.An
|
|
|
708
666
|
|
|
709
667
|
|
|
710
668
|
async def _cleanup_stale_jobs(context: t.Any) -> None:
|
|
711
|
-
"""Clean up stale job files with unknown IDs or stuck in processing state."""
|
|
712
669
|
if not context.progress_dir.exists():
|
|
713
670
|
return
|
|
714
671
|
|
|
@@ -722,15 +679,14 @@ async def _cleanup_stale_jobs(context: t.Any) -> None:
|
|
|
722
679
|
|
|
723
680
|
progress_data = json.loads(progress_file.read_text())
|
|
724
681
|
|
|
725
|
-
# Check if job is stale (older than 30 minutes and stuck)
|
|
726
682
|
last_update = progress_data.get("updated_at", 0)
|
|
727
683
|
age_minutes = (current_time - last_update) / 60
|
|
728
684
|
|
|
729
685
|
is_stale = (
|
|
730
|
-
age_minutes > 30
|
|
731
|
-
or progress_data.get("job_id") == "unknown"
|
|
686
|
+
age_minutes > 30
|
|
687
|
+
or progress_data.get("job_id") == "unknown"
|
|
732
688
|
or "analyzing_failures: processing"
|
|
733
|
-
in progress_data.get("status", "")
|
|
689
|
+
in progress_data.get("status", "")
|
|
734
690
|
)
|
|
735
691
|
|
|
736
692
|
if is_stale:
|
|
@@ -738,7 +694,6 @@ async def _cleanup_stale_jobs(context: t.Any) -> None:
|
|
|
738
694
|
cleaned_count += 1
|
|
739
695
|
|
|
740
696
|
except (json.JSONDecodeError, OSError):
|
|
741
|
-
# Clean up malformed files
|
|
742
697
|
with suppress(OSError):
|
|
743
698
|
progress_file.unlink()
|
|
744
699
|
cleaned_count += 1
|
|
@@ -750,15 +705,6 @@ async def _cleanup_stale_jobs(context: t.Any) -> None:
|
|
|
750
705
|
def _register_init_crackerjack_tool(mcp_app: t.Any) -> None:
|
|
751
706
|
@mcp_app.tool()
|
|
752
707
|
async def init_crackerjack(args: str = "", kwargs: str = "{}") -> str:
|
|
753
|
-
"""Initialize or update crackerjack configuration in current project.
|
|
754
|
-
|
|
755
|
-
Args:
|
|
756
|
-
args: Optional target path (defaults to current directory)
|
|
757
|
-
kwargs: JSON string with options like {"force": true}
|
|
758
|
-
|
|
759
|
-
Returns:
|
|
760
|
-
JSON string with initialization results
|
|
761
|
-
"""
|
|
762
708
|
context = get_context()
|
|
763
709
|
if not context:
|
|
764
710
|
return _create_init_error_response("Server context not available")
|
|
@@ -775,12 +721,10 @@ def _register_init_crackerjack_tool(mcp_app: t.Any) -> None:
|
|
|
775
721
|
|
|
776
722
|
|
|
777
723
|
def _create_init_error_response(message: str) -> str:
|
|
778
|
-
"""Create standardized error response for initialization."""
|
|
779
724
|
return json.dumps({"error": message, "success": False}, indent=2)
|
|
780
725
|
|
|
781
726
|
|
|
782
727
|
def _parse_init_arguments(args: str, kwargs: str) -> tuple[t.Any, bool, str | None]:
|
|
783
|
-
"""Parse and validate initialization arguments."""
|
|
784
728
|
from pathlib import Path
|
|
785
729
|
|
|
786
730
|
target_path = args.strip() or None
|
|
@@ -792,13 +736,11 @@ def _parse_init_arguments(args: str, kwargs: str) -> tuple[t.Any, bool, str | No
|
|
|
792
736
|
|
|
793
737
|
force = extra_kwargs.get("force", False)
|
|
794
738
|
|
|
795
|
-
# Determine target path
|
|
796
739
|
if target_path:
|
|
797
740
|
target_path = Path(target_path).resolve()
|
|
798
741
|
else:
|
|
799
742
|
target_path = Path.cwd()
|
|
800
743
|
|
|
801
|
-
# Validate target path exists
|
|
802
744
|
if not target_path.exists():
|
|
803
745
|
return (
|
|
804
746
|
None,
|
|
@@ -812,15 +754,13 @@ def _parse_init_arguments(args: str, kwargs: str) -> tuple[t.Any, bool, str | No
|
|
|
812
754
|
def _execute_initialization(
|
|
813
755
|
context: t.Any, target_path: t.Any, force: bool
|
|
814
756
|
) -> dict[str, t.Any]:
|
|
815
|
-
"""Execute the initialization process."""
|
|
816
757
|
from crackerjack.services.filesystem import FileSystemService
|
|
817
758
|
from crackerjack.services.git import GitService
|
|
818
759
|
from crackerjack.services.initialization import InitializationService
|
|
819
760
|
|
|
820
|
-
# Initialize services
|
|
821
761
|
filesystem = FileSystemService()
|
|
822
762
|
git_service = GitService(context.console, context.config.project_path)
|
|
823
|
-
|
|
763
|
+
|
|
824
764
|
return InitializationService(
|
|
825
765
|
context.console, filesystem, git_service, context.config.project_path
|
|
826
766
|
).initialize_project(target_path=target_path, force=force)
|
|
@@ -829,7 +769,6 @@ def _execute_initialization(
|
|
|
829
769
|
def _create_init_success_response(
|
|
830
770
|
results: dict[str, t.Any], target_path: t.Any, force: bool
|
|
831
771
|
) -> str:
|
|
832
|
-
"""Create success response with summary information."""
|
|
833
772
|
results["command"] = "init_crackerjack"
|
|
834
773
|
results["target_path"] = str(target_path)
|
|
835
774
|
results["force"] = force
|
|
@@ -837,7 +776,6 @@ def _create_init_success_response(
|
|
|
837
776
|
|
|
838
777
|
|
|
839
778
|
def _create_init_exception_response(error: Exception, target_path: t.Any) -> str:
|
|
840
|
-
"""Create exception response for initialization failures."""
|
|
841
779
|
error_result = {
|
|
842
780
|
"error": f"Initialization failed: {error}",
|
|
843
781
|
"success": False,
|
|
@@ -848,24 +786,12 @@ def _create_init_exception_response(error: Exception, target_path: t.Any) -> str
|
|
|
848
786
|
|
|
849
787
|
|
|
850
788
|
def _register_agent_suggestions_tool(mcp_app: t.Any) -> None:
|
|
851
|
-
"""Register tool for suggesting appropriate Claude Code agents."""
|
|
852
|
-
|
|
853
789
|
@mcp_app.tool()
|
|
854
790
|
async def suggest_agents(
|
|
855
791
|
task_description: str = "",
|
|
856
792
|
project_type: str = "python",
|
|
857
793
|
current_context: str = "",
|
|
858
794
|
) -> str:
|
|
859
|
-
"""Suggest appropriate Claude Code agents based on task and context.
|
|
860
|
-
|
|
861
|
-
Args:
|
|
862
|
-
task_description: Description of the task being performed
|
|
863
|
-
project_type: Type of project (python, web, etc.)
|
|
864
|
-
current_context: Current development context or issues
|
|
865
|
-
|
|
866
|
-
Returns:
|
|
867
|
-
JSON with suggested agents and usage patterns
|
|
868
|
-
"""
|
|
869
795
|
suggestions = {
|
|
870
796
|
"primary_agents": [],
|
|
871
797
|
"task_specific_agents": [],
|
|
@@ -873,7 +799,6 @@ def _register_agent_suggestions_tool(mcp_app: t.Any) -> None:
|
|
|
873
799
|
"rationale": "",
|
|
874
800
|
}
|
|
875
801
|
|
|
876
|
-
# Always recommend crackerjack-architect for Python projects
|
|
877
802
|
if project_type.lower() == "python" or "python" in task_description.lower():
|
|
878
803
|
suggestions["primary_agents"].append(
|
|
879
804
|
{
|
|
@@ -889,13 +814,12 @@ def _register_agent_suggestions_tool(mcp_app: t.Any) -> None:
|
|
|
889
814
|
{
|
|
890
815
|
"name": "python-pro",
|
|
891
816
|
"emoji": "🐍",
|
|
892
|
-
"description": "Modern Python development with type hints, async/await patterns, and clean architecture",
|
|
817
|
+
"description": "Modern Python development with type hints, async / await patterns, and clean architecture",
|
|
893
818
|
"usage": "Use for implementing Python code with best practices",
|
|
894
819
|
"priority": "HIGH",
|
|
895
820
|
}
|
|
896
821
|
)
|
|
897
822
|
|
|
898
|
-
# Task-specific agent suggestions
|
|
899
823
|
task_lower = task_description.lower()
|
|
900
824
|
context_lower = current_context.lower()
|
|
901
825
|
|
|
@@ -905,7 +829,7 @@ def _register_agent_suggestions_tool(mcp_app: t.Any) -> None:
|
|
|
905
829
|
):
|
|
906
830
|
suggestions["task_specific_agents"].append(
|
|
907
831
|
{
|
|
908
|
-
"name": "crackerjack-test-specialist",
|
|
832
|
+
"name": "crackerjack - test-specialist",
|
|
909
833
|
"emoji": "🧪",
|
|
910
834
|
"description": "Advanced testing specialist for complex scenarios and coverage optimization",
|
|
911
835
|
"usage": "Use for test creation, debugging test failures, and coverage improvements",
|
|
@@ -915,7 +839,7 @@ def _register_agent_suggestions_tool(mcp_app: t.Any) -> None:
|
|
|
915
839
|
|
|
916
840
|
suggestions["task_specific_agents"].append(
|
|
917
841
|
{
|
|
918
|
-
"name": "pytest-hypothesis-specialist",
|
|
842
|
+
"name": "pytest - hypothesis-specialist",
|
|
919
843
|
"emoji": "🧪",
|
|
920
844
|
"description": "Advanced testing patterns and property-based testing",
|
|
921
845
|
"usage": "Use for comprehensive test development and optimization",
|
|
@@ -951,22 +875,20 @@ def _register_agent_suggestions_tool(mcp_app: t.Any) -> None:
|
|
|
951
875
|
}
|
|
952
876
|
)
|
|
953
877
|
|
|
954
|
-
# Usage patterns
|
|
955
878
|
suggestions["usage_patterns"] = [
|
|
956
|
-
'Task tool with subagent_type="crackerjack-architect" for feature planning and architecture',
|
|
957
|
-
'Task tool with subagent_type="python-pro" for implementation with best practices',
|
|
958
|
-
'Task tool with subagent_type="crackerjack-test-specialist" for comprehensive testing',
|
|
959
|
-
'Task tool with subagent_type="security-auditor" for security validation',
|
|
879
|
+
'Task tool with subagent_type ="crackerjack-architect" for feature planning and architecture',
|
|
880
|
+
'Task tool with subagent_type ="python-pro" for implementation with best practices',
|
|
881
|
+
'Task tool with subagent_type ="crackerjack - test-specialist" for comprehensive testing',
|
|
882
|
+
'Task tool with subagent_type ="security-auditor" for security validation',
|
|
960
883
|
]
|
|
961
884
|
|
|
962
|
-
# Rationale
|
|
963
885
|
if "crackerjack-architect" in [
|
|
964
886
|
agent["name"] for agent in suggestions["primary_agents"]
|
|
965
887
|
]:
|
|
966
888
|
suggestions["rationale"] = (
|
|
967
889
|
"The crackerjack-architect agent is essential for this Python project as it ensures "
|
|
968
890
|
"code follows crackerjack patterns from the start, eliminating retrofitting needs. "
|
|
969
|
-
"Combined with python-pro for implementation and task-specific agents for specialized "
|
|
891
|
+
"Combined with python - pro for implementation and task-specific agents for specialized "
|
|
970
892
|
"work, this provides comprehensive development support with built-in quality assurance."
|
|
971
893
|
)
|
|
972
894
|
|
|
@@ -978,16 +900,6 @@ def _register_agent_suggestions_tool(mcp_app: t.Any) -> None:
|
|
|
978
900
|
file_patterns: str = "",
|
|
979
901
|
recent_changes: str = "",
|
|
980
902
|
) -> str:
|
|
981
|
-
"""Detect and suggest agents based on current development context.
|
|
982
|
-
|
|
983
|
-
Args:
|
|
984
|
-
error_context: Current errors or issues being faced
|
|
985
|
-
file_patterns: File types or patterns being worked on
|
|
986
|
-
recent_changes: Recent changes or commits
|
|
987
|
-
|
|
988
|
-
Returns:
|
|
989
|
-
JSON with agent recommendations based on context analysis
|
|
990
|
-
"""
|
|
991
903
|
recommendations = {
|
|
992
904
|
"urgent_agents": [],
|
|
993
905
|
"suggested_agents": [],
|
|
@@ -995,16 +907,12 @@ def _register_agent_suggestions_tool(mcp_app: t.Any) -> None:
|
|
|
995
907
|
"detection_reasoning": "",
|
|
996
908
|
}
|
|
997
909
|
|
|
998
|
-
# Add urgent agents based on error context
|
|
999
910
|
_add_urgent_agents_for_errors(recommendations, error_context)
|
|
1000
911
|
|
|
1001
|
-
# Add general suggestions for Python projects
|
|
1002
912
|
_add_python_project_suggestions(recommendations, file_patterns)
|
|
1003
913
|
|
|
1004
|
-
# Set workflow recommendations
|
|
1005
914
|
_set_workflow_recommendations(recommendations)
|
|
1006
915
|
|
|
1007
|
-
# Generate detection reasoning
|
|
1008
916
|
_generate_detection_reasoning(recommendations)
|
|
1009
917
|
|
|
1010
918
|
return json.dumps(recommendations, indent=2)
|
|
@@ -1013,16 +921,15 @@ def _register_agent_suggestions_tool(mcp_app: t.Any) -> None:
|
|
|
1013
921
|
def _add_urgent_agents_for_errors(
|
|
1014
922
|
recommendations: dict[str, t.Any], error_context: str
|
|
1015
923
|
) -> None:
|
|
1016
|
-
"""Add urgent agent recommendations based on error context."""
|
|
1017
924
|
if any(
|
|
1018
925
|
word in error_context.lower()
|
|
1019
926
|
for word in ("test fail", "coverage", "pytest", "assertion")
|
|
1020
927
|
):
|
|
1021
928
|
recommendations["urgent_agents"].append(
|
|
1022
929
|
{
|
|
1023
|
-
"agent": "crackerjack-test-specialist",
|
|
1024
|
-
"reason": "Test failures detected
|
|
1025
|
-
"action": 'Task tool with subagent_type="crackerjack-test-specialist" to analyze and fix test issues',
|
|
930
|
+
"agent": "crackerjack - test-specialist",
|
|
931
|
+
"reason": "Test failures detected-specialist needed for debugging and fixes",
|
|
932
|
+
"action": 'Task tool with subagent_type ="crackerjack - test-specialist" to analyze and fix test issues',
|
|
1026
933
|
}
|
|
1027
934
|
)
|
|
1028
935
|
|
|
@@ -1033,8 +940,8 @@ def _add_urgent_agents_for_errors(
|
|
|
1033
940
|
recommendations["urgent_agents"].append(
|
|
1034
941
|
{
|
|
1035
942
|
"agent": "security-auditor",
|
|
1036
|
-
"reason": "Security issues detected
|
|
1037
|
-
"action": 'Task tool with subagent_type="security-auditor" to review and fix security vulnerabilities',
|
|
943
|
+
"reason": "Security issues detected-immediate audit required",
|
|
944
|
+
"action": 'Task tool with subagent_type ="security-auditor" to review and fix security vulnerabilities',
|
|
1038
945
|
}
|
|
1039
946
|
)
|
|
1040
947
|
|
|
@@ -1045,8 +952,8 @@ def _add_urgent_agents_for_errors(
|
|
|
1045
952
|
recommendations["urgent_agents"].append(
|
|
1046
953
|
{
|
|
1047
954
|
"agent": "crackerjack-architect",
|
|
1048
|
-
"reason": "Complexity issues detected
|
|
1049
|
-
"action": 'Task tool with subagent_type="crackerjack-architect" to simplify and restructure code',
|
|
955
|
+
"reason": "Complexity issues detected-architectural review needed",
|
|
956
|
+
"action": 'Task tool with subagent_type ="crackerjack-architect" to simplify and restructure code',
|
|
1050
957
|
}
|
|
1051
958
|
)
|
|
1052
959
|
|
|
@@ -1054,13 +961,12 @@ def _add_urgent_agents_for_errors(
|
|
|
1054
961
|
def _add_python_project_suggestions(
|
|
1055
962
|
recommendations: dict[str, t.Any], file_patterns: str
|
|
1056
963
|
) -> None:
|
|
1057
|
-
"""Add general suggestions for Python projects."""
|
|
1058
964
|
if "python" in file_patterns.lower() or ".py" in file_patterns:
|
|
1059
965
|
recommendations["suggested_agents"].extend(
|
|
1060
966
|
[
|
|
1061
967
|
{
|
|
1062
968
|
"agent": "crackerjack-architect",
|
|
1063
|
-
"reason": "Python project detected
|
|
969
|
+
"reason": "Python project detected-ensure crackerjack compliance",
|
|
1064
970
|
"priority": "HIGH",
|
|
1065
971
|
},
|
|
1066
972
|
{
|
|
@@ -1073,23 +979,21 @@ def _add_python_project_suggestions(
|
|
|
1073
979
|
|
|
1074
980
|
|
|
1075
981
|
def _set_workflow_recommendations(recommendations: dict[str, t.Any]) -> None:
|
|
1076
|
-
"""Set workflow recommendations based on urgent agents."""
|
|
1077
982
|
if recommendations["urgent_agents"]:
|
|
1078
983
|
recommendations["workflow_recommendations"] = [
|
|
1079
984
|
"Address urgent issues first with specialized agents",
|
|
1080
|
-
"Run crackerjack quality checks after fixes: python -m crackerjack
|
|
985
|
+
"Run crackerjack quality checks after fixes: python - m crackerjack-t",
|
|
1081
986
|
"Use crackerjack-architect for ongoing compliance",
|
|
1082
987
|
]
|
|
1083
988
|
else:
|
|
1084
989
|
recommendations["workflow_recommendations"] = [
|
|
1085
990
|
"Start with crackerjack-architect for proper planning",
|
|
1086
991
|
"Use python-pro for implementation",
|
|
1087
|
-
"Run continuous quality checks: python
|
|
992
|
+
"Run continuous quality checks: python-m crackerjack",
|
|
1088
993
|
]
|
|
1089
994
|
|
|
1090
995
|
|
|
1091
996
|
def _generate_detection_reasoning(recommendations: dict[str, t.Any]) -> None:
|
|
1092
|
-
"""Generate detection reasoning based on recommendations."""
|
|
1093
997
|
recommendations["detection_reasoning"] = (
|
|
1094
998
|
f"Analysis of context revealed {len(recommendations['urgent_agents'])} urgent issues "
|
|
1095
999
|
f"and {len(recommendations['suggested_agents'])} general recommendations. "
|