crackerjack 0.37.9__py3-none-any.whl → 0.45.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.
- crackerjack/README.md +19 -0
- crackerjack/__init__.py +30 -1
- crackerjack/__main__.py +342 -1263
- crackerjack/adapters/README.md +18 -0
- crackerjack/adapters/__init__.py +27 -5
- crackerjack/adapters/_output_paths.py +167 -0
- crackerjack/adapters/_qa_adapter_base.py +309 -0
- crackerjack/adapters/_tool_adapter_base.py +706 -0
- crackerjack/adapters/ai/README.md +65 -0
- crackerjack/adapters/ai/__init__.py +5 -0
- crackerjack/adapters/ai/claude.py +853 -0
- crackerjack/adapters/complexity/README.md +53 -0
- crackerjack/adapters/complexity/__init__.py +10 -0
- crackerjack/adapters/complexity/complexipy.py +641 -0
- crackerjack/adapters/dependency/__init__.py +22 -0
- crackerjack/adapters/dependency/pip_audit.py +418 -0
- crackerjack/adapters/format/README.md +72 -0
- crackerjack/adapters/format/__init__.py +11 -0
- crackerjack/adapters/format/mdformat.py +313 -0
- crackerjack/adapters/format/ruff.py +516 -0
- crackerjack/adapters/lint/README.md +47 -0
- crackerjack/adapters/lint/__init__.py +11 -0
- crackerjack/adapters/lint/codespell.py +273 -0
- crackerjack/adapters/lsp/README.md +49 -0
- crackerjack/adapters/lsp/__init__.py +27 -0
- crackerjack/adapters/{rust_tool_manager.py → lsp/_manager.py} +3 -3
- crackerjack/adapters/{skylos_adapter.py → lsp/skylos.py} +59 -7
- crackerjack/adapters/{zuban_adapter.py → lsp/zuban.py} +3 -6
- crackerjack/adapters/refactor/README.md +59 -0
- crackerjack/adapters/refactor/__init__.py +12 -0
- crackerjack/adapters/refactor/creosote.py +318 -0
- crackerjack/adapters/refactor/refurb.py +406 -0
- crackerjack/adapters/refactor/skylos.py +494 -0
- crackerjack/adapters/sast/README.md +132 -0
- crackerjack/adapters/sast/__init__.py +32 -0
- crackerjack/adapters/sast/_base.py +201 -0
- crackerjack/adapters/sast/bandit.py +423 -0
- crackerjack/adapters/sast/pyscn.py +405 -0
- crackerjack/adapters/sast/semgrep.py +241 -0
- crackerjack/adapters/security/README.md +111 -0
- crackerjack/adapters/security/__init__.py +17 -0
- crackerjack/adapters/security/gitleaks.py +339 -0
- crackerjack/adapters/type/README.md +52 -0
- crackerjack/adapters/type/__init__.py +12 -0
- crackerjack/adapters/type/pyrefly.py +402 -0
- crackerjack/adapters/type/ty.py +402 -0
- crackerjack/adapters/type/zuban.py +522 -0
- crackerjack/adapters/utility/README.md +51 -0
- crackerjack/adapters/utility/__init__.py +10 -0
- crackerjack/adapters/utility/checks.py +884 -0
- crackerjack/agents/README.md +264 -0
- crackerjack/agents/__init__.py +40 -12
- crackerjack/agents/base.py +1 -0
- crackerjack/agents/claude_code_bridge.py +641 -0
- crackerjack/agents/coordinator.py +49 -53
- crackerjack/agents/dry_agent.py +187 -3
- crackerjack/agents/enhanced_coordinator.py +279 -0
- crackerjack/agents/enhanced_proactive_agent.py +185 -0
- crackerjack/agents/error_middleware.py +53 -0
- crackerjack/agents/formatting_agent.py +6 -8
- crackerjack/agents/helpers/__init__.py +9 -0
- crackerjack/agents/helpers/performance/__init__.py +22 -0
- crackerjack/agents/helpers/performance/performance_ast_analyzer.py +357 -0
- crackerjack/agents/helpers/performance/performance_pattern_detector.py +909 -0
- crackerjack/agents/helpers/performance/performance_recommender.py +572 -0
- crackerjack/agents/helpers/refactoring/__init__.py +22 -0
- crackerjack/agents/helpers/refactoring/code_transformer.py +536 -0
- crackerjack/agents/helpers/refactoring/complexity_analyzer.py +344 -0
- crackerjack/agents/helpers/refactoring/dead_code_detector.py +437 -0
- crackerjack/agents/helpers/test_creation/__init__.py +19 -0
- crackerjack/agents/helpers/test_creation/test_ast_analyzer.py +216 -0
- crackerjack/agents/helpers/test_creation/test_coverage_analyzer.py +643 -0
- crackerjack/agents/helpers/test_creation/test_template_generator.py +1031 -0
- crackerjack/agents/performance_agent.py +121 -1152
- crackerjack/agents/refactoring_agent.py +156 -655
- crackerjack/agents/semantic_agent.py +479 -0
- crackerjack/agents/semantic_helpers.py +356 -0
- crackerjack/agents/test_creation_agent.py +19 -1605
- crackerjack/api.py +5 -7
- crackerjack/cli/README.md +394 -0
- crackerjack/cli/__init__.py +1 -1
- crackerjack/cli/cache_handlers.py +23 -18
- crackerjack/cli/cache_handlers_enhanced.py +1 -4
- crackerjack/cli/facade.py +70 -8
- crackerjack/cli/formatting.py +13 -0
- crackerjack/cli/handlers/__init__.py +85 -0
- crackerjack/cli/handlers/advanced.py +103 -0
- crackerjack/cli/handlers/ai_features.py +62 -0
- crackerjack/cli/handlers/analytics.py +479 -0
- crackerjack/cli/handlers/changelog.py +271 -0
- crackerjack/cli/handlers/config_handlers.py +16 -0
- crackerjack/cli/handlers/coverage.py +84 -0
- crackerjack/cli/handlers/documentation.py +280 -0
- crackerjack/cli/handlers/main_handlers.py +497 -0
- crackerjack/cli/handlers/monitoring.py +371 -0
- crackerjack/cli/handlers.py +249 -49
- crackerjack/cli/interactive.py +8 -5
- crackerjack/cli/options.py +203 -110
- crackerjack/cli/semantic_handlers.py +292 -0
- crackerjack/cli/version.py +19 -0
- crackerjack/code_cleaner.py +60 -24
- crackerjack/config/README.md +472 -0
- crackerjack/config/__init__.py +256 -0
- crackerjack/config/global_lock_config.py +191 -54
- crackerjack/config/hooks.py +188 -16
- crackerjack/config/loader.py +239 -0
- crackerjack/config/settings.py +141 -0
- crackerjack/config/tool_commands.py +331 -0
- crackerjack/core/README.md +393 -0
- crackerjack/core/async_workflow_orchestrator.py +79 -53
- crackerjack/core/autofix_coordinator.py +22 -9
- crackerjack/core/container.py +10 -9
- crackerjack/core/enhanced_container.py +9 -9
- crackerjack/core/performance.py +1 -1
- crackerjack/core/performance_monitor.py +5 -3
- crackerjack/core/phase_coordinator.py +1018 -634
- crackerjack/core/proactive_workflow.py +3 -3
- crackerjack/core/retry.py +275 -0
- crackerjack/core/service_watchdog.py +167 -23
- crackerjack/core/session_coordinator.py +187 -382
- crackerjack/core/timeout_manager.py +161 -44
- crackerjack/core/workflow/__init__.py +21 -0
- crackerjack/core/workflow/workflow_ai_coordinator.py +863 -0
- crackerjack/core/workflow/workflow_event_orchestrator.py +1107 -0
- crackerjack/core/workflow/workflow_issue_parser.py +714 -0
- crackerjack/core/workflow/workflow_phase_executor.py +1158 -0
- crackerjack/core/workflow/workflow_security_gates.py +400 -0
- crackerjack/core/workflow_orchestrator.py +1247 -953
- crackerjack/data/README.md +11 -0
- crackerjack/data/__init__.py +8 -0
- crackerjack/data/models.py +79 -0
- crackerjack/data/repository.py +210 -0
- crackerjack/decorators/README.md +180 -0
- crackerjack/decorators/__init__.py +35 -0
- crackerjack/decorators/error_handling.py +649 -0
- crackerjack/decorators/error_handling_decorators.py +334 -0
- crackerjack/decorators/helpers.py +58 -0
- crackerjack/decorators/patterns.py +281 -0
- crackerjack/decorators/utils.py +58 -0
- crackerjack/docs/README.md +11 -0
- crackerjack/docs/generated/api/CLI_REFERENCE.md +1 -1
- crackerjack/documentation/README.md +11 -0
- crackerjack/documentation/ai_templates.py +1 -1
- crackerjack/documentation/dual_output_generator.py +11 -9
- crackerjack/documentation/reference_generator.py +104 -59
- crackerjack/dynamic_config.py +52 -61
- crackerjack/errors.py +1 -1
- crackerjack/events/README.md +11 -0
- crackerjack/events/__init__.py +16 -0
- crackerjack/events/telemetry.py +175 -0
- crackerjack/events/workflow_bus.py +346 -0
- crackerjack/exceptions/README.md +301 -0
- crackerjack/exceptions/__init__.py +5 -0
- crackerjack/exceptions/config.py +4 -0
- crackerjack/exceptions/tool_execution_error.py +245 -0
- crackerjack/executors/README.md +591 -0
- crackerjack/executors/__init__.py +2 -0
- crackerjack/executors/async_hook_executor.py +539 -77
- crackerjack/executors/cached_hook_executor.py +3 -3
- crackerjack/executors/hook_executor.py +967 -102
- crackerjack/executors/hook_lock_manager.py +31 -22
- crackerjack/executors/individual_hook_executor.py +66 -32
- crackerjack/executors/lsp_aware_hook_executor.py +136 -57
- crackerjack/executors/progress_hook_executor.py +282 -0
- crackerjack/executors/tool_proxy.py +23 -7
- crackerjack/hooks/README.md +485 -0
- crackerjack/hooks/lsp_hook.py +8 -9
- crackerjack/intelligence/README.md +557 -0
- crackerjack/interactive.py +37 -10
- crackerjack/managers/README.md +369 -0
- crackerjack/managers/async_hook_manager.py +41 -57
- crackerjack/managers/hook_manager.py +449 -79
- crackerjack/managers/publish_manager.py +81 -36
- crackerjack/managers/test_command_builder.py +290 -12
- crackerjack/managers/test_executor.py +93 -8
- crackerjack/managers/test_manager.py +1082 -75
- crackerjack/managers/test_progress.py +118 -26
- crackerjack/mcp/README.md +374 -0
- crackerjack/mcp/cache.py +25 -2
- crackerjack/mcp/client_runner.py +35 -18
- crackerjack/mcp/context.py +9 -9
- crackerjack/mcp/dashboard.py +24 -8
- crackerjack/mcp/enhanced_progress_monitor.py +34 -23
- crackerjack/mcp/file_monitor.py +27 -6
- crackerjack/mcp/progress_components.py +45 -34
- crackerjack/mcp/progress_monitor.py +6 -9
- crackerjack/mcp/rate_limiter.py +11 -7
- crackerjack/mcp/server.py +2 -0
- crackerjack/mcp/server_core.py +187 -55
- crackerjack/mcp/service_watchdog.py +12 -9
- crackerjack/mcp/task_manager.py +2 -2
- crackerjack/mcp/tools/README.md +27 -0
- crackerjack/mcp/tools/__init__.py +2 -0
- crackerjack/mcp/tools/core_tools.py +75 -52
- crackerjack/mcp/tools/execution_tools.py +87 -31
- crackerjack/mcp/tools/intelligence_tools.py +2 -2
- crackerjack/mcp/tools/proactive_tools.py +1 -1
- crackerjack/mcp/tools/semantic_tools.py +584 -0
- crackerjack/mcp/tools/utility_tools.py +180 -132
- crackerjack/mcp/tools/workflow_executor.py +87 -46
- crackerjack/mcp/websocket/README.md +31 -0
- crackerjack/mcp/websocket/app.py +11 -1
- crackerjack/mcp/websocket/event_bridge.py +188 -0
- crackerjack/mcp/websocket/jobs.py +27 -4
- crackerjack/mcp/websocket/monitoring/__init__.py +25 -0
- crackerjack/mcp/websocket/monitoring/api/__init__.py +19 -0
- crackerjack/mcp/websocket/monitoring/api/dependencies.py +141 -0
- crackerjack/mcp/websocket/monitoring/api/heatmap.py +154 -0
- crackerjack/mcp/websocket/monitoring/api/intelligence.py +199 -0
- crackerjack/mcp/websocket/monitoring/api/metrics.py +203 -0
- crackerjack/mcp/websocket/monitoring/api/telemetry.py +101 -0
- crackerjack/mcp/websocket/monitoring/dashboard.py +18 -0
- crackerjack/mcp/websocket/monitoring/factory.py +109 -0
- crackerjack/mcp/websocket/monitoring/filters.py +10 -0
- crackerjack/mcp/websocket/monitoring/metrics.py +64 -0
- crackerjack/mcp/websocket/monitoring/models.py +90 -0
- crackerjack/mcp/websocket/monitoring/utils.py +171 -0
- crackerjack/mcp/websocket/monitoring/websocket_manager.py +78 -0
- crackerjack/mcp/websocket/monitoring/websockets/__init__.py +17 -0
- crackerjack/mcp/websocket/monitoring/websockets/dependencies.py +126 -0
- crackerjack/mcp/websocket/monitoring/websockets/heatmap.py +176 -0
- crackerjack/mcp/websocket/monitoring/websockets/intelligence.py +291 -0
- crackerjack/mcp/websocket/monitoring/websockets/metrics.py +291 -0
- crackerjack/mcp/websocket/monitoring_endpoints.py +16 -2930
- crackerjack/mcp/websocket/server.py +1 -3
- crackerjack/mcp/websocket/websocket_handler.py +107 -6
- crackerjack/models/README.md +308 -0
- crackerjack/models/__init__.py +10 -1
- crackerjack/models/config.py +639 -22
- crackerjack/models/config_adapter.py +6 -6
- crackerjack/models/protocols.py +1167 -23
- crackerjack/models/pydantic_models.py +320 -0
- crackerjack/models/qa_config.py +145 -0
- crackerjack/models/qa_results.py +134 -0
- crackerjack/models/results.py +35 -0
- crackerjack/models/semantic_models.py +258 -0
- crackerjack/models/task.py +19 -3
- crackerjack/models/test_models.py +60 -0
- crackerjack/monitoring/README.md +11 -0
- crackerjack/monitoring/ai_agent_watchdog.py +5 -4
- crackerjack/monitoring/metrics_collector.py +4 -3
- crackerjack/monitoring/regression_prevention.py +4 -3
- crackerjack/monitoring/websocket_server.py +4 -241
- crackerjack/orchestration/README.md +340 -0
- crackerjack/orchestration/__init__.py +43 -0
- crackerjack/orchestration/advanced_orchestrator.py +20 -67
- crackerjack/orchestration/cache/README.md +312 -0
- crackerjack/orchestration/cache/__init__.py +37 -0
- crackerjack/orchestration/cache/memory_cache.py +338 -0
- crackerjack/orchestration/cache/tool_proxy_cache.py +340 -0
- crackerjack/orchestration/config.py +297 -0
- crackerjack/orchestration/coverage_improvement.py +13 -6
- crackerjack/orchestration/execution_strategies.py +6 -6
- crackerjack/orchestration/hook_orchestrator.py +1398 -0
- crackerjack/orchestration/strategies/README.md +401 -0
- crackerjack/orchestration/strategies/__init__.py +39 -0
- crackerjack/orchestration/strategies/adaptive_strategy.py +630 -0
- crackerjack/orchestration/strategies/parallel_strategy.py +237 -0
- crackerjack/orchestration/strategies/sequential_strategy.py +299 -0
- crackerjack/orchestration/test_progress_streamer.py +1 -1
- crackerjack/plugins/README.md +11 -0
- crackerjack/plugins/hooks.py +3 -2
- crackerjack/plugins/loader.py +3 -3
- crackerjack/plugins/managers.py +1 -1
- crackerjack/py313.py +191 -0
- crackerjack/security/README.md +11 -0
- crackerjack/services/README.md +374 -0
- crackerjack/services/__init__.py +8 -21
- crackerjack/services/ai/README.md +295 -0
- crackerjack/services/ai/__init__.py +7 -0
- crackerjack/services/ai/advanced_optimizer.py +878 -0
- crackerjack/services/{contextual_ai_assistant.py → ai/contextual_ai_assistant.py} +5 -3
- crackerjack/services/ai/embeddings.py +444 -0
- crackerjack/services/ai/intelligent_commit.py +328 -0
- crackerjack/services/ai/predictive_analytics.py +510 -0
- crackerjack/services/api_extractor.py +5 -3
- crackerjack/services/bounded_status_operations.py +45 -5
- crackerjack/services/cache.py +249 -318
- crackerjack/services/changelog_automation.py +7 -3
- crackerjack/services/command_execution_service.py +305 -0
- crackerjack/services/config_integrity.py +83 -39
- crackerjack/services/config_merge.py +9 -6
- crackerjack/services/config_service.py +198 -0
- crackerjack/services/config_template.py +13 -26
- crackerjack/services/coverage_badge_service.py +6 -4
- crackerjack/services/coverage_ratchet.py +53 -27
- crackerjack/services/debug.py +18 -7
- crackerjack/services/dependency_analyzer.py +4 -4
- crackerjack/services/dependency_monitor.py +13 -13
- crackerjack/services/documentation_generator.py +4 -2
- crackerjack/services/documentation_service.py +62 -33
- crackerjack/services/enhanced_filesystem.py +81 -27
- crackerjack/services/enterprise_optimizer.py +1 -1
- crackerjack/services/error_pattern_analyzer.py +10 -10
- crackerjack/services/file_filter.py +221 -0
- crackerjack/services/file_hasher.py +5 -7
- crackerjack/services/file_io_service.py +361 -0
- crackerjack/services/file_modifier.py +615 -0
- crackerjack/services/filesystem.py +80 -109
- crackerjack/services/git.py +99 -5
- crackerjack/services/health_metrics.py +4 -6
- crackerjack/services/heatmap_generator.py +12 -3
- crackerjack/services/incremental_executor.py +380 -0
- crackerjack/services/initialization.py +101 -49
- crackerjack/services/log_manager.py +2 -2
- crackerjack/services/logging.py +120 -68
- crackerjack/services/lsp_client.py +12 -12
- crackerjack/services/memory_optimizer.py +27 -22
- crackerjack/services/monitoring/README.md +30 -0
- crackerjack/services/monitoring/__init__.py +9 -0
- crackerjack/services/monitoring/dependency_monitor.py +678 -0
- crackerjack/services/monitoring/error_pattern_analyzer.py +676 -0
- crackerjack/services/monitoring/health_metrics.py +716 -0
- crackerjack/services/monitoring/metrics.py +587 -0
- crackerjack/services/{performance_benchmarks.py → monitoring/performance_benchmarks.py} +100 -14
- crackerjack/services/{performance_cache.py → monitoring/performance_cache.py} +21 -15
- crackerjack/services/{performance_monitor.py → monitoring/performance_monitor.py} +10 -6
- crackerjack/services/parallel_executor.py +166 -55
- crackerjack/services/patterns/__init__.py +142 -0
- crackerjack/services/patterns/agents.py +107 -0
- crackerjack/services/patterns/code/__init__.py +15 -0
- crackerjack/services/patterns/code/detection.py +118 -0
- crackerjack/services/patterns/code/imports.py +107 -0
- crackerjack/services/patterns/code/paths.py +159 -0
- crackerjack/services/patterns/code/performance.py +119 -0
- crackerjack/services/patterns/code/replacement.py +36 -0
- crackerjack/services/patterns/core.py +212 -0
- crackerjack/services/patterns/documentation/__init__.py +14 -0
- crackerjack/services/patterns/documentation/badges_markdown.py +96 -0
- crackerjack/services/patterns/documentation/comments_blocks.py +83 -0
- crackerjack/services/patterns/documentation/docstrings.py +89 -0
- crackerjack/services/patterns/formatting.py +226 -0
- crackerjack/services/patterns/operations.py +339 -0
- crackerjack/services/patterns/security/__init__.py +23 -0
- crackerjack/services/patterns/security/code_injection.py +122 -0
- crackerjack/services/patterns/security/credentials.py +190 -0
- crackerjack/services/patterns/security/path_traversal.py +221 -0
- crackerjack/services/patterns/security/unsafe_operations.py +216 -0
- crackerjack/services/patterns/templates.py +62 -0
- crackerjack/services/patterns/testing/__init__.py +18 -0
- crackerjack/services/patterns/testing/error_patterns.py +107 -0
- crackerjack/services/patterns/testing/pytest_output.py +126 -0
- crackerjack/services/patterns/tool_output/__init__.py +16 -0
- crackerjack/services/patterns/tool_output/bandit.py +72 -0
- crackerjack/services/patterns/tool_output/other.py +97 -0
- crackerjack/services/patterns/tool_output/pyright.py +67 -0
- crackerjack/services/patterns/tool_output/ruff.py +44 -0
- crackerjack/services/patterns/url_sanitization.py +114 -0
- crackerjack/services/patterns/utilities.py +42 -0
- crackerjack/services/patterns/utils.py +339 -0
- crackerjack/services/patterns/validation.py +46 -0
- crackerjack/services/patterns/versioning.py +62 -0
- crackerjack/services/predictive_analytics.py +21 -8
- crackerjack/services/profiler.py +280 -0
- crackerjack/services/quality/README.md +415 -0
- crackerjack/services/quality/__init__.py +11 -0
- crackerjack/services/quality/anomaly_detector.py +392 -0
- crackerjack/services/quality/pattern_cache.py +333 -0
- crackerjack/services/quality/pattern_detector.py +479 -0
- crackerjack/services/quality/qa_orchestrator.py +491 -0
- crackerjack/services/{quality_baseline.py → quality/quality_baseline.py} +163 -2
- crackerjack/services/{quality_baseline_enhanced.py → quality/quality_baseline_enhanced.py} +4 -1
- crackerjack/services/{quality_intelligence.py → quality/quality_intelligence.py} +180 -16
- crackerjack/services/regex_patterns.py +58 -2987
- crackerjack/services/regex_utils.py +55 -29
- crackerjack/services/secure_status_formatter.py +42 -15
- crackerjack/services/secure_subprocess.py +35 -2
- crackerjack/services/security.py +16 -8
- crackerjack/services/server_manager.py +40 -51
- crackerjack/services/smart_scheduling.py +46 -6
- crackerjack/services/status_authentication.py +3 -3
- crackerjack/services/thread_safe_status_collector.py +1 -0
- crackerjack/services/tool_filter.py +368 -0
- crackerjack/services/tool_version_service.py +9 -5
- crackerjack/services/unified_config.py +43 -351
- crackerjack/services/vector_store.py +689 -0
- crackerjack/services/version_analyzer.py +6 -4
- crackerjack/services/version_checker.py +14 -8
- crackerjack/services/zuban_lsp_service.py +5 -4
- crackerjack/slash_commands/README.md +11 -0
- crackerjack/slash_commands/init.md +2 -12
- crackerjack/slash_commands/run.md +84 -50
- crackerjack/tools/README.md +11 -0
- crackerjack/tools/__init__.py +30 -0
- crackerjack/tools/_git_utils.py +105 -0
- crackerjack/tools/check_added_large_files.py +139 -0
- crackerjack/tools/check_ast.py +105 -0
- crackerjack/tools/check_json.py +103 -0
- crackerjack/tools/check_jsonschema.py +297 -0
- crackerjack/tools/check_toml.py +103 -0
- crackerjack/tools/check_yaml.py +110 -0
- crackerjack/tools/codespell_wrapper.py +72 -0
- crackerjack/tools/end_of_file_fixer.py +202 -0
- crackerjack/tools/format_json.py +128 -0
- crackerjack/tools/mdformat_wrapper.py +114 -0
- crackerjack/tools/trailing_whitespace.py +198 -0
- crackerjack/tools/validate_regex_patterns.py +7 -3
- crackerjack/ui/README.md +11 -0
- crackerjack/ui/dashboard_renderer.py +28 -0
- crackerjack/ui/templates/README.md +11 -0
- crackerjack/utils/console_utils.py +13 -0
- crackerjack/utils/dependency_guard.py +230 -0
- crackerjack/utils/retry_utils.py +275 -0
- crackerjack/workflows/README.md +590 -0
- crackerjack/workflows/__init__.py +46 -0
- crackerjack/workflows/actions.py +811 -0
- crackerjack/workflows/auto_fix.py +444 -0
- crackerjack/workflows/container_builder.py +499 -0
- crackerjack/workflows/definitions.py +443 -0
- crackerjack/workflows/engine.py +177 -0
- crackerjack/workflows/event_bridge.py +242 -0
- {crackerjack-0.37.9.dist-info → crackerjack-0.45.2.dist-info}/METADATA +678 -98
- crackerjack-0.45.2.dist-info/RECORD +478 -0
- {crackerjack-0.37.9.dist-info → crackerjack-0.45.2.dist-info}/WHEEL +1 -1
- crackerjack/managers/test_manager_backup.py +0 -1075
- crackerjack/mcp/tools/execution_tools_backup.py +0 -1011
- crackerjack/mixins/__init__.py +0 -3
- crackerjack/mixins/error_handling.py +0 -145
- crackerjack/services/config.py +0 -358
- crackerjack/ui/server_panels.py +0 -125
- crackerjack-0.37.9.dist-info/RECORD +0 -231
- /crackerjack/adapters/{rust_tool_adapter.py → lsp/_base.py} +0 -0
- /crackerjack/adapters/{lsp_client.py → lsp/_client.py} +0 -0
- {crackerjack-0.37.9.dist-info → crackerjack-0.45.2.dist-info}/entry_points.txt +0 -0
- {crackerjack-0.37.9.dist-info → crackerjack-0.45.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,1011 +0,0 @@
|
|
|
1
|
-
import asyncio
|
|
2
|
-
import json
|
|
3
|
-
import time
|
|
4
|
-
import typing as t
|
|
5
|
-
import uuid
|
|
6
|
-
from contextlib import suppress
|
|
7
|
-
|
|
8
|
-
from crackerjack.mcp.context import get_context
|
|
9
|
-
|
|
10
|
-
from .progress_tools import _update_progress
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
def register_execution_tools(mcp_app: t.Any) -> None:
|
|
14
|
-
_register_execute_crackerjack_tool(mcp_app)
|
|
15
|
-
_register_smart_error_analysis_tool(mcp_app)
|
|
16
|
-
_register_init_crackerjack_tool(mcp_app)
|
|
17
|
-
_register_agent_suggestions_tool(mcp_app)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
def _register_execute_crackerjack_tool(mcp_app: t.Any) -> None:
|
|
21
|
-
@mcp_app.tool()
|
|
22
|
-
async def execute_crackerjack(args: str, kwargs: str) -> str:
|
|
23
|
-
context = get_context()
|
|
24
|
-
validation_error = await _validate_context_and_rate_limit(context)
|
|
25
|
-
if validation_error:
|
|
26
|
-
return validation_error
|
|
27
|
-
|
|
28
|
-
job_id = str(uuid.uuid4())[:8]
|
|
29
|
-
|
|
30
|
-
kwargs_result = _parse_kwargs(kwargs)
|
|
31
|
-
if "error" in kwargs_result:
|
|
32
|
-
return json.dumps(kwargs_result)
|
|
33
|
-
|
|
34
|
-
extra_kwargs = kwargs_result["kwargs"]
|
|
35
|
-
|
|
36
|
-
try:
|
|
37
|
-
result = await _execute_crackerjack_sync(
|
|
38
|
-
job_id,
|
|
39
|
-
args,
|
|
40
|
-
extra_kwargs,
|
|
41
|
-
context,
|
|
42
|
-
)
|
|
43
|
-
return json.dumps(result, indent=2)
|
|
44
|
-
except Exception as e:
|
|
45
|
-
return json.dumps(
|
|
46
|
-
{
|
|
47
|
-
"job_id": job_id,
|
|
48
|
-
"status": "failed",
|
|
49
|
-
"error": f"Execution failed: {e}",
|
|
50
|
-
},
|
|
51
|
-
indent=2,
|
|
52
|
-
)
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
def _register_smart_error_analysis_tool(mcp_app: t.Any) -> None:
|
|
56
|
-
@mcp_app.tool()
|
|
57
|
-
async def smart_error_analysis(use_cache: bool = True) -> str:
|
|
58
|
-
context = get_context()
|
|
59
|
-
if not context:
|
|
60
|
-
return '{"error": "Server context not available"}'
|
|
61
|
-
|
|
62
|
-
try:
|
|
63
|
-
from crackerjack.services.debug import get_ai_agent_debugger
|
|
64
|
-
|
|
65
|
-
get_ai_agent_debugger()
|
|
66
|
-
|
|
67
|
-
cached_patterns = _get_cached_patterns(context, use_cache)
|
|
68
|
-
analysis = _build_error_analysis(use_cache, cached_patterns)
|
|
69
|
-
|
|
70
|
-
return json.dumps(analysis, indent=2)
|
|
71
|
-
|
|
72
|
-
except Exception as e:
|
|
73
|
-
return f'{{"error": "Smart error analysis failed: {e}"}}'
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
async def _validate_context_and_rate_limit(context: t.Any) -> str | None:
|
|
77
|
-
if not context:
|
|
78
|
-
return '{"error": "Server context not available"}'
|
|
79
|
-
|
|
80
|
-
if context.rate_limiter:
|
|
81
|
-
allowed, details = await context.rate_limiter.check_request_allowed("default")
|
|
82
|
-
if not allowed:
|
|
83
|
-
return f'{{"error": "Rate limit exceeded: {details.get("reason", "unknown")}", "success": false}}'
|
|
84
|
-
|
|
85
|
-
return None
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
def _handle_task_exception(job_id: str, task: asyncio.Task[t.Any]) -> None:
|
|
89
|
-
import tempfile
|
|
90
|
-
from pathlib import Path
|
|
91
|
-
|
|
92
|
-
try:
|
|
93
|
-
exception = task.exception()
|
|
94
|
-
if exception:
|
|
95
|
-
debug_file = (
|
|
96
|
-
Path(tempfile.gettempdir()) / f"crackerjack - task-error -{job_id}.log"
|
|
97
|
-
)
|
|
98
|
-
with debug_file.open("w") as f:
|
|
99
|
-
f.write(
|
|
100
|
-
f"Background task {job_id} failed with exception: {exception}\n",
|
|
101
|
-
)
|
|
102
|
-
f.write(f"Exception type: {type(exception)}\n")
|
|
103
|
-
import traceback
|
|
104
|
-
|
|
105
|
-
f.write(
|
|
106
|
-
f"Traceback: \n{traceback.format_exception(type(exception), exception, exception.__traceback__)}\n",
|
|
107
|
-
)
|
|
108
|
-
except Exception as e:
|
|
109
|
-
with suppress(Exception):
|
|
110
|
-
debug_file = (
|
|
111
|
-
Path(tempfile.gettempdir())
|
|
112
|
-
/ f"crackerjack - logging-error -{job_id}.log"
|
|
113
|
-
)
|
|
114
|
-
with debug_file.open("w") as f:
|
|
115
|
-
f.write(f"Failed to log task exception: {e}\n")
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
def _parse_kwargs(kwargs: str) -> dict[str, t.Any]:
|
|
119
|
-
try:
|
|
120
|
-
return {"kwargs": json.loads(kwargs) if kwargs.strip() else {}}
|
|
121
|
-
except json.JSONDecodeError as e:
|
|
122
|
-
return {"error": f"Invalid JSON in kwargs: {e}"}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
def _get_cached_patterns(context: t.Any, use_cache: bool) -> list[t.Any]:
|
|
126
|
-
if use_cache and hasattr(context, "error_cache"):
|
|
127
|
-
return getattr(context.error_cache, "patterns", [])
|
|
128
|
-
return []
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
def _build_error_analysis(
|
|
132
|
-
use_cache: bool,
|
|
133
|
-
cached_patterns: list[t.Any],
|
|
134
|
-
) -> dict[str, t.Any]:
|
|
135
|
-
analysis = {
|
|
136
|
-
"analysis_type": "smart_error_analysis",
|
|
137
|
-
"use_cache": use_cache,
|
|
138
|
-
"cached_patterns_count": len(cached_patterns),
|
|
139
|
-
"common_patterns": [
|
|
140
|
-
{
|
|
141
|
-
"type": "import_error",
|
|
142
|
-
"frequency": "high",
|
|
143
|
-
"typical_fix": "Check import paths and dependencies",
|
|
144
|
-
},
|
|
145
|
-
{
|
|
146
|
-
"type": "type_annotation_missing",
|
|
147
|
-
"frequency": "medium",
|
|
148
|
-
"typical_fix": "Add proper type hints to functions and methods",
|
|
149
|
-
},
|
|
150
|
-
{
|
|
151
|
-
"type": "test_failure",
|
|
152
|
-
"frequency": "medium",
|
|
153
|
-
"typical_fix": "Review test expectations and implementation",
|
|
154
|
-
},
|
|
155
|
-
],
|
|
156
|
-
"recommendations": [
|
|
157
|
-
"Run fast hooks first to fix formatting issues",
|
|
158
|
-
"Execute tests to identify functional problems",
|
|
159
|
-
"Run comprehensive hooks for quality analysis",
|
|
160
|
-
],
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
if cached_patterns:
|
|
164
|
-
analysis["cached_patterns"] = cached_patterns[:5]
|
|
165
|
-
|
|
166
|
-
return analysis
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
async def _execute_crackerjack_sync(
|
|
170
|
-
job_id: str,
|
|
171
|
-
args: str,
|
|
172
|
-
kwargs: dict[str, t.Any],
|
|
173
|
-
context: t.Any,
|
|
174
|
-
) -> dict[str, t.Any]:
|
|
175
|
-
if not context:
|
|
176
|
-
return {"job_id": job_id, "status": "failed", "error": "No context available"}
|
|
177
|
-
|
|
178
|
-
max_iterations = kwargs.get("max_iterations", 10)
|
|
179
|
-
current_iteration = 1
|
|
180
|
-
|
|
181
|
-
try:
|
|
182
|
-
await _initialize_execution(job_id, max_iterations, current_iteration, context)
|
|
183
|
-
|
|
184
|
-
orchestrator, use_advanced_orchestrator = await _setup_orchestrator(
|
|
185
|
-
job_id,
|
|
186
|
-
max_iterations,
|
|
187
|
-
current_iteration,
|
|
188
|
-
kwargs,
|
|
189
|
-
context,
|
|
190
|
-
)
|
|
191
|
-
|
|
192
|
-
return await _run_workflow_iterations(
|
|
193
|
-
job_id,
|
|
194
|
-
max_iterations,
|
|
195
|
-
orchestrator,
|
|
196
|
-
use_advanced_orchestrator,
|
|
197
|
-
kwargs,
|
|
198
|
-
)
|
|
199
|
-
|
|
200
|
-
except Exception as e:
|
|
201
|
-
_update_progress(
|
|
202
|
-
job_id=job_id,
|
|
203
|
-
status="failed",
|
|
204
|
-
iteration=current_iteration,
|
|
205
|
-
max_iterations=max_iterations,
|
|
206
|
-
current_stage="error",
|
|
207
|
-
message=f"Execution failed: {e}",
|
|
208
|
-
)
|
|
209
|
-
context.safe_print(f"Execution failed: {e}")
|
|
210
|
-
return {"job_id": job_id, "status": "failed", "error": str(e)}
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
async def _initialize_execution(
|
|
214
|
-
job_id: str,
|
|
215
|
-
max_iterations: int,
|
|
216
|
-
current_iteration: int,
|
|
217
|
-
context: t.Any,
|
|
218
|
-
) -> None:
|
|
219
|
-
_update_progress(
|
|
220
|
-
job_id=job_id,
|
|
221
|
-
iteration=current_iteration,
|
|
222
|
-
max_iterations=max_iterations,
|
|
223
|
-
overall_progress=2,
|
|
224
|
-
message="Initializing crackerjack execution",
|
|
225
|
-
)
|
|
226
|
-
|
|
227
|
-
status_result = await _check_status_and_prepare(job_id, context)
|
|
228
|
-
if status_result.get("should_abort", False):
|
|
229
|
-
msg = f"Execution aborted: {status_result['reason']}"
|
|
230
|
-
raise RuntimeError(msg)
|
|
231
|
-
|
|
232
|
-
_update_progress(
|
|
233
|
-
job_id=job_id,
|
|
234
|
-
iteration=current_iteration,
|
|
235
|
-
max_iterations=max_iterations,
|
|
236
|
-
overall_progress=5,
|
|
237
|
-
current_stage="status_verified",
|
|
238
|
-
message="Status check complete-no conflicts detected",
|
|
239
|
-
)
|
|
240
|
-
|
|
241
|
-
await _cleanup_stale_jobs(context)
|
|
242
|
-
|
|
243
|
-
await _ensure_services_running(job_id, context)
|
|
244
|
-
|
|
245
|
-
_update_progress(
|
|
246
|
-
job_id=job_id,
|
|
247
|
-
iteration=current_iteration,
|
|
248
|
-
max_iterations=max_iterations,
|
|
249
|
-
overall_progress=10,
|
|
250
|
-
current_stage="services_ready",
|
|
251
|
-
message="Services initialized successfully",
|
|
252
|
-
)
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
async def _setup_orchestrator(
|
|
256
|
-
job_id: str,
|
|
257
|
-
max_iterations: int,
|
|
258
|
-
current_iteration: int,
|
|
259
|
-
kwargs: dict[str, t.Any],
|
|
260
|
-
context: t.Any,
|
|
261
|
-
) -> tuple[t.Any, bool]:
|
|
262
|
-
context.safe_print("Using Standard WorkflowOrchestrator for MCP compatibility")
|
|
263
|
-
orchestrator = _create_standard_orchestrator(job_id, kwargs, context)
|
|
264
|
-
use_advanced_orchestrator = False
|
|
265
|
-
|
|
266
|
-
orchestrator_type = "Standard Orchestrator (MCP Compatible)"
|
|
267
|
-
_update_progress(
|
|
268
|
-
job_id=job_id,
|
|
269
|
-
iteration=current_iteration,
|
|
270
|
-
max_iterations=max_iterations,
|
|
271
|
-
overall_progress=15,
|
|
272
|
-
current_stage="orchestrator_ready",
|
|
273
|
-
message=f"Initialized {orchestrator_type}",
|
|
274
|
-
)
|
|
275
|
-
|
|
276
|
-
return orchestrator, use_advanced_orchestrator
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
async def _create_advanced_orchestrator(
|
|
280
|
-
job_id: str,
|
|
281
|
-
kwargs: dict[str, t.Any],
|
|
282
|
-
context: t.Any,
|
|
283
|
-
) -> t.Any:
|
|
284
|
-
from crackerjack.core.session_coordinator import SessionCoordinator
|
|
285
|
-
from crackerjack.orchestration.advanced_orchestrator import (
|
|
286
|
-
AdvancedWorkflowOrchestrator,
|
|
287
|
-
)
|
|
288
|
-
from crackerjack.orchestration.execution_strategies import (
|
|
289
|
-
AICoordinationMode,
|
|
290
|
-
AIIntelligence,
|
|
291
|
-
ExecutionStrategy,
|
|
292
|
-
OrchestrationConfig,
|
|
293
|
-
ProgressLevel,
|
|
294
|
-
StreamingMode,
|
|
295
|
-
)
|
|
296
|
-
|
|
297
|
-
optimal_config = OrchestrationConfig(
|
|
298
|
-
execution_strategy=ExecutionStrategy.ADAPTIVE,
|
|
299
|
-
progress_level=ProgressLevel.DETAILED,
|
|
300
|
-
streaming_mode=StreamingMode.WEBSOCKET,
|
|
301
|
-
ai_coordination_mode=AICoordinationMode.COORDINATOR,
|
|
302
|
-
ai_intelligence=AIIntelligence.ADAPTIVE,
|
|
303
|
-
correlation_tracking=True,
|
|
304
|
-
failure_analysis=True,
|
|
305
|
-
intelligent_retry=True,
|
|
306
|
-
max_parallel_hooks=3,
|
|
307
|
-
max_parallel_tests=4,
|
|
308
|
-
timeout_multiplier=1.0,
|
|
309
|
-
debug_level="standard",
|
|
310
|
-
log_individual_outputs=False,
|
|
311
|
-
preserve_temp_files=False,
|
|
312
|
-
)
|
|
313
|
-
|
|
314
|
-
session = SessionCoordinator(
|
|
315
|
-
context.console,
|
|
316
|
-
context.config.project_path,
|
|
317
|
-
web_job_id=job_id,
|
|
318
|
-
)
|
|
319
|
-
orchestrator = AdvancedWorkflowOrchestrator(
|
|
320
|
-
console=context.console,
|
|
321
|
-
pkg_path=context.config.project_path,
|
|
322
|
-
session=session,
|
|
323
|
-
config=optimal_config,
|
|
324
|
-
)
|
|
325
|
-
|
|
326
|
-
if kwargs.get("debug", False):
|
|
327
|
-
orchestrator.individual_executor.set_mcp_mode(False)
|
|
328
|
-
context.safe_print("🐛 Debug mode enabled-full output mode")
|
|
329
|
-
|
|
330
|
-
return orchestrator
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
def _create_standard_orchestrator(
|
|
334
|
-
job_id: str,
|
|
335
|
-
kwargs: dict[str, t.Any],
|
|
336
|
-
context: t.Any,
|
|
337
|
-
) -> t.Any:
|
|
338
|
-
from crackerjack.core.workflow_orchestrator import WorkflowOrchestrator
|
|
339
|
-
|
|
340
|
-
return WorkflowOrchestrator(
|
|
341
|
-
console=context.console,
|
|
342
|
-
pkg_path=context.config.project_path,
|
|
343
|
-
dry_run=kwargs.get("dry_run", False),
|
|
344
|
-
web_job_id=job_id,
|
|
345
|
-
)
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
async def _run_workflow_iterations(
|
|
349
|
-
job_id: str,
|
|
350
|
-
max_iterations: int,
|
|
351
|
-
orchestrator: t.Any,
|
|
352
|
-
use_advanced_orchestrator: bool,
|
|
353
|
-
kwargs: dict[str, t.Any],
|
|
354
|
-
) -> dict[str, t.Any]:
|
|
355
|
-
success = False
|
|
356
|
-
current_iteration = 1
|
|
357
|
-
|
|
358
|
-
for iteration in range(1, max_iterations + 1):
|
|
359
|
-
current_iteration = iteration
|
|
360
|
-
|
|
361
|
-
_update_progress(
|
|
362
|
-
job_id=job_id,
|
|
363
|
-
iteration=current_iteration,
|
|
364
|
-
max_iterations=max_iterations,
|
|
365
|
-
overall_progress=int((iteration / max_iterations) * 80),
|
|
366
|
-
current_stage=f"iteration_{iteration}",
|
|
367
|
-
message=f"Running iteration {iteration} / {max_iterations}",
|
|
368
|
-
)
|
|
369
|
-
|
|
370
|
-
options = _create_workflow_options(kwargs)
|
|
371
|
-
|
|
372
|
-
try:
|
|
373
|
-
success = await _execute_single_iteration(
|
|
374
|
-
orchestrator,
|
|
375
|
-
use_advanced_orchestrator,
|
|
376
|
-
options,
|
|
377
|
-
)
|
|
378
|
-
|
|
379
|
-
if success:
|
|
380
|
-
return _create_success_result(
|
|
381
|
-
job_id,
|
|
382
|
-
current_iteration,
|
|
383
|
-
max_iterations,
|
|
384
|
-
iteration,
|
|
385
|
-
)
|
|
386
|
-
|
|
387
|
-
if iteration < max_iterations:
|
|
388
|
-
await _handle_iteration_retry(
|
|
389
|
-
job_id,
|
|
390
|
-
current_iteration,
|
|
391
|
-
max_iterations,
|
|
392
|
-
iteration,
|
|
393
|
-
)
|
|
394
|
-
continue
|
|
395
|
-
|
|
396
|
-
except Exception as e:
|
|
397
|
-
if not await _handle_iteration_error(iteration, max_iterations, e):
|
|
398
|
-
break
|
|
399
|
-
|
|
400
|
-
return _create_failure_result(job_id, current_iteration, max_iterations)
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
def _create_workflow_options(kwargs: dict[str, t.Any]) -> t.Any:
|
|
404
|
-
from crackerjack.models.config import WorkflowOptions
|
|
405
|
-
|
|
406
|
-
options = WorkflowOptions()
|
|
407
|
-
options.testing.test = kwargs.get("test", True)
|
|
408
|
-
options.ai.ai_agent = kwargs.get("ai_agent", True)
|
|
409
|
-
options.hooks.skip_hooks = kwargs.get("skip_hooks", False)
|
|
410
|
-
|
|
411
|
-
return options
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
async def _execute_single_iteration(
|
|
415
|
-
orchestrator: t.Any,
|
|
416
|
-
use_advanced_orchestrator: bool,
|
|
417
|
-
options: t.Any,
|
|
418
|
-
) -> bool:
|
|
419
|
-
if use_advanced_orchestrator:
|
|
420
|
-
result = await orchestrator.execute_orchestrated_workflow(options)
|
|
421
|
-
return bool(result)
|
|
422
|
-
result = await orchestrator.run_complete_workflow(options)
|
|
423
|
-
return bool(result)
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
def _create_success_result(
|
|
427
|
-
job_id: str,
|
|
428
|
-
current_iteration: int,
|
|
429
|
-
max_iterations: int,
|
|
430
|
-
iteration: int,
|
|
431
|
-
) -> dict[str, t.Any]:
|
|
432
|
-
_update_progress(
|
|
433
|
-
job_id=job_id,
|
|
434
|
-
status="completed",
|
|
435
|
-
iteration=current_iteration,
|
|
436
|
-
max_iterations=max_iterations,
|
|
437
|
-
overall_progress=100,
|
|
438
|
-
current_stage="completed",
|
|
439
|
-
message=f"Successfully completed after {iteration} iterations",
|
|
440
|
-
)
|
|
441
|
-
return {
|
|
442
|
-
"job_id": job_id,
|
|
443
|
-
"status": "completed",
|
|
444
|
-
"iteration": current_iteration,
|
|
445
|
-
"message": f"Successfully completed after {iteration} iterations",
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
async def _handle_iteration_retry(
|
|
450
|
-
job_id: str,
|
|
451
|
-
current_iteration: int,
|
|
452
|
-
max_iterations: int,
|
|
453
|
-
iteration: int,
|
|
454
|
-
) -> None:
|
|
455
|
-
_update_progress(
|
|
456
|
-
job_id=job_id,
|
|
457
|
-
iteration=current_iteration,
|
|
458
|
-
max_iterations=max_iterations,
|
|
459
|
-
overall_progress=int((iteration / max_iterations) * 80),
|
|
460
|
-
current_stage="retrying",
|
|
461
|
-
message=f"Iteration {iteration} failed, retrying...",
|
|
462
|
-
)
|
|
463
|
-
await asyncio.sleep(1)
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
async def _handle_iteration_error(
|
|
467
|
-
iteration: int,
|
|
468
|
-
max_iterations: int,
|
|
469
|
-
error: Exception,
|
|
470
|
-
) -> bool:
|
|
471
|
-
if iteration >= max_iterations:
|
|
472
|
-
return False
|
|
473
|
-
await asyncio.sleep(1)
|
|
474
|
-
return True
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
def _create_failure_result(
|
|
478
|
-
job_id: str,
|
|
479
|
-
current_iteration: int,
|
|
480
|
-
max_iterations: int,
|
|
481
|
-
) -> dict[str, t.Any]:
|
|
482
|
-
_update_progress(
|
|
483
|
-
job_id=job_id,
|
|
484
|
-
status="failed",
|
|
485
|
-
iteration=current_iteration,
|
|
486
|
-
max_iterations=max_iterations,
|
|
487
|
-
overall_progress=80,
|
|
488
|
-
current_stage="failed",
|
|
489
|
-
message=f"Failed after {max_iterations} iterations",
|
|
490
|
-
)
|
|
491
|
-
return {
|
|
492
|
-
"job_id": job_id,
|
|
493
|
-
"status": "failed",
|
|
494
|
-
"iteration": current_iteration,
|
|
495
|
-
"message": f"Failed after {max_iterations} iterations",
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
async def _ensure_services_running(job_id: str, context: t.Any) -> None:
|
|
500
|
-
import subprocess
|
|
501
|
-
|
|
502
|
-
_update_progress(
|
|
503
|
-
job_id=job_id,
|
|
504
|
-
current_stage="service_startup",
|
|
505
|
-
message="Checking required services...",
|
|
506
|
-
)
|
|
507
|
-
|
|
508
|
-
websocket_running = False
|
|
509
|
-
with suppress(Exception):
|
|
510
|
-
from crackerjack.services.server_manager import find_websocket_server_processes
|
|
511
|
-
|
|
512
|
-
websocket_processes = find_websocket_server_processes()
|
|
513
|
-
websocket_running = len(websocket_processes) > 0
|
|
514
|
-
|
|
515
|
-
if not websocket_running:
|
|
516
|
-
_update_progress(
|
|
517
|
-
job_id=job_id,
|
|
518
|
-
current_stage="service_startup",
|
|
519
|
-
message="Starting WebSocket server...",
|
|
520
|
-
)
|
|
521
|
-
|
|
522
|
-
try:
|
|
523
|
-
subprocess.Popen(
|
|
524
|
-
["python", "- m", "crackerjack", "- - start - websocket-server"],
|
|
525
|
-
cwd=context.config.project_path,
|
|
526
|
-
stdout=subprocess.DEVNULL,
|
|
527
|
-
stderr=subprocess.DEVNULL,
|
|
528
|
-
start_new_session=True,
|
|
529
|
-
)
|
|
530
|
-
|
|
531
|
-
for _i in range(10):
|
|
532
|
-
with suppress(Exception):
|
|
533
|
-
websocket_processes = find_websocket_server_processes()
|
|
534
|
-
if websocket_processes:
|
|
535
|
-
context.safe_print("✅ WebSocket server started successfully")
|
|
536
|
-
break
|
|
537
|
-
await asyncio.sleep(0.5)
|
|
538
|
-
else:
|
|
539
|
-
context.safe_print("⚠️ WebSocket server may not have started properly")
|
|
540
|
-
|
|
541
|
-
except Exception as e:
|
|
542
|
-
context.safe_print(f"⚠️ Failed to start WebSocket server: {e}")
|
|
543
|
-
else:
|
|
544
|
-
context.safe_print("✅ WebSocket server already running")
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
async def _check_status_and_prepare(job_id: str, context: t.Any) -> dict[str, t.Any]:
|
|
548
|
-
_update_progress(
|
|
549
|
-
job_id=job_id,
|
|
550
|
-
current_stage="status_check",
|
|
551
|
-
message="🔍 Checking system status to prevent conflicts...",
|
|
552
|
-
)
|
|
553
|
-
|
|
554
|
-
try:
|
|
555
|
-
status_info = await _get_status_info()
|
|
556
|
-
if "error" in status_info:
|
|
557
|
-
return _handle_status_error(status_info, context)
|
|
558
|
-
|
|
559
|
-
cleanup_performed = []
|
|
560
|
-
|
|
561
|
-
_check_active_jobs(status_info, context)
|
|
562
|
-
|
|
563
|
-
cleanup_performed.extend(_check_resource_cleanup(status_info, context))
|
|
564
|
-
|
|
565
|
-
_check_service_health(status_info, context)
|
|
566
|
-
|
|
567
|
-
context.safe_print("✅ Status check complete-ready to proceed")
|
|
568
|
-
|
|
569
|
-
return {
|
|
570
|
-
"should_abort": False,
|
|
571
|
-
"reason": "",
|
|
572
|
-
"status_info": status_info,
|
|
573
|
-
"cleanup_performed": cleanup_performed,
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
except Exception as e:
|
|
577
|
-
return _handle_status_exception(e, context)
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
async def _get_status_info() -> dict[str, t.Any]:
|
|
581
|
-
from .monitoring_tools import _get_comprehensive_status
|
|
582
|
-
|
|
583
|
-
return await _get_comprehensive_status()
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
def _handle_status_error(
|
|
587
|
-
status_info: dict[str, t.Any],
|
|
588
|
-
context: t.Any,
|
|
589
|
-
) -> dict[str, t.Any]:
|
|
590
|
-
context.safe_print(f"⚠️ Status check failed: {status_info['error']}")
|
|
591
|
-
return {
|
|
592
|
-
"should_abort": False,
|
|
593
|
-
"reason": "",
|
|
594
|
-
"status_info": status_info,
|
|
595
|
-
"cleanup_performed": [],
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
def _check_active_jobs(status_info: dict[str, t.Any], context: t.Any) -> None:
|
|
600
|
-
active_jobs = [
|
|
601
|
-
j
|
|
602
|
-
for j in status_info.get("jobs", {}).get("details", [])
|
|
603
|
-
if j.get("status") == "running"
|
|
604
|
-
]
|
|
605
|
-
|
|
606
|
-
if active_jobs:
|
|
607
|
-
_handle_conflicting_jobs(active_jobs, context)
|
|
608
|
-
else:
|
|
609
|
-
context.safe_print("✅ No active jobs detected-safe to proceed")
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
def _handle_conflicting_jobs(
|
|
613
|
-
active_jobs: list[dict[str, t.Any]],
|
|
614
|
-
context: t.Any,
|
|
615
|
-
) -> None:
|
|
616
|
-
conflicting_jobs = active_jobs
|
|
617
|
-
|
|
618
|
-
if conflicting_jobs:
|
|
619
|
-
job_ids = [j.get("job_id", "unknown") for j in conflicting_jobs]
|
|
620
|
-
context.safe_print(
|
|
621
|
-
f"⚠️ Found {len(conflicting_jobs)} active job(s): {', '.join(job_ids[:3])}",
|
|
622
|
-
)
|
|
623
|
-
context.safe_print(
|
|
624
|
-
" Running concurrent crackerjack instances may cause file conflicts",
|
|
625
|
-
)
|
|
626
|
-
context.safe_print(" Proceeding with caution...")
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
def _check_resource_cleanup(status_info: dict[str, t.Any], context: t.Any) -> list[str]:
|
|
630
|
-
cleanup_performed = []
|
|
631
|
-
|
|
632
|
-
temp_files_count = (
|
|
633
|
-
status_info.get("server_stats", {})
|
|
634
|
-
.get("resource_usage", {})
|
|
635
|
-
.get("temp_files_count", 0)
|
|
636
|
-
)
|
|
637
|
-
|
|
638
|
-
if temp_files_count > 50:
|
|
639
|
-
context.safe_print(
|
|
640
|
-
f"🗑️ Found {temp_files_count} temporary files-cleanup recommended",
|
|
641
|
-
)
|
|
642
|
-
cleanup_performed.append("temp_files_flagged")
|
|
643
|
-
|
|
644
|
-
return cleanup_performed
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
def _check_service_health(status_info: dict[str, t.Any], context: t.Any) -> None:
|
|
648
|
-
services = status_info.get("services", {})
|
|
649
|
-
mcp_running = services.get("mcp_server", {}).get("running", False)
|
|
650
|
-
websocket_running = services.get("websocket_server", {}).get("running", False)
|
|
651
|
-
|
|
652
|
-
if not mcp_running:
|
|
653
|
-
context.safe_print("⚠️ MCP server not running - will auto-start if needed")
|
|
654
|
-
|
|
655
|
-
if not websocket_running:
|
|
656
|
-
context.safe_print("📡 WebSocket server not running - will auto-start")
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
def _handle_status_exception(error: Exception, context: t.Any) -> dict[str, t.Any]:
|
|
660
|
-
context.safe_print(f"⚠️ Status check encountered error: {error}")
|
|
661
|
-
return {
|
|
662
|
-
"should_abort": False,
|
|
663
|
-
"reason": "",
|
|
664
|
-
"status_info": {"error": str(error)},
|
|
665
|
-
"cleanup_performed": [],
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
async def _cleanup_stale_jobs(context: t.Any) -> None:
|
|
670
|
-
if not context.progress_dir.exists():
|
|
671
|
-
return
|
|
672
|
-
|
|
673
|
-
current_time = time.time()
|
|
674
|
-
cleaned_count = 0
|
|
675
|
-
|
|
676
|
-
with suppress(Exception):
|
|
677
|
-
for progress_file in context.progress_dir.glob("job-*.json"):
|
|
678
|
-
try:
|
|
679
|
-
import json
|
|
680
|
-
|
|
681
|
-
progress_data = json.loads(progress_file.read_text())
|
|
682
|
-
|
|
683
|
-
last_update = progress_data.get("updated_at", 0)
|
|
684
|
-
age_minutes = (current_time - last_update) / 60
|
|
685
|
-
|
|
686
|
-
is_stale = (
|
|
687
|
-
age_minutes > 30
|
|
688
|
-
or progress_data.get("job_id") == "unknown"
|
|
689
|
-
or "analyzing_failures: processing"
|
|
690
|
-
in progress_data.get("status", "")
|
|
691
|
-
)
|
|
692
|
-
|
|
693
|
-
if is_stale:
|
|
694
|
-
progress_file.unlink()
|
|
695
|
-
cleaned_count += 1
|
|
696
|
-
|
|
697
|
-
except (json.JSONDecodeError, OSError):
|
|
698
|
-
with suppress(OSError):
|
|
699
|
-
progress_file.unlink()
|
|
700
|
-
cleaned_count += 1
|
|
701
|
-
|
|
702
|
-
if cleaned_count > 0:
|
|
703
|
-
context.safe_print(f"🗑️ Cleaned up {cleaned_count} stale job files")
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
def _register_init_crackerjack_tool(mcp_app: t.Any) -> None:
|
|
707
|
-
@mcp_app.tool()
|
|
708
|
-
async def init_crackerjack(args: str = "", kwargs: str = "{}") -> str:
|
|
709
|
-
context = get_context()
|
|
710
|
-
if not context:
|
|
711
|
-
return _create_init_error_response("Server context not available")
|
|
712
|
-
|
|
713
|
-
target_path, force, parse_error = _parse_init_arguments(args, kwargs)
|
|
714
|
-
if parse_error:
|
|
715
|
-
return parse_error
|
|
716
|
-
|
|
717
|
-
try:
|
|
718
|
-
results = _execute_initialization(context, target_path, force)
|
|
719
|
-
if isinstance(results, bool):
|
|
720
|
-
return json.dumps({"success": results})
|
|
721
|
-
return _create_init_success_response(results, target_path, force)
|
|
722
|
-
except Exception as e:
|
|
723
|
-
return _create_init_exception_response(e, target_path)
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
def _create_init_error_response(message: str) -> str:
|
|
727
|
-
return json.dumps({"error": message, "success": False}, indent=2)
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
def _parse_init_arguments(args: str, kwargs: str) -> tuple[t.Any, bool, str | None]:
|
|
731
|
-
from pathlib import Path
|
|
732
|
-
|
|
733
|
-
target_path = args.strip() or None
|
|
734
|
-
|
|
735
|
-
try:
|
|
736
|
-
extra_kwargs: dict[str, t.Any] = json.loads(kwargs) if kwargs.strip() else {}
|
|
737
|
-
except json.JSONDecodeError as e:
|
|
738
|
-
return None, False, _create_init_error_response(f"Invalid JSON in kwargs: {e}")
|
|
739
|
-
|
|
740
|
-
force = extra_kwargs.get("force", False)
|
|
741
|
-
|
|
742
|
-
if target_path:
|
|
743
|
-
target_path_obj = Path(target_path).resolve()
|
|
744
|
-
target_path = str(target_path_obj)
|
|
745
|
-
else:
|
|
746
|
-
target_path_obj = Path.cwd()
|
|
747
|
-
target_path = str(target_path_obj)
|
|
748
|
-
|
|
749
|
-
if not Path(target_path).exists():
|
|
750
|
-
return (
|
|
751
|
-
None,
|
|
752
|
-
False,
|
|
753
|
-
_create_init_error_response(f"Target path does not exist: {target_path}"),
|
|
754
|
-
)
|
|
755
|
-
|
|
756
|
-
return target_path, force, None
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
def _execute_initialization(context: t.Any, target_path: t.Any, force: bool) -> bool:
|
|
760
|
-
from crackerjack.services.filesystem import FileSystemService
|
|
761
|
-
from crackerjack.services.git import GitService
|
|
762
|
-
from crackerjack.services.initialization import InitializationService
|
|
763
|
-
|
|
764
|
-
filesystem = FileSystemService()
|
|
765
|
-
git_service = GitService(context.console, context.config.project_path)
|
|
766
|
-
|
|
767
|
-
return InitializationService(
|
|
768
|
-
context.console, filesystem, git_service, context.config.project_path
|
|
769
|
-
).initialize_project(target_path=target_path, force=force)
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
def _create_init_success_response(
|
|
773
|
-
results: dict[str, t.Any], target_path: t.Any, force: bool
|
|
774
|
-
) -> str:
|
|
775
|
-
results["command"] = "init_crackerjack"
|
|
776
|
-
results["target_path"] = str(target_path)
|
|
777
|
-
results["force"] = force
|
|
778
|
-
return json.dumps(results, indent=2)
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
def _create_init_exception_response(error: Exception, target_path: t.Any) -> str:
|
|
782
|
-
error_result = {
|
|
783
|
-
"error": f"Initialization failed: {error}",
|
|
784
|
-
"success": False,
|
|
785
|
-
"command": "init_crackerjack",
|
|
786
|
-
"target_path": str(target_path) if target_path else "current_directory",
|
|
787
|
-
}
|
|
788
|
-
return json.dumps(error_result, indent=2)
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
def _register_agent_suggestions_tool(mcp_app: t.Any) -> None:
|
|
792
|
-
@mcp_app.tool()
|
|
793
|
-
async def suggest_agents(
|
|
794
|
-
task_description: str = "",
|
|
795
|
-
project_type: str = "python",
|
|
796
|
-
current_context: str = "",
|
|
797
|
-
) -> str:
|
|
798
|
-
suggestions: dict[str, list[dict[str, str]] | list[str] | str] = {
|
|
799
|
-
"primary_agents": t.cast(list[dict[str, str]], []),
|
|
800
|
-
"task_specific_agents": t.cast(list[dict[str, str]], []),
|
|
801
|
-
"usage_patterns": t.cast(list[str], []),
|
|
802
|
-
"rationale": "",
|
|
803
|
-
}
|
|
804
|
-
|
|
805
|
-
# Type cast the lists to ensure proper typing
|
|
806
|
-
primary_agents: list[dict[str, str]] = t.cast(
|
|
807
|
-
list[dict[str, str]], suggestions["primary_agents"]
|
|
808
|
-
)
|
|
809
|
-
task_specific_agents: list[dict[str, str]] = t.cast(
|
|
810
|
-
list[dict[str, str]], suggestions["task_specific_agents"]
|
|
811
|
-
)
|
|
812
|
-
t.cast(list[str], suggestions["usage_patterns"])
|
|
813
|
-
|
|
814
|
-
if project_type.lower() == "python" or "python" in task_description.lower():
|
|
815
|
-
primary_agents.extend(
|
|
816
|
-
(
|
|
817
|
-
{
|
|
818
|
-
"name": "crackerjack-architect",
|
|
819
|
-
"emoji": "🏗️",
|
|
820
|
-
"description": "Expert in crackerjack's modular architecture and Python project management patterns",
|
|
821
|
-
"usage": "Use PROACTIVELY for all feature development, architectural decisions, and ensuring code follows crackerjack standards",
|
|
822
|
-
"priority": "HIGH",
|
|
823
|
-
},
|
|
824
|
-
{
|
|
825
|
-
"name": "python-pro",
|
|
826
|
-
"emoji": "🐍",
|
|
827
|
-
"description": "Modern Python development with type hints, async/await patterns, and clean architecture",
|
|
828
|
-
"usage": "Use for implementing Python code with best practices",
|
|
829
|
-
"priority": "HIGH",
|
|
830
|
-
},
|
|
831
|
-
)
|
|
832
|
-
)
|
|
833
|
-
|
|
834
|
-
task_lower = task_description.lower()
|
|
835
|
-
context_lower = current_context.lower()
|
|
836
|
-
|
|
837
|
-
if any(
|
|
838
|
-
word in task_lower + context_lower
|
|
839
|
-
for word in ("test", "testing", "coverage", "pytest")
|
|
840
|
-
):
|
|
841
|
-
task_specific_agents.extend(
|
|
842
|
-
(
|
|
843
|
-
{
|
|
844
|
-
"name": "crackerjack-test-specialist",
|
|
845
|
-
"emoji": "🧪",
|
|
846
|
-
"description": "Advanced testing specialist for complex scenarios and coverage optimization",
|
|
847
|
-
"usage": "Use for test creation, debugging test failures, and coverage improvements",
|
|
848
|
-
"priority": "HIGH",
|
|
849
|
-
},
|
|
850
|
-
{
|
|
851
|
-
"name": "pytest-hypothesis-specialist",
|
|
852
|
-
"emoji": "🧪",
|
|
853
|
-
"description": "Advanced testing patterns and property-based testing",
|
|
854
|
-
"usage": "Use for comprehensive test development and optimization",
|
|
855
|
-
"priority": "MEDIUM",
|
|
856
|
-
},
|
|
857
|
-
)
|
|
858
|
-
)
|
|
859
|
-
|
|
860
|
-
if any(
|
|
861
|
-
word in task_lower + context_lower
|
|
862
|
-
for word in ("security", "vulnerability", "auth", "permission")
|
|
863
|
-
):
|
|
864
|
-
task_specific_agents.append(
|
|
865
|
-
{
|
|
866
|
-
"name": "security-auditor",
|
|
867
|
-
"emoji": "🔒",
|
|
868
|
-
"description": "Security auditing and vulnerability detection specialist",
|
|
869
|
-
"usage": "Use for identifying and mitigating security vulnerabilities",
|
|
870
|
-
"priority": "HIGH",
|
|
871
|
-
}
|
|
872
|
-
)
|
|
873
|
-
|
|
874
|
-
if any(
|
|
875
|
-
word in task_lower + context_lower
|
|
876
|
-
for word in ("architecture", "design", "api", "backend")
|
|
877
|
-
):
|
|
878
|
-
task_specific_agents.append(
|
|
879
|
-
{
|
|
880
|
-
"name": "backend-architect",
|
|
881
|
-
"emoji": "🏗️",
|
|
882
|
-
"description": "Backend architecture and system design specialist",
|
|
883
|
-
"usage": "Use for complex backend design decisions and system architecture",
|
|
884
|
-
"priority": "MEDIUM",
|
|
885
|
-
}
|
|
886
|
-
)
|
|
887
|
-
|
|
888
|
-
suggestions["usage_patterns"] = [
|
|
889
|
-
'Task tool with subagent_type ="crackerjack-architect" for feature planning and architecture',
|
|
890
|
-
'Task tool with subagent_type ="python-pro" for implementation with best practices',
|
|
891
|
-
'Task tool with subagent_type ="crackerjack - test-specialist" for comprehensive testing',
|
|
892
|
-
'Task tool with subagent_type ="security-auditor" for security validation',
|
|
893
|
-
]
|
|
894
|
-
|
|
895
|
-
if "crackerjack-architect" in [
|
|
896
|
-
agent["name"] for agent in suggestions["primary_agents"]
|
|
897
|
-
]:
|
|
898
|
-
suggestions["rationale"] = (
|
|
899
|
-
"The crackerjack-architect agent is essential for this Python project as it ensures "
|
|
900
|
-
"code follows crackerjack patterns from the start, eliminating retrofitting needs. "
|
|
901
|
-
"Combined with python - pro for implementation and task-specific agents for specialized "
|
|
902
|
-
"work, this provides comprehensive development support with built-in quality assurance."
|
|
903
|
-
)
|
|
904
|
-
|
|
905
|
-
return json.dumps(suggestions, indent=2)
|
|
906
|
-
|
|
907
|
-
@mcp_app.tool()
|
|
908
|
-
async def detect_agent_needs(
|
|
909
|
-
error_context: str = "",
|
|
910
|
-
file_patterns: str = "",
|
|
911
|
-
recent_changes: str = "",
|
|
912
|
-
) -> str:
|
|
913
|
-
recommendations = {
|
|
914
|
-
"urgent_agents": [],
|
|
915
|
-
"suggested_agents": [],
|
|
916
|
-
"workflow_recommendations": [],
|
|
917
|
-
"detection_reasoning": "",
|
|
918
|
-
}
|
|
919
|
-
|
|
920
|
-
_add_urgent_agents_for_errors(recommendations, error_context)
|
|
921
|
-
|
|
922
|
-
_add_python_project_suggestions(recommendations, file_patterns)
|
|
923
|
-
|
|
924
|
-
_set_workflow_recommendations(recommendations)
|
|
925
|
-
|
|
926
|
-
_generate_detection_reasoning(recommendations)
|
|
927
|
-
|
|
928
|
-
return json.dumps(recommendations, indent=2)
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
def _add_urgent_agents_for_errors(
|
|
932
|
-
recommendations: dict[str, t.Any], error_context: str
|
|
933
|
-
) -> None:
|
|
934
|
-
if any(
|
|
935
|
-
word in error_context.lower()
|
|
936
|
-
for word in ("test fail", "coverage", "pytest", "assertion")
|
|
937
|
-
):
|
|
938
|
-
recommendations["urgent_agents"].append(
|
|
939
|
-
{
|
|
940
|
-
"agent": "crackerjack - test-specialist",
|
|
941
|
-
"reason": "Test failures detected-specialist needed for debugging and fixes",
|
|
942
|
-
"action": 'Task tool with subagent_type ="crackerjack - test-specialist" to analyze and fix test issues',
|
|
943
|
-
}
|
|
944
|
-
)
|
|
945
|
-
|
|
946
|
-
if any(
|
|
947
|
-
word in error_context.lower()
|
|
948
|
-
for word in ("security", "vulnerability", "bandit", "unsafe")
|
|
949
|
-
):
|
|
950
|
-
recommendations["urgent_agents"].append(
|
|
951
|
-
{
|
|
952
|
-
"agent": "security-auditor",
|
|
953
|
-
"reason": "Security issues detected-immediate audit required",
|
|
954
|
-
"action": 'Task tool with subagent_type ="security-auditor" to review and fix security vulnerabilities',
|
|
955
|
-
}
|
|
956
|
-
)
|
|
957
|
-
|
|
958
|
-
if any(
|
|
959
|
-
word in error_context.lower()
|
|
960
|
-
for word in ("complexity", "refactor", "too complex")
|
|
961
|
-
):
|
|
962
|
-
recommendations["urgent_agents"].append(
|
|
963
|
-
{
|
|
964
|
-
"agent": "crackerjack-architect",
|
|
965
|
-
"reason": "Complexity issues detected-architectural review needed",
|
|
966
|
-
"action": 'Task tool with subagent_type ="crackerjack-architect" to simplify and restructure code',
|
|
967
|
-
}
|
|
968
|
-
)
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
def _add_python_project_suggestions(
|
|
972
|
-
recommendations: dict[str, t.Any], file_patterns: str
|
|
973
|
-
) -> None:
|
|
974
|
-
if "python" in file_patterns.lower() or ".py" in file_patterns:
|
|
975
|
-
recommendations["suggested_agents"].extend(
|
|
976
|
-
[
|
|
977
|
-
{
|
|
978
|
-
"agent": "crackerjack-architect",
|
|
979
|
-
"reason": "Python project detected-ensure crackerjack compliance",
|
|
980
|
-
"priority": "HIGH",
|
|
981
|
-
},
|
|
982
|
-
{
|
|
983
|
-
"agent": "python-pro",
|
|
984
|
-
"reason": "Python development best practices",
|
|
985
|
-
"priority": "HIGH",
|
|
986
|
-
},
|
|
987
|
-
]
|
|
988
|
-
)
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
def _set_workflow_recommendations(recommendations: dict[str, t.Any]) -> None:
|
|
992
|
-
if recommendations["urgent_agents"]:
|
|
993
|
-
recommendations["workflow_recommendations"] = [
|
|
994
|
-
"Address urgent issues first with specialized agents",
|
|
995
|
-
"Run crackerjack quality checks after fixes: python - m crackerjack-t",
|
|
996
|
-
"Use crackerjack-architect for ongoing compliance",
|
|
997
|
-
]
|
|
998
|
-
else:
|
|
999
|
-
recommendations["workflow_recommendations"] = [
|
|
1000
|
-
"Start with crackerjack-architect for proper planning",
|
|
1001
|
-
"Use python-pro for implementation",
|
|
1002
|
-
"Run continuous quality checks: python-m crackerjack",
|
|
1003
|
-
]
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
def _generate_detection_reasoning(recommendations: dict[str, t.Any]) -> None:
|
|
1007
|
-
recommendations["detection_reasoning"] = (
|
|
1008
|
-
f"Analysis of context revealed {len(recommendations['urgent_agents'])} urgent issues "
|
|
1009
|
-
f"and {len(recommendations['suggested_agents'])} general recommendations. "
|
|
1010
|
-
"Prioritize urgent agents first, then follow standard workflow patterns."
|
|
1011
|
-
)
|