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
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
"""Parallel execution strategy for hook orchestration.
|
|
2
|
+
|
|
3
|
+
Implements concurrent hook execution with resource limits, timeout handling,
|
|
4
|
+
and exception isolation. Uses asyncio.Semaphore for throttling.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import asyncio
|
|
10
|
+
import logging
|
|
11
|
+
import typing as t
|
|
12
|
+
|
|
13
|
+
from crackerjack.config.hooks import HookDefinition
|
|
14
|
+
from crackerjack.models.task import HookResult
|
|
15
|
+
|
|
16
|
+
# Module-level logger
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ParallelExecutionStrategy:
|
|
21
|
+
"""Parallel execution strategy with resource limits.
|
|
22
|
+
|
|
23
|
+
Features:
|
|
24
|
+
- Concurrent execution using asyncio.gather()
|
|
25
|
+
- Semaphore-based resource limiting (max concurrent hooks)
|
|
26
|
+
- Per-hook timeout handling with asyncio.wait_for()
|
|
27
|
+
- Exception isolation (one failure doesn't stop others)
|
|
28
|
+
- Structured logging for execution flow
|
|
29
|
+
|
|
30
|
+
Use when:
|
|
31
|
+
- Hooks are independent (no dependencies)
|
|
32
|
+
- Want to maximize throughput
|
|
33
|
+
- System has sufficient resources
|
|
34
|
+
|
|
35
|
+
Example:
|
|
36
|
+
```python
|
|
37
|
+
strategy = ParallelExecutionStrategy(max_parallel=3)
|
|
38
|
+
results = await strategy.execute(hooks=[hook1, hook2, hook3], timeout=300)
|
|
39
|
+
```
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
def __init__(
|
|
43
|
+
self,
|
|
44
|
+
max_parallel: int = 3,
|
|
45
|
+
default_timeout: int = 300,
|
|
46
|
+
) -> None:
|
|
47
|
+
"""Initialize parallel execution strategy.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
max_parallel: Maximum concurrent hook executions
|
|
51
|
+
default_timeout: Default timeout per hook in seconds
|
|
52
|
+
"""
|
|
53
|
+
self.max_parallel = max_parallel
|
|
54
|
+
self.default_timeout = default_timeout
|
|
55
|
+
self.semaphore: asyncio.Semaphore | None = None
|
|
56
|
+
|
|
57
|
+
logger.debug(
|
|
58
|
+
"ParallelExecutionStrategy initialized",
|
|
59
|
+
extra={
|
|
60
|
+
"max_parallel": max_parallel,
|
|
61
|
+
"default_timeout": default_timeout,
|
|
62
|
+
},
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
async def execute(
|
|
66
|
+
self,
|
|
67
|
+
hooks: list[HookDefinition],
|
|
68
|
+
max_parallel: int | None = None,
|
|
69
|
+
timeout: int | None = None,
|
|
70
|
+
executor_callable: t.Callable[[HookDefinition], t.Awaitable[HookResult]]
|
|
71
|
+
| None = None,
|
|
72
|
+
) -> list[HookResult]:
|
|
73
|
+
"""Execute hooks in parallel with resource limits.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
hooks: List of hook definitions to execute
|
|
77
|
+
max_parallel: Optional override for max concurrent executions
|
|
78
|
+
timeout: Optional override for default timeout
|
|
79
|
+
executor_callable: Async function that executes a single hook
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
List of HookResult objects (same order as input hooks)
|
|
83
|
+
"""
|
|
84
|
+
if not hooks:
|
|
85
|
+
logger.debug("No hooks to execute")
|
|
86
|
+
return []
|
|
87
|
+
|
|
88
|
+
max_par = max_parallel or self.max_parallel
|
|
89
|
+
timeout_sec = timeout or self.default_timeout
|
|
90
|
+
|
|
91
|
+
# Create fresh semaphore for this execution
|
|
92
|
+
self.semaphore = asyncio.Semaphore(max_par)
|
|
93
|
+
|
|
94
|
+
logger.info(
|
|
95
|
+
"Starting parallel execution",
|
|
96
|
+
extra={
|
|
97
|
+
"hook_count": len(hooks),
|
|
98
|
+
"max_parallel": max_par,
|
|
99
|
+
"timeout": timeout_sec,
|
|
100
|
+
},
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
async def execute_with_limit(hook: HookDefinition) -> HookResult:
|
|
104
|
+
"""Execute hook with semaphore and timeout."""
|
|
105
|
+
async with self.semaphore: # type: ignore
|
|
106
|
+
try:
|
|
107
|
+
hook_timeout = hook.timeout or timeout_sec
|
|
108
|
+
logger.debug(
|
|
109
|
+
f"Executing hook {hook.name}",
|
|
110
|
+
extra={
|
|
111
|
+
"hook": hook.name,
|
|
112
|
+
"timeout": hook_timeout,
|
|
113
|
+
},
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
if executor_callable:
|
|
117
|
+
result = await asyncio.wait_for(
|
|
118
|
+
executor_callable(hook), timeout=hook_timeout
|
|
119
|
+
)
|
|
120
|
+
else:
|
|
121
|
+
# Placeholder if no executor provided
|
|
122
|
+
result = self._placeholder_result(hook)
|
|
123
|
+
|
|
124
|
+
logger.debug(
|
|
125
|
+
f"Hook {hook.name} completed",
|
|
126
|
+
extra={
|
|
127
|
+
"hook": hook.name,
|
|
128
|
+
"status": result.status,
|
|
129
|
+
"duration": result.duration,
|
|
130
|
+
},
|
|
131
|
+
)
|
|
132
|
+
return result
|
|
133
|
+
|
|
134
|
+
except TimeoutError:
|
|
135
|
+
logger.warning(
|
|
136
|
+
f"Hook {hook.name} timed out",
|
|
137
|
+
extra={
|
|
138
|
+
"hook": hook.name,
|
|
139
|
+
"timeout": hook_timeout,
|
|
140
|
+
},
|
|
141
|
+
)
|
|
142
|
+
return HookResult(
|
|
143
|
+
id=hook.name,
|
|
144
|
+
name=hook.name,
|
|
145
|
+
status="timeout",
|
|
146
|
+
duration=hook_timeout,
|
|
147
|
+
issues_found=[f"Hook timed out after {hook_timeout}s"],
|
|
148
|
+
)
|
|
149
|
+
except Exception as e:
|
|
150
|
+
logger.error(
|
|
151
|
+
f"Hook {hook.name} raised exception",
|
|
152
|
+
extra={
|
|
153
|
+
"hook": hook.name,
|
|
154
|
+
"exception": str(e),
|
|
155
|
+
"exception_type": type(e).__name__,
|
|
156
|
+
},
|
|
157
|
+
)
|
|
158
|
+
return HookResult(
|
|
159
|
+
id=hook.name,
|
|
160
|
+
name=hook.name,
|
|
161
|
+
status="error",
|
|
162
|
+
duration=0.0,
|
|
163
|
+
issues_found=[f"Exception: {type(e).__name__}: {e}"],
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
# Create tasks for all hooks
|
|
167
|
+
tasks = [execute_with_limit(hook) for hook in hooks]
|
|
168
|
+
|
|
169
|
+
# Execute all tasks concurrently
|
|
170
|
+
results = await asyncio.gather(*tasks, return_exceptions=True)
|
|
171
|
+
|
|
172
|
+
# Handle any unexpected exceptions (shouldn't happen due to try/except above)
|
|
173
|
+
final_results = []
|
|
174
|
+
for hook, result in zip(hooks, results):
|
|
175
|
+
if isinstance(result, HookResult):
|
|
176
|
+
final_results.append(result)
|
|
177
|
+
else:
|
|
178
|
+
logger.error(
|
|
179
|
+
"Unexpected exception from gather",
|
|
180
|
+
extra={
|
|
181
|
+
"hook": hook.name,
|
|
182
|
+
"exception": str(result),
|
|
183
|
+
"exception_type": type(result).__name__,
|
|
184
|
+
},
|
|
185
|
+
)
|
|
186
|
+
final_results.append(self._error_result(hook, result))
|
|
187
|
+
|
|
188
|
+
logger.info(
|
|
189
|
+
"Parallel execution complete",
|
|
190
|
+
extra={
|
|
191
|
+
"total_hooks": len(final_results),
|
|
192
|
+
"passed": sum(1 for r in final_results if r.status == "passed"),
|
|
193
|
+
"failed": sum(1 for r in final_results if r.status == "failed"),
|
|
194
|
+
"errors": sum(
|
|
195
|
+
1 for r in final_results if r.status in ("timeout", "error")
|
|
196
|
+
),
|
|
197
|
+
},
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
return final_results
|
|
201
|
+
|
|
202
|
+
def get_execution_order(
|
|
203
|
+
self,
|
|
204
|
+
hooks: list[HookDefinition],
|
|
205
|
+
) -> list[list[HookDefinition]]:
|
|
206
|
+
"""Return batches of hooks for execution.
|
|
207
|
+
|
|
208
|
+
Parallel strategy can execute all hooks in a single batch.
|
|
209
|
+
|
|
210
|
+
Args:
|
|
211
|
+
hooks: List of hook definitions
|
|
212
|
+
|
|
213
|
+
Returns:
|
|
214
|
+
List containing one batch with all hooks
|
|
215
|
+
"""
|
|
216
|
+
return [hooks] if hooks else []
|
|
217
|
+
|
|
218
|
+
def _placeholder_result(self, hook: HookDefinition) -> HookResult:
|
|
219
|
+
"""Create placeholder result when no executor provided."""
|
|
220
|
+
return HookResult(
|
|
221
|
+
id=hook.name,
|
|
222
|
+
name=hook.name,
|
|
223
|
+
status="passed",
|
|
224
|
+
duration=0.0,
|
|
225
|
+
issues_found=[], # Initialize with empty list to match expected format
|
|
226
|
+
files_processed=0,
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
def _error_result(self, hook: HookDefinition, error: BaseException) -> HookResult:
|
|
230
|
+
"""Create error HookResult from exception."""
|
|
231
|
+
return HookResult(
|
|
232
|
+
id=hook.name,
|
|
233
|
+
name=hook.name,
|
|
234
|
+
status="error",
|
|
235
|
+
duration=0.0,
|
|
236
|
+
issues_found=[f"Exception: {type(error).__name__}: {error}"],
|
|
237
|
+
)
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
"""Sequential execution strategy for hook orchestration.
|
|
2
|
+
|
|
3
|
+
Implements one-at-a-time hook execution with support for early exit on
|
|
4
|
+
critical failures and dependency ordering.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import asyncio
|
|
10
|
+
import logging
|
|
11
|
+
import typing as t
|
|
12
|
+
|
|
13
|
+
from crackerjack.config.hooks import HookDefinition, SecurityLevel
|
|
14
|
+
from crackerjack.models.task import HookResult
|
|
15
|
+
|
|
16
|
+
# Module-level logger
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class SequentialExecutionStrategy:
|
|
21
|
+
"""Sequential execution strategy for dependent hooks.
|
|
22
|
+
|
|
23
|
+
Features:
|
|
24
|
+
- One-at-a-time execution (respects dependencies)
|
|
25
|
+
- Early exit on critical security failures
|
|
26
|
+
- Per-hook timeout handling
|
|
27
|
+
- Comprehensive logging for debugging
|
|
28
|
+
|
|
29
|
+
Use when:
|
|
30
|
+
- Hooks have dependencies (gitleaks → bandit)
|
|
31
|
+
- Resource constraints require sequential execution
|
|
32
|
+
- Debugging requires isolated execution
|
|
33
|
+
- Critical failures should stop the pipeline
|
|
34
|
+
|
|
35
|
+
Example:
|
|
36
|
+
```python
|
|
37
|
+
strategy = SequentialExecutionStrategy()
|
|
38
|
+
results = await strategy.execute(hooks=[hook1, hook2, hook3], timeout=300)
|
|
39
|
+
```
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
def __init__(
|
|
43
|
+
self,
|
|
44
|
+
default_timeout: int = 300,
|
|
45
|
+
stop_on_critical_failure: bool = True,
|
|
46
|
+
) -> None:
|
|
47
|
+
"""Initialize sequential execution strategy.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
default_timeout: Default timeout per hook in seconds
|
|
51
|
+
stop_on_critical_failure: Stop execution if critical hook fails
|
|
52
|
+
"""
|
|
53
|
+
self.default_timeout = default_timeout
|
|
54
|
+
self.stop_on_critical_failure = stop_on_critical_failure
|
|
55
|
+
|
|
56
|
+
logger.debug(
|
|
57
|
+
"SequentialExecutionStrategy initialized",
|
|
58
|
+
extra={
|
|
59
|
+
"default_timeout": default_timeout,
|
|
60
|
+
"stop_on_critical_failure": stop_on_critical_failure,
|
|
61
|
+
},
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
async def execute(
|
|
65
|
+
self,
|
|
66
|
+
hooks: list[HookDefinition],
|
|
67
|
+
max_parallel: int | None = None, # Ignored for sequential
|
|
68
|
+
timeout: int | None = None,
|
|
69
|
+
executor_callable: t.Callable[[HookDefinition], t.Awaitable[HookResult]]
|
|
70
|
+
| None = None,
|
|
71
|
+
) -> list[HookResult]:
|
|
72
|
+
"""Execute hooks sequentially.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
hooks: List of hook definitions to execute
|
|
76
|
+
max_parallel: Ignored (kept for protocol compatibility)
|
|
77
|
+
timeout: Optional override for default timeout
|
|
78
|
+
executor_callable: Async function that executes a single hook
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
List of HookResult objects (may be partial if early exit)
|
|
82
|
+
"""
|
|
83
|
+
if not hooks:
|
|
84
|
+
logger.debug("No hooks to execute")
|
|
85
|
+
return []
|
|
86
|
+
|
|
87
|
+
timeout_sec = timeout or self.default_timeout
|
|
88
|
+
self._log_execution_start(hooks, timeout_sec)
|
|
89
|
+
|
|
90
|
+
results = []
|
|
91
|
+
for idx, hook in enumerate(hooks, 1):
|
|
92
|
+
result = await self._execute_single_hook(
|
|
93
|
+
hook, idx, len(hooks), timeout_sec, executor_callable
|
|
94
|
+
)
|
|
95
|
+
results.append(result)
|
|
96
|
+
|
|
97
|
+
if self._should_stop_execution(hook, result):
|
|
98
|
+
self._log_early_exit(hook, results, hooks)
|
|
99
|
+
break
|
|
100
|
+
|
|
101
|
+
self._log_execution_complete(results, hooks)
|
|
102
|
+
return results
|
|
103
|
+
|
|
104
|
+
def _log_execution_start(
|
|
105
|
+
self, hooks: list[HookDefinition], timeout_sec: int
|
|
106
|
+
) -> None:
|
|
107
|
+
"""Log sequential execution start information."""
|
|
108
|
+
logger.info(
|
|
109
|
+
"Starting sequential execution",
|
|
110
|
+
extra={
|
|
111
|
+
"hook_count": len(hooks),
|
|
112
|
+
"timeout": timeout_sec,
|
|
113
|
+
"stop_on_critical_failure": self.stop_on_critical_failure,
|
|
114
|
+
},
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
async def _execute_single_hook(
|
|
118
|
+
self,
|
|
119
|
+
hook: HookDefinition,
|
|
120
|
+
idx: int,
|
|
121
|
+
total_hooks: int,
|
|
122
|
+
timeout_sec: int,
|
|
123
|
+
executor_callable: t.Callable[[HookDefinition], t.Awaitable[HookResult]] | None,
|
|
124
|
+
) -> HookResult:
|
|
125
|
+
"""Execute a single hook with error handling."""
|
|
126
|
+
try:
|
|
127
|
+
hook_timeout = hook.timeout or timeout_sec
|
|
128
|
+
self._log_hook_execution(hook, idx, total_hooks, hook_timeout)
|
|
129
|
+
|
|
130
|
+
result = await self._run_hook(hook, hook_timeout, executor_callable)
|
|
131
|
+
self._log_hook_completion(hook, result)
|
|
132
|
+
return result
|
|
133
|
+
|
|
134
|
+
except TimeoutError:
|
|
135
|
+
return self._handle_timeout(hook, hook.timeout or timeout_sec)
|
|
136
|
+
except Exception as e:
|
|
137
|
+
return self._handle_exception(hook, e)
|
|
138
|
+
|
|
139
|
+
def _log_hook_execution(
|
|
140
|
+
self, hook: HookDefinition, idx: int, total_hooks: int, hook_timeout: int
|
|
141
|
+
) -> None:
|
|
142
|
+
"""Log hook execution start."""
|
|
143
|
+
logger.debug(
|
|
144
|
+
f"Executing hook {idx}/{total_hooks}: {hook.name}",
|
|
145
|
+
extra={
|
|
146
|
+
"hook": hook.name,
|
|
147
|
+
"hook_index": idx,
|
|
148
|
+
"total_hooks": total_hooks,
|
|
149
|
+
"timeout": hook_timeout,
|
|
150
|
+
"security_level": hook.security_level.value,
|
|
151
|
+
},
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
async def _run_hook(
|
|
155
|
+
self,
|
|
156
|
+
hook: HookDefinition,
|
|
157
|
+
hook_timeout: int,
|
|
158
|
+
executor_callable: t.Callable[[HookDefinition], t.Awaitable[HookResult]] | None,
|
|
159
|
+
) -> HookResult:
|
|
160
|
+
"""Run hook with executor or return placeholder."""
|
|
161
|
+
if executor_callable:
|
|
162
|
+
return await asyncio.wait_for(executor_callable(hook), timeout=hook_timeout)
|
|
163
|
+
return self._placeholder_result(hook)
|
|
164
|
+
|
|
165
|
+
def _log_hook_completion(self, hook: HookDefinition, result: HookResult) -> None:
|
|
166
|
+
"""Log hook execution completion."""
|
|
167
|
+
logger.debug(
|
|
168
|
+
f"Hook {hook.name} completed",
|
|
169
|
+
extra={
|
|
170
|
+
"hook": hook.name,
|
|
171
|
+
"status": result.status,
|
|
172
|
+
"duration": result.duration,
|
|
173
|
+
},
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
def _handle_timeout(self, hook: HookDefinition, hook_timeout: int) -> HookResult:
|
|
177
|
+
"""Handle hook timeout error."""
|
|
178
|
+
logger.warning(
|
|
179
|
+
f"Hook {hook.name} timed out",
|
|
180
|
+
extra={
|
|
181
|
+
"hook": hook.name,
|
|
182
|
+
"timeout": hook_timeout,
|
|
183
|
+
},
|
|
184
|
+
)
|
|
185
|
+
return HookResult(
|
|
186
|
+
id=hook.name,
|
|
187
|
+
name=hook.name,
|
|
188
|
+
status="timeout",
|
|
189
|
+
duration=hook_timeout,
|
|
190
|
+
issues_found=[f"Hook timed out after {hook_timeout}s"],
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
def _handle_exception(
|
|
194
|
+
self, hook: HookDefinition, exception: Exception
|
|
195
|
+
) -> HookResult:
|
|
196
|
+
"""Handle hook execution exception."""
|
|
197
|
+
logger.error(
|
|
198
|
+
f"Hook {hook.name} raised exception",
|
|
199
|
+
extra={
|
|
200
|
+
"hook": hook.name,
|
|
201
|
+
"exception": str(exception),
|
|
202
|
+
"exception_type": type(exception).__name__,
|
|
203
|
+
},
|
|
204
|
+
)
|
|
205
|
+
return HookResult(
|
|
206
|
+
id=hook.name,
|
|
207
|
+
name=hook.name,
|
|
208
|
+
status="error",
|
|
209
|
+
duration=0.0,
|
|
210
|
+
issues_found=[f"Exception: {type(exception).__name__}: {exception}"],
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
def _log_early_exit(
|
|
214
|
+
self,
|
|
215
|
+
hook: HookDefinition,
|
|
216
|
+
results: list[HookResult],
|
|
217
|
+
hooks: list[HookDefinition],
|
|
218
|
+
) -> None:
|
|
219
|
+
"""Log early exit due to critical failure."""
|
|
220
|
+
remaining_hooks = len(hooks) - len(results)
|
|
221
|
+
logger.warning(
|
|
222
|
+
f"Critical hook {hook.name} failed, stopping execution",
|
|
223
|
+
extra={
|
|
224
|
+
"hook": hook.name,
|
|
225
|
+
"security_level": hook.security_level.value,
|
|
226
|
+
"executed_hooks": len(results),
|
|
227
|
+
"remaining_hooks": remaining_hooks,
|
|
228
|
+
},
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
def _log_execution_complete(
|
|
232
|
+
self, results: list[HookResult], hooks: list[HookDefinition]
|
|
233
|
+
) -> None:
|
|
234
|
+
"""Log sequential execution completion."""
|
|
235
|
+
logger.info(
|
|
236
|
+
"Sequential execution complete",
|
|
237
|
+
extra={
|
|
238
|
+
"total_hooks": len(results),
|
|
239
|
+
"executed": len(results),
|
|
240
|
+
"skipped": len(hooks) - len(results),
|
|
241
|
+
"passed": sum(1 for r in results if r.status == "passed"),
|
|
242
|
+
"failed": sum(1 for r in results if r.status == "failed"),
|
|
243
|
+
"errors": sum(1 for r in results if r.status in ("timeout", "error")),
|
|
244
|
+
},
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
def get_execution_order(
|
|
248
|
+
self,
|
|
249
|
+
hooks: list[HookDefinition],
|
|
250
|
+
) -> list[list[HookDefinition]]:
|
|
251
|
+
"""Return batches of hooks for execution.
|
|
252
|
+
|
|
253
|
+
Sequential strategy returns one hook per batch.
|
|
254
|
+
|
|
255
|
+
Args:
|
|
256
|
+
hooks: List of hook definitions
|
|
257
|
+
|
|
258
|
+
Returns:
|
|
259
|
+
List of batches, each containing one hook
|
|
260
|
+
"""
|
|
261
|
+
return [[hook] for hook in hooks]
|
|
262
|
+
|
|
263
|
+
def _should_stop_execution(
|
|
264
|
+
self,
|
|
265
|
+
hook: HookDefinition,
|
|
266
|
+
result: HookResult,
|
|
267
|
+
) -> bool:
|
|
268
|
+
"""Determine if execution should stop based on hook result.
|
|
269
|
+
|
|
270
|
+
Early exit conditions:
|
|
271
|
+
- stop_on_critical_failure is True
|
|
272
|
+
- Hook security level is CRITICAL
|
|
273
|
+
- Result status is failed, timeout, or error
|
|
274
|
+
|
|
275
|
+
Args:
|
|
276
|
+
hook: Hook definition that was executed
|
|
277
|
+
result: Result from hook execution
|
|
278
|
+
|
|
279
|
+
Returns:
|
|
280
|
+
True if execution should stop, False otherwise
|
|
281
|
+
"""
|
|
282
|
+
if not self.stop_on_critical_failure:
|
|
283
|
+
return False
|
|
284
|
+
|
|
285
|
+
is_critical = hook.security_level == SecurityLevel.CRITICAL
|
|
286
|
+
is_failure = result.status in ("failed", "timeout", "error")
|
|
287
|
+
|
|
288
|
+
return is_critical and is_failure
|
|
289
|
+
|
|
290
|
+
def _placeholder_result(self, hook: HookDefinition) -> HookResult:
|
|
291
|
+
"""Create placeholder result when no executor provided."""
|
|
292
|
+
return HookResult(
|
|
293
|
+
id=hook.name,
|
|
294
|
+
name=hook.name,
|
|
295
|
+
status="passed",
|
|
296
|
+
duration=0.0,
|
|
297
|
+
issues_found=[], # Initialize with empty list to match expected format
|
|
298
|
+
files_processed=0,
|
|
299
|
+
)
|
|
@@ -5,7 +5,7 @@ import typing as t
|
|
|
5
5
|
from dataclasses import dataclass
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
|
|
8
|
-
from
|
|
8
|
+
from acb.console import Console
|
|
9
9
|
|
|
10
10
|
from crackerjack.models.protocols import OptionsProtocol
|
|
11
11
|
from crackerjack.services.regex_patterns import SAFE_PATTERNS, CompiledPatternCache
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
> Crackerjack Docs: [Main](<../../README.md>) | [Crackerjack Package](<../README.md>) | [Plugins](<./README.md>)
|
|
2
|
+
|
|
3
|
+
# Plugins
|
|
4
|
+
|
|
5
|
+
Optional plugins and extensions to the core system.
|
|
6
|
+
|
|
7
|
+
## Related
|
|
8
|
+
|
|
9
|
+
- [Crackerjack Package](<../README.md>) - Parent package
|
|
10
|
+
- [Agents](<../agents/README.md>) - AI agent system
|
|
11
|
+
- [Services](<../services/README.md>) - Core services that plugins extend
|
crackerjack/plugins/hooks.py
CHANGED
|
@@ -3,7 +3,7 @@ import subprocess
|
|
|
3
3
|
from dataclasses import dataclass, field
|
|
4
4
|
from pathlib import Path
|
|
5
5
|
|
|
6
|
-
from
|
|
6
|
+
from acb.console import Console
|
|
7
7
|
|
|
8
8
|
from crackerjack.config.hooks import HookDefinition, HookStage
|
|
9
9
|
from crackerjack.models.protocols import OptionsProtocol
|
|
@@ -131,9 +131,10 @@ class CustomHookPlugin(HookPluginBase):
|
|
|
131
131
|
try:
|
|
132
132
|
if hook_def.command is None:
|
|
133
133
|
return HookResult(
|
|
134
|
+
id=f"hook_{hook_def.name}",
|
|
134
135
|
name=hook_def.name,
|
|
135
136
|
status="failed",
|
|
136
|
-
|
|
137
|
+
issues_found=["Hook command is None"],
|
|
137
138
|
duration=0.0,
|
|
138
139
|
)
|
|
139
140
|
cmd = hook_def.command.copy()
|
crackerjack/plugins/loader.py
CHANGED
|
@@ -132,7 +132,7 @@ class PluginLoader:
|
|
|
132
132
|
|
|
133
133
|
def _try_factory_function(
|
|
134
134
|
self,
|
|
135
|
-
factory: t.Callable,
|
|
135
|
+
factory: t.Callable[..., t.Any],
|
|
136
136
|
name: str,
|
|
137
137
|
) -> PluginBase | None:
|
|
138
138
|
try:
|
|
@@ -264,7 +264,7 @@ class PluginDiscovery:
|
|
|
264
264
|
if not directory.exists() or not directory.is_dir():
|
|
265
265
|
return []
|
|
266
266
|
|
|
267
|
-
plugin_files = []
|
|
267
|
+
plugin_files: list[Path] = []
|
|
268
268
|
|
|
269
269
|
patterns = ["*.py", "*.json", "*.yaml", "*.yml"]
|
|
270
270
|
|
|
@@ -277,7 +277,7 @@ class PluginDiscovery:
|
|
|
277
277
|
return [f for f in plugin_files if self._looks_like_plugin_file(f)]
|
|
278
278
|
|
|
279
279
|
def discover_in_project(self, project_path: Path) -> list[Path]:
|
|
280
|
-
plugin_files = []
|
|
280
|
+
plugin_files: list[Path] = []
|
|
281
281
|
|
|
282
282
|
plugin_dirs = [
|
|
283
283
|
project_path / "plugins",
|