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,641 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Bridge between crackerjack's built-in agents and Claude Code's external agents.
|
|
3
|
+
|
|
4
|
+
This module provides integration between the internal agent system and Claude Code's
|
|
5
|
+
specialized agents located in ~/.claude/agents. It enables crackerjack's built-in
|
|
6
|
+
agents to consult with expert external agents for complex scenarios.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import logging
|
|
10
|
+
import typing as t
|
|
11
|
+
from contextlib import suppress
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
from crackerjack.services.file_modifier import SafeFileModifier
|
|
15
|
+
|
|
16
|
+
from .base import AgentContext, FixResult, Issue, IssueType
|
|
17
|
+
|
|
18
|
+
# Conditional import - ClaudeCodeFixer may not be available
|
|
19
|
+
_claude_ai_available = False
|
|
20
|
+
ClaudeCodeFixer: type[t.Any] | None = None
|
|
21
|
+
|
|
22
|
+
with suppress(ImportError):
|
|
23
|
+
from crackerjack.adapters.ai.claude import ClaudeCodeFixer # type: ignore[no-redef]
|
|
24
|
+
|
|
25
|
+
_claude_ai_available = True
|
|
26
|
+
|
|
27
|
+
# Mapping of internal issue types to Claude Code external agents
|
|
28
|
+
CLAUDE_CODE_AGENT_MAPPING = {
|
|
29
|
+
IssueType.COMPLEXITY: ["refactoring-specialist", "crackerjack-architect"],
|
|
30
|
+
IssueType.DRY_VIOLATION: ["refactoring-specialist", "crackerjack-architect"],
|
|
31
|
+
IssueType.PERFORMANCE: ["performance-specialist", "python-pro"],
|
|
32
|
+
IssueType.SECURITY: ["security-auditor", "python-pro"],
|
|
33
|
+
IssueType.TYPE_ERROR: ["python-pro", "crackerjack-architect"],
|
|
34
|
+
IssueType.TEST_FAILURE: ["crackerjack-test-specialist", "python-pro"],
|
|
35
|
+
IssueType.TEST_ORGANIZATION: ["crackerjack-test-specialist", "testing-specialist"],
|
|
36
|
+
IssueType.IMPORT_ERROR: ["python-pro", "refactoring-specialist"],
|
|
37
|
+
IssueType.DOCUMENTATION: ["documentation-specialist", "crackerjack-architect"],
|
|
38
|
+
IssueType.FORMATTING: ["python-pro"],
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
# Minimum confidence threshold for consulting external agents
|
|
42
|
+
EXTERNAL_CONSULTATION_THRESHOLD = 0.8
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class ClaudeCodeBridge:
|
|
46
|
+
"""Bridge for consulting Claude Code external agents with real AI integration."""
|
|
47
|
+
|
|
48
|
+
def __init__(self, context: AgentContext) -> None:
|
|
49
|
+
self.context = context
|
|
50
|
+
self.logger = logging.getLogger(__name__)
|
|
51
|
+
self._agent_path = Path.home() / ".claude" / "agents"
|
|
52
|
+
self._consultation_cache: dict[str, dict[str, t.Any]] = {}
|
|
53
|
+
|
|
54
|
+
# Real AI integration components (if available)
|
|
55
|
+
self.ai_fixer: t.Any | None = None # ClaudeCodeFixer instance or None
|
|
56
|
+
self.file_modifier = SafeFileModifier()
|
|
57
|
+
self._ai_available = _claude_ai_available
|
|
58
|
+
|
|
59
|
+
if not self._ai_available:
|
|
60
|
+
self.logger.warning(
|
|
61
|
+
"Claude AI adapter not available - AI-powered fixes disabled"
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
def should_consult_external_agent(
|
|
65
|
+
self, issue: Issue, internal_confidence: float
|
|
66
|
+
) -> bool:
|
|
67
|
+
"""Determine if we should consult an external Claude Code agent."""
|
|
68
|
+
# Only consult for complex issues that meet threshold
|
|
69
|
+
if internal_confidence >= EXTERNAL_CONSULTATION_THRESHOLD:
|
|
70
|
+
return False
|
|
71
|
+
|
|
72
|
+
# Check if we have relevant external agents for this issue type
|
|
73
|
+
return issue.type in CLAUDE_CODE_AGENT_MAPPING
|
|
74
|
+
|
|
75
|
+
def _get_agent_mapping(self) -> dict[t.Any, list[str]]:
|
|
76
|
+
"""Get the agent mapping for external access."""
|
|
77
|
+
return CLAUDE_CODE_AGENT_MAPPING
|
|
78
|
+
|
|
79
|
+
def _get_consultation_threshold(self) -> float:
|
|
80
|
+
"""Get the consultation threshold for external access."""
|
|
81
|
+
return EXTERNAL_CONSULTATION_THRESHOLD
|
|
82
|
+
|
|
83
|
+
def get_recommended_external_agents(self, issue: Issue) -> list[str]:
|
|
84
|
+
"""Get list of recommended external agents for an issue."""
|
|
85
|
+
return CLAUDE_CODE_AGENT_MAPPING.get(issue.type, [])
|
|
86
|
+
|
|
87
|
+
def verify_agent_availability(self, agent_name: str) -> bool:
|
|
88
|
+
"""Check if a Claude Code agent file exists."""
|
|
89
|
+
agent_file = self._agent_path / f"{agent_name}.md"
|
|
90
|
+
return agent_file.exists()
|
|
91
|
+
|
|
92
|
+
async def consult_external_agent(
|
|
93
|
+
self, issue: Issue, agent_name: str, context: dict[str, t.Any] | None = None
|
|
94
|
+
) -> dict[str, t.Any]:
|
|
95
|
+
"""
|
|
96
|
+
Consult with a Claude Code external agent for expert guidance.
|
|
97
|
+
|
|
98
|
+
This method would ideally use the Task tool to invoke external agents,
|
|
99
|
+
but since we're within crackerjack's internal system, we'll simulate
|
|
100
|
+
the consultation process and provide structured recommendations.
|
|
101
|
+
"""
|
|
102
|
+
cache_key = (
|
|
103
|
+
f"{agent_name}:{issue.type.value}:{issue.file_path}:{issue.line_number}"
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
if cache_key in self._consultation_cache:
|
|
107
|
+
self.logger.debug(f"Using cached consultation for {agent_name}")
|
|
108
|
+
return self._consultation_cache[cache_key]
|
|
109
|
+
|
|
110
|
+
if not self.verify_agent_availability(agent_name):
|
|
111
|
+
self.logger.warning(f"Agent {agent_name} not available in ~/.claude/agents")
|
|
112
|
+
return {"status": "unavailable", "recommendations": []}
|
|
113
|
+
|
|
114
|
+
# Generate consultation based on agent expertise and issue type
|
|
115
|
+
consultation = await self._generate_agent_consultation(
|
|
116
|
+
issue, agent_name, context
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
# Cache successful consultations
|
|
120
|
+
if consultation.get("status") == "success":
|
|
121
|
+
self._consultation_cache[cache_key] = consultation
|
|
122
|
+
|
|
123
|
+
return consultation
|
|
124
|
+
|
|
125
|
+
async def _generate_agent_consultation(
|
|
126
|
+
self, issue: Issue, agent_name: str, context: dict[str, t.Any] | None = None
|
|
127
|
+
) -> dict[str, t.Any]:
|
|
128
|
+
"""Generate structured consultation response from agent expertise."""
|
|
129
|
+
consultation: dict[str, t.Any] = {
|
|
130
|
+
"status": "success",
|
|
131
|
+
"agent": agent_name,
|
|
132
|
+
"issue_type": issue.type.value,
|
|
133
|
+
"recommendations": [],
|
|
134
|
+
"patterns": [],
|
|
135
|
+
"validation_steps": [],
|
|
136
|
+
"confidence": 0.9,
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
# Agent-specific consultation logic
|
|
140
|
+
if agent_name == "crackerjack-architect":
|
|
141
|
+
consultation.update(
|
|
142
|
+
await self._consult_crackerjack_architect(issue, context)
|
|
143
|
+
)
|
|
144
|
+
elif agent_name == "python-pro":
|
|
145
|
+
consultation.update(await self._consult_python_pro(issue, context))
|
|
146
|
+
elif agent_name == "security-auditor":
|
|
147
|
+
consultation.update(await self._consult_security_auditor(issue, context))
|
|
148
|
+
elif agent_name == "refactoring-specialist":
|
|
149
|
+
consultation.update(
|
|
150
|
+
await self._consult_refactoring_specialist(issue, context)
|
|
151
|
+
)
|
|
152
|
+
elif agent_name == "crackerjack-test-specialist":
|
|
153
|
+
consultation.update(await self._consult_test_specialist(issue, context))
|
|
154
|
+
else:
|
|
155
|
+
consultation.update(
|
|
156
|
+
await self._consult_generic_agent(issue, agent_name, context)
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
return consultation
|
|
160
|
+
|
|
161
|
+
async def _consult_crackerjack_architect(
|
|
162
|
+
self, issue: Issue, context: dict[str, t.Any] | None = None
|
|
163
|
+
) -> dict[str, t.Any]:
|
|
164
|
+
"""Consult with crackerjack-architect for architectural guidance."""
|
|
165
|
+
return {
|
|
166
|
+
"recommendations": [
|
|
167
|
+
"Apply clean code principles (DRY, YAGNI, KISS)",
|
|
168
|
+
"Follow crackerjack's modular architecture patterns",
|
|
169
|
+
"Use protocol-based dependency injection",
|
|
170
|
+
"Break complex functions into focused helper methods",
|
|
171
|
+
"Maintain single responsibility principle",
|
|
172
|
+
],
|
|
173
|
+
"patterns": [
|
|
174
|
+
"extract_method",
|
|
175
|
+
"dependency_injection",
|
|
176
|
+
"protocol_interfaces",
|
|
177
|
+
"helper_methods",
|
|
178
|
+
"single_responsibility",
|
|
179
|
+
],
|
|
180
|
+
"validation_steps": [
|
|
181
|
+
"run_complexity_check",
|
|
182
|
+
"verify_type_annotations",
|
|
183
|
+
"check_architectural_consistency",
|
|
184
|
+
"validate_against_crackerjack_patterns",
|
|
185
|
+
],
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
async def _consult_python_pro(
|
|
189
|
+
self, issue: Issue, context: dict[str, t.Any] | None = None
|
|
190
|
+
) -> dict[str, t.Any]:
|
|
191
|
+
"""Consult with python-pro for Python-specific best practices."""
|
|
192
|
+
return {
|
|
193
|
+
"recommendations": [
|
|
194
|
+
"Use modern Python 3.13+ type hints with | unions",
|
|
195
|
+
"Apply proper error handling patterns",
|
|
196
|
+
"Follow PEP 8 style guidelines",
|
|
197
|
+
"Use pathlib over os.path",
|
|
198
|
+
"Implement proper context managers",
|
|
199
|
+
],
|
|
200
|
+
"patterns": [
|
|
201
|
+
"type_annotations",
|
|
202
|
+
"context_managers",
|
|
203
|
+
"exception_handling",
|
|
204
|
+
"python_idioms",
|
|
205
|
+
"modern_syntax",
|
|
206
|
+
],
|
|
207
|
+
"validation_steps": [
|
|
208
|
+
"run_type_checking",
|
|
209
|
+
"verify_python_compatibility",
|
|
210
|
+
"check_style_compliance",
|
|
211
|
+
"validate_error_handling",
|
|
212
|
+
],
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
async def _consult_security_auditor(
|
|
216
|
+
self, issue: Issue, context: dict[str, t.Any] | None = None
|
|
217
|
+
) -> dict[str, t.Any]:
|
|
218
|
+
"""Consult with security-auditor for security best practices."""
|
|
219
|
+
return {
|
|
220
|
+
"recommendations": [
|
|
221
|
+
"Never use hardcoded paths or credentials",
|
|
222
|
+
"Use secure temp file creation",
|
|
223
|
+
"Avoid shell=True in subprocess calls",
|
|
224
|
+
"Implement proper input validation",
|
|
225
|
+
"Use environment variables for sensitive data",
|
|
226
|
+
],
|
|
227
|
+
"patterns": [
|
|
228
|
+
"secure_temp_files",
|
|
229
|
+
"input_validation",
|
|
230
|
+
"safe_subprocess",
|
|
231
|
+
"environment_variables",
|
|
232
|
+
"sanitization",
|
|
233
|
+
],
|
|
234
|
+
"validation_steps": [
|
|
235
|
+
"run_security_scan",
|
|
236
|
+
"check_for_hardcoded_secrets",
|
|
237
|
+
"validate_subprocess_calls",
|
|
238
|
+
"verify_temp_file_handling",
|
|
239
|
+
],
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
async def _consult_refactoring_specialist(
|
|
243
|
+
self, issue: Issue, context: dict[str, t.Any] | None = None
|
|
244
|
+
) -> dict[str, t.Any]:
|
|
245
|
+
"""Consult with refactoring-specialist for code improvement."""
|
|
246
|
+
return {
|
|
247
|
+
"recommendations": [
|
|
248
|
+
"Break down complex functions (complexity ≤ 15)",
|
|
249
|
+
"Extract common patterns into utilities",
|
|
250
|
+
"Remove dead code and unused imports",
|
|
251
|
+
"Apply DRY principle to eliminate duplication",
|
|
252
|
+
"Use composition over inheritance",
|
|
253
|
+
],
|
|
254
|
+
"patterns": [
|
|
255
|
+
"extract_method",
|
|
256
|
+
"eliminate_duplication",
|
|
257
|
+
"dead_code_removal",
|
|
258
|
+
"complexity_reduction",
|
|
259
|
+
"composition_pattern",
|
|
260
|
+
],
|
|
261
|
+
"validation_steps": [
|
|
262
|
+
"measure_complexity_reduction",
|
|
263
|
+
"verify_test_coverage_maintained",
|
|
264
|
+
"check_for_dead_code",
|
|
265
|
+
"validate_duplication_removal",
|
|
266
|
+
],
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
async def _consult_test_specialist(
|
|
270
|
+
self, issue: Issue, context: dict[str, t.Any] | None = None
|
|
271
|
+
) -> dict[str, t.Any]:
|
|
272
|
+
"""Consult with crackerjack-test-specialist for testing guidance."""
|
|
273
|
+
return {
|
|
274
|
+
"recommendations": [
|
|
275
|
+
"Avoid complex async tests that can hang",
|
|
276
|
+
"Use synchronous config tests for reliability",
|
|
277
|
+
"Mock external dependencies properly",
|
|
278
|
+
"Follow crackerjack's testing patterns",
|
|
279
|
+
"Maintain test coverage ratchet",
|
|
280
|
+
],
|
|
281
|
+
"patterns": [
|
|
282
|
+
"synchronous_tests",
|
|
283
|
+
"proper_mocking",
|
|
284
|
+
"test_organization",
|
|
285
|
+
"coverage_improvement",
|
|
286
|
+
"fixture_patterns",
|
|
287
|
+
],
|
|
288
|
+
"validation_steps": [
|
|
289
|
+
"run_test_suite",
|
|
290
|
+
"verify_coverage_increase",
|
|
291
|
+
"check_test_reliability",
|
|
292
|
+
"validate_mock_usage",
|
|
293
|
+
],
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
async def _consult_generic_agent(
|
|
297
|
+
self, issue: Issue, agent_name: str, context: dict[str, t.Any] | None = None
|
|
298
|
+
) -> dict[str, t.Any]:
|
|
299
|
+
"""Generic consultation for unspecified agents."""
|
|
300
|
+
return {
|
|
301
|
+
"recommendations": [
|
|
302
|
+
f"Consult {agent_name} documentation for specific guidance",
|
|
303
|
+
"Apply domain-specific best practices",
|
|
304
|
+
"Follow established patterns and conventions",
|
|
305
|
+
],
|
|
306
|
+
"patterns": ["domain_specific_patterns"],
|
|
307
|
+
"validation_steps": ["validate_domain_requirements"],
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
async def _ensure_ai_fixer(self) -> t.Any:
|
|
311
|
+
"""Lazy initialization of AI fixer adapter.
|
|
312
|
+
|
|
313
|
+
Returns:
|
|
314
|
+
Initialized ClaudeCodeFixer instance
|
|
315
|
+
|
|
316
|
+
Raises:
|
|
317
|
+
RuntimeError: If Claude AI is not available or initialization fails
|
|
318
|
+
"""
|
|
319
|
+
if not self._ai_available:
|
|
320
|
+
raise RuntimeError(
|
|
321
|
+
"Claude AI adapter not available - install ACB with 'uv add acb[ai]'"
|
|
322
|
+
)
|
|
323
|
+
|
|
324
|
+
if self.ai_fixer is None:
|
|
325
|
+
if ClaudeCodeFixer is None:
|
|
326
|
+
raise RuntimeError("ClaudeCodeFixer import failed")
|
|
327
|
+
|
|
328
|
+
self.ai_fixer = ClaudeCodeFixer()
|
|
329
|
+
await self.ai_fixer.init()
|
|
330
|
+
self.logger.debug("Claude AI fixer initialized")
|
|
331
|
+
|
|
332
|
+
return self.ai_fixer
|
|
333
|
+
|
|
334
|
+
def _extract_ai_response_fields(
|
|
335
|
+
self, ai_result: dict[str, t.Any]
|
|
336
|
+
) -> tuple[str, str, float, list[str], list[str]]:
|
|
337
|
+
"""Extract fields from AI result."""
|
|
338
|
+
fixed_code = str(ai_result.get("fixed_code", ""))
|
|
339
|
+
explanation = str(ai_result.get("explanation", "No explanation"))
|
|
340
|
+
confidence = float(ai_result.get("confidence", 0.0))
|
|
341
|
+
changes_made = ai_result.get("changes_made", [])
|
|
342
|
+
potential_side_effects = ai_result.get("potential_side_effects", [])
|
|
343
|
+
|
|
344
|
+
return fixed_code, explanation, confidence, changes_made, potential_side_effects
|
|
345
|
+
|
|
346
|
+
async def _apply_fix_to_file(
|
|
347
|
+
self, file_path: str, fixed_code: str, dry_run: bool
|
|
348
|
+
) -> dict[str, t.Any]:
|
|
349
|
+
"""Apply the fix to the file using SafeFileModifier."""
|
|
350
|
+
modify_result = await self.file_modifier.apply_fix(
|
|
351
|
+
file_path=file_path,
|
|
352
|
+
fixed_content=fixed_code,
|
|
353
|
+
dry_run=dry_run,
|
|
354
|
+
create_backup=True,
|
|
355
|
+
)
|
|
356
|
+
return modify_result
|
|
357
|
+
|
|
358
|
+
def _handle_successful_ai_fix(
|
|
359
|
+
self,
|
|
360
|
+
issue: Issue,
|
|
361
|
+
file_path: str,
|
|
362
|
+
confidence: float,
|
|
363
|
+
changes_made: list[str],
|
|
364
|
+
potential_side_effects: list[str],
|
|
365
|
+
fix_type: str,
|
|
366
|
+
) -> FixResult:
|
|
367
|
+
"""Handle the case when the AI successfully fixes the issue."""
|
|
368
|
+
self.logger.info(
|
|
369
|
+
f"Successfully applied AI fix to {file_path} (confidence: {confidence:.2f})"
|
|
370
|
+
)
|
|
371
|
+
|
|
372
|
+
return FixResult(
|
|
373
|
+
success=True,
|
|
374
|
+
confidence=confidence,
|
|
375
|
+
fixes_applied=[f"Fixed {fix_type} in {file_path}"],
|
|
376
|
+
remaining_issues=[],
|
|
377
|
+
recommendations=[
|
|
378
|
+
issue.message,
|
|
379
|
+
*[f"Change: {change}" for change in changes_made],
|
|
380
|
+
*[
|
|
381
|
+
f"Potential side effect: {effect}"
|
|
382
|
+
for effect in potential_side_effects
|
|
383
|
+
],
|
|
384
|
+
],
|
|
385
|
+
files_modified=[file_path],
|
|
386
|
+
)
|
|
387
|
+
|
|
388
|
+
def _handle_dry_run_response(
|
|
389
|
+
self, confidence: float, changes_made: list[str], issue: Issue
|
|
390
|
+
) -> FixResult:
|
|
391
|
+
"""Handle the case for dry-run mode."""
|
|
392
|
+
return FixResult(
|
|
393
|
+
success=True,
|
|
394
|
+
confidence=confidence,
|
|
395
|
+
fixes_applied=[],
|
|
396
|
+
remaining_issues=[issue.id],
|
|
397
|
+
recommendations=[
|
|
398
|
+
f"AI suggests (dry-run): {issue.message}",
|
|
399
|
+
*[f"Change: {change}" for change in changes_made],
|
|
400
|
+
],
|
|
401
|
+
files_modified=[],
|
|
402
|
+
)
|
|
403
|
+
|
|
404
|
+
def _handle_error_response(self, error_msg: str, issue: Issue) -> FixResult:
|
|
405
|
+
"""Handle the case when there's an error in AI fix."""
|
|
406
|
+
self.logger.error(f"AI fix failed: {error_msg}")
|
|
407
|
+
|
|
408
|
+
return FixResult(
|
|
409
|
+
success=False,
|
|
410
|
+
confidence=0.0,
|
|
411
|
+
fixes_applied=[],
|
|
412
|
+
remaining_issues=[issue.id],
|
|
413
|
+
recommendations=[f"AI fix failed: {error_msg}"],
|
|
414
|
+
files_modified=[],
|
|
415
|
+
)
|
|
416
|
+
|
|
417
|
+
def _handle_low_confidence_response(
|
|
418
|
+
self, confidence: float, explanation: str, issue: Issue
|
|
419
|
+
) -> FixResult:
|
|
420
|
+
"""Handle the case when confidence is too low."""
|
|
421
|
+
min_confidence = 0.7 # Match AI fixer's default
|
|
422
|
+
self.logger.warning(
|
|
423
|
+
f"AI confidence {confidence:.2f} below threshold {min_confidence}"
|
|
424
|
+
)
|
|
425
|
+
|
|
426
|
+
return FixResult(
|
|
427
|
+
success=False,
|
|
428
|
+
confidence=confidence,
|
|
429
|
+
fixes_applied=[],
|
|
430
|
+
remaining_issues=[issue.id],
|
|
431
|
+
recommendations=[
|
|
432
|
+
f"AI fix confidence {confidence:.2f} too low (threshold: {min_confidence})",
|
|
433
|
+
explanation,
|
|
434
|
+
],
|
|
435
|
+
files_modified=[],
|
|
436
|
+
)
|
|
437
|
+
|
|
438
|
+
async def _validate_ai_result(
|
|
439
|
+
self, ai_result: dict[str, t.Any], issue: Issue
|
|
440
|
+
) -> tuple[str, str, float, list[str], list[str]] | None:
|
|
441
|
+
"""Validate AI result and extract fields.
|
|
442
|
+
|
|
443
|
+
Returns:
|
|
444
|
+
Tuple of (fixed_code, explanation, confidence, changes_made, side_effects)
|
|
445
|
+
or None if validation failed (already returned FixResult)
|
|
446
|
+
"""
|
|
447
|
+
# Check if AI fix was successful
|
|
448
|
+
if not ai_result.get("success"):
|
|
449
|
+
ai_result.get("error", "Unknown AI error")
|
|
450
|
+
return None
|
|
451
|
+
|
|
452
|
+
# Extract AI response fields
|
|
453
|
+
(
|
|
454
|
+
fixed_code,
|
|
455
|
+
explanation,
|
|
456
|
+
confidence,
|
|
457
|
+
changes_made,
|
|
458
|
+
potential_side_effects,
|
|
459
|
+
) = self._extract_ai_response_fields(ai_result)
|
|
460
|
+
|
|
461
|
+
# Validate confidence threshold
|
|
462
|
+
min_confidence = 0.7 # Match AI fixer's default
|
|
463
|
+
if confidence < min_confidence:
|
|
464
|
+
return None
|
|
465
|
+
|
|
466
|
+
return (
|
|
467
|
+
fixed_code,
|
|
468
|
+
explanation,
|
|
469
|
+
confidence,
|
|
470
|
+
changes_made,
|
|
471
|
+
potential_side_effects,
|
|
472
|
+
)
|
|
473
|
+
|
|
474
|
+
async def _apply_ai_fix(
|
|
475
|
+
self,
|
|
476
|
+
file_path: str,
|
|
477
|
+
fixed_code: str,
|
|
478
|
+
confidence: float,
|
|
479
|
+
changes_made: list[str],
|
|
480
|
+
potential_side_effects: list[str],
|
|
481
|
+
fix_type: str,
|
|
482
|
+
issue: Issue,
|
|
483
|
+
dry_run: bool,
|
|
484
|
+
) -> FixResult:
|
|
485
|
+
"""Apply AI fix to file using SafeFileModifier."""
|
|
486
|
+
modify_result = await self._apply_fix_to_file(file_path, fixed_code, dry_run)
|
|
487
|
+
|
|
488
|
+
if not modify_result.get("success"):
|
|
489
|
+
error_msg = modify_result.get("error", "Unknown modification error")
|
|
490
|
+
self.logger.error(f"File modification failed: {error_msg}")
|
|
491
|
+
|
|
492
|
+
return FixResult(
|
|
493
|
+
success=False,
|
|
494
|
+
confidence=confidence,
|
|
495
|
+
fixes_applied=[],
|
|
496
|
+
remaining_issues=[issue.id],
|
|
497
|
+
recommendations=[
|
|
498
|
+
f"File modification failed: {error_msg}",
|
|
499
|
+
"",
|
|
500
|
+
],
|
|
501
|
+
files_modified=[],
|
|
502
|
+
)
|
|
503
|
+
|
|
504
|
+
# Success - fix applied
|
|
505
|
+
return self._handle_successful_ai_fix(
|
|
506
|
+
issue,
|
|
507
|
+
file_path,
|
|
508
|
+
confidence,
|
|
509
|
+
changes_made,
|
|
510
|
+
potential_side_effects,
|
|
511
|
+
fix_type,
|
|
512
|
+
)
|
|
513
|
+
|
|
514
|
+
async def consult_on_issue(
|
|
515
|
+
self,
|
|
516
|
+
issue: Issue,
|
|
517
|
+
dry_run: bool = False,
|
|
518
|
+
) -> FixResult:
|
|
519
|
+
"""Consult with Claude AI to fix an issue using real AI integration.
|
|
520
|
+
|
|
521
|
+
This method replaces the simulation-based approach with real AI-powered
|
|
522
|
+
code fixing. It:
|
|
523
|
+
1. Calls the ClaudeCodeFixer adapter to generate a fix
|
|
524
|
+
2. Validates the AI response (confidence, success)
|
|
525
|
+
3. Uses SafeFileModifier to safely apply changes
|
|
526
|
+
4. Handles errors gracefully
|
|
527
|
+
5. Returns a proper FixResult
|
|
528
|
+
|
|
529
|
+
Args:
|
|
530
|
+
issue: Issue to fix
|
|
531
|
+
dry_run: If True, only generate fix without applying
|
|
532
|
+
|
|
533
|
+
Returns:
|
|
534
|
+
FixResult with fix details and success status
|
|
535
|
+
"""
|
|
536
|
+
try:
|
|
537
|
+
# Initialize AI fixer if needed
|
|
538
|
+
fixer = await self._ensure_ai_fixer()
|
|
539
|
+
|
|
540
|
+
# Extract issue details for AI context
|
|
541
|
+
file_path = str(issue.file_path) if issue.file_path else "unknown"
|
|
542
|
+
issue_description = issue.message # Issue uses 'message' not 'description'
|
|
543
|
+
code_snippet = "\n".join(issue.details) if issue.details else ""
|
|
544
|
+
fix_type = issue.type.value
|
|
545
|
+
|
|
546
|
+
self.logger.info(
|
|
547
|
+
f"Consulting Claude AI for {fix_type} issue in {file_path}"
|
|
548
|
+
)
|
|
549
|
+
|
|
550
|
+
# Call AI fixer to generate code fix
|
|
551
|
+
ai_result = await fixer.fix_code_issue(
|
|
552
|
+
file_path=file_path,
|
|
553
|
+
issue_description=issue_description,
|
|
554
|
+
code_context=code_snippet,
|
|
555
|
+
fix_type=fix_type,
|
|
556
|
+
)
|
|
557
|
+
|
|
558
|
+
# Validate AI result
|
|
559
|
+
validation_result = await self._validate_ai_result(ai_result, issue)
|
|
560
|
+
if validation_result is None:
|
|
561
|
+
# Validation failed - extract error from ai_result
|
|
562
|
+
if not ai_result.get("success"):
|
|
563
|
+
error_msg = ai_result.get("error", "Unknown AI error")
|
|
564
|
+
return self._handle_error_response(error_msg, issue)
|
|
565
|
+
else:
|
|
566
|
+
# Low confidence
|
|
567
|
+
_, explanation, confidence, *_ = self._extract_ai_response_fields(
|
|
568
|
+
ai_result
|
|
569
|
+
)
|
|
570
|
+
return self._handle_low_confidence_response(
|
|
571
|
+
confidence, explanation, issue
|
|
572
|
+
)
|
|
573
|
+
|
|
574
|
+
(
|
|
575
|
+
fixed_code,
|
|
576
|
+
explanation,
|
|
577
|
+
confidence,
|
|
578
|
+
changes_made,
|
|
579
|
+
potential_side_effects,
|
|
580
|
+
) = validation_result
|
|
581
|
+
|
|
582
|
+
# Apply fix using SafeFileModifier
|
|
583
|
+
if not dry_run and fixed_code:
|
|
584
|
+
return await self._apply_ai_fix(
|
|
585
|
+
file_path,
|
|
586
|
+
fixed_code,
|
|
587
|
+
confidence,
|
|
588
|
+
changes_made,
|
|
589
|
+
potential_side_effects,
|
|
590
|
+
fix_type,
|
|
591
|
+
issue,
|
|
592
|
+
dry_run,
|
|
593
|
+
)
|
|
594
|
+
else:
|
|
595
|
+
# Dry-run mode or no code - just report recommendation
|
|
596
|
+
return self._handle_dry_run_response(confidence, changes_made, issue)
|
|
597
|
+
|
|
598
|
+
except Exception as e:
|
|
599
|
+
self.logger.exception(f"Unexpected error in consult_on_issue: {e}")
|
|
600
|
+
|
|
601
|
+
return FixResult(
|
|
602
|
+
success=False,
|
|
603
|
+
confidence=0.0,
|
|
604
|
+
fixes_applied=[],
|
|
605
|
+
remaining_issues=[issue.id],
|
|
606
|
+
recommendations=[f"Unexpected error: {e}"],
|
|
607
|
+
files_modified=[],
|
|
608
|
+
)
|
|
609
|
+
|
|
610
|
+
def create_enhanced_fix_result(
|
|
611
|
+
self, base_result: FixResult, consultations: list[dict[str, t.Any]]
|
|
612
|
+
) -> FixResult:
|
|
613
|
+
"""Enhance a FixResult with external agent consultations."""
|
|
614
|
+
enhanced_result = FixResult(
|
|
615
|
+
success=base_result.success,
|
|
616
|
+
confidence=base_result.confidence,
|
|
617
|
+
fixes_applied=base_result.fixes_applied.copy(),
|
|
618
|
+
remaining_issues=base_result.remaining_issues.copy(),
|
|
619
|
+
recommendations=base_result.recommendations.copy(),
|
|
620
|
+
files_modified=base_result.files_modified.copy(),
|
|
621
|
+
)
|
|
622
|
+
|
|
623
|
+
# Aggregate recommendations from all consultations
|
|
624
|
+
for consultation in consultations:
|
|
625
|
+
if consultation.get("status") == "success":
|
|
626
|
+
agent_name = consultation.get("agent", "unknown")
|
|
627
|
+
enhanced_result.recommendations.extend(
|
|
628
|
+
[
|
|
629
|
+
f"[{agent_name}] {rec}"
|
|
630
|
+
for rec in consultation.get("recommendations", [])
|
|
631
|
+
]
|
|
632
|
+
)
|
|
633
|
+
|
|
634
|
+
# Boost confidence if external agents provided guidance
|
|
635
|
+
external_confidence = consultation.get("confidence", 0.0)
|
|
636
|
+
enhanced_result.confidence = max(
|
|
637
|
+
enhanced_result.confidence,
|
|
638
|
+
(enhanced_result.confidence + external_confidence) / 2,
|
|
639
|
+
)
|
|
640
|
+
|
|
641
|
+
return enhanced_result
|