crackerjack 0.18.2__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 +96 -2
- crackerjack/__main__.py +637 -138
- crackerjack/adapters/README.md +18 -0
- crackerjack/adapters/__init__.py +39 -0
- 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/lsp/_base.py +194 -0
- crackerjack/adapters/lsp/_client.py +358 -0
- crackerjack/adapters/lsp/_manager.py +193 -0
- crackerjack/adapters/lsp/skylos.py +283 -0
- crackerjack/adapters/lsp/zuban.py +557 -0
- 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 +66 -0
- crackerjack/agents/architect_agent.py +238 -0
- crackerjack/agents/base.py +167 -0
- crackerjack/agents/claude_code_bridge.py +641 -0
- crackerjack/agents/coordinator.py +600 -0
- crackerjack/agents/documentation_agent.py +520 -0
- crackerjack/agents/dry_agent.py +585 -0
- 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 +230 -0
- 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/import_optimization_agent.py +1181 -0
- crackerjack/agents/performance_agent.py +325 -0
- crackerjack/agents/performance_helpers.py +205 -0
- crackerjack/agents/proactive_agent.py +55 -0
- crackerjack/agents/refactoring_agent.py +511 -0
- crackerjack/agents/refactoring_helpers.py +247 -0
- crackerjack/agents/security_agent.py +793 -0
- crackerjack/agents/semantic_agent.py +479 -0
- crackerjack/agents/semantic_helpers.py +356 -0
- crackerjack/agents/test_creation_agent.py +570 -0
- crackerjack/agents/test_specialist_agent.py +526 -0
- crackerjack/agents/tracker.py +110 -0
- crackerjack/api.py +647 -0
- crackerjack/cli/README.md +394 -0
- crackerjack/cli/__init__.py +24 -0
- crackerjack/cli/cache_handlers.py +209 -0
- crackerjack/cli/cache_handlers_enhanced.py +680 -0
- crackerjack/cli/facade.py +162 -0
- 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 +700 -0
- crackerjack/cli/interactive.py +488 -0
- crackerjack/cli/options.py +1216 -0
- crackerjack/cli/semantic_handlers.py +292 -0
- crackerjack/cli/utils.py +19 -0
- crackerjack/cli/version.py +19 -0
- crackerjack/code_cleaner.py +1307 -0
- crackerjack/config/README.md +472 -0
- crackerjack/config/__init__.py +275 -0
- crackerjack/config/global_lock_config.py +207 -0
- crackerjack/config/hooks.py +390 -0
- 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/__init__.py +0 -0
- crackerjack/core/async_workflow_orchestrator.py +738 -0
- crackerjack/core/autofix_coordinator.py +282 -0
- crackerjack/core/container.py +105 -0
- crackerjack/core/enhanced_container.py +583 -0
- crackerjack/core/file_lifecycle.py +472 -0
- crackerjack/core/performance.py +244 -0
- crackerjack/core/performance_monitor.py +357 -0
- crackerjack/core/phase_coordinator.py +1227 -0
- crackerjack/core/proactive_workflow.py +267 -0
- crackerjack/core/resource_manager.py +425 -0
- crackerjack/core/retry.py +275 -0
- crackerjack/core/service_watchdog.py +601 -0
- crackerjack/core/session_coordinator.py +239 -0
- crackerjack/core/timeout_manager.py +563 -0
- crackerjack/core/websocket_lifecycle.py +410 -0
- 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 +2243 -0
- 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/INDEX.md +11 -0
- crackerjack/docs/README.md +11 -0
- crackerjack/docs/generated/api/API_REFERENCE.md +10895 -0
- crackerjack/docs/generated/api/CLI_REFERENCE.md +109 -0
- crackerjack/docs/generated/api/CROSS_REFERENCES.md +1755 -0
- crackerjack/docs/generated/api/PROTOCOLS.md +3 -0
- crackerjack/docs/generated/api/SERVICES.md +1252 -0
- crackerjack/documentation/README.md +11 -0
- crackerjack/documentation/__init__.py +31 -0
- crackerjack/documentation/ai_templates.py +756 -0
- crackerjack/documentation/dual_output_generator.py +767 -0
- crackerjack/documentation/mkdocs_integration.py +518 -0
- crackerjack/documentation/reference_generator.py +1065 -0
- crackerjack/dynamic_config.py +678 -0
- crackerjack/errors.py +378 -0
- 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 +13 -0
- crackerjack/executors/async_hook_executor.py +938 -0
- crackerjack/executors/cached_hook_executor.py +316 -0
- crackerjack/executors/hook_executor.py +1295 -0
- crackerjack/executors/hook_lock_manager.py +708 -0
- crackerjack/executors/individual_hook_executor.py +739 -0
- crackerjack/executors/lsp_aware_hook_executor.py +349 -0
- crackerjack/executors/progress_hook_executor.py +282 -0
- crackerjack/executors/tool_proxy.py +433 -0
- crackerjack/hooks/README.md +485 -0
- crackerjack/hooks/lsp_hook.py +93 -0
- crackerjack/intelligence/README.md +557 -0
- crackerjack/intelligence/__init__.py +37 -0
- crackerjack/intelligence/adaptive_learning.py +693 -0
- crackerjack/intelligence/agent_orchestrator.py +485 -0
- crackerjack/intelligence/agent_registry.py +377 -0
- crackerjack/intelligence/agent_selector.py +439 -0
- crackerjack/intelligence/integration.py +250 -0
- crackerjack/interactive.py +719 -0
- crackerjack/managers/README.md +369 -0
- crackerjack/managers/__init__.py +11 -0
- crackerjack/managers/async_hook_manager.py +135 -0
- crackerjack/managers/hook_manager.py +585 -0
- crackerjack/managers/publish_manager.py +631 -0
- crackerjack/managers/test_command_builder.py +391 -0
- crackerjack/managers/test_executor.py +474 -0
- crackerjack/managers/test_manager.py +1357 -0
- crackerjack/managers/test_progress.py +187 -0
- crackerjack/mcp/README.md +374 -0
- crackerjack/mcp/__init__.py +0 -0
- crackerjack/mcp/cache.py +352 -0
- crackerjack/mcp/client_runner.py +121 -0
- crackerjack/mcp/context.py +802 -0
- crackerjack/mcp/dashboard.py +657 -0
- crackerjack/mcp/enhanced_progress_monitor.py +493 -0
- crackerjack/mcp/file_monitor.py +394 -0
- crackerjack/mcp/progress_components.py +607 -0
- crackerjack/mcp/progress_monitor.py +1016 -0
- crackerjack/mcp/rate_limiter.py +336 -0
- crackerjack/mcp/server.py +24 -0
- crackerjack/mcp/server_core.py +526 -0
- crackerjack/mcp/service_watchdog.py +505 -0
- crackerjack/mcp/state.py +407 -0
- crackerjack/mcp/task_manager.py +259 -0
- crackerjack/mcp/tools/README.md +27 -0
- crackerjack/mcp/tools/__init__.py +19 -0
- crackerjack/mcp/tools/core_tools.py +469 -0
- crackerjack/mcp/tools/error_analyzer.py +283 -0
- crackerjack/mcp/tools/execution_tools.py +384 -0
- crackerjack/mcp/tools/intelligence_tool_registry.py +46 -0
- crackerjack/mcp/tools/intelligence_tools.py +264 -0
- crackerjack/mcp/tools/monitoring_tools.py +628 -0
- crackerjack/mcp/tools/proactive_tools.py +367 -0
- crackerjack/mcp/tools/progress_tools.py +222 -0
- crackerjack/mcp/tools/semantic_tools.py +584 -0
- crackerjack/mcp/tools/utility_tools.py +358 -0
- crackerjack/mcp/tools/workflow_executor.py +699 -0
- crackerjack/mcp/websocket/README.md +31 -0
- crackerjack/mcp/websocket/__init__.py +14 -0
- crackerjack/mcp/websocket/app.py +54 -0
- crackerjack/mcp/websocket/endpoints.py +492 -0
- crackerjack/mcp/websocket/event_bridge.py +188 -0
- crackerjack/mcp/websocket/jobs.py +406 -0
- 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 +21 -0
- crackerjack/mcp/websocket/server.py +174 -0
- crackerjack/mcp/websocket/websocket_handler.py +276 -0
- crackerjack/mcp/websocket_server.py +10 -0
- crackerjack/models/README.md +308 -0
- crackerjack/models/__init__.py +40 -0
- crackerjack/models/config.py +730 -0
- crackerjack/models/config_adapter.py +265 -0
- crackerjack/models/protocols.py +1535 -0
- crackerjack/models/pydantic_models.py +320 -0
- crackerjack/models/qa_config.py +145 -0
- crackerjack/models/qa_results.py +134 -0
- crackerjack/models/resource_protocols.py +299 -0
- crackerjack/models/results.py +35 -0
- crackerjack/models/semantic_models.py +258 -0
- crackerjack/models/task.py +173 -0
- crackerjack/models/test_models.py +60 -0
- crackerjack/monitoring/README.md +11 -0
- crackerjack/monitoring/__init__.py +0 -0
- crackerjack/monitoring/ai_agent_watchdog.py +405 -0
- crackerjack/monitoring/metrics_collector.py +427 -0
- crackerjack/monitoring/regression_prevention.py +580 -0
- crackerjack/monitoring/websocket_server.py +406 -0
- crackerjack/orchestration/README.md +340 -0
- crackerjack/orchestration/__init__.py +43 -0
- crackerjack/orchestration/advanced_orchestrator.py +894 -0
- 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 +180 -0
- crackerjack/orchestration/execution_strategies.py +361 -0
- 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 +647 -0
- crackerjack/plugins/README.md +11 -0
- crackerjack/plugins/__init__.py +15 -0
- crackerjack/plugins/base.py +200 -0
- crackerjack/plugins/hooks.py +254 -0
- crackerjack/plugins/loader.py +335 -0
- crackerjack/plugins/managers.py +264 -0
- crackerjack/py313.py +191 -0
- crackerjack/security/README.md +11 -0
- crackerjack/security/__init__.py +0 -0
- crackerjack/security/audit.py +197 -0
- crackerjack/services/README.md +374 -0
- crackerjack/services/__init__.py +9 -0
- crackerjack/services/ai/README.md +295 -0
- crackerjack/services/ai/__init__.py +7 -0
- crackerjack/services/ai/advanced_optimizer.py +878 -0
- crackerjack/services/ai/contextual_ai_assistant.py +542 -0
- 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/anomaly_detector.py +392 -0
- crackerjack/services/api_extractor.py +617 -0
- crackerjack/services/backup_service.py +467 -0
- crackerjack/services/bounded_status_operations.py +530 -0
- crackerjack/services/cache.py +369 -0
- crackerjack/services/changelog_automation.py +399 -0
- crackerjack/services/command_execution_service.py +305 -0
- crackerjack/services/config_integrity.py +132 -0
- crackerjack/services/config_merge.py +546 -0
- crackerjack/services/config_service.py +198 -0
- crackerjack/services/config_template.py +493 -0
- crackerjack/services/coverage_badge_service.py +173 -0
- crackerjack/services/coverage_ratchet.py +381 -0
- crackerjack/services/debug.py +733 -0
- crackerjack/services/dependency_analyzer.py +460 -0
- crackerjack/services/dependency_monitor.py +622 -0
- crackerjack/services/documentation_generator.py +493 -0
- crackerjack/services/documentation_service.py +704 -0
- crackerjack/services/enhanced_filesystem.py +497 -0
- crackerjack/services/enterprise_optimizer.py +865 -0
- crackerjack/services/error_pattern_analyzer.py +676 -0
- crackerjack/services/file_filter.py +221 -0
- crackerjack/services/file_hasher.py +149 -0
- crackerjack/services/file_io_service.py +361 -0
- crackerjack/services/file_modifier.py +615 -0
- crackerjack/services/filesystem.py +381 -0
- crackerjack/services/git.py +422 -0
- crackerjack/services/health_metrics.py +615 -0
- crackerjack/services/heatmap_generator.py +744 -0
- crackerjack/services/incremental_executor.py +380 -0
- crackerjack/services/initialization.py +823 -0
- crackerjack/services/input_validator.py +668 -0
- crackerjack/services/intelligent_commit.py +327 -0
- crackerjack/services/log_manager.py +289 -0
- crackerjack/services/logging.py +228 -0
- crackerjack/services/lsp_client.py +628 -0
- crackerjack/services/memory_optimizer.py +414 -0
- crackerjack/services/metrics.py +587 -0
- 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/monitoring/performance_benchmarks.py +410 -0
- crackerjack/services/monitoring/performance_cache.py +388 -0
- crackerjack/services/monitoring/performance_monitor.py +569 -0
- crackerjack/services/parallel_executor.py +527 -0
- crackerjack/services/pattern_cache.py +333 -0
- crackerjack/services/pattern_detector.py +478 -0
- 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 +523 -0
- 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/quality_baseline.py +395 -0
- crackerjack/services/quality/quality_baseline_enhanced.py +649 -0
- crackerjack/services/quality/quality_intelligence.py +949 -0
- crackerjack/services/regex_patterns.py +58 -0
- crackerjack/services/regex_utils.py +483 -0
- crackerjack/services/secure_path_utils.py +524 -0
- crackerjack/services/secure_status_formatter.py +450 -0
- crackerjack/services/secure_subprocess.py +635 -0
- crackerjack/services/security.py +239 -0
- crackerjack/services/security_logger.py +495 -0
- crackerjack/services/server_manager.py +411 -0
- crackerjack/services/smart_scheduling.py +167 -0
- crackerjack/services/status_authentication.py +460 -0
- crackerjack/services/status_security_manager.py +315 -0
- crackerjack/services/terminal_utils.py +0 -0
- crackerjack/services/thread_safe_status_collector.py +441 -0
- crackerjack/services/tool_filter.py +368 -0
- crackerjack/services/tool_version_service.py +43 -0
- crackerjack/services/unified_config.py +115 -0
- crackerjack/services/validation_rate_limiter.py +220 -0
- crackerjack/services/vector_store.py +689 -0
- crackerjack/services/version_analyzer.py +461 -0
- crackerjack/services/version_checker.py +223 -0
- crackerjack/services/websocket_resource_limiter.py +438 -0
- crackerjack/services/zuban_lsp_service.py +391 -0
- crackerjack/slash_commands/README.md +11 -0
- crackerjack/slash_commands/__init__.py +59 -0
- crackerjack/slash_commands/init.md +112 -0
- crackerjack/slash_commands/run.md +197 -0
- crackerjack/slash_commands/status.md +127 -0
- 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_input_validator_patterns.py +236 -0
- crackerjack/tools/validate_regex_patterns.py +188 -0
- crackerjack/ui/README.md +11 -0
- crackerjack/ui/__init__.py +1 -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.45.2.dist-info/METADATA +1678 -0
- crackerjack-0.45.2.dist-info/RECORD +478 -0
- {crackerjack-0.18.2.dist-info → crackerjack-0.45.2.dist-info}/WHEEL +1 -1
- crackerjack-0.45.2.dist-info/entry_points.txt +2 -0
- crackerjack/.gitignore +0 -14
- crackerjack/.libcst.codemod.yaml +0 -18
- crackerjack/.pdm.toml +0 -1
- crackerjack/.pre-commit-config.yaml +0 -91
- crackerjack/.pytest_cache/.gitignore +0 -2
- crackerjack/.pytest_cache/CACHEDIR.TAG +0 -4
- crackerjack/.pytest_cache/README.md +0 -8
- crackerjack/.pytest_cache/v/cache/nodeids +0 -1
- crackerjack/.pytest_cache/v/cache/stepwise +0 -1
- crackerjack/.ruff_cache/.gitignore +0 -1
- crackerjack/.ruff_cache/0.1.11/3256171999636029978 +0 -0
- crackerjack/.ruff_cache/0.1.14/602324811142551221 +0 -0
- crackerjack/.ruff_cache/0.1.4/10355199064880463147 +0 -0
- crackerjack/.ruff_cache/0.1.6/15140459877605758699 +0 -0
- crackerjack/.ruff_cache/0.1.7/1790508110482614856 +0 -0
- crackerjack/.ruff_cache/0.1.9/17041001205004563469 +0 -0
- crackerjack/.ruff_cache/0.11.2/4070660268492669020 +0 -0
- crackerjack/.ruff_cache/0.11.3/9818742842212983150 +0 -0
- crackerjack/.ruff_cache/0.11.4/9818742842212983150 +0 -0
- crackerjack/.ruff_cache/0.11.6/3557596832929915217 +0 -0
- crackerjack/.ruff_cache/0.11.7/10386934055395314831 +0 -0
- crackerjack/.ruff_cache/0.11.7/3557596832929915217 +0 -0
- crackerjack/.ruff_cache/0.11.8/530407680854991027 +0 -0
- crackerjack/.ruff_cache/0.2.0/10047773857155985907 +0 -0
- crackerjack/.ruff_cache/0.2.1/8522267973936635051 +0 -0
- crackerjack/.ruff_cache/0.2.2/18053836298936336950 +0 -0
- crackerjack/.ruff_cache/0.3.0/12548816621480535786 +0 -0
- crackerjack/.ruff_cache/0.3.3/11081883392474770722 +0 -0
- crackerjack/.ruff_cache/0.3.4/676973378459347183 +0 -0
- crackerjack/.ruff_cache/0.3.5/16311176246009842383 +0 -0
- crackerjack/.ruff_cache/0.5.7/1493622539551733492 +0 -0
- crackerjack/.ruff_cache/0.5.7/6231957614044513175 +0 -0
- crackerjack/.ruff_cache/0.5.7/9932762556785938009 +0 -0
- crackerjack/.ruff_cache/0.6.0/11982804814124138945 +0 -0
- crackerjack/.ruff_cache/0.6.0/12055761203849489982 +0 -0
- crackerjack/.ruff_cache/0.6.2/1206147804896221174 +0 -0
- crackerjack/.ruff_cache/0.6.4/1206147804896221174 +0 -0
- crackerjack/.ruff_cache/0.6.5/1206147804896221174 +0 -0
- crackerjack/.ruff_cache/0.6.7/3657366982708166874 +0 -0
- crackerjack/.ruff_cache/0.6.9/285614542852677309 +0 -0
- crackerjack/.ruff_cache/0.7.1/1024065805990144819 +0 -0
- crackerjack/.ruff_cache/0.7.1/285614542852677309 +0 -0
- crackerjack/.ruff_cache/0.7.3/16061516852537040135 +0 -0
- crackerjack/.ruff_cache/0.8.4/16354268377385700367 +0 -0
- crackerjack/.ruff_cache/0.9.10/12813592349865671909 +0 -0
- crackerjack/.ruff_cache/0.9.10/923908772239632759 +0 -0
- crackerjack/.ruff_cache/0.9.3/13948373885254993391 +0 -0
- crackerjack/.ruff_cache/0.9.9/12813592349865671909 +0 -0
- crackerjack/.ruff_cache/0.9.9/8843823720003377982 +0 -0
- crackerjack/.ruff_cache/CACHEDIR.TAG +0 -1
- crackerjack/crackerjack.py +0 -855
- crackerjack/pyproject.toml +0 -214
- crackerjack-0.18.2.dist-info/METADATA +0 -420
- crackerjack-0.18.2.dist-info/RECORD +0 -59
- crackerjack-0.18.2.dist-info/entry_points.txt +0 -4
- {crackerjack-0.18.2.dist-info → crackerjack-0.45.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,738 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import time
|
|
3
|
+
import typing as t
|
|
4
|
+
from contextlib import suppress
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from acb.depends import Inject, depends
|
|
8
|
+
from acb.logger import Logger
|
|
9
|
+
from rich.console import Console
|
|
10
|
+
|
|
11
|
+
from crackerjack.agents.base import FixResult, Issue, IssueType, Priority
|
|
12
|
+
from crackerjack.models.protocols import OptionsProtocol
|
|
13
|
+
|
|
14
|
+
from .phase_coordinator import PhaseCoordinator
|
|
15
|
+
from .session_coordinator import SessionCoordinator
|
|
16
|
+
from .timeout_manager import TimeoutStrategy, get_timeout_manager
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class AsyncWorkflowPipeline:
|
|
20
|
+
@depends.inject
|
|
21
|
+
def __init__(
|
|
22
|
+
self,
|
|
23
|
+
logger: Inject[Logger],
|
|
24
|
+
console: Inject[Console],
|
|
25
|
+
pkg_path: Path,
|
|
26
|
+
session: SessionCoordinator,
|
|
27
|
+
phases: PhaseCoordinator,
|
|
28
|
+
) -> None:
|
|
29
|
+
self.console = console
|
|
30
|
+
self.pkg_path = pkg_path
|
|
31
|
+
self.session = session
|
|
32
|
+
self.phases = phases
|
|
33
|
+
self.logger = logger
|
|
34
|
+
self.timeout_manager = get_timeout_manager()
|
|
35
|
+
self._active_tasks: list[asyncio.Task[t.Any]] = []
|
|
36
|
+
self.resource_context: t.Any | None = None
|
|
37
|
+
|
|
38
|
+
async def run_complete_workflow_async(self, options: OptionsProtocol) -> bool:
|
|
39
|
+
start_time = time.time()
|
|
40
|
+
self.session.initialize_session_tracking(options)
|
|
41
|
+
self.session.track_task("workflow", "Complete async crackerjack workflow")
|
|
42
|
+
|
|
43
|
+
try:
|
|
44
|
+
async with self.timeout_manager.timeout_context(
|
|
45
|
+
"complete_workflow", strategy=TimeoutStrategy.GRACEFUL_DEGRADATION
|
|
46
|
+
):
|
|
47
|
+
if hasattr(options, "ai_agent") and options.ai_agent:
|
|
48
|
+
success = await self._execute_ai_agent_workflow_async(options)
|
|
49
|
+
else:
|
|
50
|
+
success = await self._execute_workflow_phases_async(options)
|
|
51
|
+
self.session.finalize_session(start_time, success)
|
|
52
|
+
return success
|
|
53
|
+
except KeyboardInterrupt:
|
|
54
|
+
self.console.print("Interrupted by user")
|
|
55
|
+
self.session.fail_task("workflow", "Interrupted by user")
|
|
56
|
+
return False
|
|
57
|
+
except Exception as e:
|
|
58
|
+
self.console.print(f"Error: {e}")
|
|
59
|
+
self.session.fail_task("workflow", f"Unexpected error: {e}")
|
|
60
|
+
return False
|
|
61
|
+
finally:
|
|
62
|
+
self.session.cleanup_resources()
|
|
63
|
+
|
|
64
|
+
async def _execute_workflow_phases_async(self, options: OptionsProtocol) -> bool:
|
|
65
|
+
success = True
|
|
66
|
+
|
|
67
|
+
self.phases.run_configuration_phase(options) # type: ignore[arg-type]
|
|
68
|
+
|
|
69
|
+
if not await self._execute_cleaning_phase_async(options):
|
|
70
|
+
success = False
|
|
71
|
+
|
|
72
|
+
self.session.fail_task("workflow", "Cleaning phase failed")
|
|
73
|
+
return False
|
|
74
|
+
|
|
75
|
+
if not await self._execute_quality_phase_async(options):
|
|
76
|
+
success = False
|
|
77
|
+
|
|
78
|
+
return False
|
|
79
|
+
|
|
80
|
+
if not self.phases.run_publishing_phase(options): # type: ignore[arg-type]
|
|
81
|
+
success = False
|
|
82
|
+
self.session.fail_task("workflow", "Publishing failed")
|
|
83
|
+
return False
|
|
84
|
+
|
|
85
|
+
if not self.phases.run_commit_phase(options): # type: ignore[arg-type]
|
|
86
|
+
success = False
|
|
87
|
+
|
|
88
|
+
return success
|
|
89
|
+
|
|
90
|
+
async def _cleanup_active_tasks(self) -> None:
|
|
91
|
+
if not self._active_tasks:
|
|
92
|
+
return
|
|
93
|
+
|
|
94
|
+
self.logger.info(f"Cleaning up {len(self._active_tasks)} active tasks")
|
|
95
|
+
|
|
96
|
+
for task in self._active_tasks:
|
|
97
|
+
if not task.done():
|
|
98
|
+
task.cancel()
|
|
99
|
+
|
|
100
|
+
if self._active_tasks:
|
|
101
|
+
try:
|
|
102
|
+
await asyncio.wait_for(
|
|
103
|
+
asyncio.gather(*self._active_tasks, return_exceptions=True),
|
|
104
|
+
timeout=30.0,
|
|
105
|
+
)
|
|
106
|
+
except TimeoutError:
|
|
107
|
+
self.logger.warning("Timeout waiting for task cleanup")
|
|
108
|
+
|
|
109
|
+
self._active_tasks.clear()
|
|
110
|
+
|
|
111
|
+
async def _execute_cleaning_phase_async(self, options: OptionsProtocol) -> bool:
|
|
112
|
+
if not options.clean:
|
|
113
|
+
return True
|
|
114
|
+
|
|
115
|
+
result = await self.timeout_manager.with_timeout(
|
|
116
|
+
"file_operations",
|
|
117
|
+
asyncio.to_thread(self.phases.run_cleaning_phase, options), # type: ignore[arg-type]
|
|
118
|
+
strategy=TimeoutStrategy.RETRY_WITH_BACKOFF,
|
|
119
|
+
)
|
|
120
|
+
return bool(result) # type: ignore[return-value]
|
|
121
|
+
|
|
122
|
+
async def _execute_quality_phase_async(self, options: OptionsProtocol) -> bool:
|
|
123
|
+
if hasattr(options, "fast") and options.fast:
|
|
124
|
+
return await self._run_fast_hooks_async(options)
|
|
125
|
+
if hasattr(options, "comp") and options.comp:
|
|
126
|
+
return await self._run_comprehensive_hooks_async(options)
|
|
127
|
+
print(f"DEBUG: options.test = {options.test}")
|
|
128
|
+
if options.test:
|
|
129
|
+
return await self._execute_test_workflow_async(options)
|
|
130
|
+
return await self._execute_standard_hooks_workflow_async(options)
|
|
131
|
+
|
|
132
|
+
async def _execute_test_workflow_async(self, options: OptionsProtocol) -> bool:
|
|
133
|
+
overall_success = True
|
|
134
|
+
|
|
135
|
+
if not await self._run_fast_hooks_async(options):
|
|
136
|
+
overall_success = False
|
|
137
|
+
self.session.fail_task("workflow", "Fast hooks failed")
|
|
138
|
+
return False
|
|
139
|
+
|
|
140
|
+
try:
|
|
141
|
+
test_task, hooks_task = self._create_parallel_tasks(options)
|
|
142
|
+
done, pending = await self._execute_parallel_tasks(test_task, hooks_task)
|
|
143
|
+
|
|
144
|
+
await self._cleanup_pending_tasks(pending)
|
|
145
|
+
|
|
146
|
+
test_success, hooks_success = await self._process_task_results(
|
|
147
|
+
done, test_task, hooks_task
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
return self._validate_workflow_results(
|
|
151
|
+
test_success, hooks_success, overall_success
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
except Exception as e:
|
|
155
|
+
self.logger.error(f"Test workflow execution error: {e}")
|
|
156
|
+
self.session.fail_task("workflow", f"Test workflow error: {e}")
|
|
157
|
+
return False
|
|
158
|
+
|
|
159
|
+
def _create_parallel_tasks(
|
|
160
|
+
self, options: OptionsProtocol
|
|
161
|
+
) -> tuple[asyncio.Task[bool], asyncio.Task[bool]]:
|
|
162
|
+
test_task = asyncio.create_task(
|
|
163
|
+
self.timeout_manager.with_timeout(
|
|
164
|
+
"test_execution",
|
|
165
|
+
self._run_testing_phase_async(options),
|
|
166
|
+
strategy=TimeoutStrategy.GRACEFUL_DEGRADATION,
|
|
167
|
+
)
|
|
168
|
+
)
|
|
169
|
+
hooks_task = asyncio.create_task(
|
|
170
|
+
self.timeout_manager.with_timeout(
|
|
171
|
+
"comprehensive_hooks",
|
|
172
|
+
self._run_comprehensive_hooks_async(options),
|
|
173
|
+
strategy=TimeoutStrategy.GRACEFUL_DEGRADATION,
|
|
174
|
+
)
|
|
175
|
+
)
|
|
176
|
+
return test_task, hooks_task
|
|
177
|
+
|
|
178
|
+
async def _execute_parallel_tasks(
|
|
179
|
+
self, test_task: asyncio.Task[bool], hooks_task: asyncio.Task[bool]
|
|
180
|
+
) -> tuple[set[asyncio.Task[bool]], set[asyncio.Task[bool]]]:
|
|
181
|
+
combined_timeout = (
|
|
182
|
+
self.timeout_manager.get_timeout("test_execution")
|
|
183
|
+
+ self.timeout_manager.get_timeout("comprehensive_hooks")
|
|
184
|
+
+ 60
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
done, pending = await asyncio.wait(
|
|
188
|
+
[test_task, hooks_task],
|
|
189
|
+
timeout=combined_timeout,
|
|
190
|
+
return_when=asyncio.ALL_COMPLETED,
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
return done, pending
|
|
194
|
+
|
|
195
|
+
@staticmethod
|
|
196
|
+
async def _cleanup_pending_tasks(pending: set[asyncio.Task[t.Any]]) -> None:
|
|
197
|
+
for task in pending:
|
|
198
|
+
task.cancel()
|
|
199
|
+
with suppress(asyncio.CancelledError):
|
|
200
|
+
await task
|
|
201
|
+
|
|
202
|
+
async def _process_task_results(
|
|
203
|
+
self,
|
|
204
|
+
done: set[asyncio.Task[bool]],
|
|
205
|
+
test_task: asyncio.Task[bool],
|
|
206
|
+
hooks_task: asyncio.Task[bool],
|
|
207
|
+
) -> tuple[bool, bool]:
|
|
208
|
+
test_success = hooks_success = False
|
|
209
|
+
|
|
210
|
+
for task in done:
|
|
211
|
+
try:
|
|
212
|
+
result = await task
|
|
213
|
+
if task == test_task:
|
|
214
|
+
test_success = result
|
|
215
|
+
elif task == hooks_task:
|
|
216
|
+
hooks_success = result
|
|
217
|
+
except Exception as e:
|
|
218
|
+
self.logger.error(f"Task execution error: {e}")
|
|
219
|
+
if task == test_task:
|
|
220
|
+
test_success = False
|
|
221
|
+
elif task == hooks_task:
|
|
222
|
+
hooks_success = False
|
|
223
|
+
|
|
224
|
+
return test_success, hooks_success
|
|
225
|
+
|
|
226
|
+
def _validate_workflow_results(
|
|
227
|
+
self, test_success: bool, hooks_success: bool, overall_success: bool
|
|
228
|
+
) -> bool:
|
|
229
|
+
if not test_success:
|
|
230
|
+
overall_success = False
|
|
231
|
+
self.session.fail_task("workflow", "Testing failed")
|
|
232
|
+
return False
|
|
233
|
+
|
|
234
|
+
if not hooks_success:
|
|
235
|
+
overall_success = False
|
|
236
|
+
self.session.fail_task("workflow", "Comprehensive hooks failed")
|
|
237
|
+
return False
|
|
238
|
+
|
|
239
|
+
return overall_success
|
|
240
|
+
|
|
241
|
+
async def _execute_standard_hooks_workflow_async(
|
|
242
|
+
self,
|
|
243
|
+
options: OptionsProtocol,
|
|
244
|
+
) -> bool:
|
|
245
|
+
hooks_success = await self._run_hooks_phase_async(options)
|
|
246
|
+
if not hooks_success:
|
|
247
|
+
self.session.fail_task("workflow", "Hooks failed")
|
|
248
|
+
return False
|
|
249
|
+
return True
|
|
250
|
+
|
|
251
|
+
async def _create_managed_task(
|
|
252
|
+
self,
|
|
253
|
+
coro: t.Coroutine[t.Any, t.Any, t.Any],
|
|
254
|
+
timeout: float = 300.0,
|
|
255
|
+
task_name: str = "workflow_task",
|
|
256
|
+
) -> asyncio.Task[t.Any]:
|
|
257
|
+
task = asyncio.create_task(coro, name=task_name)
|
|
258
|
+
|
|
259
|
+
if self.resource_context:
|
|
260
|
+
self.resource_context.managed_task(task, timeout)
|
|
261
|
+
|
|
262
|
+
self._active_tasks.append(task)
|
|
263
|
+
return task
|
|
264
|
+
|
|
265
|
+
async def _run_fast_hooks_async(self, options: OptionsProtocol) -> bool:
|
|
266
|
+
result = await self.timeout_manager.with_timeout(
|
|
267
|
+
"fast_hooks",
|
|
268
|
+
asyncio.to_thread(self.phases.run_fast_hooks_only, options), # type: ignore[arg-type]
|
|
269
|
+
strategy=TimeoutStrategy.RETRY_WITH_BACKOFF,
|
|
270
|
+
)
|
|
271
|
+
return bool(result) # type: ignore[return-value]
|
|
272
|
+
|
|
273
|
+
async def _run_comprehensive_hooks_async(self, options: OptionsProtocol) -> bool:
|
|
274
|
+
result = await self.timeout_manager.with_timeout(
|
|
275
|
+
"comprehensive_hooks",
|
|
276
|
+
asyncio.to_thread(self.phases.run_comprehensive_hooks_only, options), # type: ignore[arg-type]
|
|
277
|
+
strategy=TimeoutStrategy.GRACEFUL_DEGRADATION,
|
|
278
|
+
)
|
|
279
|
+
return bool(result) # type: ignore[return-value]
|
|
280
|
+
|
|
281
|
+
async def _run_hooks_phase_async(self, options: OptionsProtocol) -> bool:
|
|
282
|
+
result = await self.timeout_manager.with_timeout(
|
|
283
|
+
"comprehensive_hooks",
|
|
284
|
+
asyncio.to_thread(self.phases.run_hooks_phase, options), # type: ignore[arg-type]
|
|
285
|
+
strategy=TimeoutStrategy.GRACEFUL_DEGRADATION,
|
|
286
|
+
)
|
|
287
|
+
return bool(result) # type: ignore[return-value]
|
|
288
|
+
|
|
289
|
+
async def _run_testing_phase_async(self, options: OptionsProtocol) -> bool:
|
|
290
|
+
result = await self.timeout_manager.with_timeout(
|
|
291
|
+
"test_execution",
|
|
292
|
+
asyncio.to_thread(self.phases.run_testing_phase, options), # type: ignore[arg-type]
|
|
293
|
+
strategy=TimeoutStrategy.GRACEFUL_DEGRADATION,
|
|
294
|
+
)
|
|
295
|
+
return bool(result) # type: ignore[return-value]
|
|
296
|
+
|
|
297
|
+
async def _execute_ai_agent_workflow_async(
|
|
298
|
+
self, options: OptionsProtocol, max_iterations: int = 10
|
|
299
|
+
) -> bool:
|
|
300
|
+
self.console.print(
|
|
301
|
+
f"🤖 Starting AI Agent workflow (max {max_iterations} iterations)"
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
self.phases.run_configuration_phase(options) # type: ignore[arg-type]
|
|
305
|
+
|
|
306
|
+
if not await self._execute_cleaning_phase_async(options):
|
|
307
|
+
self.session.fail_task("workflow", "Cleaning phase failed")
|
|
308
|
+
return False
|
|
309
|
+
|
|
310
|
+
iteration_success = await self._run_iterative_quality_improvement(
|
|
311
|
+
options, max_iterations
|
|
312
|
+
)
|
|
313
|
+
if not iteration_success:
|
|
314
|
+
return False
|
|
315
|
+
|
|
316
|
+
return await self._run_final_workflow_phases(options)
|
|
317
|
+
|
|
318
|
+
async def _run_iterative_quality_improvement(
|
|
319
|
+
self, options: OptionsProtocol, max_iterations: int
|
|
320
|
+
) -> bool:
|
|
321
|
+
for iteration in range(1, max_iterations + 1):
|
|
322
|
+
self.console.print(f"\n🔄 Iteration {iteration}/{max_iterations}")
|
|
323
|
+
|
|
324
|
+
try:
|
|
325
|
+
iteration_result = await self.timeout_manager.with_timeout(
|
|
326
|
+
"workflow_iteration",
|
|
327
|
+
self._execute_single_iteration(options, iteration),
|
|
328
|
+
strategy=TimeoutStrategy.GRACEFUL_DEGRADATION,
|
|
329
|
+
)
|
|
330
|
+
|
|
331
|
+
if iteration_result == "success":
|
|
332
|
+
self.console.print("✅ All quality checks passed !")
|
|
333
|
+
return True
|
|
334
|
+
elif iteration_result == "failed":
|
|
335
|
+
return False
|
|
336
|
+
|
|
337
|
+
except Exception as e:
|
|
338
|
+
self.logger.error(f"Iteration {iteration} failed with error: {e}")
|
|
339
|
+
self.console.print(f"⚠️ Iteration {iteration} failed: {e}")
|
|
340
|
+
|
|
341
|
+
if iteration == max_iterations:
|
|
342
|
+
return False
|
|
343
|
+
|
|
344
|
+
self.console.print(
|
|
345
|
+
f"❌ Failed to achieve code quality after {max_iterations} iterations"
|
|
346
|
+
)
|
|
347
|
+
self.session.fail_task("workflow", f"Failed after {max_iterations} iterations")
|
|
348
|
+
return False
|
|
349
|
+
|
|
350
|
+
async def _execute_single_iteration(
|
|
351
|
+
self, options: OptionsProtocol, iteration: int
|
|
352
|
+
) -> str:
|
|
353
|
+
fast_hooks_success = await self._run_fast_hooks_with_retry_async(options)
|
|
354
|
+
|
|
355
|
+
test_issues = await self._collect_test_issues_async(options)
|
|
356
|
+
hook_issues = await self._collect_comprehensive_hook_issues_async(options)
|
|
357
|
+
|
|
358
|
+
if fast_hooks_success and not test_issues and not hook_issues:
|
|
359
|
+
return "success"
|
|
360
|
+
|
|
361
|
+
if test_issues or hook_issues:
|
|
362
|
+
fix_success = await self._apply_ai_fixes_async(
|
|
363
|
+
options, test_issues, hook_issues, iteration
|
|
364
|
+
)
|
|
365
|
+
if not fix_success:
|
|
366
|
+
self.console.print(f"❌ AI fixing failed in iteration {iteration}")
|
|
367
|
+
self.session.fail_task(
|
|
368
|
+
"workflow", f"AI fixing failed in iteration {iteration}"
|
|
369
|
+
)
|
|
370
|
+
return "failed"
|
|
371
|
+
|
|
372
|
+
return "continue"
|
|
373
|
+
|
|
374
|
+
def _parse_issues_for_agents(
|
|
375
|
+
self, test_issues: list[str], hook_issues: list[str]
|
|
376
|
+
) -> list[Issue]:
|
|
377
|
+
structured_issues = []
|
|
378
|
+
|
|
379
|
+
for issue in hook_issues:
|
|
380
|
+
parsed_issue = self._parse_single_hook_issue(issue)
|
|
381
|
+
structured_issues.append(parsed_issue)
|
|
382
|
+
|
|
383
|
+
for issue in test_issues:
|
|
384
|
+
parsed_issue = self._parse_single_test_issue(issue)
|
|
385
|
+
structured_issues.append(parsed_issue)
|
|
386
|
+
|
|
387
|
+
return structured_issues
|
|
388
|
+
|
|
389
|
+
def _parse_single_hook_issue(self, issue: str) -> Issue:
|
|
390
|
+
from crackerjack.agents.base import IssueType, Priority
|
|
391
|
+
|
|
392
|
+
if "refurb: " in issue and "[FURB" in issue:
|
|
393
|
+
return self._parse_refurb_issue(issue)
|
|
394
|
+
|
|
395
|
+
hook_type_mapping = {
|
|
396
|
+
"pyright: ": (IssueType.TYPE_ERROR, Priority.HIGH, "pyright"),
|
|
397
|
+
"Type error": (IssueType.TYPE_ERROR, Priority.HIGH, "pyright"),
|
|
398
|
+
"bandit: ": (IssueType.SECURITY, Priority.HIGH, "bandit"),
|
|
399
|
+
"vulture: ": (IssueType.DEAD_CODE, Priority.MEDIUM, "vulture"),
|
|
400
|
+
"complexipy: ": (IssueType.COMPLEXITY, Priority.MEDIUM, "complexipy"),
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
for keyword, (issue_type, priority, stage) in hook_type_mapping.items():
|
|
404
|
+
if keyword in issue:
|
|
405
|
+
return self._create_generic_issue(issue, issue_type, priority, stage)
|
|
406
|
+
|
|
407
|
+
return self._create_generic_issue(
|
|
408
|
+
issue, IssueType.FORMATTING, Priority.MEDIUM, "hook"
|
|
409
|
+
)
|
|
410
|
+
|
|
411
|
+
def _parse_refurb_issue(self, issue: str) -> Issue:
|
|
412
|
+
import re
|
|
413
|
+
import uuid
|
|
414
|
+
|
|
415
|
+
from crackerjack.agents.base import Issue, IssueType, Priority
|
|
416
|
+
|
|
417
|
+
match = re.search(
|
|
418
|
+
r"refurb: \s *(.+?): (\d +): (\d +)\s +\[(\w +)\]: \s *(.+)", issue
|
|
419
|
+
)
|
|
420
|
+
if match:
|
|
421
|
+
file_path, line_num, _, error_code, message = match.groups()
|
|
422
|
+
return Issue(
|
|
423
|
+
id=str(uuid.uuid4()),
|
|
424
|
+
type=IssueType.FORMATTING,
|
|
425
|
+
severity=Priority.MEDIUM,
|
|
426
|
+
message=f"[{error_code}] {message}",
|
|
427
|
+
file_path=file_path,
|
|
428
|
+
line_number=int(line_num),
|
|
429
|
+
details=[issue],
|
|
430
|
+
stage="refurb",
|
|
431
|
+
)
|
|
432
|
+
|
|
433
|
+
return self._create_generic_issue(
|
|
434
|
+
issue, IssueType.FORMATTING, Priority.MEDIUM, "refurb"
|
|
435
|
+
)
|
|
436
|
+
|
|
437
|
+
@staticmethod
|
|
438
|
+
def _parse_single_test_issue(issue: str) -> Issue:
|
|
439
|
+
import uuid
|
|
440
|
+
|
|
441
|
+
from crackerjack.agents.base import Issue, IssueType, Priority
|
|
442
|
+
|
|
443
|
+
if "FAILED" in issue or "ERROR" in issue:
|
|
444
|
+
severity = Priority.HIGH
|
|
445
|
+
else:
|
|
446
|
+
severity = Priority.MEDIUM
|
|
447
|
+
|
|
448
|
+
return Issue(
|
|
449
|
+
id=str(uuid.uuid4()),
|
|
450
|
+
type=IssueType.TEST_FAILURE,
|
|
451
|
+
severity=severity,
|
|
452
|
+
message=issue,
|
|
453
|
+
details=[issue],
|
|
454
|
+
stage="test",
|
|
455
|
+
)
|
|
456
|
+
|
|
457
|
+
@staticmethod
|
|
458
|
+
def _create_generic_issue(
|
|
459
|
+
issue: str, issue_type: IssueType, priority: Priority, stage: str
|
|
460
|
+
) -> Issue:
|
|
461
|
+
import uuid
|
|
462
|
+
|
|
463
|
+
from crackerjack.agents.base import Issue
|
|
464
|
+
|
|
465
|
+
return Issue(
|
|
466
|
+
id=str(uuid.uuid4()),
|
|
467
|
+
type=issue_type,
|
|
468
|
+
severity=priority,
|
|
469
|
+
message=issue,
|
|
470
|
+
details=[issue],
|
|
471
|
+
stage=stage,
|
|
472
|
+
)
|
|
473
|
+
|
|
474
|
+
async def _run_final_workflow_phases(self, options: OptionsProtocol) -> bool:
|
|
475
|
+
if not self.phases.run_publishing_phase(options): # type: ignore[arg-type]
|
|
476
|
+
self.session.fail_task("workflow", "Publishing failed")
|
|
477
|
+
return False
|
|
478
|
+
|
|
479
|
+
if not self.phases.run_commit_phase(options): # type: ignore[arg-type]
|
|
480
|
+
self.session.fail_task("workflow", "Commit failed")
|
|
481
|
+
return False
|
|
482
|
+
|
|
483
|
+
return True
|
|
484
|
+
|
|
485
|
+
async def _run_fast_hooks_with_retry_async(self, options: OptionsProtocol) -> bool:
|
|
486
|
+
return await asyncio.to_thread(self.phases.run_fast_hooks_only, options) # type: ignore[arg-type]
|
|
487
|
+
|
|
488
|
+
async def _collect_test_issues_async(self, options: OptionsProtocol) -> list[str]:
|
|
489
|
+
if not options.test:
|
|
490
|
+
return []
|
|
491
|
+
|
|
492
|
+
try:
|
|
493
|
+
success = await self.timeout_manager.with_timeout(
|
|
494
|
+
"test_execution",
|
|
495
|
+
self._run_testing_phase_async(options),
|
|
496
|
+
strategy=TimeoutStrategy.GRACEFUL_DEGRADATION,
|
|
497
|
+
)
|
|
498
|
+
if success:
|
|
499
|
+
return []
|
|
500
|
+
else:
|
|
501
|
+
test_failures = self.phases.test_manager.get_test_failures()
|
|
502
|
+
if test_failures:
|
|
503
|
+
return [f"Test failure: {failure}" for failure in test_failures]
|
|
504
|
+
else:
|
|
505
|
+
return ["Test failures detected-see logs for details"]
|
|
506
|
+
except Exception as e:
|
|
507
|
+
return [f"Test execution error: {e}"]
|
|
508
|
+
|
|
509
|
+
async def _collect_comprehensive_hook_issues_async(
|
|
510
|
+
self, options: OptionsProtocol
|
|
511
|
+
) -> list[str]:
|
|
512
|
+
try:
|
|
513
|
+
hook_results = await self.timeout_manager.with_timeout(
|
|
514
|
+
"comprehensive_hooks",
|
|
515
|
+
asyncio.to_thread(self.phases.hook_manager.run_comprehensive_hooks), # type: ignore[arg-type]
|
|
516
|
+
strategy=TimeoutStrategy.GRACEFUL_DEGRADATION,
|
|
517
|
+
)
|
|
518
|
+
|
|
519
|
+
all_issues = []
|
|
520
|
+
for result in hook_results:
|
|
521
|
+
if (
|
|
522
|
+
result.status in ("failed", "error", "timeout")
|
|
523
|
+
and result.issues_found
|
|
524
|
+
):
|
|
525
|
+
hook_context = f"{result.name}: "
|
|
526
|
+
for issue in result.issues_found:
|
|
527
|
+
all_issues.append(hook_context + issue)
|
|
528
|
+
|
|
529
|
+
return all_issues
|
|
530
|
+
|
|
531
|
+
except Exception as e:
|
|
532
|
+
return [f"Comprehensive hooks error: {e}"]
|
|
533
|
+
|
|
534
|
+
async def _apply_ai_fixes_async(
|
|
535
|
+
self,
|
|
536
|
+
options: OptionsProtocol,
|
|
537
|
+
test_issues: list[str],
|
|
538
|
+
hook_issues: list[str],
|
|
539
|
+
iteration: int,
|
|
540
|
+
) -> bool:
|
|
541
|
+
all_issues = test_issues + hook_issues
|
|
542
|
+
if not all_issues:
|
|
543
|
+
return True
|
|
544
|
+
|
|
545
|
+
self.console.print(
|
|
546
|
+
f"🔧 Applying AI fixes for {len(all_issues)} issues in iteration {iteration}"
|
|
547
|
+
)
|
|
548
|
+
|
|
549
|
+
try:
|
|
550
|
+
result = await self.timeout_manager.with_timeout(
|
|
551
|
+
"ai_agent_processing",
|
|
552
|
+
self._execute_ai_fix_workflow(test_issues, hook_issues, iteration),
|
|
553
|
+
strategy=TimeoutStrategy.GRACEFUL_DEGRADATION,
|
|
554
|
+
)
|
|
555
|
+
return bool(result)
|
|
556
|
+
except Exception as e:
|
|
557
|
+
return self._handle_ai_fix_error(e)
|
|
558
|
+
|
|
559
|
+
async def _execute_ai_fix_workflow(
|
|
560
|
+
self, test_issues: list[str], hook_issues: list[str], iteration: int
|
|
561
|
+
) -> bool:
|
|
562
|
+
structured_issues = self._parse_issues_for_agents(test_issues, hook_issues)
|
|
563
|
+
|
|
564
|
+
if not structured_issues:
|
|
565
|
+
self.console.print("⚠️ No actionable issues found for AI agents")
|
|
566
|
+
return True
|
|
567
|
+
|
|
568
|
+
coordinator = self._create_agent_coordinator()
|
|
569
|
+
|
|
570
|
+
fix_result = await self.timeout_manager.with_timeout(
|
|
571
|
+
"ai_agent_processing",
|
|
572
|
+
coordinator.handle_issues(structured_issues),
|
|
573
|
+
strategy=TimeoutStrategy.GRACEFUL_DEGRADATION,
|
|
574
|
+
)
|
|
575
|
+
|
|
576
|
+
self._report_fix_results(fix_result, iteration)
|
|
577
|
+
return bool(fix_result.success if fix_result else False)
|
|
578
|
+
|
|
579
|
+
def _create_agent_coordinator(self) -> t.Any:
|
|
580
|
+
from crackerjack.agents.base import AgentContext
|
|
581
|
+
from crackerjack.agents.enhanced_coordinator import create_enhanced_coordinator
|
|
582
|
+
|
|
583
|
+
context = AgentContext(project_path=self.pkg_path)
|
|
584
|
+
# Use enhanced coordinator with Claude Code agent integration
|
|
585
|
+
return create_enhanced_coordinator(context=context, enable_external_agents=True)
|
|
586
|
+
|
|
587
|
+
def _report_fix_results(self, fix_result: FixResult, iteration: int) -> None:
|
|
588
|
+
if fix_result.success:
|
|
589
|
+
self._report_successful_fixes(fix_result, iteration)
|
|
590
|
+
else:
|
|
591
|
+
self._report_failed_fixes(fix_result, iteration)
|
|
592
|
+
|
|
593
|
+
def _report_successful_fixes(self, fix_result: FixResult, iteration: int) -> None:
|
|
594
|
+
self.console.print(f"✅ AI fixes applied successfully in iteration {iteration}")
|
|
595
|
+
if fix_result.fixes_applied:
|
|
596
|
+
self.console.print(f" Applied {len(fix_result.fixes_applied)} fixes")
|
|
597
|
+
|
|
598
|
+
def _report_failed_fixes(self, fix_result: FixResult, iteration: int) -> None:
|
|
599
|
+
self.console.print(f"⚠️ Some AI fixes failed in iteration {iteration}")
|
|
600
|
+
if fix_result.remaining_issues:
|
|
601
|
+
for error in fix_result.remaining_issues[:3]:
|
|
602
|
+
self.console.print(f" Error: {error}")
|
|
603
|
+
|
|
604
|
+
def _handle_ai_fix_error(self, error: Exception) -> bool:
|
|
605
|
+
self.logger.error(f"AI fixing failed: {error}")
|
|
606
|
+
self.console.print(f"❌ AI agent system error: {error}")
|
|
607
|
+
return False
|
|
608
|
+
|
|
609
|
+
|
|
610
|
+
class AsyncWorkflowOrchestrator:
|
|
611
|
+
@depends.inject
|
|
612
|
+
def __init__(
|
|
613
|
+
self,
|
|
614
|
+
logger: Inject[Logger],
|
|
615
|
+
console: Inject[Console],
|
|
616
|
+
pkg_path: Path | None = None,
|
|
617
|
+
dry_run: bool = False,
|
|
618
|
+
web_job_id: str | None = None,
|
|
619
|
+
verbose: bool = False,
|
|
620
|
+
debug: bool = False,
|
|
621
|
+
changed_only: bool = False,
|
|
622
|
+
) -> None:
|
|
623
|
+
# Initialize console and pkg_path first
|
|
624
|
+
self.console = console
|
|
625
|
+
self.pkg_path = pkg_path or Path.cwd()
|
|
626
|
+
self.dry_run = dry_run
|
|
627
|
+
self.web_job_id = web_job_id
|
|
628
|
+
self.verbose = verbose
|
|
629
|
+
self.debug = debug
|
|
630
|
+
self.changed_only = changed_only
|
|
631
|
+
|
|
632
|
+
# Configure ACB dependency injection using native patterns
|
|
633
|
+
from acb.depends import depends
|
|
634
|
+
|
|
635
|
+
# Register core dependencies directly with ACB
|
|
636
|
+
depends.set(Path, self.pkg_path)
|
|
637
|
+
|
|
638
|
+
# Import protocols for retrieving dependencies via ACB
|
|
639
|
+
from crackerjack.models.protocols import (
|
|
640
|
+
ConfigMergeServiceProtocol,
|
|
641
|
+
FileSystemInterface,
|
|
642
|
+
GitInterface,
|
|
643
|
+
HookManager,
|
|
644
|
+
PublishManager,
|
|
645
|
+
TestManagerProtocol,
|
|
646
|
+
)
|
|
647
|
+
|
|
648
|
+
# Setup services with ACB DI (reuse from WorkflowOrchestrator)
|
|
649
|
+
from .workflow_orchestrator import WorkflowOrchestrator
|
|
650
|
+
|
|
651
|
+
# Use a temporary orchestrator instance just for service setup
|
|
652
|
+
temp_orch = WorkflowOrchestrator.__new__(WorkflowOrchestrator)
|
|
653
|
+
temp_orch.console = self.console
|
|
654
|
+
temp_orch.pkg_path = self.pkg_path
|
|
655
|
+
temp_orch.verbose = self.verbose
|
|
656
|
+
temp_orch._setup_acb_services()
|
|
657
|
+
|
|
658
|
+
self._initialize_logging()
|
|
659
|
+
|
|
660
|
+
self.logger = logger
|
|
661
|
+
|
|
662
|
+
# Create coordinators - dependencies retrieved via ACB's depends.get_sync()
|
|
663
|
+
self.session = SessionCoordinator(self.console, self.pkg_path, self.web_job_id)
|
|
664
|
+
self.phases = PhaseCoordinator(
|
|
665
|
+
console=self.console,
|
|
666
|
+
pkg_path=self.pkg_path,
|
|
667
|
+
session=self.session,
|
|
668
|
+
filesystem=depends.get_sync(FileSystemInterface),
|
|
669
|
+
git_service=depends.get_sync(GitInterface),
|
|
670
|
+
hook_manager=depends.get_sync(HookManager),
|
|
671
|
+
test_manager=depends.get_sync(TestManagerProtocol),
|
|
672
|
+
publish_manager=depends.get_sync(PublishManager),
|
|
673
|
+
config_merge_service=depends.get_sync(ConfigMergeServiceProtocol),
|
|
674
|
+
)
|
|
675
|
+
|
|
676
|
+
self.async_pipeline = AsyncWorkflowPipeline(
|
|
677
|
+
pkg_path=self.pkg_path,
|
|
678
|
+
session=self.session,
|
|
679
|
+
phases=self.phases,
|
|
680
|
+
)
|
|
681
|
+
|
|
682
|
+
def _initialize_logging(self) -> None:
|
|
683
|
+
from crackerjack.services.log_manager import get_log_manager
|
|
684
|
+
|
|
685
|
+
log_manager = get_log_manager()
|
|
686
|
+
session_id = getattr(self, "web_job_id", None) or str(int(time.time()))[:8]
|
|
687
|
+
debug_log_file = log_manager.create_debug_log_file(session_id)
|
|
688
|
+
|
|
689
|
+
log_level = "DEBUG" if self.debug else "INFO"
|
|
690
|
+
self.logger.set_level(log_level)
|
|
691
|
+
self.logger.add_file_handler(debug_log_file)
|
|
692
|
+
|
|
693
|
+
async def run_complete_workflow_async(self, options: OptionsProtocol) -> bool:
|
|
694
|
+
return await self.async_pipeline.run_complete_workflow_async(options)
|
|
695
|
+
|
|
696
|
+
def run_complete_workflow(self, options: OptionsProtocol) -> bool:
|
|
697
|
+
return asyncio.run(self.run_complete_workflow_async(options))
|
|
698
|
+
|
|
699
|
+
def run_cleaning_phase(self, options: OptionsProtocol) -> bool:
|
|
700
|
+
result = self.phases.run_cleaning_phase(options) # type: ignore[arg-type]
|
|
701
|
+
return bool(result)
|
|
702
|
+
|
|
703
|
+
def run_fast_hooks_only(self, options: OptionsProtocol) -> bool:
|
|
704
|
+
result = self.phases.run_fast_hooks_only(options) # type: ignore[arg-type]
|
|
705
|
+
return bool(result)
|
|
706
|
+
|
|
707
|
+
def run_comprehensive_hooks_only(self, options: OptionsProtocol) -> bool:
|
|
708
|
+
result = self.phases.run_comprehensive_hooks_only(options) # type: ignore[arg-type]
|
|
709
|
+
return bool(result)
|
|
710
|
+
|
|
711
|
+
def run_hooks_phase(self, options: OptionsProtocol) -> bool:
|
|
712
|
+
result = self.phases.run_hooks_phase(options) # type: ignore[arg-type]
|
|
713
|
+
return bool(result)
|
|
714
|
+
|
|
715
|
+
def run_testing_phase(self, options: OptionsProtocol) -> bool:
|
|
716
|
+
result = self.phases.run_testing_phase(options) # type: ignore[arg-type]
|
|
717
|
+
return bool(result)
|
|
718
|
+
|
|
719
|
+
def run_publishing_phase(self, options: OptionsProtocol) -> bool:
|
|
720
|
+
result = self.phases.run_publishing_phase(options) # type: ignore[arg-type]
|
|
721
|
+
return bool(result)
|
|
722
|
+
|
|
723
|
+
def run_commit_phase(self, options: OptionsProtocol) -> bool:
|
|
724
|
+
result = self.phases.run_commit_phase(options) # type: ignore[arg-type]
|
|
725
|
+
return bool(result)
|
|
726
|
+
|
|
727
|
+
def run_configuration_phase(self, options: OptionsProtocol) -> bool:
|
|
728
|
+
result = self.phases.run_configuration_phase(options) # type: ignore[arg-type]
|
|
729
|
+
return bool(result)
|
|
730
|
+
|
|
731
|
+
def _cleanup_resources(self) -> None:
|
|
732
|
+
self.session.cleanup_resources()
|
|
733
|
+
|
|
734
|
+
def _register_cleanup(self, cleanup_handler: t.Callable[[], None]) -> None:
|
|
735
|
+
self.session.register_cleanup(cleanup_handler)
|
|
736
|
+
|
|
737
|
+
def _track_lock_file(self, lock_file_path: Path) -> None:
|
|
738
|
+
self.session.track_lock_file(lock_file_path)
|