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
|
@@ -4,9 +4,10 @@ import re
|
|
|
4
4
|
from datetime import datetime
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
|
|
7
|
-
from
|
|
7
|
+
from acb.console import Console
|
|
8
|
+
from acb.depends import Inject, depends
|
|
8
9
|
|
|
9
|
-
from .
|
|
10
|
+
from crackerjack.models.protocols import GitServiceProtocol
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
class ChangelogEntry:
|
|
@@ -33,7 +34,10 @@ class ChangelogEntry:
|
|
|
33
34
|
class ChangelogGenerator:
|
|
34
35
|
"""Generate and update changelogs based on git commits."""
|
|
35
36
|
|
|
36
|
-
|
|
37
|
+
@depends.inject
|
|
38
|
+
def __init__(
|
|
39
|
+
self, console: Inject[Console], git_service: Inject[GitServiceProtocol]
|
|
40
|
+
) -> None:
|
|
37
41
|
self.console = console
|
|
38
42
|
self.git = git_service
|
|
39
43
|
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
"""Unified command execution service with consistent error handling and timeouts."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import subprocess
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from loguru import logger
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class CommandExecutionService:
|
|
11
|
+
"""Unified command execution with consistent error handling, timeouts, and caching."""
|
|
12
|
+
|
|
13
|
+
def __init__(self, default_timeout: int = 30):
|
|
14
|
+
"""
|
|
15
|
+
Initialize the command execution service.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
default_timeout: Default timeout in seconds for commands
|
|
19
|
+
"""
|
|
20
|
+
self.default_timeout = default_timeout
|
|
21
|
+
|
|
22
|
+
async def run_command(
|
|
23
|
+
self,
|
|
24
|
+
cmd: str | list[str],
|
|
25
|
+
cwd: str | Path | None = None,
|
|
26
|
+
env: dict[str, str] | None = None,
|
|
27
|
+
timeout: int | None = None,
|
|
28
|
+
capture_output: bool = True,
|
|
29
|
+
check: bool = True,
|
|
30
|
+
) -> subprocess.CompletedProcess:
|
|
31
|
+
"""
|
|
32
|
+
Run a command with timeout and error handling.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
cmd: Command to run as a string or list of strings
|
|
36
|
+
cwd: Working directory to run the command in
|
|
37
|
+
env: Environment variables to use
|
|
38
|
+
timeout: Timeout in seconds (uses default if not specified)
|
|
39
|
+
capture_output: Whether to capture stdout/stderr
|
|
40
|
+
check: If True, raises exception on non-zero exit code
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
CompletedProcess instance with results
|
|
44
|
+
|
|
45
|
+
Raises:
|
|
46
|
+
subprocess.TimeoutExpired: If command times out
|
|
47
|
+
subprocess.CalledProcessError: If command fails and check=True
|
|
48
|
+
"""
|
|
49
|
+
timeout = timeout or self.default_timeout
|
|
50
|
+
str_cmd = " ".join(cmd) if isinstance(cmd, list) else cmd
|
|
51
|
+
logger.debug(f"Executing command: {str_cmd}")
|
|
52
|
+
|
|
53
|
+
try:
|
|
54
|
+
self._get_executable(cmd)
|
|
55
|
+
process = await self._create_subprocess(cmd, capture_output, cwd, env)
|
|
56
|
+
return await self._execute_process(
|
|
57
|
+
process, cmd, str_cmd, timeout, check, capture_output
|
|
58
|
+
)
|
|
59
|
+
except FileNotFoundError:
|
|
60
|
+
logger.error(f"Command not found: {self._get_executable(cmd)}")
|
|
61
|
+
raise
|
|
62
|
+
except Exception as e:
|
|
63
|
+
logger.error(f"Command execution failed: {str_cmd}, Error: {e}")
|
|
64
|
+
raise
|
|
65
|
+
|
|
66
|
+
def _get_executable(self, cmd: str | list[str]) -> str:
|
|
67
|
+
"""Extract executable name from command."""
|
|
68
|
+
if isinstance(cmd, list):
|
|
69
|
+
return cmd[0] if cmd else ""
|
|
70
|
+
else:
|
|
71
|
+
parts = cmd.split()
|
|
72
|
+
return parts[0] if parts else ""
|
|
73
|
+
|
|
74
|
+
async def _create_subprocess(
|
|
75
|
+
self,
|
|
76
|
+
cmd: str | list[str],
|
|
77
|
+
capture_output: bool,
|
|
78
|
+
cwd: str | Path | None,
|
|
79
|
+
env: dict[str, str] | None,
|
|
80
|
+
) -> asyncio.subprocess.Process:
|
|
81
|
+
"""Create subprocess with proper configuration."""
|
|
82
|
+
return await asyncio.create_subprocess_exec(
|
|
83
|
+
*(cmd if isinstance(cmd, list) else cmd.split()),
|
|
84
|
+
stdout=asyncio.subprocess.PIPE if capture_output else None,
|
|
85
|
+
stderr=asyncio.subprocess.PIPE if capture_output else None,
|
|
86
|
+
cwd=cwd,
|
|
87
|
+
env=env,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
async def _execute_process(
|
|
91
|
+
self,
|
|
92
|
+
process: asyncio.subprocess.Process,
|
|
93
|
+
cmd: str | list[str],
|
|
94
|
+
str_cmd: str,
|
|
95
|
+
timeout: int,
|
|
96
|
+
check: bool,
|
|
97
|
+
capture_output: bool,
|
|
98
|
+
) -> subprocess.CompletedProcess:
|
|
99
|
+
"""Execute the process and handle the result."""
|
|
100
|
+
try:
|
|
101
|
+
stdout, stderr = await asyncio.wait_for(
|
|
102
|
+
process.communicate(), timeout=timeout
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
return_code = process.returncode if process.returncode is not None else 0
|
|
106
|
+
completed_process = subprocess.CompletedProcess(
|
|
107
|
+
cmd,
|
|
108
|
+
return_code,
|
|
109
|
+
stdout.decode() if stdout else None,
|
|
110
|
+
stderr.decode() if stderr else None,
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
if check and process.returncode != 0:
|
|
114
|
+
logger.error(
|
|
115
|
+
f"Command failed with exit code {process.returncode}: {str_cmd}"
|
|
116
|
+
)
|
|
117
|
+
raise subprocess.CalledProcessError(
|
|
118
|
+
return_code,
|
|
119
|
+
cmd,
|
|
120
|
+
output=completed_process.stdout,
|
|
121
|
+
stderr=completed_process.stderr,
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
logger.debug(f"Command completed successfully: {str_cmd}")
|
|
125
|
+
return completed_process
|
|
126
|
+
|
|
127
|
+
except TimeoutError:
|
|
128
|
+
# Handle timeout
|
|
129
|
+
process.kill()
|
|
130
|
+
await process.wait() # Ensure process is cleaned up
|
|
131
|
+
logger.error(f"Command timed out after {timeout}s: {str_cmd}")
|
|
132
|
+
raise subprocess.TimeoutExpired(cmd, timeout)
|
|
133
|
+
|
|
134
|
+
def run_command_sync(
|
|
135
|
+
self,
|
|
136
|
+
cmd: str | list[str],
|
|
137
|
+
cwd: str | Path | None = None,
|
|
138
|
+
env: dict[str, str] | None = None,
|
|
139
|
+
timeout: int | None = None,
|
|
140
|
+
capture_output: bool = True,
|
|
141
|
+
check: bool = True,
|
|
142
|
+
) -> subprocess.CompletedProcess:
|
|
143
|
+
"""
|
|
144
|
+
Synchronous version of run_command.
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
cmd: Command to run as a string or list of strings
|
|
148
|
+
cwd: Working directory to run the command in
|
|
149
|
+
env: Environment variables to use
|
|
150
|
+
timeout: Timeout in seconds (uses default if not specified)
|
|
151
|
+
capture_output: Whether to capture stdout/stderr
|
|
152
|
+
check: If True, raises exception on non-zero exit code
|
|
153
|
+
|
|
154
|
+
Returns:
|
|
155
|
+
CompletedProcess instance with results
|
|
156
|
+
"""
|
|
157
|
+
timeout = timeout or self.default_timeout
|
|
158
|
+
str_cmd = " ".join(cmd) if isinstance(cmd, list) else cmd
|
|
159
|
+
|
|
160
|
+
try:
|
|
161
|
+
logger.debug(f"Executing sync command: {str_cmd}")
|
|
162
|
+
|
|
163
|
+
result = subprocess.run(
|
|
164
|
+
cmd,
|
|
165
|
+
cwd=cwd,
|
|
166
|
+
env=env,
|
|
167
|
+
timeout=timeout,
|
|
168
|
+
capture_output=capture_output,
|
|
169
|
+
text=True, # Return strings instead of bytes
|
|
170
|
+
check=check,
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
logger.debug(f"Sync command completed: {str_cmd}")
|
|
174
|
+
return result
|
|
175
|
+
|
|
176
|
+
except subprocess.TimeoutExpired:
|
|
177
|
+
logger.error(f"Sync command timed out after {timeout}s: {str_cmd}")
|
|
178
|
+
raise
|
|
179
|
+
except Exception as e:
|
|
180
|
+
logger.error(f"Sync command execution failed: {str_cmd}, Error: {e}")
|
|
181
|
+
raise
|
|
182
|
+
|
|
183
|
+
async def run_multiple_commands(
|
|
184
|
+
self,
|
|
185
|
+
commands: list[str | list[str]],
|
|
186
|
+
cwd: str | Path | None = None,
|
|
187
|
+
env: dict[str, str] | None = None,
|
|
188
|
+
timeout: int | None = None,
|
|
189
|
+
parallel: bool = False,
|
|
190
|
+
) -> list[subprocess.CompletedProcess]:
|
|
191
|
+
"""
|
|
192
|
+
Run multiple commands sequentially or in parallel.
|
|
193
|
+
|
|
194
|
+
Args:
|
|
195
|
+
commands: List of commands to run
|
|
196
|
+
cwd: Working directory to run the commands in
|
|
197
|
+
env: Environment variables to use
|
|
198
|
+
timeout: Timeout in seconds for each command
|
|
199
|
+
parallel: If True, run commands in parallel; otherwise sequentially
|
|
200
|
+
|
|
201
|
+
Returns:
|
|
202
|
+
List of CompletedProcess instances with results
|
|
203
|
+
"""
|
|
204
|
+
results = []
|
|
205
|
+
|
|
206
|
+
if parallel:
|
|
207
|
+
# Run commands in parallel
|
|
208
|
+
tasks = [
|
|
209
|
+
self.run_command(cmd, cwd=cwd, env=env, timeout=timeout)
|
|
210
|
+
for cmd in commands
|
|
211
|
+
]
|
|
212
|
+
results = await asyncio.gather(*tasks)
|
|
213
|
+
else:
|
|
214
|
+
# Run commands sequentially
|
|
215
|
+
for cmd in commands:
|
|
216
|
+
result = await self.run_command(cmd, cwd=cwd, env=env, timeout=timeout)
|
|
217
|
+
results.append(result)
|
|
218
|
+
|
|
219
|
+
return results
|
|
220
|
+
|
|
221
|
+
async def command_exists(self, command: str) -> bool:
|
|
222
|
+
"""
|
|
223
|
+
Check if a command exists in the system.
|
|
224
|
+
|
|
225
|
+
Args:
|
|
226
|
+
command: Command to check
|
|
227
|
+
|
|
228
|
+
Returns:
|
|
229
|
+
True if command exists, False otherwise
|
|
230
|
+
"""
|
|
231
|
+
try:
|
|
232
|
+
# Try running 'which' on Unix-like systems or 'where' on Windows
|
|
233
|
+
import platform
|
|
234
|
+
|
|
235
|
+
if platform.system() == "Windows":
|
|
236
|
+
check_cmd = ["where", command]
|
|
237
|
+
else:
|
|
238
|
+
check_cmd = ["which", command]
|
|
239
|
+
|
|
240
|
+
result = await self.run_command(
|
|
241
|
+
check_cmd,
|
|
242
|
+
capture_output=True,
|
|
243
|
+
check=False, # Don't raise on non-zero exit (which returns 1 if not found)
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
return result.returncode == 0
|
|
247
|
+
except (subprocess.CalledProcessError, FileNotFoundError):
|
|
248
|
+
# If the check command itself fails, command likely doesn't exist
|
|
249
|
+
return False
|
|
250
|
+
|
|
251
|
+
async def run_command_with_retries(
|
|
252
|
+
self,
|
|
253
|
+
cmd: str | list[str],
|
|
254
|
+
max_retries: int = 3,
|
|
255
|
+
cwd: str | Path | None = None,
|
|
256
|
+
env: dict[str, str] | None = None,
|
|
257
|
+
timeout: int | None = None,
|
|
258
|
+
capture_output: bool = True,
|
|
259
|
+
check: bool = True,
|
|
260
|
+
backoff_factor: float = 1.0,
|
|
261
|
+
) -> subprocess.CompletedProcess:
|
|
262
|
+
"""
|
|
263
|
+
Run a command with retry logic.
|
|
264
|
+
|
|
265
|
+
Args:
|
|
266
|
+
cmd: Command to run
|
|
267
|
+
max_retries: Maximum number of retry attempts
|
|
268
|
+
cwd: Working directory
|
|
269
|
+
env: Environment variables
|
|
270
|
+
timeout: Timeout for each attempt
|
|
271
|
+
capture_output: Whether to capture output
|
|
272
|
+
check: Whether to check return code
|
|
273
|
+
backoff_factor: Factor by which to multiply wait time between retries
|
|
274
|
+
|
|
275
|
+
Returns:
|
|
276
|
+
CompletedProcess instance with results
|
|
277
|
+
"""
|
|
278
|
+
for attempt in range(
|
|
279
|
+
max_retries + 1
|
|
280
|
+
): # +1 because first attempt doesn't count as retry
|
|
281
|
+
try:
|
|
282
|
+
return await self.run_command(
|
|
283
|
+
cmd,
|
|
284
|
+
cwd=cwd,
|
|
285
|
+
env=env,
|
|
286
|
+
timeout=timeout,
|
|
287
|
+
capture_output=capture_output,
|
|
288
|
+
check=check,
|
|
289
|
+
)
|
|
290
|
+
except (subprocess.TimeoutExpired, subprocess.CalledProcessError) as e:
|
|
291
|
+
if attempt == max_retries:
|
|
292
|
+
# Last attempt, re-raise the exception
|
|
293
|
+
logger.error(f"Command failed after {max_retries} retries: {cmd}")
|
|
294
|
+
raise
|
|
295
|
+
else:
|
|
296
|
+
# Wait before retrying with exponential backoff
|
|
297
|
+
wait_time = backoff_factor * (2**attempt)
|
|
298
|
+
logger.warning(
|
|
299
|
+
f"Command failed on attempt {attempt + 1}, "
|
|
300
|
+
f"retrying in {wait_time}s: {cmd}. Error: {e}"
|
|
301
|
+
)
|
|
302
|
+
await asyncio.sleep(wait_time)
|
|
303
|
+
|
|
304
|
+
# This line should never be reached due to the loop logic
|
|
305
|
+
raise RuntimeError("Unexpected error in run_command_with_retries")
|
|
@@ -1,15 +1,58 @@
|
|
|
1
|
+
import tomllib
|
|
2
|
+
import typing as t
|
|
1
3
|
from pathlib import Path
|
|
2
4
|
|
|
3
|
-
from
|
|
5
|
+
from acb.console import Console
|
|
6
|
+
from acb.depends import Inject, depends
|
|
4
7
|
|
|
8
|
+
from crackerjack.exceptions.config import ConfigIntegrityError
|
|
9
|
+
from crackerjack.models.protocols import ConfigIntegrityServiceProtocol, ServiceProtocol
|
|
5
10
|
|
|
6
|
-
|
|
7
|
-
|
|
11
|
+
|
|
12
|
+
class ConfigIntegrityService(ConfigIntegrityServiceProtocol, ServiceProtocol):
|
|
13
|
+
@depends.inject
|
|
14
|
+
def __init__(self, console: Inject[Console], project_path: Path) -> None:
|
|
8
15
|
self.console = console
|
|
9
16
|
self.project_path = project_path
|
|
10
17
|
self.cache_dir = Path.home() / ".cache" / "crackerjack"
|
|
11
18
|
self.cache_dir.mkdir(parents=True, exist_ok=True)
|
|
12
19
|
|
|
20
|
+
def initialize(self) -> None:
|
|
21
|
+
pass
|
|
22
|
+
|
|
23
|
+
def cleanup(self) -> None:
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
def health_check(self) -> bool:
|
|
27
|
+
return True
|
|
28
|
+
|
|
29
|
+
def shutdown(self) -> None:
|
|
30
|
+
pass
|
|
31
|
+
|
|
32
|
+
def metrics(self) -> dict[str, t.Any]:
|
|
33
|
+
return {}
|
|
34
|
+
|
|
35
|
+
def is_healthy(self) -> bool:
|
|
36
|
+
return True
|
|
37
|
+
|
|
38
|
+
def register_resource(self, resource: t.Any) -> None:
|
|
39
|
+
pass
|
|
40
|
+
|
|
41
|
+
def cleanup_resource(self, resource: t.Any) -> None:
|
|
42
|
+
pass
|
|
43
|
+
|
|
44
|
+
def record_error(self, error: Exception) -> None:
|
|
45
|
+
pass
|
|
46
|
+
|
|
47
|
+
def increment_requests(self) -> None:
|
|
48
|
+
pass
|
|
49
|
+
|
|
50
|
+
def get_custom_metric(self, name: str) -> t.Any:
|
|
51
|
+
return None
|
|
52
|
+
|
|
53
|
+
def set_custom_metric(self, name: str, value: t.Any) -> None:
|
|
54
|
+
pass
|
|
55
|
+
|
|
13
56
|
def check_config_integrity(self) -> bool:
|
|
14
57
|
config_files = [
|
|
15
58
|
".pre-commit-config.yaml",
|
|
@@ -20,13 +63,21 @@ class ConfigIntegrityService:
|
|
|
20
63
|
|
|
21
64
|
for file_name in config_files:
|
|
22
65
|
file_path = self.project_path / file_name
|
|
23
|
-
if file_path.exists()
|
|
24
|
-
|
|
66
|
+
if file_path.exists():
|
|
67
|
+
try:
|
|
68
|
+
if self._check_file_drift(file_path):
|
|
69
|
+
drift_detected = True
|
|
70
|
+
except ConfigIntegrityError as e:
|
|
71
|
+
self.console.print(
|
|
72
|
+
f"[red]❌ Error checking {file_path.name}: {e}[/ red]"
|
|
73
|
+
)
|
|
74
|
+
drift_detected = True
|
|
25
75
|
|
|
26
|
-
|
|
27
|
-
self.
|
|
28
|
-
|
|
29
|
-
|
|
76
|
+
try:
|
|
77
|
+
if not self._has_required_config_sections():
|
|
78
|
+
drift_detected = True
|
|
79
|
+
except ConfigIntegrityError as e:
|
|
80
|
+
self.console.print(f"[red]❌ Configuration integrity error: {e}[/ red]")
|
|
30
81
|
drift_detected = True
|
|
31
82
|
|
|
32
83
|
return drift_detected
|
|
@@ -39,50 +90,43 @@ class ConfigIntegrityService:
|
|
|
39
90
|
current_hash = hash(current_content)
|
|
40
91
|
|
|
41
92
|
if cache_file.exists():
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
f"[yellow]⚠️ {file_path.name} has been modified manually[/ yellow]",
|
|
49
|
-
)
|
|
50
|
-
return True
|
|
93
|
+
cached_hash = int(cache_file.read_text().strip())
|
|
94
|
+
if current_hash != cached_hash:
|
|
95
|
+
self.console.print(
|
|
96
|
+
f"[yellow]⚠️ {file_path.name} has been modified manually[/ yellow]",
|
|
97
|
+
)
|
|
98
|
+
return True
|
|
51
99
|
|
|
52
100
|
cache_file.write_text(str(current_hash))
|
|
53
101
|
return False
|
|
54
102
|
|
|
55
103
|
except OSError as e:
|
|
56
|
-
|
|
57
|
-
|
|
104
|
+
raise ConfigIntegrityError(
|
|
105
|
+
f"Failed to check file drift for {file_path.name}: {e}"
|
|
106
|
+
) from e
|
|
58
107
|
|
|
59
108
|
def _has_required_config_sections(self) -> bool:
|
|
60
109
|
pyproject = self.project_path / "pyproject.toml"
|
|
61
110
|
if not pyproject.exists():
|
|
62
|
-
|
|
111
|
+
raise ConfigIntegrityError("pyproject.toml not found.")
|
|
63
112
|
|
|
64
113
|
try:
|
|
65
|
-
import tomllib
|
|
66
|
-
|
|
67
114
|
with pyproject.open("rb") as f:
|
|
68
115
|
config = tomllib.load(f)
|
|
116
|
+
except Exception as e:
|
|
117
|
+
raise ConfigIntegrityError(f"Error parsing pyproject.toml: {e}") from e
|
|
69
118
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
for section in required:
|
|
73
|
-
keys = section.split(".")
|
|
74
|
-
current = config
|
|
119
|
+
required = ["tool.ruff", "tool.pyright", "tool.pytest.ini_options"]
|
|
75
120
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
f"[yellow]⚠️ Missing required config section: {section}[/ yellow]",
|
|
80
|
-
)
|
|
81
|
-
return False
|
|
82
|
-
current = current[key]
|
|
121
|
+
for section in required:
|
|
122
|
+
keys = section.split(".")
|
|
123
|
+
current = config
|
|
83
124
|
|
|
84
|
-
|
|
125
|
+
for key in keys:
|
|
126
|
+
if key not in current:
|
|
127
|
+
raise ConfigIntegrityError(
|
|
128
|
+
f"Missing required config section: {section} in pyproject.toml"
|
|
129
|
+
)
|
|
130
|
+
current = current[key]
|
|
85
131
|
|
|
86
|
-
|
|
87
|
-
self.console.print(f"[red]❌ Error parsing pyproject.toml: {e}[/ red]")
|
|
88
|
-
return False
|
|
132
|
+
return True
|
|
@@ -6,27 +6,30 @@ from pathlib import Path
|
|
|
6
6
|
import tomli
|
|
7
7
|
import tomli_w
|
|
8
8
|
import yaml
|
|
9
|
-
from
|
|
9
|
+
from acb.console import Console
|
|
10
|
+
from acb.depends import Inject, depends
|
|
11
|
+
from acb.logger import Logger
|
|
10
12
|
|
|
11
13
|
from crackerjack.models.protocols import (
|
|
12
14
|
ConfigMergeServiceProtocol,
|
|
13
15
|
FileSystemInterface,
|
|
14
16
|
GitInterface,
|
|
15
17
|
)
|
|
16
|
-
from crackerjack.services.logging import get_logger
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
class ConfigMergeService(ConfigMergeServiceProtocol):
|
|
21
|
+
@depends.inject
|
|
20
22
|
def __init__(
|
|
21
23
|
self,
|
|
22
|
-
console: Console,
|
|
23
|
-
filesystem: FileSystemInterface,
|
|
24
|
-
git_service: GitInterface,
|
|
24
|
+
console: Inject[Console],
|
|
25
|
+
filesystem: Inject[FileSystemInterface],
|
|
26
|
+
git_service: Inject[GitInterface],
|
|
27
|
+
logger: Inject[Logger],
|
|
25
28
|
) -> None:
|
|
26
29
|
self.console = console
|
|
27
30
|
self.filesystem = filesystem
|
|
28
31
|
self.git_service = git_service
|
|
29
|
-
self.logger =
|
|
32
|
+
self.logger = logger
|
|
30
33
|
|
|
31
34
|
def smart_merge_pyproject(
|
|
32
35
|
self,
|