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,380 @@
|
|
|
1
|
+
"""Incremental execution with intelligent caching.
|
|
2
|
+
|
|
3
|
+
Phase 10.3.2: Implements file hash tracking and persistent caching to skip
|
|
4
|
+
unchanged files and reuse previous results.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import hashlib
|
|
8
|
+
import json
|
|
9
|
+
from collections.abc import Callable
|
|
10
|
+
from contextlib import suppress
|
|
11
|
+
from dataclasses import dataclass, field
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from typing import Any
|
|
14
|
+
|
|
15
|
+
from crackerjack.services.profiler import ToolProfiler
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass
|
|
19
|
+
class FileHash:
|
|
20
|
+
"""File hash metadata."""
|
|
21
|
+
|
|
22
|
+
path: str
|
|
23
|
+
hash: str
|
|
24
|
+
size: int
|
|
25
|
+
modified_time: float
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass
|
|
29
|
+
class CacheEntry:
|
|
30
|
+
"""Cached execution result."""
|
|
31
|
+
|
|
32
|
+
tool_name: str
|
|
33
|
+
file_hash: FileHash
|
|
34
|
+
result: Any
|
|
35
|
+
timestamp: float
|
|
36
|
+
success: bool
|
|
37
|
+
error_message: str | None = None
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass
|
|
41
|
+
class ExecutionResult:
|
|
42
|
+
"""Result of incremental execution."""
|
|
43
|
+
|
|
44
|
+
tool_name: str
|
|
45
|
+
files_processed: int
|
|
46
|
+
files_cached: int
|
|
47
|
+
files_changed: int
|
|
48
|
+
cache_hit_rate: float
|
|
49
|
+
execution_time: float
|
|
50
|
+
results: dict[str, Any] = field(default_factory=dict)
|
|
51
|
+
|
|
52
|
+
@property
|
|
53
|
+
def cache_effective(self) -> bool:
|
|
54
|
+
"""Whether caching was effective (>50% hit rate)."""
|
|
55
|
+
return self.cache_hit_rate >= 50.0
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class IncrementalExecutor:
|
|
59
|
+
"""Executes tools incrementally with intelligent caching."""
|
|
60
|
+
|
|
61
|
+
def __init__(
|
|
62
|
+
self,
|
|
63
|
+
cache_dir: Path | None = None,
|
|
64
|
+
ttl_seconds: int = 86400, # 24 hours
|
|
65
|
+
profiler: ToolProfiler | None = None,
|
|
66
|
+
):
|
|
67
|
+
"""Initialize incremental executor.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
cache_dir: Directory for cache storage
|
|
71
|
+
ttl_seconds: Time-to-live for cache entries (default: 24 hours)
|
|
72
|
+
profiler: Optional profiler for performance tracking
|
|
73
|
+
"""
|
|
74
|
+
self.cache_dir = cache_dir or Path.cwd() / ".crackerjack" / "cache"
|
|
75
|
+
self.cache_dir.mkdir(parents=True, exist_ok=True)
|
|
76
|
+
self.ttl_seconds = ttl_seconds
|
|
77
|
+
self.profiler = profiler
|
|
78
|
+
self._cache: dict[str, CacheEntry] = {}
|
|
79
|
+
self._file_hashes: dict[str, FileHash] = {}
|
|
80
|
+
self._load_cache()
|
|
81
|
+
|
|
82
|
+
def _compute_file_hash(self, file_path: Path) -> FileHash:
|
|
83
|
+
"""Compute hash for a file.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
file_path: Path to file
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
FileHash with metadata
|
|
90
|
+
"""
|
|
91
|
+
try:
|
|
92
|
+
content = file_path.read_bytes()
|
|
93
|
+
hash_value = hashlib.sha256(content).hexdigest()
|
|
94
|
+
stat = file_path.stat()
|
|
95
|
+
|
|
96
|
+
return FileHash(
|
|
97
|
+
path=str(file_path),
|
|
98
|
+
hash=hash_value,
|
|
99
|
+
size=stat.st_size,
|
|
100
|
+
modified_time=stat.st_mtime,
|
|
101
|
+
)
|
|
102
|
+
except OSError:
|
|
103
|
+
# Return empty hash for files that can't be read
|
|
104
|
+
return FileHash(
|
|
105
|
+
path=str(file_path),
|
|
106
|
+
hash="",
|
|
107
|
+
size=0,
|
|
108
|
+
modified_time=0.0,
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
def _cache_key(self, tool_name: str, file_hash: FileHash) -> str:
|
|
112
|
+
"""Generate cache key.
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
tool_name: Name of the tool
|
|
116
|
+
file_hash: File hash metadata
|
|
117
|
+
|
|
118
|
+
Returns:
|
|
119
|
+
Cache key string
|
|
120
|
+
"""
|
|
121
|
+
return f"{tool_name}:{file_hash.hash}"
|
|
122
|
+
|
|
123
|
+
def _load_cache(self) -> None:
|
|
124
|
+
"""Load cache from disk."""
|
|
125
|
+
cache_file = self.cache_dir / "incremental_cache.json"
|
|
126
|
+
if not cache_file.exists():
|
|
127
|
+
return
|
|
128
|
+
|
|
129
|
+
try:
|
|
130
|
+
data = json.loads(cache_file.read_text())
|
|
131
|
+
import time
|
|
132
|
+
|
|
133
|
+
current_time = time.time()
|
|
134
|
+
|
|
135
|
+
for entry_data in data.get("entries", []):
|
|
136
|
+
# Skip expired entries
|
|
137
|
+
if current_time - entry_data["timestamp"] > self.ttl_seconds:
|
|
138
|
+
continue
|
|
139
|
+
|
|
140
|
+
file_hash = FileHash(**entry_data["file_hash"])
|
|
141
|
+
entry = CacheEntry(
|
|
142
|
+
tool_name=entry_data["tool_name"],
|
|
143
|
+
file_hash=file_hash,
|
|
144
|
+
result=entry_data["result"],
|
|
145
|
+
timestamp=entry_data["timestamp"],
|
|
146
|
+
success=entry_data["success"],
|
|
147
|
+
error_message=entry_data.get("error_message"),
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
key = self._cache_key(entry.tool_name, file_hash)
|
|
151
|
+
self._cache[key] = entry
|
|
152
|
+
except (json.JSONDecodeError, KeyError, OSError):
|
|
153
|
+
# Corrupted cache - start fresh
|
|
154
|
+
self._cache = {}
|
|
155
|
+
|
|
156
|
+
def _save_cache(self) -> None:
|
|
157
|
+
"""Save cache to disk."""
|
|
158
|
+
cache_file = self.cache_dir / "incremental_cache.json"
|
|
159
|
+
|
|
160
|
+
data = {
|
|
161
|
+
"entries": [
|
|
162
|
+
{
|
|
163
|
+
"tool_name": entry.tool_name,
|
|
164
|
+
"file_hash": {
|
|
165
|
+
"path": entry.file_hash.path,
|
|
166
|
+
"hash": entry.file_hash.hash,
|
|
167
|
+
"size": entry.file_hash.size,
|
|
168
|
+
"modified_time": entry.file_hash.modified_time,
|
|
169
|
+
},
|
|
170
|
+
"result": entry.result,
|
|
171
|
+
"timestamp": entry.timestamp,
|
|
172
|
+
"success": entry.success,
|
|
173
|
+
"error_message": entry.error_message,
|
|
174
|
+
}
|
|
175
|
+
for entry in self._cache.values()
|
|
176
|
+
]
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
with suppress(OSError):
|
|
180
|
+
cache_file.write_text(json.dumps(data, indent=2))
|
|
181
|
+
|
|
182
|
+
def execute_incremental(
|
|
183
|
+
self,
|
|
184
|
+
tool_name: str,
|
|
185
|
+
files: list[Path],
|
|
186
|
+
tool_func: Callable[[Path], Any],
|
|
187
|
+
force_rerun: bool = False,
|
|
188
|
+
) -> ExecutionResult:
|
|
189
|
+
"""Execute tool incrementally with caching.
|
|
190
|
+
|
|
191
|
+
Args:
|
|
192
|
+
tool_name: Name of the tool
|
|
193
|
+
files: List of files to process
|
|
194
|
+
tool_func: Function to execute on each file
|
|
195
|
+
force_rerun: Skip cache and rerun all files
|
|
196
|
+
|
|
197
|
+
Returns:
|
|
198
|
+
ExecutionResult with statistics
|
|
199
|
+
"""
|
|
200
|
+
import time
|
|
201
|
+
|
|
202
|
+
start_time = time.perf_counter()
|
|
203
|
+
|
|
204
|
+
files_cached = 0
|
|
205
|
+
files_changed = 0
|
|
206
|
+
results: dict[str, Any] = {}
|
|
207
|
+
|
|
208
|
+
for file_path in files:
|
|
209
|
+
# Compute current hash
|
|
210
|
+
current_hash = self._compute_file_hash(file_path)
|
|
211
|
+
cache_key = self._cache_key(tool_name, current_hash)
|
|
212
|
+
|
|
213
|
+
# Check cache
|
|
214
|
+
if not force_rerun and cache_key in self._cache:
|
|
215
|
+
cached_entry = self._cache[cache_key]
|
|
216
|
+
results[str(file_path)] = cached_entry.result
|
|
217
|
+
files_cached += 1
|
|
218
|
+
|
|
219
|
+
# Update profiler cache stats
|
|
220
|
+
if self.profiler and tool_name in self.profiler.results:
|
|
221
|
+
self.profiler.results[tool_name].cache_hits += 1
|
|
222
|
+
else:
|
|
223
|
+
# Execute tool
|
|
224
|
+
try:
|
|
225
|
+
result = tool_func(file_path)
|
|
226
|
+
success = True
|
|
227
|
+
error_msg = None
|
|
228
|
+
except Exception as e:
|
|
229
|
+
result = None
|
|
230
|
+
success = False
|
|
231
|
+
error_msg = str(e)
|
|
232
|
+
|
|
233
|
+
results[str(file_path)] = result
|
|
234
|
+
files_changed += 1
|
|
235
|
+
|
|
236
|
+
# Update profiler cache stats
|
|
237
|
+
if self.profiler and tool_name in self.profiler.results:
|
|
238
|
+
self.profiler.results[tool_name].cache_misses += 1
|
|
239
|
+
|
|
240
|
+
# Store in cache
|
|
241
|
+
entry = CacheEntry(
|
|
242
|
+
tool_name=tool_name,
|
|
243
|
+
file_hash=current_hash,
|
|
244
|
+
result=result,
|
|
245
|
+
timestamp=time.time(),
|
|
246
|
+
success=success,
|
|
247
|
+
error_message=error_msg,
|
|
248
|
+
)
|
|
249
|
+
self._cache[cache_key] = entry
|
|
250
|
+
|
|
251
|
+
# Calculate statistics
|
|
252
|
+
total_files = len(files)
|
|
253
|
+
cache_hit_rate = (files_cached / total_files * 100) if total_files > 0 else 0.0
|
|
254
|
+
execution_time = time.perf_counter() - start_time
|
|
255
|
+
|
|
256
|
+
# Save cache
|
|
257
|
+
self._save_cache()
|
|
258
|
+
|
|
259
|
+
return ExecutionResult(
|
|
260
|
+
tool_name=tool_name,
|
|
261
|
+
files_processed=total_files,
|
|
262
|
+
files_cached=files_cached,
|
|
263
|
+
files_changed=files_changed,
|
|
264
|
+
cache_hit_rate=cache_hit_rate,
|
|
265
|
+
execution_time=execution_time,
|
|
266
|
+
results=results,
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
def get_changed_files(
|
|
270
|
+
self,
|
|
271
|
+
tool_name: str,
|
|
272
|
+
files: list[Path],
|
|
273
|
+
) -> list[Path]:
|
|
274
|
+
"""Get list of files that have changed since last execution.
|
|
275
|
+
|
|
276
|
+
Args:
|
|
277
|
+
tool_name: Name of the tool
|
|
278
|
+
files: List of files to check
|
|
279
|
+
|
|
280
|
+
Returns:
|
|
281
|
+
List of changed files
|
|
282
|
+
"""
|
|
283
|
+
changed_files: list[Path] = []
|
|
284
|
+
|
|
285
|
+
for file_path in files:
|
|
286
|
+
current_hash = self._compute_file_hash(file_path)
|
|
287
|
+
cache_key = self._cache_key(tool_name, current_hash)
|
|
288
|
+
|
|
289
|
+
# If not in cache or hash differs, it's changed
|
|
290
|
+
if cache_key not in self._cache:
|
|
291
|
+
changed_files.append(file_path)
|
|
292
|
+
|
|
293
|
+
return changed_files
|
|
294
|
+
|
|
295
|
+
def invalidate_file(self, file_path: Path) -> int:
|
|
296
|
+
"""Invalidate all cache entries for a file.
|
|
297
|
+
|
|
298
|
+
Args:
|
|
299
|
+
file_path: Path to file
|
|
300
|
+
|
|
301
|
+
Returns:
|
|
302
|
+
Number of entries invalidated
|
|
303
|
+
"""
|
|
304
|
+
file_str = str(file_path)
|
|
305
|
+
invalidated = 0
|
|
306
|
+
|
|
307
|
+
# Remove all cache entries for this file
|
|
308
|
+
keys_to_remove = [
|
|
309
|
+
key
|
|
310
|
+
for key, entry in self._cache.items()
|
|
311
|
+
if entry.file_hash.path == file_str
|
|
312
|
+
]
|
|
313
|
+
|
|
314
|
+
for key in keys_to_remove:
|
|
315
|
+
del self._cache[key]
|
|
316
|
+
invalidated += 1
|
|
317
|
+
|
|
318
|
+
if invalidated > 0:
|
|
319
|
+
self._save_cache()
|
|
320
|
+
|
|
321
|
+
return invalidated
|
|
322
|
+
|
|
323
|
+
def clear_cache(self, tool_name: str | None = None) -> int:
|
|
324
|
+
"""Clear cache entries.
|
|
325
|
+
|
|
326
|
+
Args:
|
|
327
|
+
tool_name: Optional tool name to clear (clears all if None)
|
|
328
|
+
|
|
329
|
+
Returns:
|
|
330
|
+
Number of entries cleared
|
|
331
|
+
"""
|
|
332
|
+
if tool_name is None:
|
|
333
|
+
# Clear all
|
|
334
|
+
count = len(self._cache)
|
|
335
|
+
self._cache = {}
|
|
336
|
+
else:
|
|
337
|
+
# Clear specific tool
|
|
338
|
+
keys_to_remove = [
|
|
339
|
+
key
|
|
340
|
+
for key, entry in self._cache.items()
|
|
341
|
+
if entry.tool_name == tool_name
|
|
342
|
+
]
|
|
343
|
+
count = len(keys_to_remove)
|
|
344
|
+
for key in keys_to_remove:
|
|
345
|
+
del self._cache[key]
|
|
346
|
+
|
|
347
|
+
if count > 0:
|
|
348
|
+
self._save_cache()
|
|
349
|
+
|
|
350
|
+
return count
|
|
351
|
+
|
|
352
|
+
def get_cache_stats(self) -> dict[str, Any]:
|
|
353
|
+
"""Get cache statistics.
|
|
354
|
+
|
|
355
|
+
Returns:
|
|
356
|
+
Dictionary with cache statistics
|
|
357
|
+
"""
|
|
358
|
+
total_entries = len(self._cache)
|
|
359
|
+
tools = {entry.tool_name for entry in self._cache.values()}
|
|
360
|
+
success_count = sum(1 for entry in self._cache.values() if entry.success)
|
|
361
|
+
|
|
362
|
+
return {
|
|
363
|
+
"total_entries": total_entries,
|
|
364
|
+
"unique_tools": len(tools),
|
|
365
|
+
"success_rate": (success_count / total_entries * 100)
|
|
366
|
+
if total_entries > 0
|
|
367
|
+
else 0.0,
|
|
368
|
+
"cache_size_mb": self._estimate_cache_size(),
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
def _estimate_cache_size(self) -> float:
|
|
372
|
+
"""Estimate cache size in MB.
|
|
373
|
+
|
|
374
|
+
Returns:
|
|
375
|
+
Estimated size in megabytes
|
|
376
|
+
"""
|
|
377
|
+
cache_file = self.cache_dir / "incremental_cache.json"
|
|
378
|
+
if cache_file.exists():
|
|
379
|
+
return cache_file.stat().st_size / 1024 / 1024
|
|
380
|
+
return 0.0
|
|
@@ -5,7 +5,8 @@ from pathlib import Path
|
|
|
5
5
|
|
|
6
6
|
import tomli
|
|
7
7
|
import yaml
|
|
8
|
-
from
|
|
8
|
+
from acb.console import Console
|
|
9
|
+
from acb.depends import Inject, depends
|
|
9
10
|
|
|
10
11
|
from crackerjack.models.protocols import ConfigMergeServiceProtocol
|
|
11
12
|
|
|
@@ -16,9 +17,10 @@ from .input_validator import get_input_validator, validate_and_sanitize_path
|
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
class InitializationService:
|
|
20
|
+
@depends.inject
|
|
19
21
|
def __init__(
|
|
20
22
|
self,
|
|
21
|
-
console: Console,
|
|
23
|
+
console: Inject[Console],
|
|
22
24
|
filesystem: FileSystemService,
|
|
23
25
|
git_service: GitService,
|
|
24
26
|
pkg_path: Path,
|
|
@@ -30,7 +32,7 @@ class InitializationService:
|
|
|
30
32
|
self.pkg_path = pkg_path
|
|
31
33
|
|
|
32
34
|
self.config_merge_service = config_merge_service or ConfigMergeService(
|
|
33
|
-
|
|
35
|
+
filesystem, git_service
|
|
34
36
|
)
|
|
35
37
|
|
|
36
38
|
def initialize_project(self, project_path: str | Path) -> bool:
|
|
@@ -116,8 +118,8 @@ class InitializationService:
|
|
|
116
118
|
}
|
|
117
119
|
|
|
118
120
|
def _get_config_files(self) -> dict[str, str]:
|
|
121
|
+
# Skip pre-commit configuration to prevent hook installation
|
|
119
122
|
return {
|
|
120
|
-
".pre-commit-config.yaml": "smart_merge",
|
|
121
123
|
"pyproject.toml": "smart_merge",
|
|
122
124
|
".gitignore": "smart_merge_gitignore",
|
|
123
125
|
"CLAUDE.md": "smart_append",
|
|
@@ -125,6 +127,92 @@ class InitializationService:
|
|
|
125
127
|
"example.mcp.json": "special",
|
|
126
128
|
}
|
|
127
129
|
|
|
130
|
+
def _apply_merge_strategy(
|
|
131
|
+
self,
|
|
132
|
+
merge_strategy: str,
|
|
133
|
+
source_file: Path,
|
|
134
|
+
target_file: Path,
|
|
135
|
+
file_name: str,
|
|
136
|
+
project_name: str,
|
|
137
|
+
force: bool,
|
|
138
|
+
results: dict[str, t.Any],
|
|
139
|
+
) -> None:
|
|
140
|
+
"""Apply the appropriate merge strategy for the config file."""
|
|
141
|
+
if merge_strategy == "smart_merge":
|
|
142
|
+
self._smart_merge_config(
|
|
143
|
+
source_file,
|
|
144
|
+
target_file,
|
|
145
|
+
file_name,
|
|
146
|
+
project_name,
|
|
147
|
+
force,
|
|
148
|
+
results,
|
|
149
|
+
)
|
|
150
|
+
elif merge_strategy == "smart_merge_gitignore":
|
|
151
|
+
self._smart_merge_gitignore(
|
|
152
|
+
target_file,
|
|
153
|
+
project_name,
|
|
154
|
+
force,
|
|
155
|
+
results,
|
|
156
|
+
)
|
|
157
|
+
elif merge_strategy == "smart_append":
|
|
158
|
+
self._smart_append_config(
|
|
159
|
+
source_file,
|
|
160
|
+
target_file,
|
|
161
|
+
file_name,
|
|
162
|
+
project_name,
|
|
163
|
+
force,
|
|
164
|
+
results,
|
|
165
|
+
)
|
|
166
|
+
elif merge_strategy == "replace_if_missing":
|
|
167
|
+
self._handle_replace_if_missing(
|
|
168
|
+
source_file,
|
|
169
|
+
target_file,
|
|
170
|
+
file_name,
|
|
171
|
+
project_name,
|
|
172
|
+
force,
|
|
173
|
+
results,
|
|
174
|
+
)
|
|
175
|
+
else:
|
|
176
|
+
self._handle_default_strategy(
|
|
177
|
+
source_file,
|
|
178
|
+
target_file,
|
|
179
|
+
file_name,
|
|
180
|
+
project_name,
|
|
181
|
+
force,
|
|
182
|
+
results,
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
def _handle_replace_if_missing(
|
|
186
|
+
self,
|
|
187
|
+
source_file: Path,
|
|
188
|
+
target_file: Path,
|
|
189
|
+
file_name: str,
|
|
190
|
+
project_name: str,
|
|
191
|
+
force: bool,
|
|
192
|
+
results: dict[str, t.Any],
|
|
193
|
+
) -> None:
|
|
194
|
+
"""Handle replace_if_missing strategy."""
|
|
195
|
+
if not target_file.exists() or force:
|
|
196
|
+
content = self._read_and_process_content(source_file, True, project_name)
|
|
197
|
+
self._write_file_and_track(target_file, content, file_name, results)
|
|
198
|
+
else:
|
|
199
|
+
self._skip_existing_file(file_name, results)
|
|
200
|
+
|
|
201
|
+
def _handle_default_strategy(
|
|
202
|
+
self,
|
|
203
|
+
source_file: Path,
|
|
204
|
+
target_file: Path,
|
|
205
|
+
file_name: str,
|
|
206
|
+
project_name: str,
|
|
207
|
+
force: bool,
|
|
208
|
+
results: dict[str, t.Any],
|
|
209
|
+
) -> None:
|
|
210
|
+
"""Handle default copy strategy."""
|
|
211
|
+
if not self._should_copy_file(target_file, force, file_name, results):
|
|
212
|
+
return
|
|
213
|
+
content = self._read_and_process_content(source_file, True, project_name)
|
|
214
|
+
self._write_file_and_track(target_file, content, file_name, results)
|
|
215
|
+
|
|
128
216
|
def _process_config_file(
|
|
129
217
|
self,
|
|
130
218
|
file_name: str,
|
|
@@ -148,51 +236,15 @@ class InitializationService:
|
|
|
148
236
|
return
|
|
149
237
|
|
|
150
238
|
try:
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
elif merge_strategy == "smart_merge_gitignore":
|
|
161
|
-
self._smart_merge_gitignore(
|
|
162
|
-
target_file,
|
|
163
|
-
project_name,
|
|
164
|
-
force,
|
|
165
|
-
results,
|
|
166
|
-
)
|
|
167
|
-
elif merge_strategy == "smart_append":
|
|
168
|
-
self._smart_append_config(
|
|
169
|
-
source_file,
|
|
170
|
-
target_file,
|
|
171
|
-
file_name,
|
|
172
|
-
project_name,
|
|
173
|
-
force,
|
|
174
|
-
results,
|
|
175
|
-
)
|
|
176
|
-
elif merge_strategy == "replace_if_missing":
|
|
177
|
-
if not target_file.exists() or force:
|
|
178
|
-
content = self._read_and_process_content(
|
|
179
|
-
source_file,
|
|
180
|
-
True,
|
|
181
|
-
project_name,
|
|
182
|
-
)
|
|
183
|
-
self._write_file_and_track(target_file, content, file_name, results)
|
|
184
|
-
else:
|
|
185
|
-
self._skip_existing_file(file_name, results)
|
|
186
|
-
else:
|
|
187
|
-
if not self._should_copy_file(target_file, force, file_name, results):
|
|
188
|
-
return
|
|
189
|
-
content = self._read_and_process_content(
|
|
190
|
-
source_file,
|
|
191
|
-
True,
|
|
192
|
-
project_name,
|
|
193
|
-
)
|
|
194
|
-
self._write_file_and_track(target_file, content, file_name, results)
|
|
195
|
-
|
|
239
|
+
self._apply_merge_strategy(
|
|
240
|
+
merge_strategy,
|
|
241
|
+
source_file,
|
|
242
|
+
target_file,
|
|
243
|
+
file_name,
|
|
244
|
+
project_name,
|
|
245
|
+
force,
|
|
246
|
+
results,
|
|
247
|
+
)
|
|
196
248
|
except Exception as e:
|
|
197
249
|
self._handle_file_processing_error(file_name, e, results)
|
|
198
250
|
|