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,114 @@
|
|
|
1
|
+
"""Git-aware wrapper for mdformat.
|
|
2
|
+
|
|
3
|
+
This wrapper ensures mdformat only checks git-tracked markdown files,
|
|
4
|
+
automatically respecting .gitignore patterns without needing manual skip
|
|
5
|
+
configuration.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
python -m crackerjack.tools.mdformat_wrapper [mdformat args...]
|
|
9
|
+
|
|
10
|
+
Exit Codes:
|
|
11
|
+
Same as mdformat (0 = no issues, 1 = issues found, etc.)
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import subprocess
|
|
17
|
+
import sys
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
|
|
20
|
+
from ._git_utils import get_git_tracked_files
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def main(argv: list[str] | None = None) -> int:
|
|
24
|
+
"""Run mdformat on git-tracked markdown files only.
|
|
25
|
+
|
|
26
|
+
This wrapper automatically discovers git-tracked .md and .markdown files
|
|
27
|
+
and passes them to mdformat, ensuring .gitignore patterns are respected.
|
|
28
|
+
|
|
29
|
+
Behavior:
|
|
30
|
+
- First run: Formats files and returns exit code 1 (fail to signal changes)
|
|
31
|
+
- Second run: Files already formatted, returns exit code 0 (pass)
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
argv: Optional arguments to pass to mdformat
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
Exit code: 0 if no changes needed, 1 if files were formatted
|
|
38
|
+
"""
|
|
39
|
+
# Get all git-tracked markdown files (automatically respects .gitignore)
|
|
40
|
+
md_files = get_git_tracked_files("*.md")
|
|
41
|
+
markdown_files = get_git_tracked_files("*.markdown")
|
|
42
|
+
files = md_files + markdown_files
|
|
43
|
+
|
|
44
|
+
if not files:
|
|
45
|
+
print("No git-tracked markdown files found", file=sys.stderr) # noqa: T201
|
|
46
|
+
return 0 # No files is not an error for formatters
|
|
47
|
+
|
|
48
|
+
# Build mdformat command with git-tracked files
|
|
49
|
+
cmd = ["mdformat"]
|
|
50
|
+
|
|
51
|
+
# Add any additional arguments passed to wrapper
|
|
52
|
+
if argv:
|
|
53
|
+
cmd.extend(argv)
|
|
54
|
+
|
|
55
|
+
# Add file paths at the end
|
|
56
|
+
cmd.extend([str(f) for f in files])
|
|
57
|
+
|
|
58
|
+
# Execute mdformat
|
|
59
|
+
try:
|
|
60
|
+
# First, check if files need formatting (dry-run)
|
|
61
|
+
check_cmd = cmd + ["--check"]
|
|
62
|
+
check_result = subprocess.run(
|
|
63
|
+
check_cmd,
|
|
64
|
+
cwd=Path.cwd(),
|
|
65
|
+
check=False,
|
|
66
|
+
capture_output=True,
|
|
67
|
+
text=True,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
# If check passed (exit code 0), files are already formatted
|
|
71
|
+
if check_result.returncode == 0:
|
|
72
|
+
print(f"All {len(files)} markdown files already formatted correctly")
|
|
73
|
+
return 0
|
|
74
|
+
|
|
75
|
+
# Files need formatting - run mdformat to fix them
|
|
76
|
+
format_result = subprocess.run(
|
|
77
|
+
cmd,
|
|
78
|
+
cwd=Path.cwd(),
|
|
79
|
+
check=False,
|
|
80
|
+
capture_output=True,
|
|
81
|
+
text=True,
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
# Forward output to stdout/stderr
|
|
85
|
+
if format_result.stdout:
|
|
86
|
+
print(format_result.stdout, end="")
|
|
87
|
+
if format_result.stderr:
|
|
88
|
+
print(format_result.stderr, end="", file=sys.stderr)
|
|
89
|
+
|
|
90
|
+
# Return exit code 1 to indicate files were formatted (changes made)
|
|
91
|
+
# This causes the hook to fail on first run, pass on second run
|
|
92
|
+
files_formatted = (
|
|
93
|
+
check_result.returncode
|
|
94
|
+
) # Non-zero means files needed formatting
|
|
95
|
+
if files_formatted:
|
|
96
|
+
print(
|
|
97
|
+
f"Formatted {len(files)} markdown files - run crackerjack again to verify"
|
|
98
|
+
)
|
|
99
|
+
return 1 # Fail to signal changes were made
|
|
100
|
+
|
|
101
|
+
return 0
|
|
102
|
+
except FileNotFoundError:
|
|
103
|
+
print(
|
|
104
|
+
"Error: mdformat not found. Install with: uv pip install mdformat mdformat-ruff",
|
|
105
|
+
file=sys.stderr,
|
|
106
|
+
) # noqa: T201
|
|
107
|
+
return 127 # Command not found
|
|
108
|
+
except Exception as e:
|
|
109
|
+
print(f"Error running mdformat: {e}", file=sys.stderr) # noqa: T201
|
|
110
|
+
return 1
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
if __name__ == "__main__":
|
|
114
|
+
sys.exit(main(sys.argv[1:]))
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"""Remove trailing whitespace from files.
|
|
2
|
+
|
|
3
|
+
This tool is a native Python implementation replacing pre-commit's
|
|
4
|
+
trailing-whitespace hook. It scans files for lines with trailing whitespace
|
|
5
|
+
and automatically removes it.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
python -m crackerjack.tools.trailing_whitespace [files...]
|
|
9
|
+
|
|
10
|
+
Exit Codes:
|
|
11
|
+
0: No trailing whitespace found (or successfully fixed)
|
|
12
|
+
1: Trailing whitespace found and fixed (files modified)
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import argparse
|
|
18
|
+
import sys
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
|
|
21
|
+
from ._git_utils import get_files_by_extension
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def has_trailing_whitespace(line: str) -> bool:
|
|
25
|
+
"""Check if a line has trailing whitespace.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
line: Line to check (should include newline if present)
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
True if line has trailing whitespace before newline
|
|
32
|
+
"""
|
|
33
|
+
# Remove trailing newline for checking
|
|
34
|
+
line_stripped = line.rstrip("\n\r")
|
|
35
|
+
# Check if there's whitespace at the end
|
|
36
|
+
return line_stripped != line_stripped.rstrip()
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def fix_trailing_whitespace(file_path: Path) -> bool:
|
|
40
|
+
"""Remove trailing whitespace from a file.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
file_path: Path to file to process
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
True if file was modified, False if no changes needed
|
|
47
|
+
"""
|
|
48
|
+
try:
|
|
49
|
+
# Read file content
|
|
50
|
+
content = file_path.read_text(encoding="utf-8")
|
|
51
|
+
lines = content.splitlines(keepends=True)
|
|
52
|
+
|
|
53
|
+
# Process lines
|
|
54
|
+
modified = False
|
|
55
|
+
new_lines = []
|
|
56
|
+
for line in lines:
|
|
57
|
+
if has_trailing_whitespace(line):
|
|
58
|
+
# Remove trailing whitespace but preserve newline
|
|
59
|
+
stripped = line.rstrip()
|
|
60
|
+
if line.endswith("\n"):
|
|
61
|
+
stripped += "\n"
|
|
62
|
+
elif line.endswith("\r\n"):
|
|
63
|
+
stripped += "\r\n"
|
|
64
|
+
new_lines.append(stripped)
|
|
65
|
+
modified = True
|
|
66
|
+
else:
|
|
67
|
+
new_lines.append(line)
|
|
68
|
+
|
|
69
|
+
# Write back if modified
|
|
70
|
+
if modified:
|
|
71
|
+
file_path.write_text("".join(new_lines), encoding="utf-8")
|
|
72
|
+
print(f"Fixed trailing whitespace: {file_path}") # noqa: T201
|
|
73
|
+
|
|
74
|
+
return modified
|
|
75
|
+
|
|
76
|
+
except UnicodeDecodeError:
|
|
77
|
+
# Skip binary files
|
|
78
|
+
return False
|
|
79
|
+
except Exception as e:
|
|
80
|
+
print(f"Error processing {file_path}: {e}", file=sys.stderr) # noqa: T201
|
|
81
|
+
return False
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _collect_files_to_check(args: argparse.Namespace) -> list[Path]:
|
|
85
|
+
"""Collect files to check for trailing whitespace.
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
args: Parsed command-line arguments
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
List of file paths to process
|
|
92
|
+
"""
|
|
93
|
+
# Default to all git-tracked files if none specified
|
|
94
|
+
if not args.files:
|
|
95
|
+
# Get all tracked text files (respects .gitignore via git ls-files)
|
|
96
|
+
files = get_files_by_extension(
|
|
97
|
+
[".py", ".md", ".txt", ".yaml", ".yml", ".toml", ".json"]
|
|
98
|
+
)
|
|
99
|
+
if not files:
|
|
100
|
+
# Fallback to Python files if not in git repo
|
|
101
|
+
files = list(Path.cwd().rglob("*.py"))
|
|
102
|
+
else:
|
|
103
|
+
files = args.files
|
|
104
|
+
|
|
105
|
+
# Filter to existing files only
|
|
106
|
+
return [f for f in files if f.is_file()]
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _process_files_in_check_mode(files: list[Path]) -> int:
|
|
110
|
+
"""Process files in check-only mode.
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
files: List of file paths to check
|
|
114
|
+
|
|
115
|
+
Returns:
|
|
116
|
+
Count of files with trailing whitespace
|
|
117
|
+
"""
|
|
118
|
+
modified_count = 0
|
|
119
|
+
for file_path in files:
|
|
120
|
+
content = file_path.read_text(encoding="utf-8")
|
|
121
|
+
lines = content.splitlines(keepends=True)
|
|
122
|
+
if any(has_trailing_whitespace(line) for line in lines):
|
|
123
|
+
print(f"Trailing whitespace found: {file_path}") # noqa: T201
|
|
124
|
+
modified_count += 1
|
|
125
|
+
return modified_count
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def _process_files_in_fix_mode(files: list[Path]) -> int:
|
|
129
|
+
"""Process files in fix mode.
|
|
130
|
+
|
|
131
|
+
Args:
|
|
132
|
+
files: List of file paths to fix
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
Count of files modified
|
|
136
|
+
"""
|
|
137
|
+
modified_count = 0
|
|
138
|
+
for file_path in files:
|
|
139
|
+
if fix_trailing_whitespace(file_path):
|
|
140
|
+
modified_count += 1
|
|
141
|
+
return modified_count
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def main(argv: list[str] | None = None) -> int:
|
|
145
|
+
"""Main entry point for trailing-whitespace tool.
|
|
146
|
+
|
|
147
|
+
Args:
|
|
148
|
+
argv: Command-line arguments (defaults to sys.argv[1:])
|
|
149
|
+
|
|
150
|
+
Returns:
|
|
151
|
+
Exit code: 0 if no files modified, 1 if files were modified
|
|
152
|
+
"""
|
|
153
|
+
parser = argparse.ArgumentParser(
|
|
154
|
+
description="Remove trailing whitespace from files"
|
|
155
|
+
)
|
|
156
|
+
parser.add_argument(
|
|
157
|
+
"files",
|
|
158
|
+
nargs="*",
|
|
159
|
+
type=Path,
|
|
160
|
+
help="Files to check (default: all Python files in current directory)",
|
|
161
|
+
)
|
|
162
|
+
parser.add_argument(
|
|
163
|
+
"--check",
|
|
164
|
+
action="store_true",
|
|
165
|
+
help="Check only, don't modify files",
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
args = parser.parse_args(argv)
|
|
169
|
+
|
|
170
|
+
files = _collect_files_to_check(args)
|
|
171
|
+
|
|
172
|
+
if not files:
|
|
173
|
+
print("No files to check") # noqa: T201
|
|
174
|
+
return 0
|
|
175
|
+
|
|
176
|
+
# Process files based on mode
|
|
177
|
+
if args.check:
|
|
178
|
+
modified_count = _process_files_in_check_mode(files)
|
|
179
|
+
else:
|
|
180
|
+
modified_count = _process_files_in_fix_mode(files)
|
|
181
|
+
|
|
182
|
+
# Return appropriate exit code
|
|
183
|
+
if modified_count > 0:
|
|
184
|
+
if args.check:
|
|
185
|
+
print(f"\n{modified_count} file(s) with trailing whitespace") # noqa: T201
|
|
186
|
+
else:
|
|
187
|
+
print(f"\nFixed {modified_count} file(s)") # noqa: T201
|
|
188
|
+
# Align with pre-commit semantics so HookExecutor treats this as pass
|
|
189
|
+
# when a formatter modifies files but exits with code 1.
|
|
190
|
+
print("files were modified by this hook") # noqa: T201
|
|
191
|
+
return 1
|
|
192
|
+
|
|
193
|
+
print("No trailing whitespace found") # noqa: T201
|
|
194
|
+
return 0
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
if __name__ == "__main__":
|
|
198
|
+
sys.exit(main())
|
|
@@ -145,6 +145,10 @@ def validate_file(file_path: Path) -> list[tuple[int, str]]:
|
|
|
145
145
|
|
|
146
146
|
|
|
147
147
|
def main(file_paths: list[str]) -> int:
|
|
148
|
+
if not file_paths:
|
|
149
|
+
print("✅ No Python files to validate")
|
|
150
|
+
return 0
|
|
151
|
+
|
|
148
152
|
exit_code = 0
|
|
149
153
|
|
|
150
154
|
for file_path_str in file_paths:
|
|
@@ -167,15 +171,15 @@ def main(file_paths: list[str]) -> int:
|
|
|
167
171
|
if exit_code == 0:
|
|
168
172
|
print("✅ All regex patterns validated successfully!")
|
|
169
173
|
else:
|
|
170
|
-
print("\n" + "=" *
|
|
174
|
+
print("\n" + "=" * 70)
|
|
171
175
|
print("REGEX VALIDATION FAILED")
|
|
172
|
-
print("=" *
|
|
176
|
+
print("=" * 70)
|
|
173
177
|
print("To fix these issues: ")
|
|
174
178
|
print("1. Use patterns from crackerjack.services.regex_patterns")
|
|
175
179
|
print("2. Add new patterns to SAFE_PATTERNS with comprehensive tests")
|
|
176
180
|
print("3. Use '# REGEX OK: reason' comment for legitimate exceptions")
|
|
177
181
|
print("4. Fix \\g<1> replacement syntax (no spaces)")
|
|
178
|
-
print("=" *
|
|
182
|
+
print("=" * 70)
|
|
179
183
|
|
|
180
184
|
return exit_code
|
|
181
185
|
|
crackerjack/ui/README.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
> Crackerjack Docs: [Main](<../../README.md>) | [Crackerjack Package](<../README.md>) | [UI](<./README.md>)
|
|
2
|
+
|
|
3
|
+
# UI
|
|
4
|
+
|
|
5
|
+
User interface components and templates.
|
|
6
|
+
|
|
7
|
+
## Related
|
|
8
|
+
|
|
9
|
+
- [Crackerjack Package](<../README.md>) - Parent package
|
|
10
|
+
- [UI Templates](<./templates/README.md>) - Template files for UI components
|
|
11
|
+
- [MCP](<../mcp/README.md>) - MCP progress monitor UI
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""Utilities for rendering the monitoring dashboard UI."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from functools import lru_cache
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
_TEMPLATE_DIR = Path(__file__).with_suffix("").parent / "templates"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _load_asset(filename: str) -> str:
|
|
12
|
+
path = _TEMPLATE_DIR / filename
|
|
13
|
+
if not path.exists():
|
|
14
|
+
msg = f"Dashboard asset not found: {filename}"
|
|
15
|
+
raise FileNotFoundError(msg)
|
|
16
|
+
return path.read_text(encoding="utf-8")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@lru_cache(maxsize=1)
|
|
20
|
+
def render_monitoring_dashboard() -> str:
|
|
21
|
+
"""Render the monitoring dashboard HTML using cached assets."""
|
|
22
|
+
html_template = _load_asset("monitoring_dashboard.html")
|
|
23
|
+
css_styles = _load_asset("monitoring_dashboard.css")
|
|
24
|
+
javascript_code = _load_asset("monitoring_dashboard.js")
|
|
25
|
+
return html_template.format(
|
|
26
|
+
css_styles=css_styles,
|
|
27
|
+
javascript_code=javascript_code,
|
|
28
|
+
)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
> Crackerjack Docs: [Main](<../../../README.md>) | [Crackerjack Package](<../../README.md>) | [UI](<../README.md>) | [Templates](<./README.md>)
|
|
2
|
+
|
|
3
|
+
# UI Templates
|
|
4
|
+
|
|
5
|
+
Templates used by UI components.
|
|
6
|
+
|
|
7
|
+
## Related
|
|
8
|
+
|
|
9
|
+
- [UI](<../README.md>) - Parent UI package
|
|
10
|
+
- [Crackerjack Package](<../../README.md>) - Root package
|
|
11
|
+
- [Data](<../../data/README.md>) - Static data and assets
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from crackerjack.config import get_console_width
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def separator(char: str = "-", width: int | None = None) -> str:
|
|
7
|
+
"""Return a horizontal separator string.
|
|
8
|
+
|
|
9
|
+
- char: the character to repeat (default '-')
|
|
10
|
+
- width: explicit width; if None, uses configured console width
|
|
11
|
+
"""
|
|
12
|
+
w = width if isinstance(width, int) and width > 0 else get_console_width()
|
|
13
|
+
return char * w
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Dependency Guard module to ensure proper dependency injection.
|
|
3
|
+
|
|
4
|
+
This module provides utilities to ensure that dependencies are properly
|
|
5
|
+
registered in the ACB dependency injection system and to handle cases
|
|
6
|
+
where dependencies might be registered as empty tuples or other invalid
|
|
7
|
+
values.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import sys
|
|
11
|
+
import typing
|
|
12
|
+
from typing import Any
|
|
13
|
+
|
|
14
|
+
from acb.depends import depends
|
|
15
|
+
from acb.logger import Logger
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _should_log_debug() -> bool:
|
|
19
|
+
"""Check if debug mode is active via CLI flags.
|
|
20
|
+
|
|
21
|
+
Uses sys.argv directly for early detection before flag parsing.
|
|
22
|
+
This is thread-safe as sys.argv is read-only during execution.
|
|
23
|
+
"""
|
|
24
|
+
return any(
|
|
25
|
+
arg in ("--debug", "-d", "--ai-debug") or arg.startswith("--debug=")
|
|
26
|
+
for arg in sys.argv[1:]
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _log_dependency_issue(message: str, level: str = "WARNING") -> None:
|
|
31
|
+
"""Log dependency issues only in debug mode.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
message: The log message to emit
|
|
35
|
+
level: Log level (INFO, WARNING, ERROR)
|
|
36
|
+
"""
|
|
37
|
+
if not _should_log_debug():
|
|
38
|
+
return
|
|
39
|
+
# Use stderr for diagnostic messages (stdout reserved for user output)
|
|
40
|
+
print(f"[CRACKERJACK:{level}] {message}", file=sys.stderr)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def ensure_logger_dependency() -> None:
|
|
44
|
+
"""
|
|
45
|
+
Ensure that Logger and LoggerProtocol are properly registered in the DI container.
|
|
46
|
+
This prevents issues where empty tuples might get registered instead of logger instances.
|
|
47
|
+
"""
|
|
48
|
+
# Check if Logger is registered and has a valid instance
|
|
49
|
+
try:
|
|
50
|
+
logger_instance = depends.get_sync(Logger)
|
|
51
|
+
# If we get an empty tuple, string, or other invalid value, replace it
|
|
52
|
+
if isinstance(logger_instance, tuple) and len(logger_instance) == 0:
|
|
53
|
+
_log_dependency_issue(
|
|
54
|
+
"Logger dependency was registered as empty tuple, replacing with fresh instance"
|
|
55
|
+
)
|
|
56
|
+
# Create a new logger instance to replace the invalid one
|
|
57
|
+
from acb.logger import Logger as ACBLogger
|
|
58
|
+
|
|
59
|
+
fresh_logger = ACBLogger()
|
|
60
|
+
depends.set(Logger, fresh_logger)
|
|
61
|
+
elif isinstance(logger_instance, str):
|
|
62
|
+
_log_dependency_issue(
|
|
63
|
+
f"Logger dependency was registered as string ({logger_instance!r}), replacing with fresh instance"
|
|
64
|
+
)
|
|
65
|
+
# Create a new logger instance to replace the invalid one
|
|
66
|
+
from acb.logger import Logger as ACBLogger
|
|
67
|
+
|
|
68
|
+
fresh_logger = ACBLogger()
|
|
69
|
+
depends.set(Logger, fresh_logger)
|
|
70
|
+
except Exception:
|
|
71
|
+
# If there's no logger registered at all, create one
|
|
72
|
+
from acb.logger import Logger as ACBLogger
|
|
73
|
+
|
|
74
|
+
fresh_logger = ACBLogger()
|
|
75
|
+
depends.set(Logger, fresh_logger)
|
|
76
|
+
|
|
77
|
+
# Do the same check for LoggerProtocol if it exists
|
|
78
|
+
# Import once to avoid typing issues
|
|
79
|
+
try:
|
|
80
|
+
from crackerjack.models.protocols import LoggerProtocol as _LoggerProtocol
|
|
81
|
+
|
|
82
|
+
logger_proto_instance = depends.get_sync(_LoggerProtocol)
|
|
83
|
+
if isinstance(logger_proto_instance, tuple) and len(logger_proto_instance) == 0:
|
|
84
|
+
_log_dependency_issue(
|
|
85
|
+
"LoggerProtocol dependency was registered as empty tuple, replacing with fresh instance"
|
|
86
|
+
)
|
|
87
|
+
from acb.logger import Logger as ACBLogger
|
|
88
|
+
|
|
89
|
+
fresh_logger = ACBLogger()
|
|
90
|
+
depends.set(_LoggerProtocol, fresh_logger)
|
|
91
|
+
elif isinstance(logger_proto_instance, str):
|
|
92
|
+
_log_dependency_issue(
|
|
93
|
+
f"LoggerProtocol dependency was registered as string ({logger_proto_instance!r}), replacing with fresh instance"
|
|
94
|
+
)
|
|
95
|
+
from acb.logger import Logger as ACBLogger
|
|
96
|
+
|
|
97
|
+
fresh_logger = ACBLogger()
|
|
98
|
+
depends.set(_LoggerProtocol, fresh_logger)
|
|
99
|
+
except ImportError:
|
|
100
|
+
# LoggerProtocol doesn't exist, that's fine
|
|
101
|
+
pass
|
|
102
|
+
except Exception:
|
|
103
|
+
# If there's no LoggerProtocol registered, create one
|
|
104
|
+
try:
|
|
105
|
+
from acb.logger import Logger as ACBLogger
|
|
106
|
+
|
|
107
|
+
fresh_logger = ACBLogger()
|
|
108
|
+
_log_dependency_issue(
|
|
109
|
+
"Registering LoggerProtocol with fresh logger instance", level="INFO"
|
|
110
|
+
)
|
|
111
|
+
# Register the fresh_logger instance with the LoggerProtocol
|
|
112
|
+
depends.set(_LoggerProtocol, fresh_logger)
|
|
113
|
+
except NameError:
|
|
114
|
+
# _LoggerProtocol is not defined if the import failed
|
|
115
|
+
pass
|
|
116
|
+
except Exception:
|
|
117
|
+
pass # Any other error, just continue
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def validate_dependency_registration(
|
|
121
|
+
dep_type: type[Any], fallback_factory: typing.Callable | None = None
|
|
122
|
+
) -> bool:
|
|
123
|
+
"""
|
|
124
|
+
Validate that a dependency is properly registered and not an empty tuple or string.
|
|
125
|
+
|
|
126
|
+
Args:
|
|
127
|
+
dep_type: The type of dependency to validate
|
|
128
|
+
fallback_factory: Optional factory function to create a fallback instance if needed
|
|
129
|
+
|
|
130
|
+
Returns:
|
|
131
|
+
True if the dependency is properly registered, False otherwise
|
|
132
|
+
"""
|
|
133
|
+
try:
|
|
134
|
+
instance = depends.get_sync(dep_type)
|
|
135
|
+
# Check if it's an empty tuple (the problematic case)
|
|
136
|
+
if isinstance(instance, tuple) and len(instance) == 0:
|
|
137
|
+
_log_dependency_issue(
|
|
138
|
+
f"Dependency {dep_type} was registered as empty tuple"
|
|
139
|
+
)
|
|
140
|
+
# Replace with a fallback if provided
|
|
141
|
+
if fallback_factory:
|
|
142
|
+
fallback_instance = fallback_factory()
|
|
143
|
+
depends.set(dep_type, fallback_instance)
|
|
144
|
+
_log_dependency_issue(
|
|
145
|
+
f"Replaced empty tuple for {dep_type} with new instance",
|
|
146
|
+
level="INFO",
|
|
147
|
+
)
|
|
148
|
+
return True
|
|
149
|
+
return False
|
|
150
|
+
# Check if it's a string (another problematic case)
|
|
151
|
+
elif isinstance(instance, str):
|
|
152
|
+
_log_dependency_issue(
|
|
153
|
+
f"Dependency {dep_type} was registered as string: {instance!r}"
|
|
154
|
+
)
|
|
155
|
+
# Replace with a fallback if provided
|
|
156
|
+
if fallback_factory:
|
|
157
|
+
fallback_instance = fallback_factory()
|
|
158
|
+
depends.set(dep_type, fallback_instance)
|
|
159
|
+
_log_dependency_issue(
|
|
160
|
+
f"Replaced string for {dep_type} with new instance", level="INFO"
|
|
161
|
+
)
|
|
162
|
+
return True
|
|
163
|
+
return False
|
|
164
|
+
return True
|
|
165
|
+
except Exception:
|
|
166
|
+
# If dependency doesn't exist at all, return False
|
|
167
|
+
return False
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def safe_get_logger() -> Logger:
|
|
171
|
+
"""
|
|
172
|
+
Safely get a logger instance, ensuring it's not an empty tuple or string.
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
A valid logger instance
|
|
176
|
+
"""
|
|
177
|
+
try:
|
|
178
|
+
logger_instance = depends.get_sync(Logger)
|
|
179
|
+
if isinstance(logger_instance, tuple) and len(logger_instance) == 0:
|
|
180
|
+
_log_dependency_issue(
|
|
181
|
+
"Logger dependency was an empty tuple in safe_get_logger, replacing with fresh instance"
|
|
182
|
+
)
|
|
183
|
+
# Create and register a fresh logger
|
|
184
|
+
from acb.logger import Logger as ACBLogger
|
|
185
|
+
|
|
186
|
+
fresh_logger = ACBLogger()
|
|
187
|
+
depends.set(Logger, fresh_logger)
|
|
188
|
+
return fresh_logger
|
|
189
|
+
elif isinstance(logger_instance, str):
|
|
190
|
+
_log_dependency_issue(
|
|
191
|
+
f"Logger dependency was a string ({logger_instance!r}) in safe_get_logger, replacing with fresh instance"
|
|
192
|
+
)
|
|
193
|
+
# Create and register a fresh logger
|
|
194
|
+
from acb.logger import Logger as ACBLogger
|
|
195
|
+
|
|
196
|
+
fresh_logger = ACBLogger()
|
|
197
|
+
depends.set(Logger, fresh_logger)
|
|
198
|
+
return fresh_logger
|
|
199
|
+
return logger_instance
|
|
200
|
+
except Exception:
|
|
201
|
+
# If no logger is registered, create one
|
|
202
|
+
from acb.logger import Logger as ACBLogger
|
|
203
|
+
|
|
204
|
+
_log_dependency_issue(
|
|
205
|
+
"No logger registered, creating and registering a fresh logger instance",
|
|
206
|
+
level="INFO",
|
|
207
|
+
)
|
|
208
|
+
fresh_logger = ACBLogger()
|
|
209
|
+
depends.set(Logger, fresh_logger)
|
|
210
|
+
return fresh_logger
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def check_all_dependencies_for_empty_tuples():
|
|
214
|
+
"""
|
|
215
|
+
Debug function to check all registered dependencies for empty tuples.
|
|
216
|
+
This can help identify which dependencies have been incorrectly registered.
|
|
217
|
+
"""
|
|
218
|
+
# This would require access to the internal state of the ACB DI system
|
|
219
|
+
# which might not be available, so we'll just print a notice
|
|
220
|
+
_log_dependency_issue(
|
|
221
|
+
"Dependency check: To check all dependencies for empty tuples, you would need access to ACB's internal container state.",
|
|
222
|
+
level="INFO",
|
|
223
|
+
)
|
|
224
|
+
_log_dependency_issue(
|
|
225
|
+
"This is currently not possible without modifying ACB itself.", level="INFO"
|
|
226
|
+
)
|
|
227
|
+
_log_dependency_issue(
|
|
228
|
+
"The best approach is to use the individual validation functions for known problematic dependencies.",
|
|
229
|
+
level="INFO",
|
|
230
|
+
)
|