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,301 @@
|
|
|
1
|
+
> Crackerjack Docs: [Main](<../../README.md>) | [Crackerjack Package](<../README.md>) | [Exceptions](<./README.md>)
|
|
2
|
+
|
|
3
|
+
# Exceptions
|
|
4
|
+
|
|
5
|
+
Custom exception types with rich formatting and context-aware error reporting. Provides enhanced UX for tool execution failures and configuration issues.
|
|
6
|
+
|
|
7
|
+
## Exception Hierarchy
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
BaseException
|
|
11
|
+
└── Exception
|
|
12
|
+
├── ToolExecutionError # Rich tool execution failures
|
|
13
|
+
└── ConfigIntegrityError # Configuration validation issues
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Custom Exception Types
|
|
17
|
+
|
|
18
|
+
### ToolExecutionError
|
|
19
|
+
|
|
20
|
+
Enhanced error with rich formatting for failed tool executions. Provides detailed context including exit codes, stdout/stderr, duration, and actionable suggestions.
|
|
21
|
+
|
|
22
|
+
**Features:**
|
|
23
|
+
|
|
24
|
+
- Rich console formatting with syntax highlighting
|
|
25
|
+
- Automatic output truncation for readability
|
|
26
|
+
- Actionable error messages with suggestions
|
|
27
|
+
- Context tracking (command, cwd, duration)
|
|
28
|
+
- Integration with Crackerjack's console system
|
|
29
|
+
|
|
30
|
+
**Constructor:**
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
ToolExecutionError(
|
|
34
|
+
tool: str, # Tool name that failed
|
|
35
|
+
exit_code: int, # Process exit code
|
|
36
|
+
stdout: str = "", # Standard output
|
|
37
|
+
stderr: str = "", # Standard error
|
|
38
|
+
command: list[str] | None = None, # Full command executed
|
|
39
|
+
cwd: Path | None = None, # Working directory
|
|
40
|
+
duration: float | None = None, # Execution duration (seconds)
|
|
41
|
+
)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**Usage Example:**
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
from crackerjack.exceptions import ToolExecutionError
|
|
48
|
+
from pathlib import Path
|
|
49
|
+
|
|
50
|
+
try:
|
|
51
|
+
result = subprocess.run(
|
|
52
|
+
["ruff", "check", "."], capture_output=True, text=True, cwd=project_dir
|
|
53
|
+
)
|
|
54
|
+
if result.returncode != 0:
|
|
55
|
+
raise ToolExecutionError(
|
|
56
|
+
tool="ruff",
|
|
57
|
+
exit_code=result.returncode,
|
|
58
|
+
stdout=result.stdout,
|
|
59
|
+
stderr=result.stderr,
|
|
60
|
+
command=["ruff", "check", "."],
|
|
61
|
+
cwd=project_dir,
|
|
62
|
+
duration=2.5,
|
|
63
|
+
)
|
|
64
|
+
except ToolExecutionError as e:
|
|
65
|
+
# Rich formatted output
|
|
66
|
+
console.print(e.format_rich())
|
|
67
|
+
|
|
68
|
+
# Or get actionable message
|
|
69
|
+
print(e.get_actionable_message())
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**Rich Formatting:**
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
from acb.console import Console
|
|
76
|
+
|
|
77
|
+
console = Console()
|
|
78
|
+
|
|
79
|
+
# Create error
|
|
80
|
+
error = ToolExecutionError(
|
|
81
|
+
tool="pytest",
|
|
82
|
+
exit_code=1,
|
|
83
|
+
stderr="test_example.py::test_feature FAILED",
|
|
84
|
+
duration=3.2,
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
# Display with rich formatting
|
|
88
|
+
panel = error.format_rich(console)
|
|
89
|
+
console.print(panel)
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
**Output:**
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
╭─ ❌ Tool Execution Failed: pytest ─────────────╮
|
|
96
|
+
│ Tool: pytest │
|
|
97
|
+
│ Exit Code: 1 │
|
|
98
|
+
│ Duration: 3.20s │
|
|
99
|
+
│ │
|
|
100
|
+
│ Error Output: │
|
|
101
|
+
│ test_example.py::test_feature FAILED │
|
|
102
|
+
╰────────────────────────────────────────────────╯
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
**Actionable Messages:**
|
|
106
|
+
|
|
107
|
+
The `get_actionable_message()` method provides smart error pattern detection:
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
error = ToolExecutionError(
|
|
111
|
+
tool="ruff", exit_code=1, stderr="ModuleNotFoundError: No module named 'requests'"
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
print(error.get_actionable_message())
|
|
115
|
+
# Output:
|
|
116
|
+
# Tool 'ruff' failed with exit code 1
|
|
117
|
+
# → Check Python dependencies are installed (try: uv sync)
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
**Common Patterns Detected:**
|
|
121
|
+
|
|
122
|
+
- Permission denied → Check file permissions
|
|
123
|
+
- Command not found → Ensure tool is installed
|
|
124
|
+
- Timeout errors → Increase timeout setting
|
|
125
|
+
- Syntax errors → Check code syntax
|
|
126
|
+
- Import errors → Run dependency sync
|
|
127
|
+
- Type errors → Fix type annotations
|
|
128
|
+
- Out of memory → Reduce batch size
|
|
129
|
+
|
|
130
|
+
### ConfigIntegrityError
|
|
131
|
+
|
|
132
|
+
Simple exception for configuration validation and integrity issues.
|
|
133
|
+
|
|
134
|
+
**Usage Example:**
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
from crackerjack.exceptions import ConfigIntegrityError
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def validate_config(config: dict) -> None:
|
|
141
|
+
if "required_field" not in config:
|
|
142
|
+
raise ConfigIntegrityError(
|
|
143
|
+
"Missing required field 'required_field' in configuration"
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
if config.get("version") != "1.0":
|
|
147
|
+
raise ConfigIntegrityError(
|
|
148
|
+
f"Unsupported config version: {config.get('version')}"
|
|
149
|
+
)
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Error Handling Patterns
|
|
153
|
+
|
|
154
|
+
### Pattern 1: Tool Execution with Context
|
|
155
|
+
|
|
156
|
+
```python
|
|
157
|
+
from crackerjack.exceptions import ToolExecutionError
|
|
158
|
+
import subprocess
|
|
159
|
+
import time
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def run_tool(tool: str, args: list[str], cwd: Path) -> bool:
|
|
163
|
+
"""Run tool with comprehensive error reporting."""
|
|
164
|
+
start = time.time()
|
|
165
|
+
|
|
166
|
+
try:
|
|
167
|
+
result = subprocess.run(
|
|
168
|
+
[tool] + args, capture_output=True, text=True, cwd=cwd, timeout=300
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
if result.returncode != 0:
|
|
172
|
+
raise ToolExecutionError(
|
|
173
|
+
tool=tool,
|
|
174
|
+
exit_code=result.returncode,
|
|
175
|
+
stdout=result.stdout,
|
|
176
|
+
stderr=result.stderr,
|
|
177
|
+
command=[tool] + args,
|
|
178
|
+
cwd=cwd,
|
|
179
|
+
duration=time.time() - start,
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
return True
|
|
183
|
+
|
|
184
|
+
except subprocess.TimeoutExpired as e:
|
|
185
|
+
raise ToolExecutionError(
|
|
186
|
+
tool=tool,
|
|
187
|
+
exit_code=-1,
|
|
188
|
+
stderr=f"Tool execution timed out after {e.timeout}s",
|
|
189
|
+
command=[tool] + args,
|
|
190
|
+
cwd=cwd,
|
|
191
|
+
duration=e.timeout,
|
|
192
|
+
) from e
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Pattern 2: Graceful Error Display
|
|
196
|
+
|
|
197
|
+
```python
|
|
198
|
+
from crackerjack.exceptions import ToolExecutionError
|
|
199
|
+
from acb.console import Console
|
|
200
|
+
from acb.depends import depends
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
@depends.inject
|
|
204
|
+
def execute_with_nice_errors(func: callable, console: Console = depends()) -> bool:
|
|
205
|
+
"""Execute function with rich error formatting."""
|
|
206
|
+
try:
|
|
207
|
+
return func()
|
|
208
|
+
except ToolExecutionError as e:
|
|
209
|
+
console.print(e.format_rich())
|
|
210
|
+
console.print(f"\n[yellow]{e.get_actionable_message()}[/yellow]")
|
|
211
|
+
return False
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Pattern 3: Config Validation
|
|
215
|
+
|
|
216
|
+
```python
|
|
217
|
+
from crackerjack.exceptions import ConfigIntegrityError
|
|
218
|
+
from pathlib import Path
|
|
219
|
+
import yaml
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def load_and_validate_config(path: Path) -> dict:
|
|
223
|
+
"""Load config with integrity validation."""
|
|
224
|
+
if not path.exists():
|
|
225
|
+
raise ConfigIntegrityError(f"Configuration file not found: {path}")
|
|
226
|
+
|
|
227
|
+
with open(path) as f:
|
|
228
|
+
config = yaml.safe_load(f)
|
|
229
|
+
|
|
230
|
+
required = ["version", "project_name", "settings"]
|
|
231
|
+
missing = [k for k in required if k not in config]
|
|
232
|
+
|
|
233
|
+
if missing:
|
|
234
|
+
raise ConfigIntegrityError(
|
|
235
|
+
f"Missing required config fields: {', '.join(missing)}"
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
return config
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
## Best Practices
|
|
242
|
+
|
|
243
|
+
### Use ToolExecutionError for All Tool Failures
|
|
244
|
+
|
|
245
|
+
Provides consistent, rich error reporting across the codebase:
|
|
246
|
+
|
|
247
|
+
```python
|
|
248
|
+
# ✅ Good - Rich error context
|
|
249
|
+
if exit_code != 0:
|
|
250
|
+
raise ToolExecutionError(
|
|
251
|
+
tool="mypy", exit_code=exit_code, stderr=stderr, duration=duration
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
# ❌ Bad - Generic exception
|
|
255
|
+
if exit_code != 0:
|
|
256
|
+
raise RuntimeError(f"mypy failed: {stderr}")
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### Include All Available Context
|
|
260
|
+
|
|
261
|
+
More context enables better error messages:
|
|
262
|
+
|
|
263
|
+
```python
|
|
264
|
+
# ✅ Good - Full context
|
|
265
|
+
raise ToolExecutionError(
|
|
266
|
+
tool="pytest",
|
|
267
|
+
exit_code=1,
|
|
268
|
+
stdout=result.stdout,
|
|
269
|
+
stderr=result.stderr,
|
|
270
|
+
command=full_command,
|
|
271
|
+
cwd=project_dir,
|
|
272
|
+
duration=elapsed,
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
# ⚠️ Minimal - Missing helpful context
|
|
276
|
+
raise ToolExecutionError(tool="pytest", exit_code=1)
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### Use format_rich() for User-Facing Errors
|
|
280
|
+
|
|
281
|
+
Provides best UX with Rich console integration:
|
|
282
|
+
|
|
283
|
+
```python
|
|
284
|
+
try:
|
|
285
|
+
run_checks()
|
|
286
|
+
except ToolExecutionError as e:
|
|
287
|
+
console.print(e.format_rich()) # Beautiful formatting
|
|
288
|
+
console.print(f"\n{e.get_actionable_message()}") # Smart suggestions
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
## Implementation Files
|
|
292
|
+
|
|
293
|
+
- **`tool_execution_error.py`** - ToolExecutionError with rich formatting
|
|
294
|
+
- **`config.py`** - ConfigIntegrityError for configuration validation
|
|
295
|
+
|
|
296
|
+
## Related
|
|
297
|
+
|
|
298
|
+
- [Decorators](<../decorators/README.md>) - Error handling decorators
|
|
299
|
+
- [Errors](../errors/README.md) - Core error types and CrackerjackError base
|
|
300
|
+
- [MCP](<../mcp/README.md>) - Error caching and pattern analysis
|
|
301
|
+
- [Console Integration](https://github.com/Textualize/rich) - Rich console formatting
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
"""Enhanced tool execution error with rich formatting.
|
|
2
|
+
|
|
3
|
+
Provides context-rich error reporting for failed tool executions.
|
|
4
|
+
Part of Phase 10.2.3: Development Velocity Improvements.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
from acb.console import Console
|
|
10
|
+
from rich.panel import Panel
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ToolExecutionError(Exception):
|
|
14
|
+
"""Enhanced error with context for tool execution failures.
|
|
15
|
+
|
|
16
|
+
Provides detailed information about what went wrong during tool execution,
|
|
17
|
+
including exit code, stdout, stderr, and rich formatting for better UX.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
def __init__(
|
|
21
|
+
self,
|
|
22
|
+
tool: str,
|
|
23
|
+
exit_code: int,
|
|
24
|
+
stdout: str = "",
|
|
25
|
+
stderr: str = "",
|
|
26
|
+
command: list[str] | None = None,
|
|
27
|
+
cwd: Path | None = None,
|
|
28
|
+
duration: float | None = None,
|
|
29
|
+
):
|
|
30
|
+
"""Initialize tool execution error.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
tool: Tool name that failed
|
|
34
|
+
exit_code: Process exit code
|
|
35
|
+
stdout: Standard output from tool
|
|
36
|
+
stderr: Standard error from tool
|
|
37
|
+
command: Full command that was executed (optional)
|
|
38
|
+
cwd: Working directory where command was run (optional)
|
|
39
|
+
duration: Execution duration in seconds (optional)
|
|
40
|
+
"""
|
|
41
|
+
self.tool = tool
|
|
42
|
+
self.exit_code = exit_code
|
|
43
|
+
self.stdout = stdout.strip()
|
|
44
|
+
self.stderr = stderr.strip()
|
|
45
|
+
self.command = command
|
|
46
|
+
self.cwd = cwd
|
|
47
|
+
self.duration = duration
|
|
48
|
+
|
|
49
|
+
# Create base exception message
|
|
50
|
+
message = f"Tool '{tool}' failed with exit code {exit_code}"
|
|
51
|
+
if duration is not None:
|
|
52
|
+
message += f" after {duration:.1f}s"
|
|
53
|
+
|
|
54
|
+
super().__init__(message)
|
|
55
|
+
|
|
56
|
+
def format_rich(self, console: Console | None = None) -> Panel:
|
|
57
|
+
"""Format error for rich console display with syntax highlighting.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
console: Optional console for width detection
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
Formatted rich Panel with error details
|
|
64
|
+
"""
|
|
65
|
+
# Build error content with sections
|
|
66
|
+
content_parts = []
|
|
67
|
+
|
|
68
|
+
# Tool and exit code
|
|
69
|
+
content_parts.extend(
|
|
70
|
+
(
|
|
71
|
+
f"[bold red]Tool:[/bold red] {self.tool}",
|
|
72
|
+
f"[bold red]Exit Code:[/bold red] {self.exit_code}",
|
|
73
|
+
)
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
# Duration if available
|
|
77
|
+
if self.duration is not None:
|
|
78
|
+
content_parts.append(
|
|
79
|
+
f"[bold yellow]Duration:[/bold yellow] {self.duration:.2f}s"
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
# Working directory if available
|
|
83
|
+
if self.cwd:
|
|
84
|
+
content_parts.append(f"[bold cyan]Directory:[/bold cyan] {self.cwd}")
|
|
85
|
+
|
|
86
|
+
# Command if available
|
|
87
|
+
if self.command:
|
|
88
|
+
cmd_str = " ".join(self.command)
|
|
89
|
+
# Truncate very long commands
|
|
90
|
+
if len(cmd_str) > 100:
|
|
91
|
+
cmd_str = cmd_str[:97] + "..."
|
|
92
|
+
content_parts.append(f"[bold cyan]Command:[/bold cyan] {cmd_str}")
|
|
93
|
+
|
|
94
|
+
# Standard error (most important)
|
|
95
|
+
if self.stderr:
|
|
96
|
+
content_parts.append("\n[bold yellow]Error Output:[/bold yellow]")
|
|
97
|
+
# Limit error output to last 20 lines for readability
|
|
98
|
+
stderr_lines = self.stderr.split("\n")
|
|
99
|
+
if len(stderr_lines) > 20:
|
|
100
|
+
content_parts.append("[dim]...(truncated)[/dim]")
|
|
101
|
+
stderr_lines = stderr_lines[-20:]
|
|
102
|
+
content_parts.append(self._format_output(stderr_lines))
|
|
103
|
+
|
|
104
|
+
# Standard output (if present and stderr is empty)
|
|
105
|
+
elif self.stdout:
|
|
106
|
+
content_parts.append("\n[bold yellow]Output:[/bold yellow]")
|
|
107
|
+
stdout_lines = self.stdout.split("\n")
|
|
108
|
+
if len(stdout_lines) > 20:
|
|
109
|
+
content_parts.append("[dim]...(truncated)[/dim]")
|
|
110
|
+
stdout_lines = stdout_lines[-20:]
|
|
111
|
+
content_parts.append(self._format_output(stdout_lines))
|
|
112
|
+
|
|
113
|
+
# No output available
|
|
114
|
+
else:
|
|
115
|
+
content_parts.append("\n[dim]No error output available[/dim]")
|
|
116
|
+
|
|
117
|
+
# Combine all parts
|
|
118
|
+
content = "\n".join(content_parts)
|
|
119
|
+
|
|
120
|
+
return Panel(
|
|
121
|
+
content,
|
|
122
|
+
title=f"❌ Tool Execution Failed: {self.tool}",
|
|
123
|
+
border_style="red",
|
|
124
|
+
expand=False,
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
def _format_output(self, lines: list[str]) -> str:
|
|
128
|
+
"""Format output lines with proper indentation and markup.
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
lines: Output lines to format
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
Formatted output string
|
|
135
|
+
"""
|
|
136
|
+
# Remove ANSI color codes for cleaner display
|
|
137
|
+
import re
|
|
138
|
+
|
|
139
|
+
# Standard ANSI escape sequence pattern (not security-critical, safe to use directly)
|
|
140
|
+
ansi_escape = re.compile(r"\x1b\[[0-9;]*m")
|
|
141
|
+
|
|
142
|
+
formatted_lines = []
|
|
143
|
+
for line in lines:
|
|
144
|
+
# Strip ANSI codes
|
|
145
|
+
clean_line = ansi_escape.sub("", line)
|
|
146
|
+
# Indent for readability
|
|
147
|
+
if clean_line.strip():
|
|
148
|
+
formatted_lines.append(f" {clean_line}")
|
|
149
|
+
|
|
150
|
+
return "\n".join(formatted_lines) if formatted_lines else "[dim] (empty)[/dim]"
|
|
151
|
+
|
|
152
|
+
def _get_error_suggestion(self, combined_output: str) -> str | None:
|
|
153
|
+
"""Get specific suggestion based on error patterns in output.
|
|
154
|
+
|
|
155
|
+
Args:
|
|
156
|
+
combined_output: Combined stderr and stdout in lowercase
|
|
157
|
+
|
|
158
|
+
Returns:
|
|
159
|
+
Suggestion string, or None if no pattern matched
|
|
160
|
+
"""
|
|
161
|
+
error_patterns = {
|
|
162
|
+
"permission denied": "→ Check file permissions or run with appropriate access",
|
|
163
|
+
(
|
|
164
|
+
"command not found",
|
|
165
|
+
"no such file",
|
|
166
|
+
): f"→ Ensure '{self.tool}' is installed and in PATH",
|
|
167
|
+
(
|
|
168
|
+
"timeout",
|
|
169
|
+
"timed out",
|
|
170
|
+
): "→ Tool execution timed out - consider increasing timeout",
|
|
171
|
+
(
|
|
172
|
+
"syntaxerror",
|
|
173
|
+
"syntax error",
|
|
174
|
+
): "→ Check code syntax in files being analyzed",
|
|
175
|
+
(
|
|
176
|
+
"importerror",
|
|
177
|
+
"modulenotfounderror",
|
|
178
|
+
): "→ Check Python dependencies are installed (try: uv sync)",
|
|
179
|
+
("typeerror", "type error"): "→ Fix type annotation errors in your code",
|
|
180
|
+
"out of memory": "→ Reduce batch size or increase available memory",
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
for patterns, suggestion in error_patterns.items():
|
|
184
|
+
patterns_list = patterns if isinstance(patterns, tuple) else (patterns,)
|
|
185
|
+
if any(pattern in combined_output for pattern in patterns_list):
|
|
186
|
+
return suggestion
|
|
187
|
+
|
|
188
|
+
return None
|
|
189
|
+
|
|
190
|
+
def get_actionable_message(self) -> str:
|
|
191
|
+
"""Get actionable error message for developers.
|
|
192
|
+
|
|
193
|
+
Returns:
|
|
194
|
+
Human-readable error message with suggestions
|
|
195
|
+
"""
|
|
196
|
+
messages = [f"Tool '{self.tool}' failed with exit code {self.exit_code}"]
|
|
197
|
+
|
|
198
|
+
# Add common error patterns and suggestions
|
|
199
|
+
combined_output = f"{self.stderr} {self.stdout}".lower()
|
|
200
|
+
suggestion = self._get_error_suggestion(combined_output)
|
|
201
|
+
|
|
202
|
+
if suggestion:
|
|
203
|
+
messages.append(suggestion)
|
|
204
|
+
elif self.stderr:
|
|
205
|
+
messages.append("→ Check error output above for details")
|
|
206
|
+
else:
|
|
207
|
+
messages.append(f"→ Run '{self.tool}' manually for more details")
|
|
208
|
+
|
|
209
|
+
return "\n".join(messages)
|
|
210
|
+
|
|
211
|
+
def __str__(self) -> str:
|
|
212
|
+
"""String representation for logging and debugging.
|
|
213
|
+
|
|
214
|
+
Returns:
|
|
215
|
+
Detailed string representation
|
|
216
|
+
"""
|
|
217
|
+
parts = [
|
|
218
|
+
f"ToolExecutionError: {self.tool}",
|
|
219
|
+
f"Exit Code: {self.exit_code}",
|
|
220
|
+
]
|
|
221
|
+
|
|
222
|
+
if self.duration is not None:
|
|
223
|
+
parts.append(f"Duration: {self.duration:.2f}s")
|
|
224
|
+
|
|
225
|
+
if self.command:
|
|
226
|
+
parts.append(f"Command: {' '.join(self.command)}")
|
|
227
|
+
|
|
228
|
+
if self.stderr:
|
|
229
|
+
parts.append(f"Stderr: {self.stderr[:200]}...")
|
|
230
|
+
elif self.stdout:
|
|
231
|
+
parts.append(f"Stdout: {self.stdout[:200]}...")
|
|
232
|
+
|
|
233
|
+
return " | ".join(parts)
|
|
234
|
+
|
|
235
|
+
def __repr__(self) -> str:
|
|
236
|
+
"""Developer representation.
|
|
237
|
+
|
|
238
|
+
Returns:
|
|
239
|
+
Repr string
|
|
240
|
+
"""
|
|
241
|
+
return (
|
|
242
|
+
f"ToolExecutionError(tool={self.tool!r}, "
|
|
243
|
+
f"exit_code={self.exit_code}, "
|
|
244
|
+
f"duration={self.duration})"
|
|
245
|
+
)
|