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,185 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Enhanced proactive agent that integrates Claude Code external agent consultation.
|
|
3
|
+
|
|
4
|
+
This module extends the base ProactiveAgent to consult with Claude Code's external
|
|
5
|
+
agents (like crackerjack-architect, python-pro, security-auditor) when handling
|
|
6
|
+
complex issues that require specialized expertise.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import typing as t
|
|
10
|
+
from abc import abstractmethod
|
|
11
|
+
|
|
12
|
+
from .base import AgentContext, FixResult, Issue
|
|
13
|
+
from .claude_code_bridge import ClaudeCodeBridge
|
|
14
|
+
from .proactive_agent import ProactiveAgent
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class EnhancedProactiveAgent(ProactiveAgent):
|
|
18
|
+
"""
|
|
19
|
+
Proactive agent enhanced with Claude Code external agent consultation.
|
|
20
|
+
|
|
21
|
+
This agent follows the standard crackerjack agent pattern but adds intelligent
|
|
22
|
+
consultation with external Claude Code agents for complex scenarios that
|
|
23
|
+
require specialized expertise.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
def __init__(self, context: AgentContext) -> None:
|
|
27
|
+
super().__init__(context)
|
|
28
|
+
self.claude_bridge = ClaudeCodeBridge(context)
|
|
29
|
+
self._external_consultation_enabled = True
|
|
30
|
+
|
|
31
|
+
def enable_external_consultation(self, enabled: bool = True) -> None:
|
|
32
|
+
"""Enable or disable external Claude Code agent consultation."""
|
|
33
|
+
self._external_consultation_enabled = enabled
|
|
34
|
+
|
|
35
|
+
async def _execute_with_plan(
|
|
36
|
+
self, issue: Issue, plan: dict[str, t.Any]
|
|
37
|
+
) -> FixResult:
|
|
38
|
+
"""
|
|
39
|
+
Execute fix with plan, consulting external agents when appropriate.
|
|
40
|
+
|
|
41
|
+
This method enhances the base implementation by:
|
|
42
|
+
1. First attempting the internal fix
|
|
43
|
+
2. Evaluating if external consultation would improve the result
|
|
44
|
+
3. Consulting with relevant Claude Code agents
|
|
45
|
+
4. Combining internal and external guidance for better results
|
|
46
|
+
"""
|
|
47
|
+
# First, get the internal fix result
|
|
48
|
+
internal_result = await self._execute_internal_fix(issue, plan)
|
|
49
|
+
|
|
50
|
+
# Determine if we should consult external agents
|
|
51
|
+
if not self._should_consult_external_agents(issue, internal_result, plan):
|
|
52
|
+
return internal_result
|
|
53
|
+
|
|
54
|
+
# Consult with relevant external agents
|
|
55
|
+
external_consultations = await self._consult_external_agents(issue, plan)
|
|
56
|
+
|
|
57
|
+
# Enhance the result with external guidance
|
|
58
|
+
enhanced_result = self._combine_internal_and_external_results(
|
|
59
|
+
internal_result, external_consultations
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
return enhanced_result
|
|
63
|
+
|
|
64
|
+
async def _execute_internal_fix(
|
|
65
|
+
self, issue: Issue, plan: dict[str, t.Any]
|
|
66
|
+
) -> FixResult:
|
|
67
|
+
"""Execute the internal fix using the built-in agent logic."""
|
|
68
|
+
# This calls the concrete agent's analyze_and_fix implementation
|
|
69
|
+
return await self.analyze_and_fix(issue)
|
|
70
|
+
|
|
71
|
+
def _should_consult_external_agents(
|
|
72
|
+
self, issue: Issue, internal_result: FixResult, plan: dict[str, t.Any]
|
|
73
|
+
) -> bool:
|
|
74
|
+
"""Determine if external consultation would be beneficial."""
|
|
75
|
+
if not self._external_consultation_enabled:
|
|
76
|
+
return False
|
|
77
|
+
|
|
78
|
+
# Consult external agents if:
|
|
79
|
+
# 1. Internal result has low confidence
|
|
80
|
+
# 2. Issue is complex and requires specialized expertise
|
|
81
|
+
# 3. Plan strategy indicates external specialist guidance
|
|
82
|
+
return (
|
|
83
|
+
self.claude_bridge.should_consult_external_agent(
|
|
84
|
+
issue, internal_result.confidence
|
|
85
|
+
)
|
|
86
|
+
or plan.get("strategy") == "external_specialist_guided"
|
|
87
|
+
or not internal_result.success
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
async def _consult_external_agents(
|
|
91
|
+
self, issue: Issue, plan: dict[str, t.Any]
|
|
92
|
+
) -> list[dict[str, t.Any]]:
|
|
93
|
+
"""Consult with relevant external Claude Code agents."""
|
|
94
|
+
recommended_agents = self.claude_bridge.get_recommended_external_agents(issue)
|
|
95
|
+
consultations = []
|
|
96
|
+
|
|
97
|
+
# Limit to top 2 agents to avoid overwhelming the system
|
|
98
|
+
for agent_name in recommended_agents[:2]:
|
|
99
|
+
if self.claude_bridge.verify_agent_availability(agent_name):
|
|
100
|
+
consultation = await self.claude_bridge.consult_external_agent(
|
|
101
|
+
issue, agent_name, {"plan": plan}
|
|
102
|
+
)
|
|
103
|
+
if consultation.get("status") == "success":
|
|
104
|
+
consultations.append(consultation)
|
|
105
|
+
|
|
106
|
+
return consultations
|
|
107
|
+
|
|
108
|
+
def _combine_internal_and_external_results(
|
|
109
|
+
self, internal_result: FixResult, external_consultations: list[dict[str, t.Any]]
|
|
110
|
+
) -> FixResult:
|
|
111
|
+
"""Combine internal fix result with external agent consultations."""
|
|
112
|
+
if not external_consultations:
|
|
113
|
+
return internal_result
|
|
114
|
+
|
|
115
|
+
# Use the bridge to create an enhanced result
|
|
116
|
+
enhanced_result = self.claude_bridge.create_enhanced_fix_result(
|
|
117
|
+
internal_result, external_consultations
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
# Add metadata about external consultation
|
|
121
|
+
enhanced_result.recommendations.insert(
|
|
122
|
+
0,
|
|
123
|
+
f"Enhanced with consultation from {len(external_consultations)} Claude Code agents",
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
return enhanced_result
|
|
127
|
+
|
|
128
|
+
async def plan_before_action(self, issue: Issue) -> dict[str, t.Any]:
|
|
129
|
+
"""
|
|
130
|
+
Create a plan that considers both internal and external capabilities.
|
|
131
|
+
|
|
132
|
+
This method should be implemented by concrete agents to define their
|
|
133
|
+
specific planning logic while having access to external consultation.
|
|
134
|
+
"""
|
|
135
|
+
# Default implementation - concrete agents should override this
|
|
136
|
+
if self.claude_bridge.should_consult_external_agent(issue, 0.0):
|
|
137
|
+
return {
|
|
138
|
+
"strategy": "external_specialist_guided",
|
|
139
|
+
"approach": "consult_claude_code_experts",
|
|
140
|
+
"patterns": ["external_guidance"],
|
|
141
|
+
"validation": ["verify_with_external_agents"],
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return {
|
|
145
|
+
"strategy": "internal_pattern_based",
|
|
146
|
+
"approach": "apply_internal_logic",
|
|
147
|
+
"patterns": ["standard_patterns"],
|
|
148
|
+
"validation": ["run_internal_checks"],
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
@abstractmethod
|
|
152
|
+
async def analyze_and_fix(self, issue: Issue) -> FixResult:
|
|
153
|
+
"""
|
|
154
|
+
Concrete agents must implement their specific fix logic.
|
|
155
|
+
|
|
156
|
+
This method contains the core agent-specific logic for analyzing
|
|
157
|
+
and fixing issues. The enhanced execution framework will automatically
|
|
158
|
+
handle external consultation when appropriate.
|
|
159
|
+
"""
|
|
160
|
+
pass
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
# Convenience function to enhance existing agents
|
|
164
|
+
def enhance_agent_with_claude_code_bridge(
|
|
165
|
+
agent_class: type[ProactiveAgent],
|
|
166
|
+
) -> type[EnhancedProactiveAgent]:
|
|
167
|
+
"""
|
|
168
|
+
Enhance an existing ProactiveAgent class with Claude Code external consultation.
|
|
169
|
+
|
|
170
|
+
This function creates a new class that inherits from both the original agent
|
|
171
|
+
and EnhancedProactiveAgent, providing external consultation capabilities
|
|
172
|
+
while preserving the original agent's logic.
|
|
173
|
+
"""
|
|
174
|
+
|
|
175
|
+
class EnhancedAgent(EnhancedProactiveAgent, agent_class): # type: ignore[misc,valid-type]
|
|
176
|
+
def __init__(self, context: AgentContext) -> None:
|
|
177
|
+
# Initialize both parent classes
|
|
178
|
+
EnhancedProactiveAgent.__init__(self, context)
|
|
179
|
+
agent_class.__init__(self, context)
|
|
180
|
+
|
|
181
|
+
# Preserve the original class name and metadata
|
|
182
|
+
EnhancedAgent.__name__ = f"Enhanced{agent_class.__name__}"
|
|
183
|
+
EnhancedAgent.__qualname__ = f"Enhanced{agent_class.__qualname__}"
|
|
184
|
+
|
|
185
|
+
return EnhancedAgent
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""Shared error-handling middleware helpers for agents."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import typing as t
|
|
6
|
+
from functools import wraps
|
|
7
|
+
|
|
8
|
+
from acb.console import Console
|
|
9
|
+
|
|
10
|
+
from crackerjack.agents.base import FixResult, Issue, SubAgent
|
|
11
|
+
|
|
12
|
+
if t.TYPE_CHECKING: # pragma: no cover - typing helpers
|
|
13
|
+
from crackerjack.agents.coordinator import AgentCoordinator
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def agent_error_boundary(
|
|
17
|
+
func: t.Callable[..., t.Awaitable[FixResult]],
|
|
18
|
+
) -> t.Callable[..., t.Awaitable[FixResult]]:
|
|
19
|
+
"""Decorator that centralizes error handling for agent execution.
|
|
20
|
+
|
|
21
|
+
Ensures all agent failures are logged consistently and converted into a
|
|
22
|
+
``FixResult`` that upstream orchestrators can reason about without custom
|
|
23
|
+
``try``/``except`` blocks.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
@wraps(func)
|
|
27
|
+
async def wrapper(
|
|
28
|
+
self: AgentCoordinator,
|
|
29
|
+
agent: SubAgent,
|
|
30
|
+
issue: Issue,
|
|
31
|
+
*args: t.Any,
|
|
32
|
+
**kwargs: t.Any,
|
|
33
|
+
) -> FixResult:
|
|
34
|
+
try:
|
|
35
|
+
return await func(self, agent, issue, *args, **kwargs)
|
|
36
|
+
except Exception as exc: # pragma: no cover - exercised via decorator tests
|
|
37
|
+
console: Console | None = getattr(self.context, "console", None)
|
|
38
|
+
message = f"{agent.name} encountered an error while processing issue {issue.id}: {exc}"
|
|
39
|
+
self.logger.exception(message, exc_info=exc)
|
|
40
|
+
if console is not None:
|
|
41
|
+
console.print(f"[red]{message}[/red]")
|
|
42
|
+
|
|
43
|
+
return FixResult(
|
|
44
|
+
success=False,
|
|
45
|
+
confidence=0.0,
|
|
46
|
+
remaining_issues=[message],
|
|
47
|
+
recommendations=[
|
|
48
|
+
"Review agent logs for stack trace",
|
|
49
|
+
"Re-run with --debug to capture additional context",
|
|
50
|
+
],
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
return wrapper
|
|
@@ -134,10 +134,9 @@ class FormattingAgent(SubAgent):
|
|
|
134
134
|
[
|
|
135
135
|
"uv",
|
|
136
136
|
"run",
|
|
137
|
-
"
|
|
138
|
-
"
|
|
139
|
-
"
|
|
140
|
-
"--all-files",
|
|
137
|
+
"python",
|
|
138
|
+
"-m",
|
|
139
|
+
"crackerjack.tools.trailing_whitespace",
|
|
141
140
|
],
|
|
142
141
|
)
|
|
143
142
|
|
|
@@ -149,10 +148,9 @@ class FormattingAgent(SubAgent):
|
|
|
149
148
|
[
|
|
150
149
|
"uv",
|
|
151
150
|
"run",
|
|
152
|
-
"
|
|
153
|
-
"
|
|
154
|
-
"
|
|
155
|
-
"--all-files",
|
|
151
|
+
"python",
|
|
152
|
+
"-m",
|
|
153
|
+
"crackerjack.tools.end_of_file_fixer",
|
|
156
154
|
],
|
|
157
155
|
)
|
|
158
156
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""Package for helper modules used by crackerjack agents.
|
|
2
|
+
|
|
3
|
+
This package contains supporting modules for various agent types:
|
|
4
|
+
- performance: Performance analysis and optimization helpers
|
|
5
|
+
- refactoring: Code refactoring utilities
|
|
6
|
+
- test_creation: Test generation helpers
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
# This file makes the directory a proper Python package
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""Performance optimization helpers for the PerformanceAgent.
|
|
2
|
+
|
|
3
|
+
This module provides specialized helpers for detecting and fixing performance
|
|
4
|
+
anti-patterns while maintaining the AgentContext pattern.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from .performance_ast_analyzer import PerformanceASTAnalyzer
|
|
8
|
+
from .performance_pattern_detector import (
|
|
9
|
+
ListOpAnalyzer,
|
|
10
|
+
NestedLoopAnalyzer,
|
|
11
|
+
PerformancePatternDetector,
|
|
12
|
+
)
|
|
13
|
+
from .performance_recommender import OptimizationResult, PerformanceRecommender
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
"PerformancePatternDetector",
|
|
17
|
+
"PerformanceASTAnalyzer",
|
|
18
|
+
"PerformanceRecommender",
|
|
19
|
+
"OptimizationResult",
|
|
20
|
+
"NestedLoopAnalyzer",
|
|
21
|
+
"ListOpAnalyzer",
|
|
22
|
+
]
|
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
"""AST analysis for performance complexity detection."""
|
|
2
|
+
|
|
3
|
+
import ast
|
|
4
|
+
import typing as t
|
|
5
|
+
|
|
6
|
+
from ...base import AgentContext
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class PerformanceASTAnalyzer:
|
|
10
|
+
"""Analyzes Python AST for performance-related complexity issues."""
|
|
11
|
+
|
|
12
|
+
def __init__(self, context: AgentContext) -> None:
|
|
13
|
+
"""Initialize analyzer with agent context.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
context: AgentContext for logging and operations
|
|
17
|
+
"""
|
|
18
|
+
self.context = context
|
|
19
|
+
|
|
20
|
+
def extract_performance_critical_functions(
|
|
21
|
+
self, content: str
|
|
22
|
+
) -> list[dict[str, t.Any]]:
|
|
23
|
+
"""Extract functions likely to have performance issues.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
content: File content
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
List of performance-critical functions
|
|
30
|
+
"""
|
|
31
|
+
functions: list[dict[str, t.Any]] = []
|
|
32
|
+
lines = content.split("\n")
|
|
33
|
+
current_function = None
|
|
34
|
+
|
|
35
|
+
for i, line in enumerate(lines):
|
|
36
|
+
stripped = line.strip()
|
|
37
|
+
|
|
38
|
+
if self._is_empty_or_comment_line(stripped):
|
|
39
|
+
if current_function:
|
|
40
|
+
current_function["body"] += line + "\n"
|
|
41
|
+
continue
|
|
42
|
+
|
|
43
|
+
indent = len(line) - len(line.lstrip())
|
|
44
|
+
|
|
45
|
+
if self._is_function_definition(stripped):
|
|
46
|
+
current_function = self._handle_function_definition(
|
|
47
|
+
current_function, functions, stripped, indent, i
|
|
48
|
+
)
|
|
49
|
+
elif current_function:
|
|
50
|
+
current_function = self._handle_function_body_line(
|
|
51
|
+
current_function, functions, line, stripped, indent, i
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
self._handle_last_function(current_function, functions, len(lines))
|
|
55
|
+
return functions
|
|
56
|
+
|
|
57
|
+
@staticmethod
|
|
58
|
+
def _is_empty_or_comment_line(stripped: str) -> bool:
|
|
59
|
+
"""Check if line is empty or comment.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
stripped: Stripped line
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
True if empty or comment
|
|
66
|
+
"""
|
|
67
|
+
return not stripped or stripped.startswith("#")
|
|
68
|
+
|
|
69
|
+
@staticmethod
|
|
70
|
+
def _is_function_definition(stripped: str) -> bool:
|
|
71
|
+
"""Check if line is function definition.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
stripped: Stripped line
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
True if function definition
|
|
78
|
+
"""
|
|
79
|
+
return stripped.startswith("def ") and "(" in stripped
|
|
80
|
+
|
|
81
|
+
def _handle_function_definition(
|
|
82
|
+
self,
|
|
83
|
+
current_function: dict[str, t.Any] | None,
|
|
84
|
+
functions: list[dict[str, t.Any]],
|
|
85
|
+
stripped: str,
|
|
86
|
+
indent: int,
|
|
87
|
+
line_number: int,
|
|
88
|
+
) -> dict[str, t.Any]:
|
|
89
|
+
"""Handle function definition line.
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
current_function: Current function being parsed
|
|
93
|
+
functions: List of functions
|
|
94
|
+
stripped: Stripped line
|
|
95
|
+
indent: Indentation level
|
|
96
|
+
line_number: Line number
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
New function dict
|
|
100
|
+
"""
|
|
101
|
+
if current_function and self._is_performance_critical(current_function):
|
|
102
|
+
self._finalize_function(current_function, functions, line_number)
|
|
103
|
+
|
|
104
|
+
func_name = stripped.split("(")[0].replace("def ", "").strip()
|
|
105
|
+
return {
|
|
106
|
+
"name": func_name,
|
|
107
|
+
"signature": stripped,
|
|
108
|
+
"start_line": line_number + 1,
|
|
109
|
+
"body": "",
|
|
110
|
+
"indent_level": indent,
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
def _handle_function_body_line(
|
|
114
|
+
self,
|
|
115
|
+
current_function: dict[str, t.Any],
|
|
116
|
+
functions: list[dict[str, t.Any]],
|
|
117
|
+
line: str,
|
|
118
|
+
stripped: str,
|
|
119
|
+
indent: int,
|
|
120
|
+
line_number: int,
|
|
121
|
+
) -> dict[str, t.Any] | None:
|
|
122
|
+
"""Handle line within function body.
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
current_function: Current function
|
|
126
|
+
functions: Functions list
|
|
127
|
+
line: Full line
|
|
128
|
+
stripped: Stripped line
|
|
129
|
+
indent: Indent level
|
|
130
|
+
line_number: Line number
|
|
131
|
+
|
|
132
|
+
Returns:
|
|
133
|
+
Updated current function or None
|
|
134
|
+
"""
|
|
135
|
+
if self._is_still_in_function(current_function, indent, stripped):
|
|
136
|
+
current_function["body"] += line + "\n"
|
|
137
|
+
return current_function
|
|
138
|
+
else:
|
|
139
|
+
if self._is_performance_critical(current_function):
|
|
140
|
+
self._finalize_function(current_function, functions, line_number)
|
|
141
|
+
return None
|
|
142
|
+
|
|
143
|
+
@staticmethod
|
|
144
|
+
def _is_still_in_function(
|
|
145
|
+
current_function: dict[str, t.Any], indent: int, stripped: str
|
|
146
|
+
) -> bool:
|
|
147
|
+
"""Check if still inside function.
|
|
148
|
+
|
|
149
|
+
Args:
|
|
150
|
+
current_function: Current function
|
|
151
|
+
indent: Indent level
|
|
152
|
+
stripped: Stripped line
|
|
153
|
+
|
|
154
|
+
Returns:
|
|
155
|
+
True if still inside
|
|
156
|
+
"""
|
|
157
|
+
return indent > current_function["indent_level"] or (
|
|
158
|
+
indent == current_function["indent_level"]
|
|
159
|
+
and stripped.startswith(('"', "'", "@"))
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
def _finalize_function(
|
|
163
|
+
self,
|
|
164
|
+
function: dict[str, t.Any],
|
|
165
|
+
functions: list[dict[str, t.Any]],
|
|
166
|
+
end_line: int,
|
|
167
|
+
) -> None:
|
|
168
|
+
"""Finalize function and add to results.
|
|
169
|
+
|
|
170
|
+
Args:
|
|
171
|
+
function: Function to finalize
|
|
172
|
+
functions: Functions list
|
|
173
|
+
end_line: End line number
|
|
174
|
+
"""
|
|
175
|
+
function["end_line"] = end_line
|
|
176
|
+
function["body_sample"] = function["body"][:300]
|
|
177
|
+
function["estimated_complexity"] = self._estimate_complexity(function["body"])
|
|
178
|
+
functions.append(function)
|
|
179
|
+
|
|
180
|
+
def _handle_last_function(
|
|
181
|
+
self,
|
|
182
|
+
current_function: dict[str, t.Any] | None,
|
|
183
|
+
functions: list[dict[str, t.Any]],
|
|
184
|
+
total_lines: int,
|
|
185
|
+
) -> None:
|
|
186
|
+
"""Handle last function in file.
|
|
187
|
+
|
|
188
|
+
Args:
|
|
189
|
+
current_function: Last function
|
|
190
|
+
functions: Functions list
|
|
191
|
+
total_lines: Total lines
|
|
192
|
+
"""
|
|
193
|
+
if current_function and self._is_performance_critical(current_function):
|
|
194
|
+
self._finalize_function(current_function, functions, total_lines)
|
|
195
|
+
|
|
196
|
+
@staticmethod
|
|
197
|
+
def _is_performance_critical(function_info: dict[str, t.Any]) -> bool:
|
|
198
|
+
"""Determine if function is performance-critical.
|
|
199
|
+
|
|
200
|
+
Args:
|
|
201
|
+
function_info: Function info
|
|
202
|
+
|
|
203
|
+
Returns:
|
|
204
|
+
True if performance-critical
|
|
205
|
+
"""
|
|
206
|
+
body = function_info.get("body", "")
|
|
207
|
+
name = function_info.get("name", "")
|
|
208
|
+
|
|
209
|
+
performance_indicators = [
|
|
210
|
+
"for " in body
|
|
211
|
+
and len([line for line in body.split("\n") if "for " in line]) > 1,
|
|
212
|
+
"while " in body,
|
|
213
|
+
body.count("for ") > 0 and len(body) > 200,
|
|
214
|
+
any(pattern in body for pattern in (".append(", "+=", ".extend(", "len(")),
|
|
215
|
+
any(
|
|
216
|
+
pattern in name
|
|
217
|
+
for pattern in (
|
|
218
|
+
"process",
|
|
219
|
+
"analyze",
|
|
220
|
+
"compute",
|
|
221
|
+
"calculate",
|
|
222
|
+
"optimize",
|
|
223
|
+
)
|
|
224
|
+
),
|
|
225
|
+
"range(" in body and ("1000" in body or "len(" in body),
|
|
226
|
+
]
|
|
227
|
+
|
|
228
|
+
return any(performance_indicators)
|
|
229
|
+
|
|
230
|
+
@staticmethod
|
|
231
|
+
def _estimate_complexity(body: str) -> int:
|
|
232
|
+
"""Estimate computational complexity of function.
|
|
233
|
+
|
|
234
|
+
Args:
|
|
235
|
+
body: Function body
|
|
236
|
+
|
|
237
|
+
Returns:
|
|
238
|
+
Complexity score
|
|
239
|
+
"""
|
|
240
|
+
complexity = 1
|
|
241
|
+
|
|
242
|
+
nested_for_loops = 0
|
|
243
|
+
for_depth = 0
|
|
244
|
+
lines = body.split("\n")
|
|
245
|
+
|
|
246
|
+
for line in lines:
|
|
247
|
+
stripped = line.strip()
|
|
248
|
+
if "for " in stripped:
|
|
249
|
+
for_depth += 1
|
|
250
|
+
nested_for_loops = max(nested_for_loops, for_depth)
|
|
251
|
+
elif (
|
|
252
|
+
stripped
|
|
253
|
+
and not stripped.startswith("#")
|
|
254
|
+
and len(line) - len(line.lstrip()) == 0
|
|
255
|
+
):
|
|
256
|
+
for_depth = 0
|
|
257
|
+
|
|
258
|
+
complexity = max(complexity, nested_for_loops)
|
|
259
|
+
|
|
260
|
+
if ".sort(" in body or "sorted(" in body:
|
|
261
|
+
complexity += 1
|
|
262
|
+
if body.count("len(") > 5:
|
|
263
|
+
complexity += 1
|
|
264
|
+
if ".index(" in body or ".find(" in body:
|
|
265
|
+
complexity += 1
|
|
266
|
+
|
|
267
|
+
return complexity
|
|
268
|
+
|
|
269
|
+
def analyze_performance_patterns(
|
|
270
|
+
self, semantic_insight: t.Any, current_func: dict[str, t.Any]
|
|
271
|
+
) -> dict[str, t.Any]:
|
|
272
|
+
"""Analyze semantic patterns for performance insights.
|
|
273
|
+
|
|
274
|
+
Args:
|
|
275
|
+
semantic_insight: Semantic insight from analysis
|
|
276
|
+
current_func: Current function
|
|
277
|
+
|
|
278
|
+
Returns:
|
|
279
|
+
Analysis dict
|
|
280
|
+
"""
|
|
281
|
+
analysis: dict[str, t.Any] = {
|
|
282
|
+
"issues_found": False,
|
|
283
|
+
"optimization_suggestion": "Consider reviewing similar implementations for consistency",
|
|
284
|
+
"pattern_insights": [],
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if semantic_insight.high_confidence_matches > 0:
|
|
288
|
+
analysis["issues_found"] = True
|
|
289
|
+
analysis["pattern_insights"].append(
|
|
290
|
+
f"Found {semantic_insight.high_confidence_matches} highly similar implementations"
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
performance_concerns = []
|
|
294
|
+
for pattern in semantic_insight.related_patterns:
|
|
295
|
+
content = pattern.get("content", "").lower()
|
|
296
|
+
if any(
|
|
297
|
+
concern in content for concern in ("for", "while", "+=", "append")
|
|
298
|
+
):
|
|
299
|
+
performance_concerns.append(pattern["file_path"])
|
|
300
|
+
|
|
301
|
+
if performance_concerns:
|
|
302
|
+
analysis["optimization_suggestion"] = (
|
|
303
|
+
f"Performance review needed: {len(performance_concerns)} similar functions "
|
|
304
|
+
f"may benefit from the same optimization approach"
|
|
305
|
+
)
|
|
306
|
+
analysis["pattern_insights"].append(
|
|
307
|
+
f"Similar performance patterns found in: {', '.join(list(set(performance_concerns))[:3])}"
|
|
308
|
+
)
|
|
309
|
+
|
|
310
|
+
return analysis
|
|
311
|
+
|
|
312
|
+
def analyze_code_metrics(self, tree: ast.AST) -> dict[str, t.Any]:
|
|
313
|
+
"""Analyze code metrics from AST.
|
|
314
|
+
|
|
315
|
+
Args:
|
|
316
|
+
tree: AST tree
|
|
317
|
+
|
|
318
|
+
Returns:
|
|
319
|
+
Metrics dict
|
|
320
|
+
"""
|
|
321
|
+
metrics: dict[str, t.Any] = {
|
|
322
|
+
"total_functions": 0,
|
|
323
|
+
"total_classes": 0,
|
|
324
|
+
"average_function_length": 0,
|
|
325
|
+
"max_nesting_depth": 0,
|
|
326
|
+
"high_complexity_functions": [],
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
class MetricsCollector(ast.NodeVisitor):
|
|
330
|
+
def __init__(self) -> None:
|
|
331
|
+
self.function_count = 0
|
|
332
|
+
self.class_count = 0
|
|
333
|
+
self.function_lengths: list[int] = []
|
|
334
|
+
self.max_depth = 0
|
|
335
|
+
|
|
336
|
+
def visit_FunctionDef(self, node: ast.FunctionDef) -> None:
|
|
337
|
+
self.function_count += 1
|
|
338
|
+
length = (node.end_lineno or node.lineno) - node.lineno
|
|
339
|
+
self.function_lengths.append(length)
|
|
340
|
+
self.generic_visit(node)
|
|
341
|
+
|
|
342
|
+
def visit_ClassDef(self, node: ast.ClassDef) -> None:
|
|
343
|
+
self.class_count += 1
|
|
344
|
+
self.generic_visit(node)
|
|
345
|
+
|
|
346
|
+
collector = MetricsCollector()
|
|
347
|
+
collector.visit(tree)
|
|
348
|
+
|
|
349
|
+
metrics["total_functions"] = collector.function_count
|
|
350
|
+
metrics["total_classes"] = collector.class_count
|
|
351
|
+
|
|
352
|
+
if collector.function_lengths:
|
|
353
|
+
metrics["average_function_length"] = sum(collector.function_lengths) / len(
|
|
354
|
+
collector.function_lengths
|
|
355
|
+
)
|
|
356
|
+
|
|
357
|
+
return metrics
|