crackerjack 0.18.2__py3-none-any.whl → 0.45.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- crackerjack/README.md +19 -0
- crackerjack/__init__.py +96 -2
- crackerjack/__main__.py +637 -138
- crackerjack/adapters/README.md +18 -0
- crackerjack/adapters/__init__.py +39 -0
- crackerjack/adapters/_output_paths.py +167 -0
- crackerjack/adapters/_qa_adapter_base.py +309 -0
- crackerjack/adapters/_tool_adapter_base.py +706 -0
- crackerjack/adapters/ai/README.md +65 -0
- crackerjack/adapters/ai/__init__.py +5 -0
- crackerjack/adapters/ai/claude.py +853 -0
- crackerjack/adapters/complexity/README.md +53 -0
- crackerjack/adapters/complexity/__init__.py +10 -0
- crackerjack/adapters/complexity/complexipy.py +641 -0
- crackerjack/adapters/dependency/__init__.py +22 -0
- crackerjack/adapters/dependency/pip_audit.py +418 -0
- crackerjack/adapters/format/README.md +72 -0
- crackerjack/adapters/format/__init__.py +11 -0
- crackerjack/adapters/format/mdformat.py +313 -0
- crackerjack/adapters/format/ruff.py +516 -0
- crackerjack/adapters/lint/README.md +47 -0
- crackerjack/adapters/lint/__init__.py +11 -0
- crackerjack/adapters/lint/codespell.py +273 -0
- crackerjack/adapters/lsp/README.md +49 -0
- crackerjack/adapters/lsp/__init__.py +27 -0
- crackerjack/adapters/lsp/_base.py +194 -0
- crackerjack/adapters/lsp/_client.py +358 -0
- crackerjack/adapters/lsp/_manager.py +193 -0
- crackerjack/adapters/lsp/skylos.py +283 -0
- crackerjack/adapters/lsp/zuban.py +557 -0
- crackerjack/adapters/refactor/README.md +59 -0
- crackerjack/adapters/refactor/__init__.py +12 -0
- crackerjack/adapters/refactor/creosote.py +318 -0
- crackerjack/adapters/refactor/refurb.py +406 -0
- crackerjack/adapters/refactor/skylos.py +494 -0
- crackerjack/adapters/sast/README.md +132 -0
- crackerjack/adapters/sast/__init__.py +32 -0
- crackerjack/adapters/sast/_base.py +201 -0
- crackerjack/adapters/sast/bandit.py +423 -0
- crackerjack/adapters/sast/pyscn.py +405 -0
- crackerjack/adapters/sast/semgrep.py +241 -0
- crackerjack/adapters/security/README.md +111 -0
- crackerjack/adapters/security/__init__.py +17 -0
- crackerjack/adapters/security/gitleaks.py +339 -0
- crackerjack/adapters/type/README.md +52 -0
- crackerjack/adapters/type/__init__.py +12 -0
- crackerjack/adapters/type/pyrefly.py +402 -0
- crackerjack/adapters/type/ty.py +402 -0
- crackerjack/adapters/type/zuban.py +522 -0
- crackerjack/adapters/utility/README.md +51 -0
- crackerjack/adapters/utility/__init__.py +10 -0
- crackerjack/adapters/utility/checks.py +884 -0
- crackerjack/agents/README.md +264 -0
- crackerjack/agents/__init__.py +66 -0
- crackerjack/agents/architect_agent.py +238 -0
- crackerjack/agents/base.py +167 -0
- crackerjack/agents/claude_code_bridge.py +641 -0
- crackerjack/agents/coordinator.py +600 -0
- crackerjack/agents/documentation_agent.py +520 -0
- crackerjack/agents/dry_agent.py +585 -0
- crackerjack/agents/enhanced_coordinator.py +279 -0
- crackerjack/agents/enhanced_proactive_agent.py +185 -0
- crackerjack/agents/error_middleware.py +53 -0
- crackerjack/agents/formatting_agent.py +230 -0
- crackerjack/agents/helpers/__init__.py +9 -0
- crackerjack/agents/helpers/performance/__init__.py +22 -0
- crackerjack/agents/helpers/performance/performance_ast_analyzer.py +357 -0
- crackerjack/agents/helpers/performance/performance_pattern_detector.py +909 -0
- crackerjack/agents/helpers/performance/performance_recommender.py +572 -0
- crackerjack/agents/helpers/refactoring/__init__.py +22 -0
- crackerjack/agents/helpers/refactoring/code_transformer.py +536 -0
- crackerjack/agents/helpers/refactoring/complexity_analyzer.py +344 -0
- crackerjack/agents/helpers/refactoring/dead_code_detector.py +437 -0
- crackerjack/agents/helpers/test_creation/__init__.py +19 -0
- crackerjack/agents/helpers/test_creation/test_ast_analyzer.py +216 -0
- crackerjack/agents/helpers/test_creation/test_coverage_analyzer.py +643 -0
- crackerjack/agents/helpers/test_creation/test_template_generator.py +1031 -0
- crackerjack/agents/import_optimization_agent.py +1181 -0
- crackerjack/agents/performance_agent.py +325 -0
- crackerjack/agents/performance_helpers.py +205 -0
- crackerjack/agents/proactive_agent.py +55 -0
- crackerjack/agents/refactoring_agent.py +511 -0
- crackerjack/agents/refactoring_helpers.py +247 -0
- crackerjack/agents/security_agent.py +793 -0
- crackerjack/agents/semantic_agent.py +479 -0
- crackerjack/agents/semantic_helpers.py +356 -0
- crackerjack/agents/test_creation_agent.py +570 -0
- crackerjack/agents/test_specialist_agent.py +526 -0
- crackerjack/agents/tracker.py +110 -0
- crackerjack/api.py +647 -0
- crackerjack/cli/README.md +394 -0
- crackerjack/cli/__init__.py +24 -0
- crackerjack/cli/cache_handlers.py +209 -0
- crackerjack/cli/cache_handlers_enhanced.py +680 -0
- crackerjack/cli/facade.py +162 -0
- crackerjack/cli/formatting.py +13 -0
- crackerjack/cli/handlers/__init__.py +85 -0
- crackerjack/cli/handlers/advanced.py +103 -0
- crackerjack/cli/handlers/ai_features.py +62 -0
- crackerjack/cli/handlers/analytics.py +479 -0
- crackerjack/cli/handlers/changelog.py +271 -0
- crackerjack/cli/handlers/config_handlers.py +16 -0
- crackerjack/cli/handlers/coverage.py +84 -0
- crackerjack/cli/handlers/documentation.py +280 -0
- crackerjack/cli/handlers/main_handlers.py +497 -0
- crackerjack/cli/handlers/monitoring.py +371 -0
- crackerjack/cli/handlers.py +700 -0
- crackerjack/cli/interactive.py +488 -0
- crackerjack/cli/options.py +1216 -0
- crackerjack/cli/semantic_handlers.py +292 -0
- crackerjack/cli/utils.py +19 -0
- crackerjack/cli/version.py +19 -0
- crackerjack/code_cleaner.py +1307 -0
- crackerjack/config/README.md +472 -0
- crackerjack/config/__init__.py +275 -0
- crackerjack/config/global_lock_config.py +207 -0
- crackerjack/config/hooks.py +390 -0
- crackerjack/config/loader.py +239 -0
- crackerjack/config/settings.py +141 -0
- crackerjack/config/tool_commands.py +331 -0
- crackerjack/core/README.md +393 -0
- crackerjack/core/__init__.py +0 -0
- crackerjack/core/async_workflow_orchestrator.py +738 -0
- crackerjack/core/autofix_coordinator.py +282 -0
- crackerjack/core/container.py +105 -0
- crackerjack/core/enhanced_container.py +583 -0
- crackerjack/core/file_lifecycle.py +472 -0
- crackerjack/core/performance.py +244 -0
- crackerjack/core/performance_monitor.py +357 -0
- crackerjack/core/phase_coordinator.py +1227 -0
- crackerjack/core/proactive_workflow.py +267 -0
- crackerjack/core/resource_manager.py +425 -0
- crackerjack/core/retry.py +275 -0
- crackerjack/core/service_watchdog.py +601 -0
- crackerjack/core/session_coordinator.py +239 -0
- crackerjack/core/timeout_manager.py +563 -0
- crackerjack/core/websocket_lifecycle.py +410 -0
- crackerjack/core/workflow/__init__.py +21 -0
- crackerjack/core/workflow/workflow_ai_coordinator.py +863 -0
- crackerjack/core/workflow/workflow_event_orchestrator.py +1107 -0
- crackerjack/core/workflow/workflow_issue_parser.py +714 -0
- crackerjack/core/workflow/workflow_phase_executor.py +1158 -0
- crackerjack/core/workflow/workflow_security_gates.py +400 -0
- crackerjack/core/workflow_orchestrator.py +2243 -0
- crackerjack/data/README.md +11 -0
- crackerjack/data/__init__.py +8 -0
- crackerjack/data/models.py +79 -0
- crackerjack/data/repository.py +210 -0
- crackerjack/decorators/README.md +180 -0
- crackerjack/decorators/__init__.py +35 -0
- crackerjack/decorators/error_handling.py +649 -0
- crackerjack/decorators/error_handling_decorators.py +334 -0
- crackerjack/decorators/helpers.py +58 -0
- crackerjack/decorators/patterns.py +281 -0
- crackerjack/decorators/utils.py +58 -0
- crackerjack/docs/INDEX.md +11 -0
- crackerjack/docs/README.md +11 -0
- crackerjack/docs/generated/api/API_REFERENCE.md +10895 -0
- crackerjack/docs/generated/api/CLI_REFERENCE.md +109 -0
- crackerjack/docs/generated/api/CROSS_REFERENCES.md +1755 -0
- crackerjack/docs/generated/api/PROTOCOLS.md +3 -0
- crackerjack/docs/generated/api/SERVICES.md +1252 -0
- crackerjack/documentation/README.md +11 -0
- crackerjack/documentation/__init__.py +31 -0
- crackerjack/documentation/ai_templates.py +756 -0
- crackerjack/documentation/dual_output_generator.py +767 -0
- crackerjack/documentation/mkdocs_integration.py +518 -0
- crackerjack/documentation/reference_generator.py +1065 -0
- crackerjack/dynamic_config.py +678 -0
- crackerjack/errors.py +378 -0
- crackerjack/events/README.md +11 -0
- crackerjack/events/__init__.py +16 -0
- crackerjack/events/telemetry.py +175 -0
- crackerjack/events/workflow_bus.py +346 -0
- crackerjack/exceptions/README.md +301 -0
- crackerjack/exceptions/__init__.py +5 -0
- crackerjack/exceptions/config.py +4 -0
- crackerjack/exceptions/tool_execution_error.py +245 -0
- crackerjack/executors/README.md +591 -0
- crackerjack/executors/__init__.py +13 -0
- crackerjack/executors/async_hook_executor.py +938 -0
- crackerjack/executors/cached_hook_executor.py +316 -0
- crackerjack/executors/hook_executor.py +1295 -0
- crackerjack/executors/hook_lock_manager.py +708 -0
- crackerjack/executors/individual_hook_executor.py +739 -0
- crackerjack/executors/lsp_aware_hook_executor.py +349 -0
- crackerjack/executors/progress_hook_executor.py +282 -0
- crackerjack/executors/tool_proxy.py +433 -0
- crackerjack/hooks/README.md +485 -0
- crackerjack/hooks/lsp_hook.py +93 -0
- crackerjack/intelligence/README.md +557 -0
- crackerjack/intelligence/__init__.py +37 -0
- crackerjack/intelligence/adaptive_learning.py +693 -0
- crackerjack/intelligence/agent_orchestrator.py +485 -0
- crackerjack/intelligence/agent_registry.py +377 -0
- crackerjack/intelligence/agent_selector.py +439 -0
- crackerjack/intelligence/integration.py +250 -0
- crackerjack/interactive.py +719 -0
- crackerjack/managers/README.md +369 -0
- crackerjack/managers/__init__.py +11 -0
- crackerjack/managers/async_hook_manager.py +135 -0
- crackerjack/managers/hook_manager.py +585 -0
- crackerjack/managers/publish_manager.py +631 -0
- crackerjack/managers/test_command_builder.py +391 -0
- crackerjack/managers/test_executor.py +474 -0
- crackerjack/managers/test_manager.py +1357 -0
- crackerjack/managers/test_progress.py +187 -0
- crackerjack/mcp/README.md +374 -0
- crackerjack/mcp/__init__.py +0 -0
- crackerjack/mcp/cache.py +352 -0
- crackerjack/mcp/client_runner.py +121 -0
- crackerjack/mcp/context.py +802 -0
- crackerjack/mcp/dashboard.py +657 -0
- crackerjack/mcp/enhanced_progress_monitor.py +493 -0
- crackerjack/mcp/file_monitor.py +394 -0
- crackerjack/mcp/progress_components.py +607 -0
- crackerjack/mcp/progress_monitor.py +1016 -0
- crackerjack/mcp/rate_limiter.py +336 -0
- crackerjack/mcp/server.py +24 -0
- crackerjack/mcp/server_core.py +526 -0
- crackerjack/mcp/service_watchdog.py +505 -0
- crackerjack/mcp/state.py +407 -0
- crackerjack/mcp/task_manager.py +259 -0
- crackerjack/mcp/tools/README.md +27 -0
- crackerjack/mcp/tools/__init__.py +19 -0
- crackerjack/mcp/tools/core_tools.py +469 -0
- crackerjack/mcp/tools/error_analyzer.py +283 -0
- crackerjack/mcp/tools/execution_tools.py +384 -0
- crackerjack/mcp/tools/intelligence_tool_registry.py +46 -0
- crackerjack/mcp/tools/intelligence_tools.py +264 -0
- crackerjack/mcp/tools/monitoring_tools.py +628 -0
- crackerjack/mcp/tools/proactive_tools.py +367 -0
- crackerjack/mcp/tools/progress_tools.py +222 -0
- crackerjack/mcp/tools/semantic_tools.py +584 -0
- crackerjack/mcp/tools/utility_tools.py +358 -0
- crackerjack/mcp/tools/workflow_executor.py +699 -0
- crackerjack/mcp/websocket/README.md +31 -0
- crackerjack/mcp/websocket/__init__.py +14 -0
- crackerjack/mcp/websocket/app.py +54 -0
- crackerjack/mcp/websocket/endpoints.py +492 -0
- crackerjack/mcp/websocket/event_bridge.py +188 -0
- crackerjack/mcp/websocket/jobs.py +406 -0
- crackerjack/mcp/websocket/monitoring/__init__.py +25 -0
- crackerjack/mcp/websocket/monitoring/api/__init__.py +19 -0
- crackerjack/mcp/websocket/monitoring/api/dependencies.py +141 -0
- crackerjack/mcp/websocket/monitoring/api/heatmap.py +154 -0
- crackerjack/mcp/websocket/monitoring/api/intelligence.py +199 -0
- crackerjack/mcp/websocket/monitoring/api/metrics.py +203 -0
- crackerjack/mcp/websocket/monitoring/api/telemetry.py +101 -0
- crackerjack/mcp/websocket/monitoring/dashboard.py +18 -0
- crackerjack/mcp/websocket/monitoring/factory.py +109 -0
- crackerjack/mcp/websocket/monitoring/filters.py +10 -0
- crackerjack/mcp/websocket/monitoring/metrics.py +64 -0
- crackerjack/mcp/websocket/monitoring/models.py +90 -0
- crackerjack/mcp/websocket/monitoring/utils.py +171 -0
- crackerjack/mcp/websocket/monitoring/websocket_manager.py +78 -0
- crackerjack/mcp/websocket/monitoring/websockets/__init__.py +17 -0
- crackerjack/mcp/websocket/monitoring/websockets/dependencies.py +126 -0
- crackerjack/mcp/websocket/monitoring/websockets/heatmap.py +176 -0
- crackerjack/mcp/websocket/monitoring/websockets/intelligence.py +291 -0
- crackerjack/mcp/websocket/monitoring/websockets/metrics.py +291 -0
- crackerjack/mcp/websocket/monitoring_endpoints.py +21 -0
- crackerjack/mcp/websocket/server.py +174 -0
- crackerjack/mcp/websocket/websocket_handler.py +276 -0
- crackerjack/mcp/websocket_server.py +10 -0
- crackerjack/models/README.md +308 -0
- crackerjack/models/__init__.py +40 -0
- crackerjack/models/config.py +730 -0
- crackerjack/models/config_adapter.py +265 -0
- crackerjack/models/protocols.py +1535 -0
- crackerjack/models/pydantic_models.py +320 -0
- crackerjack/models/qa_config.py +145 -0
- crackerjack/models/qa_results.py +134 -0
- crackerjack/models/resource_protocols.py +299 -0
- crackerjack/models/results.py +35 -0
- crackerjack/models/semantic_models.py +258 -0
- crackerjack/models/task.py +173 -0
- crackerjack/models/test_models.py +60 -0
- crackerjack/monitoring/README.md +11 -0
- crackerjack/monitoring/__init__.py +0 -0
- crackerjack/monitoring/ai_agent_watchdog.py +405 -0
- crackerjack/monitoring/metrics_collector.py +427 -0
- crackerjack/monitoring/regression_prevention.py +580 -0
- crackerjack/monitoring/websocket_server.py +406 -0
- crackerjack/orchestration/README.md +340 -0
- crackerjack/orchestration/__init__.py +43 -0
- crackerjack/orchestration/advanced_orchestrator.py +894 -0
- crackerjack/orchestration/cache/README.md +312 -0
- crackerjack/orchestration/cache/__init__.py +37 -0
- crackerjack/orchestration/cache/memory_cache.py +338 -0
- crackerjack/orchestration/cache/tool_proxy_cache.py +340 -0
- crackerjack/orchestration/config.py +297 -0
- crackerjack/orchestration/coverage_improvement.py +180 -0
- crackerjack/orchestration/execution_strategies.py +361 -0
- crackerjack/orchestration/hook_orchestrator.py +1398 -0
- crackerjack/orchestration/strategies/README.md +401 -0
- crackerjack/orchestration/strategies/__init__.py +39 -0
- crackerjack/orchestration/strategies/adaptive_strategy.py +630 -0
- crackerjack/orchestration/strategies/parallel_strategy.py +237 -0
- crackerjack/orchestration/strategies/sequential_strategy.py +299 -0
- crackerjack/orchestration/test_progress_streamer.py +647 -0
- crackerjack/plugins/README.md +11 -0
- crackerjack/plugins/__init__.py +15 -0
- crackerjack/plugins/base.py +200 -0
- crackerjack/plugins/hooks.py +254 -0
- crackerjack/plugins/loader.py +335 -0
- crackerjack/plugins/managers.py +264 -0
- crackerjack/py313.py +191 -0
- crackerjack/security/README.md +11 -0
- crackerjack/security/__init__.py +0 -0
- crackerjack/security/audit.py +197 -0
- crackerjack/services/README.md +374 -0
- crackerjack/services/__init__.py +9 -0
- crackerjack/services/ai/README.md +295 -0
- crackerjack/services/ai/__init__.py +7 -0
- crackerjack/services/ai/advanced_optimizer.py +878 -0
- crackerjack/services/ai/contextual_ai_assistant.py +542 -0
- crackerjack/services/ai/embeddings.py +444 -0
- crackerjack/services/ai/intelligent_commit.py +328 -0
- crackerjack/services/ai/predictive_analytics.py +510 -0
- crackerjack/services/anomaly_detector.py +392 -0
- crackerjack/services/api_extractor.py +617 -0
- crackerjack/services/backup_service.py +467 -0
- crackerjack/services/bounded_status_operations.py +530 -0
- crackerjack/services/cache.py +369 -0
- crackerjack/services/changelog_automation.py +399 -0
- crackerjack/services/command_execution_service.py +305 -0
- crackerjack/services/config_integrity.py +132 -0
- crackerjack/services/config_merge.py +546 -0
- crackerjack/services/config_service.py +198 -0
- crackerjack/services/config_template.py +493 -0
- crackerjack/services/coverage_badge_service.py +173 -0
- crackerjack/services/coverage_ratchet.py +381 -0
- crackerjack/services/debug.py +733 -0
- crackerjack/services/dependency_analyzer.py +460 -0
- crackerjack/services/dependency_monitor.py +622 -0
- crackerjack/services/documentation_generator.py +493 -0
- crackerjack/services/documentation_service.py +704 -0
- crackerjack/services/enhanced_filesystem.py +497 -0
- crackerjack/services/enterprise_optimizer.py +865 -0
- crackerjack/services/error_pattern_analyzer.py +676 -0
- crackerjack/services/file_filter.py +221 -0
- crackerjack/services/file_hasher.py +149 -0
- crackerjack/services/file_io_service.py +361 -0
- crackerjack/services/file_modifier.py +615 -0
- crackerjack/services/filesystem.py +381 -0
- crackerjack/services/git.py +422 -0
- crackerjack/services/health_metrics.py +615 -0
- crackerjack/services/heatmap_generator.py +744 -0
- crackerjack/services/incremental_executor.py +380 -0
- crackerjack/services/initialization.py +823 -0
- crackerjack/services/input_validator.py +668 -0
- crackerjack/services/intelligent_commit.py +327 -0
- crackerjack/services/log_manager.py +289 -0
- crackerjack/services/logging.py +228 -0
- crackerjack/services/lsp_client.py +628 -0
- crackerjack/services/memory_optimizer.py +414 -0
- crackerjack/services/metrics.py +587 -0
- crackerjack/services/monitoring/README.md +30 -0
- crackerjack/services/monitoring/__init__.py +9 -0
- crackerjack/services/monitoring/dependency_monitor.py +678 -0
- crackerjack/services/monitoring/error_pattern_analyzer.py +676 -0
- crackerjack/services/monitoring/health_metrics.py +716 -0
- crackerjack/services/monitoring/metrics.py +587 -0
- crackerjack/services/monitoring/performance_benchmarks.py +410 -0
- crackerjack/services/monitoring/performance_cache.py +388 -0
- crackerjack/services/monitoring/performance_monitor.py +569 -0
- crackerjack/services/parallel_executor.py +527 -0
- crackerjack/services/pattern_cache.py +333 -0
- crackerjack/services/pattern_detector.py +478 -0
- crackerjack/services/patterns/__init__.py +142 -0
- crackerjack/services/patterns/agents.py +107 -0
- crackerjack/services/patterns/code/__init__.py +15 -0
- crackerjack/services/patterns/code/detection.py +118 -0
- crackerjack/services/patterns/code/imports.py +107 -0
- crackerjack/services/patterns/code/paths.py +159 -0
- crackerjack/services/patterns/code/performance.py +119 -0
- crackerjack/services/patterns/code/replacement.py +36 -0
- crackerjack/services/patterns/core.py +212 -0
- crackerjack/services/patterns/documentation/__init__.py +14 -0
- crackerjack/services/patterns/documentation/badges_markdown.py +96 -0
- crackerjack/services/patterns/documentation/comments_blocks.py +83 -0
- crackerjack/services/patterns/documentation/docstrings.py +89 -0
- crackerjack/services/patterns/formatting.py +226 -0
- crackerjack/services/patterns/operations.py +339 -0
- crackerjack/services/patterns/security/__init__.py +23 -0
- crackerjack/services/patterns/security/code_injection.py +122 -0
- crackerjack/services/patterns/security/credentials.py +190 -0
- crackerjack/services/patterns/security/path_traversal.py +221 -0
- crackerjack/services/patterns/security/unsafe_operations.py +216 -0
- crackerjack/services/patterns/templates.py +62 -0
- crackerjack/services/patterns/testing/__init__.py +18 -0
- crackerjack/services/patterns/testing/error_patterns.py +107 -0
- crackerjack/services/patterns/testing/pytest_output.py +126 -0
- crackerjack/services/patterns/tool_output/__init__.py +16 -0
- crackerjack/services/patterns/tool_output/bandit.py +72 -0
- crackerjack/services/patterns/tool_output/other.py +97 -0
- crackerjack/services/patterns/tool_output/pyright.py +67 -0
- crackerjack/services/patterns/tool_output/ruff.py +44 -0
- crackerjack/services/patterns/url_sanitization.py +114 -0
- crackerjack/services/patterns/utilities.py +42 -0
- crackerjack/services/patterns/utils.py +339 -0
- crackerjack/services/patterns/validation.py +46 -0
- crackerjack/services/patterns/versioning.py +62 -0
- crackerjack/services/predictive_analytics.py +523 -0
- crackerjack/services/profiler.py +280 -0
- crackerjack/services/quality/README.md +415 -0
- crackerjack/services/quality/__init__.py +11 -0
- crackerjack/services/quality/anomaly_detector.py +392 -0
- crackerjack/services/quality/pattern_cache.py +333 -0
- crackerjack/services/quality/pattern_detector.py +479 -0
- crackerjack/services/quality/qa_orchestrator.py +491 -0
- crackerjack/services/quality/quality_baseline.py +395 -0
- crackerjack/services/quality/quality_baseline_enhanced.py +649 -0
- crackerjack/services/quality/quality_intelligence.py +949 -0
- crackerjack/services/regex_patterns.py +58 -0
- crackerjack/services/regex_utils.py +483 -0
- crackerjack/services/secure_path_utils.py +524 -0
- crackerjack/services/secure_status_formatter.py +450 -0
- crackerjack/services/secure_subprocess.py +635 -0
- crackerjack/services/security.py +239 -0
- crackerjack/services/security_logger.py +495 -0
- crackerjack/services/server_manager.py +411 -0
- crackerjack/services/smart_scheduling.py +167 -0
- crackerjack/services/status_authentication.py +460 -0
- crackerjack/services/status_security_manager.py +315 -0
- crackerjack/services/terminal_utils.py +0 -0
- crackerjack/services/thread_safe_status_collector.py +441 -0
- crackerjack/services/tool_filter.py +368 -0
- crackerjack/services/tool_version_service.py +43 -0
- crackerjack/services/unified_config.py +115 -0
- crackerjack/services/validation_rate_limiter.py +220 -0
- crackerjack/services/vector_store.py +689 -0
- crackerjack/services/version_analyzer.py +461 -0
- crackerjack/services/version_checker.py +223 -0
- crackerjack/services/websocket_resource_limiter.py +438 -0
- crackerjack/services/zuban_lsp_service.py +391 -0
- crackerjack/slash_commands/README.md +11 -0
- crackerjack/slash_commands/__init__.py +59 -0
- crackerjack/slash_commands/init.md +112 -0
- crackerjack/slash_commands/run.md +197 -0
- crackerjack/slash_commands/status.md +127 -0
- crackerjack/tools/README.md +11 -0
- crackerjack/tools/__init__.py +30 -0
- crackerjack/tools/_git_utils.py +105 -0
- crackerjack/tools/check_added_large_files.py +139 -0
- crackerjack/tools/check_ast.py +105 -0
- crackerjack/tools/check_json.py +103 -0
- crackerjack/tools/check_jsonschema.py +297 -0
- crackerjack/tools/check_toml.py +103 -0
- crackerjack/tools/check_yaml.py +110 -0
- crackerjack/tools/codespell_wrapper.py +72 -0
- crackerjack/tools/end_of_file_fixer.py +202 -0
- crackerjack/tools/format_json.py +128 -0
- crackerjack/tools/mdformat_wrapper.py +114 -0
- crackerjack/tools/trailing_whitespace.py +198 -0
- crackerjack/tools/validate_input_validator_patterns.py +236 -0
- crackerjack/tools/validate_regex_patterns.py +188 -0
- crackerjack/ui/README.md +11 -0
- crackerjack/ui/__init__.py +1 -0
- crackerjack/ui/dashboard_renderer.py +28 -0
- crackerjack/ui/templates/README.md +11 -0
- crackerjack/utils/console_utils.py +13 -0
- crackerjack/utils/dependency_guard.py +230 -0
- crackerjack/utils/retry_utils.py +275 -0
- crackerjack/workflows/README.md +590 -0
- crackerjack/workflows/__init__.py +46 -0
- crackerjack/workflows/actions.py +811 -0
- crackerjack/workflows/auto_fix.py +444 -0
- crackerjack/workflows/container_builder.py +499 -0
- crackerjack/workflows/definitions.py +443 -0
- crackerjack/workflows/engine.py +177 -0
- crackerjack/workflows/event_bridge.py +242 -0
- crackerjack-0.45.2.dist-info/METADATA +1678 -0
- crackerjack-0.45.2.dist-info/RECORD +478 -0
- {crackerjack-0.18.2.dist-info → crackerjack-0.45.2.dist-info}/WHEEL +1 -1
- crackerjack-0.45.2.dist-info/entry_points.txt +2 -0
- crackerjack/.gitignore +0 -14
- crackerjack/.libcst.codemod.yaml +0 -18
- crackerjack/.pdm.toml +0 -1
- crackerjack/.pre-commit-config.yaml +0 -91
- crackerjack/.pytest_cache/.gitignore +0 -2
- crackerjack/.pytest_cache/CACHEDIR.TAG +0 -4
- crackerjack/.pytest_cache/README.md +0 -8
- crackerjack/.pytest_cache/v/cache/nodeids +0 -1
- crackerjack/.pytest_cache/v/cache/stepwise +0 -1
- crackerjack/.ruff_cache/.gitignore +0 -1
- crackerjack/.ruff_cache/0.1.11/3256171999636029978 +0 -0
- crackerjack/.ruff_cache/0.1.14/602324811142551221 +0 -0
- crackerjack/.ruff_cache/0.1.4/10355199064880463147 +0 -0
- crackerjack/.ruff_cache/0.1.6/15140459877605758699 +0 -0
- crackerjack/.ruff_cache/0.1.7/1790508110482614856 +0 -0
- crackerjack/.ruff_cache/0.1.9/17041001205004563469 +0 -0
- crackerjack/.ruff_cache/0.11.2/4070660268492669020 +0 -0
- crackerjack/.ruff_cache/0.11.3/9818742842212983150 +0 -0
- crackerjack/.ruff_cache/0.11.4/9818742842212983150 +0 -0
- crackerjack/.ruff_cache/0.11.6/3557596832929915217 +0 -0
- crackerjack/.ruff_cache/0.11.7/10386934055395314831 +0 -0
- crackerjack/.ruff_cache/0.11.7/3557596832929915217 +0 -0
- crackerjack/.ruff_cache/0.11.8/530407680854991027 +0 -0
- crackerjack/.ruff_cache/0.2.0/10047773857155985907 +0 -0
- crackerjack/.ruff_cache/0.2.1/8522267973936635051 +0 -0
- crackerjack/.ruff_cache/0.2.2/18053836298936336950 +0 -0
- crackerjack/.ruff_cache/0.3.0/12548816621480535786 +0 -0
- crackerjack/.ruff_cache/0.3.3/11081883392474770722 +0 -0
- crackerjack/.ruff_cache/0.3.4/676973378459347183 +0 -0
- crackerjack/.ruff_cache/0.3.5/16311176246009842383 +0 -0
- crackerjack/.ruff_cache/0.5.7/1493622539551733492 +0 -0
- crackerjack/.ruff_cache/0.5.7/6231957614044513175 +0 -0
- crackerjack/.ruff_cache/0.5.7/9932762556785938009 +0 -0
- crackerjack/.ruff_cache/0.6.0/11982804814124138945 +0 -0
- crackerjack/.ruff_cache/0.6.0/12055761203849489982 +0 -0
- crackerjack/.ruff_cache/0.6.2/1206147804896221174 +0 -0
- crackerjack/.ruff_cache/0.6.4/1206147804896221174 +0 -0
- crackerjack/.ruff_cache/0.6.5/1206147804896221174 +0 -0
- crackerjack/.ruff_cache/0.6.7/3657366982708166874 +0 -0
- crackerjack/.ruff_cache/0.6.9/285614542852677309 +0 -0
- crackerjack/.ruff_cache/0.7.1/1024065805990144819 +0 -0
- crackerjack/.ruff_cache/0.7.1/285614542852677309 +0 -0
- crackerjack/.ruff_cache/0.7.3/16061516852537040135 +0 -0
- crackerjack/.ruff_cache/0.8.4/16354268377385700367 +0 -0
- crackerjack/.ruff_cache/0.9.10/12813592349865671909 +0 -0
- crackerjack/.ruff_cache/0.9.10/923908772239632759 +0 -0
- crackerjack/.ruff_cache/0.9.3/13948373885254993391 +0 -0
- crackerjack/.ruff_cache/0.9.9/12813592349865671909 +0 -0
- crackerjack/.ruff_cache/0.9.9/8843823720003377982 +0 -0
- crackerjack/.ruff_cache/CACHEDIR.TAG +0 -1
- crackerjack/crackerjack.py +0 -855
- crackerjack/pyproject.toml +0 -214
- crackerjack-0.18.2.dist-info/METADATA +0 -420
- crackerjack-0.18.2.dist-info/RECORD +0 -59
- crackerjack-0.18.2.dist-info/entry_points.txt +0 -4
- {crackerjack-0.18.2.dist-info → crackerjack-0.45.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Tool proxy that routes tool calls through adapters with health checks and graceful degradation."""
|
|
3
|
+
|
|
4
|
+
import asyncio
|
|
5
|
+
import sys
|
|
6
|
+
import time
|
|
7
|
+
import typing as t
|
|
8
|
+
from dataclasses import dataclass, field
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
from acb.console import Console
|
|
12
|
+
from acb.depends import depends
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass
|
|
16
|
+
class ToolHealthStatus:
|
|
17
|
+
"""Health status of a tool."""
|
|
18
|
+
|
|
19
|
+
is_healthy: bool
|
|
20
|
+
last_check: float
|
|
21
|
+
consecutive_failures: int = 0
|
|
22
|
+
last_error: str | None = None
|
|
23
|
+
fallback_recommendations: list[str] = field(default_factory=list)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dataclass
|
|
27
|
+
class CircuitBreakerState:
|
|
28
|
+
"""Circuit breaker state for a tool."""
|
|
29
|
+
|
|
30
|
+
is_open: bool = False
|
|
31
|
+
failure_count: int = 0
|
|
32
|
+
last_failure_time: float = 0
|
|
33
|
+
next_retry_time: float = 0
|
|
34
|
+
|
|
35
|
+
# Circuit breaker thresholds
|
|
36
|
+
failure_threshold: int = 3
|
|
37
|
+
retry_timeout: float = 120 # 2 minutes
|
|
38
|
+
|
|
39
|
+
def should_attempt(self) -> bool:
|
|
40
|
+
"""Check if we should attempt to use this tool."""
|
|
41
|
+
if not self.is_open:
|
|
42
|
+
return True
|
|
43
|
+
|
|
44
|
+
# Allow retry after timeout
|
|
45
|
+
return time.time() >= self.next_retry_time
|
|
46
|
+
|
|
47
|
+
def record_failure(self) -> None:
|
|
48
|
+
"""Record a tool failure."""
|
|
49
|
+
self.failure_count += 1
|
|
50
|
+
self.last_failure_time = time.time()
|
|
51
|
+
|
|
52
|
+
if self.failure_count >= self.failure_threshold:
|
|
53
|
+
self.is_open = True
|
|
54
|
+
self.next_retry_time = time.time() + self.retry_timeout
|
|
55
|
+
|
|
56
|
+
def record_success(self) -> None:
|
|
57
|
+
"""Record a tool success."""
|
|
58
|
+
self.failure_count = 0
|
|
59
|
+
self.is_open = False
|
|
60
|
+
self.next_retry_time = 0
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class ToolProxy:
|
|
64
|
+
"""Proxy that routes tool calls through adapters with health checks."""
|
|
65
|
+
|
|
66
|
+
def __init__(self, console: Console | None = None):
|
|
67
|
+
self.console = console or depends.get_sync(Console)
|
|
68
|
+
self.health_status: dict[str, ToolHealthStatus] = {}
|
|
69
|
+
self.circuit_breakers: dict[str, CircuitBreakerState] = {}
|
|
70
|
+
|
|
71
|
+
# Tool mappings to adapters
|
|
72
|
+
self.tool_adapters = {
|
|
73
|
+
"zuban": self._create_zuban_adapter,
|
|
74
|
+
"skylos": self._create_skylos_adapter,
|
|
75
|
+
"ruff": self._create_ruff_adapter,
|
|
76
|
+
"bandit": self._create_bandit_adapter,
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
# Fallback recommendations
|
|
80
|
+
self.fallback_tools = {
|
|
81
|
+
"zuban": ["pyright", "mypy"],
|
|
82
|
+
"skylos": ["vulture"],
|
|
83
|
+
"ruff": [], # Ruff is usually reliable
|
|
84
|
+
"bandit": [], # Skip security checks if bandit fails
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
def execute_tool(self, tool_name: str, args: list[str]) -> int:
|
|
88
|
+
"""Execute a tool through its adapter with health checks.
|
|
89
|
+
|
|
90
|
+
Args:
|
|
91
|
+
tool_name: Name of the tool to execute
|
|
92
|
+
args: Arguments to pass to the tool
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
Exit code (0 for success, non-zero for failure)
|
|
96
|
+
"""
|
|
97
|
+
try:
|
|
98
|
+
# Check circuit breaker
|
|
99
|
+
circuit_breaker = self._get_circuit_breaker(tool_name)
|
|
100
|
+
|
|
101
|
+
if not circuit_breaker.should_attempt():
|
|
102
|
+
self._handle_circuit_breaker_open(tool_name)
|
|
103
|
+
return self._try_fallback_tools(tool_name, args)
|
|
104
|
+
|
|
105
|
+
# Check tool health
|
|
106
|
+
if not self._check_tool_health(tool_name):
|
|
107
|
+
self._handle_unhealthy_tool(tool_name)
|
|
108
|
+
circuit_breaker.record_failure()
|
|
109
|
+
return self._try_fallback_tools(tool_name, args)
|
|
110
|
+
|
|
111
|
+
# Execute through adapter
|
|
112
|
+
result = self._execute_through_adapter(tool_name, args)
|
|
113
|
+
|
|
114
|
+
if result == 0:
|
|
115
|
+
circuit_breaker.record_success()
|
|
116
|
+
else:
|
|
117
|
+
circuit_breaker.record_failure()
|
|
118
|
+
|
|
119
|
+
return result
|
|
120
|
+
|
|
121
|
+
except Exception as e:
|
|
122
|
+
self.console.print(f"[red]Tool proxy error for {tool_name}: {e}[/red]")
|
|
123
|
+
self._get_circuit_breaker(tool_name).record_failure()
|
|
124
|
+
return self._try_fallback_tools(tool_name, args)
|
|
125
|
+
|
|
126
|
+
def _get_circuit_breaker(self, tool_name: str) -> CircuitBreakerState:
|
|
127
|
+
"""Get or create circuit breaker for tool."""
|
|
128
|
+
if tool_name not in self.circuit_breakers:
|
|
129
|
+
self.circuit_breakers[tool_name] = CircuitBreakerState()
|
|
130
|
+
return self.circuit_breakers[tool_name]
|
|
131
|
+
|
|
132
|
+
def _check_tool_health(self, tool_name: str) -> bool:
|
|
133
|
+
"""Check if a tool is healthy."""
|
|
134
|
+
current_time = time.time()
|
|
135
|
+
|
|
136
|
+
# Use cached health status if recent (within 30 seconds)
|
|
137
|
+
if tool_name in self.health_status:
|
|
138
|
+
status = self.health_status[tool_name]
|
|
139
|
+
if current_time - status.last_check < 30:
|
|
140
|
+
return status.is_healthy
|
|
141
|
+
|
|
142
|
+
# Perform actual health check
|
|
143
|
+
is_healthy = self._perform_health_check(tool_name)
|
|
144
|
+
|
|
145
|
+
self.health_status[tool_name] = ToolHealthStatus(
|
|
146
|
+
is_healthy=is_healthy,
|
|
147
|
+
last_check=current_time,
|
|
148
|
+
fallback_recommendations=list(self.fallback_tools.get(tool_name, [])),
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
return is_healthy
|
|
152
|
+
|
|
153
|
+
def _perform_health_check(self, tool_name: str) -> bool:
|
|
154
|
+
"""Perform actual health check for a tool."""
|
|
155
|
+
try:
|
|
156
|
+
if tool_name in self.tool_adapters:
|
|
157
|
+
# Use adapter health check if available
|
|
158
|
+
adapter = self.tool_adapters[tool_name]()
|
|
159
|
+
if adapter and hasattr(adapter, "check_tool_health"):
|
|
160
|
+
return bool(adapter.check_tool_health())
|
|
161
|
+
|
|
162
|
+
# Tool-specific health checks for known problematic tools
|
|
163
|
+
if tool_name == "zuban":
|
|
164
|
+
return self._check_zuban_health()
|
|
165
|
+
elif tool_name == "skylos":
|
|
166
|
+
return self._check_skylos_health()
|
|
167
|
+
|
|
168
|
+
# Fallback to basic version check
|
|
169
|
+
import subprocess
|
|
170
|
+
|
|
171
|
+
result = subprocess.run(
|
|
172
|
+
["uv", "run", tool_name, "--version"],
|
|
173
|
+
capture_output=True,
|
|
174
|
+
timeout=10,
|
|
175
|
+
text=True,
|
|
176
|
+
)
|
|
177
|
+
return result.returncode == 0
|
|
178
|
+
|
|
179
|
+
except Exception:
|
|
180
|
+
return False
|
|
181
|
+
|
|
182
|
+
def _check_zuban_health(self) -> bool:
|
|
183
|
+
"""Specific health check for Zuban that tests TOML parsing."""
|
|
184
|
+
import subprocess
|
|
185
|
+
import tempfile
|
|
186
|
+
|
|
187
|
+
try:
|
|
188
|
+
# Test basic version first
|
|
189
|
+
result = subprocess.run(
|
|
190
|
+
["uv", "run", "zuban", "--version"],
|
|
191
|
+
capture_output=True,
|
|
192
|
+
timeout=10,
|
|
193
|
+
text=True,
|
|
194
|
+
)
|
|
195
|
+
if result.returncode != 0:
|
|
196
|
+
return False
|
|
197
|
+
|
|
198
|
+
# Test actual type checking on a minimal file - this triggers TOML parsing
|
|
199
|
+
with tempfile.TemporaryDirectory() as temp_dir:
|
|
200
|
+
temp_file = Path(temp_dir) / "test.py"
|
|
201
|
+
temp_file.write_text("x: int = 1\n")
|
|
202
|
+
|
|
203
|
+
# This should trigger the TOML parsing bug if it exists
|
|
204
|
+
result = subprocess.run(
|
|
205
|
+
["uv", "run", "zuban", "check", str(temp_file)],
|
|
206
|
+
capture_output=True,
|
|
207
|
+
timeout=5, # Short timeout to catch panics
|
|
208
|
+
text=True,
|
|
209
|
+
cwd=Path.cwd(), # Run from our directory with problematic pyproject.toml
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
# If it exits cleanly (regardless of type errors), tool is healthy
|
|
213
|
+
# The key is that it doesn't panic with TOML parsing errors
|
|
214
|
+
return result.returncode in (0, 1) # 0=no errors, 1=type errors found
|
|
215
|
+
|
|
216
|
+
except (subprocess.TimeoutExpired, subprocess.CalledProcessError):
|
|
217
|
+
# Tool timed out or crashed - likely the TOML parsing bug
|
|
218
|
+
return False
|
|
219
|
+
except Exception:
|
|
220
|
+
return False
|
|
221
|
+
|
|
222
|
+
def _check_skylos_health(self) -> bool:
|
|
223
|
+
"""Specific health check for Skylos."""
|
|
224
|
+
import subprocess
|
|
225
|
+
|
|
226
|
+
try:
|
|
227
|
+
result = subprocess.run(
|
|
228
|
+
["uv", "run", "skylos", "--version"],
|
|
229
|
+
capture_output=True,
|
|
230
|
+
timeout=10,
|
|
231
|
+
text=True,
|
|
232
|
+
)
|
|
233
|
+
return result.returncode == 0
|
|
234
|
+
except Exception:
|
|
235
|
+
return False
|
|
236
|
+
|
|
237
|
+
def _execute_through_adapter(self, tool_name: str, args: list[str]) -> int:
|
|
238
|
+
"""Execute tool through its adapter if available."""
|
|
239
|
+
if tool_name in self.tool_adapters:
|
|
240
|
+
try:
|
|
241
|
+
# Use async adapter if available
|
|
242
|
+
return asyncio.run(self._execute_adapter_async(tool_name, args))
|
|
243
|
+
except Exception as e:
|
|
244
|
+
self.console.print(
|
|
245
|
+
f"[yellow]Adapter execution failed for {tool_name}: {e}[/yellow]"
|
|
246
|
+
)
|
|
247
|
+
# Fall back to direct execution
|
|
248
|
+
pass
|
|
249
|
+
|
|
250
|
+
# Direct execution as fallback
|
|
251
|
+
return self._execute_direct(tool_name, args)
|
|
252
|
+
|
|
253
|
+
async def _execute_adapter_async(self, tool_name: str, args: list[str]) -> int:
|
|
254
|
+
"""Execute tool through async adapter."""
|
|
255
|
+
adapter_factory = self.tool_adapters[tool_name]
|
|
256
|
+
adapter = adapter_factory()
|
|
257
|
+
|
|
258
|
+
# Convert args to file paths for adapter
|
|
259
|
+
target_files = self._args_to_file_paths(args)
|
|
260
|
+
|
|
261
|
+
if hasattr(adapter, "check_with_lsp_or_fallback"):
|
|
262
|
+
result = await adapter.check_with_lsp_or_fallback(target_files)
|
|
263
|
+
return 0 if result.success else 1
|
|
264
|
+
|
|
265
|
+
return self._execute_direct(tool_name, args)
|
|
266
|
+
|
|
267
|
+
def _execute_direct(self, tool_name: str, args: list[str]) -> int:
|
|
268
|
+
"""Execute tool directly without adapter."""
|
|
269
|
+
import subprocess
|
|
270
|
+
|
|
271
|
+
try:
|
|
272
|
+
cmd = ["uv", "run", tool_name] + args
|
|
273
|
+
result = subprocess.run(cmd, timeout=300)
|
|
274
|
+
return result.returncode
|
|
275
|
+
|
|
276
|
+
except subprocess.TimeoutExpired:
|
|
277
|
+
self.console.print(f"[red]Tool {tool_name} timed out[/red]")
|
|
278
|
+
return 1
|
|
279
|
+
except Exception as e:
|
|
280
|
+
self.console.print(
|
|
281
|
+
f"[red]Direct execution failed for {tool_name}: {e}[/red]"
|
|
282
|
+
)
|
|
283
|
+
return 1
|
|
284
|
+
|
|
285
|
+
def _args_to_file_paths(self, args: list[str]) -> list[Path]:
|
|
286
|
+
"""Convert command line arguments to file paths."""
|
|
287
|
+
file_paths = [
|
|
288
|
+
Path(arg) for arg in args if not arg.startswith("-") and Path(arg).exists()
|
|
289
|
+
]
|
|
290
|
+
|
|
291
|
+
# Default to current directory if no files specified
|
|
292
|
+
if not file_paths:
|
|
293
|
+
file_paths = [Path()]
|
|
294
|
+
|
|
295
|
+
return file_paths
|
|
296
|
+
|
|
297
|
+
def _try_fallback_tools(self, tool_name: str, args: list[str]) -> int:
|
|
298
|
+
"""Try fallback tools when primary tool fails."""
|
|
299
|
+
fallbacks = self.fallback_tools.get(tool_name, [])
|
|
300
|
+
|
|
301
|
+
if not fallbacks:
|
|
302
|
+
self.console.print(
|
|
303
|
+
f"[yellow]No fallback available for {tool_name}. Skipping with warning.[/yellow]"
|
|
304
|
+
)
|
|
305
|
+
return 0 # Skip with success to not block workflow
|
|
306
|
+
|
|
307
|
+
self.console.print(
|
|
308
|
+
f"[yellow]Trying fallback tools for {tool_name}: {', '.join(fallbacks)}[/yellow]"
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
for fallback in fallbacks:
|
|
312
|
+
try:
|
|
313
|
+
# Check if fallback is healthy
|
|
314
|
+
if self._check_tool_health(fallback):
|
|
315
|
+
result = self._execute_direct(fallback, args)
|
|
316
|
+
if result == 0:
|
|
317
|
+
self.console.print(
|
|
318
|
+
f"[green]Fallback {fallback} succeeded[/green]"
|
|
319
|
+
)
|
|
320
|
+
return 0
|
|
321
|
+
except Exception:
|
|
322
|
+
continue
|
|
323
|
+
|
|
324
|
+
self.console.print(
|
|
325
|
+
f"[yellow]All fallbacks failed for {tool_name}. Continuing...[/yellow]"
|
|
326
|
+
)
|
|
327
|
+
return 0 # Don't block workflow on tool failures
|
|
328
|
+
|
|
329
|
+
def _handle_circuit_breaker_open(self, tool_name: str) -> None:
|
|
330
|
+
"""Handle when circuit breaker is open."""
|
|
331
|
+
circuit_breaker = self.circuit_breakers[tool_name]
|
|
332
|
+
retry_minutes = int((circuit_breaker.next_retry_time - time.time()) / 60)
|
|
333
|
+
|
|
334
|
+
self.console.print(
|
|
335
|
+
f"[yellow]Circuit breaker open for {tool_name}. "
|
|
336
|
+
f"Will retry in {retry_minutes} minutes.[/yellow]"
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
def _handle_unhealthy_tool(self, tool_name: str) -> None:
|
|
340
|
+
"""Handle when tool is detected as unhealthy."""
|
|
341
|
+
self.console.print(
|
|
342
|
+
f"[yellow]Tool {tool_name} is unhealthy. Trying fallbacks...[/yellow]"
|
|
343
|
+
)
|
|
344
|
+
|
|
345
|
+
def _create_zuban_adapter(self) -> t.Any | None:
|
|
346
|
+
"""Create Zuban adapter instance."""
|
|
347
|
+
try:
|
|
348
|
+
from acb.depends import depends
|
|
349
|
+
|
|
350
|
+
from crackerjack.adapters.zuban_adapter import ZubanAdapter
|
|
351
|
+
from crackerjack.config import CrackerjackSettings
|
|
352
|
+
from crackerjack.orchestration.execution_strategies import ExecutionContext
|
|
353
|
+
|
|
354
|
+
# Create minimal context for adapter using ACB settings
|
|
355
|
+
settings = depends.get_sync(CrackerjackSettings)
|
|
356
|
+
|
|
357
|
+
# Import adapter from core_tools that converts settings to OptionsProtocol
|
|
358
|
+
from crackerjack.mcp.tools.core_tools import _adapt_settings_to_protocol
|
|
359
|
+
|
|
360
|
+
options = _adapt_settings_to_protocol(settings)
|
|
361
|
+
context = ExecutionContext(pkg_path=Path.cwd(), options=options)
|
|
362
|
+
return ZubanAdapter(context)
|
|
363
|
+
except (ImportError, Exception):
|
|
364
|
+
return None
|
|
365
|
+
|
|
366
|
+
def _create_skylos_adapter(self) -> t.Any | None:
|
|
367
|
+
"""Create Skylos adapter instance."""
|
|
368
|
+
try:
|
|
369
|
+
from acb.depends import depends
|
|
370
|
+
|
|
371
|
+
from crackerjack.adapters.skylos_adapter import SkylosAdapter
|
|
372
|
+
from crackerjack.config import CrackerjackSettings
|
|
373
|
+
from crackerjack.orchestration.execution_strategies import ExecutionContext
|
|
374
|
+
|
|
375
|
+
# Create minimal context for adapter using ACB settings
|
|
376
|
+
settings = depends.get_sync(CrackerjackSettings)
|
|
377
|
+
|
|
378
|
+
# Import adapter from core_tools that converts settings to OptionsProtocol
|
|
379
|
+
from crackerjack.mcp.tools.core_tools import _adapt_settings_to_protocol
|
|
380
|
+
|
|
381
|
+
options = _adapt_settings_to_protocol(settings)
|
|
382
|
+
context = ExecutionContext(pkg_path=Path.cwd(), options=options)
|
|
383
|
+
return SkylosAdapter(context)
|
|
384
|
+
except (ImportError, Exception):
|
|
385
|
+
return None
|
|
386
|
+
|
|
387
|
+
def _create_ruff_adapter(self) -> t.Any | None:
|
|
388
|
+
"""Create Ruff adapter instance."""
|
|
389
|
+
# Ruff doesn't have an adapter yet, return None for direct execution
|
|
390
|
+
return None
|
|
391
|
+
|
|
392
|
+
def _create_bandit_adapter(self) -> t.Any | None:
|
|
393
|
+
"""Create Bandit adapter instance."""
|
|
394
|
+
# Bandit doesn't have an adapter yet, return None for direct execution
|
|
395
|
+
return None
|
|
396
|
+
|
|
397
|
+
def get_tool_status(self) -> dict[str, dict[str, t.Any]]:
|
|
398
|
+
"""Get status of all tools for monitoring."""
|
|
399
|
+
status = {}
|
|
400
|
+
|
|
401
|
+
for tool_name in self.tool_adapters.keys():
|
|
402
|
+
circuit_breaker = self._get_circuit_breaker(tool_name)
|
|
403
|
+
health_status = self.health_status.get(tool_name)
|
|
404
|
+
|
|
405
|
+
status[tool_name] = {
|
|
406
|
+
"circuit_breaker_open": circuit_breaker.is_open,
|
|
407
|
+
"failure_count": circuit_breaker.failure_count,
|
|
408
|
+
"is_healthy": health_status.is_healthy if health_status else None,
|
|
409
|
+
"last_health_check": health_status.last_check
|
|
410
|
+
if health_status
|
|
411
|
+
else None,
|
|
412
|
+
"fallback_tools": self.fallback_tools.get(tool_name, []),
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
return status
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
def main() -> None:
|
|
419
|
+
"""Main entry point for tool proxy CLI."""
|
|
420
|
+
if len(sys.argv) < 2:
|
|
421
|
+
print("Usage: python -m crackerjack.executors.tool_proxy <tool_name> [args...]")
|
|
422
|
+
sys.exit(1)
|
|
423
|
+
|
|
424
|
+
tool_name = sys.argv[1]
|
|
425
|
+
args = sys.argv[2:]
|
|
426
|
+
|
|
427
|
+
proxy = ToolProxy()
|
|
428
|
+
exit_code = proxy.execute_tool(tool_name, args)
|
|
429
|
+
sys.exit(exit_code)
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
if __name__ == "__main__":
|
|
433
|
+
main()
|