crackerjack 0.18.2__py3-none-any.whl → 0.45.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- crackerjack/README.md +19 -0
- crackerjack/__init__.py +96 -2
- crackerjack/__main__.py +637 -138
- crackerjack/adapters/README.md +18 -0
- crackerjack/adapters/__init__.py +39 -0
- crackerjack/adapters/_output_paths.py +167 -0
- crackerjack/adapters/_qa_adapter_base.py +309 -0
- crackerjack/adapters/_tool_adapter_base.py +706 -0
- crackerjack/adapters/ai/README.md +65 -0
- crackerjack/adapters/ai/__init__.py +5 -0
- crackerjack/adapters/ai/claude.py +853 -0
- crackerjack/adapters/complexity/README.md +53 -0
- crackerjack/adapters/complexity/__init__.py +10 -0
- crackerjack/adapters/complexity/complexipy.py +641 -0
- crackerjack/adapters/dependency/__init__.py +22 -0
- crackerjack/adapters/dependency/pip_audit.py +418 -0
- crackerjack/adapters/format/README.md +72 -0
- crackerjack/adapters/format/__init__.py +11 -0
- crackerjack/adapters/format/mdformat.py +313 -0
- crackerjack/adapters/format/ruff.py +516 -0
- crackerjack/adapters/lint/README.md +47 -0
- crackerjack/adapters/lint/__init__.py +11 -0
- crackerjack/adapters/lint/codespell.py +273 -0
- crackerjack/adapters/lsp/README.md +49 -0
- crackerjack/adapters/lsp/__init__.py +27 -0
- crackerjack/adapters/lsp/_base.py +194 -0
- crackerjack/adapters/lsp/_client.py +358 -0
- crackerjack/adapters/lsp/_manager.py +193 -0
- crackerjack/adapters/lsp/skylos.py +283 -0
- crackerjack/adapters/lsp/zuban.py +557 -0
- crackerjack/adapters/refactor/README.md +59 -0
- crackerjack/adapters/refactor/__init__.py +12 -0
- crackerjack/adapters/refactor/creosote.py +318 -0
- crackerjack/adapters/refactor/refurb.py +406 -0
- crackerjack/adapters/refactor/skylos.py +494 -0
- crackerjack/adapters/sast/README.md +132 -0
- crackerjack/adapters/sast/__init__.py +32 -0
- crackerjack/adapters/sast/_base.py +201 -0
- crackerjack/adapters/sast/bandit.py +423 -0
- crackerjack/adapters/sast/pyscn.py +405 -0
- crackerjack/adapters/sast/semgrep.py +241 -0
- crackerjack/adapters/security/README.md +111 -0
- crackerjack/adapters/security/__init__.py +17 -0
- crackerjack/adapters/security/gitleaks.py +339 -0
- crackerjack/adapters/type/README.md +52 -0
- crackerjack/adapters/type/__init__.py +12 -0
- crackerjack/adapters/type/pyrefly.py +402 -0
- crackerjack/adapters/type/ty.py +402 -0
- crackerjack/adapters/type/zuban.py +522 -0
- crackerjack/adapters/utility/README.md +51 -0
- crackerjack/adapters/utility/__init__.py +10 -0
- crackerjack/adapters/utility/checks.py +884 -0
- crackerjack/agents/README.md +264 -0
- crackerjack/agents/__init__.py +66 -0
- crackerjack/agents/architect_agent.py +238 -0
- crackerjack/agents/base.py +167 -0
- crackerjack/agents/claude_code_bridge.py +641 -0
- crackerjack/agents/coordinator.py +600 -0
- crackerjack/agents/documentation_agent.py +520 -0
- crackerjack/agents/dry_agent.py +585 -0
- crackerjack/agents/enhanced_coordinator.py +279 -0
- crackerjack/agents/enhanced_proactive_agent.py +185 -0
- crackerjack/agents/error_middleware.py +53 -0
- crackerjack/agents/formatting_agent.py +230 -0
- crackerjack/agents/helpers/__init__.py +9 -0
- crackerjack/agents/helpers/performance/__init__.py +22 -0
- crackerjack/agents/helpers/performance/performance_ast_analyzer.py +357 -0
- crackerjack/agents/helpers/performance/performance_pattern_detector.py +909 -0
- crackerjack/agents/helpers/performance/performance_recommender.py +572 -0
- crackerjack/agents/helpers/refactoring/__init__.py +22 -0
- crackerjack/agents/helpers/refactoring/code_transformer.py +536 -0
- crackerjack/agents/helpers/refactoring/complexity_analyzer.py +344 -0
- crackerjack/agents/helpers/refactoring/dead_code_detector.py +437 -0
- crackerjack/agents/helpers/test_creation/__init__.py +19 -0
- crackerjack/agents/helpers/test_creation/test_ast_analyzer.py +216 -0
- crackerjack/agents/helpers/test_creation/test_coverage_analyzer.py +643 -0
- crackerjack/agents/helpers/test_creation/test_template_generator.py +1031 -0
- crackerjack/agents/import_optimization_agent.py +1181 -0
- crackerjack/agents/performance_agent.py +325 -0
- crackerjack/agents/performance_helpers.py +205 -0
- crackerjack/agents/proactive_agent.py +55 -0
- crackerjack/agents/refactoring_agent.py +511 -0
- crackerjack/agents/refactoring_helpers.py +247 -0
- crackerjack/agents/security_agent.py +793 -0
- crackerjack/agents/semantic_agent.py +479 -0
- crackerjack/agents/semantic_helpers.py +356 -0
- crackerjack/agents/test_creation_agent.py +570 -0
- crackerjack/agents/test_specialist_agent.py +526 -0
- crackerjack/agents/tracker.py +110 -0
- crackerjack/api.py +647 -0
- crackerjack/cli/README.md +394 -0
- crackerjack/cli/__init__.py +24 -0
- crackerjack/cli/cache_handlers.py +209 -0
- crackerjack/cli/cache_handlers_enhanced.py +680 -0
- crackerjack/cli/facade.py +162 -0
- crackerjack/cli/formatting.py +13 -0
- crackerjack/cli/handlers/__init__.py +85 -0
- crackerjack/cli/handlers/advanced.py +103 -0
- crackerjack/cli/handlers/ai_features.py +62 -0
- crackerjack/cli/handlers/analytics.py +479 -0
- crackerjack/cli/handlers/changelog.py +271 -0
- crackerjack/cli/handlers/config_handlers.py +16 -0
- crackerjack/cli/handlers/coverage.py +84 -0
- crackerjack/cli/handlers/documentation.py +280 -0
- crackerjack/cli/handlers/main_handlers.py +497 -0
- crackerjack/cli/handlers/monitoring.py +371 -0
- crackerjack/cli/handlers.py +700 -0
- crackerjack/cli/interactive.py +488 -0
- crackerjack/cli/options.py +1216 -0
- crackerjack/cli/semantic_handlers.py +292 -0
- crackerjack/cli/utils.py +19 -0
- crackerjack/cli/version.py +19 -0
- crackerjack/code_cleaner.py +1307 -0
- crackerjack/config/README.md +472 -0
- crackerjack/config/__init__.py +275 -0
- crackerjack/config/global_lock_config.py +207 -0
- crackerjack/config/hooks.py +390 -0
- crackerjack/config/loader.py +239 -0
- crackerjack/config/settings.py +141 -0
- crackerjack/config/tool_commands.py +331 -0
- crackerjack/core/README.md +393 -0
- crackerjack/core/__init__.py +0 -0
- crackerjack/core/async_workflow_orchestrator.py +738 -0
- crackerjack/core/autofix_coordinator.py +282 -0
- crackerjack/core/container.py +105 -0
- crackerjack/core/enhanced_container.py +583 -0
- crackerjack/core/file_lifecycle.py +472 -0
- crackerjack/core/performance.py +244 -0
- crackerjack/core/performance_monitor.py +357 -0
- crackerjack/core/phase_coordinator.py +1227 -0
- crackerjack/core/proactive_workflow.py +267 -0
- crackerjack/core/resource_manager.py +425 -0
- crackerjack/core/retry.py +275 -0
- crackerjack/core/service_watchdog.py +601 -0
- crackerjack/core/session_coordinator.py +239 -0
- crackerjack/core/timeout_manager.py +563 -0
- crackerjack/core/websocket_lifecycle.py +410 -0
- crackerjack/core/workflow/__init__.py +21 -0
- crackerjack/core/workflow/workflow_ai_coordinator.py +863 -0
- crackerjack/core/workflow/workflow_event_orchestrator.py +1107 -0
- crackerjack/core/workflow/workflow_issue_parser.py +714 -0
- crackerjack/core/workflow/workflow_phase_executor.py +1158 -0
- crackerjack/core/workflow/workflow_security_gates.py +400 -0
- crackerjack/core/workflow_orchestrator.py +2243 -0
- crackerjack/data/README.md +11 -0
- crackerjack/data/__init__.py +8 -0
- crackerjack/data/models.py +79 -0
- crackerjack/data/repository.py +210 -0
- crackerjack/decorators/README.md +180 -0
- crackerjack/decorators/__init__.py +35 -0
- crackerjack/decorators/error_handling.py +649 -0
- crackerjack/decorators/error_handling_decorators.py +334 -0
- crackerjack/decorators/helpers.py +58 -0
- crackerjack/decorators/patterns.py +281 -0
- crackerjack/decorators/utils.py +58 -0
- crackerjack/docs/INDEX.md +11 -0
- crackerjack/docs/README.md +11 -0
- crackerjack/docs/generated/api/API_REFERENCE.md +10895 -0
- crackerjack/docs/generated/api/CLI_REFERENCE.md +109 -0
- crackerjack/docs/generated/api/CROSS_REFERENCES.md +1755 -0
- crackerjack/docs/generated/api/PROTOCOLS.md +3 -0
- crackerjack/docs/generated/api/SERVICES.md +1252 -0
- crackerjack/documentation/README.md +11 -0
- crackerjack/documentation/__init__.py +31 -0
- crackerjack/documentation/ai_templates.py +756 -0
- crackerjack/documentation/dual_output_generator.py +767 -0
- crackerjack/documentation/mkdocs_integration.py +518 -0
- crackerjack/documentation/reference_generator.py +1065 -0
- crackerjack/dynamic_config.py +678 -0
- crackerjack/errors.py +378 -0
- crackerjack/events/README.md +11 -0
- crackerjack/events/__init__.py +16 -0
- crackerjack/events/telemetry.py +175 -0
- crackerjack/events/workflow_bus.py +346 -0
- crackerjack/exceptions/README.md +301 -0
- crackerjack/exceptions/__init__.py +5 -0
- crackerjack/exceptions/config.py +4 -0
- crackerjack/exceptions/tool_execution_error.py +245 -0
- crackerjack/executors/README.md +591 -0
- crackerjack/executors/__init__.py +13 -0
- crackerjack/executors/async_hook_executor.py +938 -0
- crackerjack/executors/cached_hook_executor.py +316 -0
- crackerjack/executors/hook_executor.py +1295 -0
- crackerjack/executors/hook_lock_manager.py +708 -0
- crackerjack/executors/individual_hook_executor.py +739 -0
- crackerjack/executors/lsp_aware_hook_executor.py +349 -0
- crackerjack/executors/progress_hook_executor.py +282 -0
- crackerjack/executors/tool_proxy.py +433 -0
- crackerjack/hooks/README.md +485 -0
- crackerjack/hooks/lsp_hook.py +93 -0
- crackerjack/intelligence/README.md +557 -0
- crackerjack/intelligence/__init__.py +37 -0
- crackerjack/intelligence/adaptive_learning.py +693 -0
- crackerjack/intelligence/agent_orchestrator.py +485 -0
- crackerjack/intelligence/agent_registry.py +377 -0
- crackerjack/intelligence/agent_selector.py +439 -0
- crackerjack/intelligence/integration.py +250 -0
- crackerjack/interactive.py +719 -0
- crackerjack/managers/README.md +369 -0
- crackerjack/managers/__init__.py +11 -0
- crackerjack/managers/async_hook_manager.py +135 -0
- crackerjack/managers/hook_manager.py +585 -0
- crackerjack/managers/publish_manager.py +631 -0
- crackerjack/managers/test_command_builder.py +391 -0
- crackerjack/managers/test_executor.py +474 -0
- crackerjack/managers/test_manager.py +1357 -0
- crackerjack/managers/test_progress.py +187 -0
- crackerjack/mcp/README.md +374 -0
- crackerjack/mcp/__init__.py +0 -0
- crackerjack/mcp/cache.py +352 -0
- crackerjack/mcp/client_runner.py +121 -0
- crackerjack/mcp/context.py +802 -0
- crackerjack/mcp/dashboard.py +657 -0
- crackerjack/mcp/enhanced_progress_monitor.py +493 -0
- crackerjack/mcp/file_monitor.py +394 -0
- crackerjack/mcp/progress_components.py +607 -0
- crackerjack/mcp/progress_monitor.py +1016 -0
- crackerjack/mcp/rate_limiter.py +336 -0
- crackerjack/mcp/server.py +24 -0
- crackerjack/mcp/server_core.py +526 -0
- crackerjack/mcp/service_watchdog.py +505 -0
- crackerjack/mcp/state.py +407 -0
- crackerjack/mcp/task_manager.py +259 -0
- crackerjack/mcp/tools/README.md +27 -0
- crackerjack/mcp/tools/__init__.py +19 -0
- crackerjack/mcp/tools/core_tools.py +469 -0
- crackerjack/mcp/tools/error_analyzer.py +283 -0
- crackerjack/mcp/tools/execution_tools.py +384 -0
- crackerjack/mcp/tools/intelligence_tool_registry.py +46 -0
- crackerjack/mcp/tools/intelligence_tools.py +264 -0
- crackerjack/mcp/tools/monitoring_tools.py +628 -0
- crackerjack/mcp/tools/proactive_tools.py +367 -0
- crackerjack/mcp/tools/progress_tools.py +222 -0
- crackerjack/mcp/tools/semantic_tools.py +584 -0
- crackerjack/mcp/tools/utility_tools.py +358 -0
- crackerjack/mcp/tools/workflow_executor.py +699 -0
- crackerjack/mcp/websocket/README.md +31 -0
- crackerjack/mcp/websocket/__init__.py +14 -0
- crackerjack/mcp/websocket/app.py +54 -0
- crackerjack/mcp/websocket/endpoints.py +492 -0
- crackerjack/mcp/websocket/event_bridge.py +188 -0
- crackerjack/mcp/websocket/jobs.py +406 -0
- crackerjack/mcp/websocket/monitoring/__init__.py +25 -0
- crackerjack/mcp/websocket/monitoring/api/__init__.py +19 -0
- crackerjack/mcp/websocket/monitoring/api/dependencies.py +141 -0
- crackerjack/mcp/websocket/monitoring/api/heatmap.py +154 -0
- crackerjack/mcp/websocket/monitoring/api/intelligence.py +199 -0
- crackerjack/mcp/websocket/monitoring/api/metrics.py +203 -0
- crackerjack/mcp/websocket/monitoring/api/telemetry.py +101 -0
- crackerjack/mcp/websocket/monitoring/dashboard.py +18 -0
- crackerjack/mcp/websocket/monitoring/factory.py +109 -0
- crackerjack/mcp/websocket/monitoring/filters.py +10 -0
- crackerjack/mcp/websocket/monitoring/metrics.py +64 -0
- crackerjack/mcp/websocket/monitoring/models.py +90 -0
- crackerjack/mcp/websocket/monitoring/utils.py +171 -0
- crackerjack/mcp/websocket/monitoring/websocket_manager.py +78 -0
- crackerjack/mcp/websocket/monitoring/websockets/__init__.py +17 -0
- crackerjack/mcp/websocket/monitoring/websockets/dependencies.py +126 -0
- crackerjack/mcp/websocket/monitoring/websockets/heatmap.py +176 -0
- crackerjack/mcp/websocket/monitoring/websockets/intelligence.py +291 -0
- crackerjack/mcp/websocket/monitoring/websockets/metrics.py +291 -0
- crackerjack/mcp/websocket/monitoring_endpoints.py +21 -0
- crackerjack/mcp/websocket/server.py +174 -0
- crackerjack/mcp/websocket/websocket_handler.py +276 -0
- crackerjack/mcp/websocket_server.py +10 -0
- crackerjack/models/README.md +308 -0
- crackerjack/models/__init__.py +40 -0
- crackerjack/models/config.py +730 -0
- crackerjack/models/config_adapter.py +265 -0
- crackerjack/models/protocols.py +1535 -0
- crackerjack/models/pydantic_models.py +320 -0
- crackerjack/models/qa_config.py +145 -0
- crackerjack/models/qa_results.py +134 -0
- crackerjack/models/resource_protocols.py +299 -0
- crackerjack/models/results.py +35 -0
- crackerjack/models/semantic_models.py +258 -0
- crackerjack/models/task.py +173 -0
- crackerjack/models/test_models.py +60 -0
- crackerjack/monitoring/README.md +11 -0
- crackerjack/monitoring/__init__.py +0 -0
- crackerjack/monitoring/ai_agent_watchdog.py +405 -0
- crackerjack/monitoring/metrics_collector.py +427 -0
- crackerjack/monitoring/regression_prevention.py +580 -0
- crackerjack/monitoring/websocket_server.py +406 -0
- crackerjack/orchestration/README.md +340 -0
- crackerjack/orchestration/__init__.py +43 -0
- crackerjack/orchestration/advanced_orchestrator.py +894 -0
- crackerjack/orchestration/cache/README.md +312 -0
- crackerjack/orchestration/cache/__init__.py +37 -0
- crackerjack/orchestration/cache/memory_cache.py +338 -0
- crackerjack/orchestration/cache/tool_proxy_cache.py +340 -0
- crackerjack/orchestration/config.py +297 -0
- crackerjack/orchestration/coverage_improvement.py +180 -0
- crackerjack/orchestration/execution_strategies.py +361 -0
- crackerjack/orchestration/hook_orchestrator.py +1398 -0
- crackerjack/orchestration/strategies/README.md +401 -0
- crackerjack/orchestration/strategies/__init__.py +39 -0
- crackerjack/orchestration/strategies/adaptive_strategy.py +630 -0
- crackerjack/orchestration/strategies/parallel_strategy.py +237 -0
- crackerjack/orchestration/strategies/sequential_strategy.py +299 -0
- crackerjack/orchestration/test_progress_streamer.py +647 -0
- crackerjack/plugins/README.md +11 -0
- crackerjack/plugins/__init__.py +15 -0
- crackerjack/plugins/base.py +200 -0
- crackerjack/plugins/hooks.py +254 -0
- crackerjack/plugins/loader.py +335 -0
- crackerjack/plugins/managers.py +264 -0
- crackerjack/py313.py +191 -0
- crackerjack/security/README.md +11 -0
- crackerjack/security/__init__.py +0 -0
- crackerjack/security/audit.py +197 -0
- crackerjack/services/README.md +374 -0
- crackerjack/services/__init__.py +9 -0
- crackerjack/services/ai/README.md +295 -0
- crackerjack/services/ai/__init__.py +7 -0
- crackerjack/services/ai/advanced_optimizer.py +878 -0
- crackerjack/services/ai/contextual_ai_assistant.py +542 -0
- crackerjack/services/ai/embeddings.py +444 -0
- crackerjack/services/ai/intelligent_commit.py +328 -0
- crackerjack/services/ai/predictive_analytics.py +510 -0
- crackerjack/services/anomaly_detector.py +392 -0
- crackerjack/services/api_extractor.py +617 -0
- crackerjack/services/backup_service.py +467 -0
- crackerjack/services/bounded_status_operations.py +530 -0
- crackerjack/services/cache.py +369 -0
- crackerjack/services/changelog_automation.py +399 -0
- crackerjack/services/command_execution_service.py +305 -0
- crackerjack/services/config_integrity.py +132 -0
- crackerjack/services/config_merge.py +546 -0
- crackerjack/services/config_service.py +198 -0
- crackerjack/services/config_template.py +493 -0
- crackerjack/services/coverage_badge_service.py +173 -0
- crackerjack/services/coverage_ratchet.py +381 -0
- crackerjack/services/debug.py +733 -0
- crackerjack/services/dependency_analyzer.py +460 -0
- crackerjack/services/dependency_monitor.py +622 -0
- crackerjack/services/documentation_generator.py +493 -0
- crackerjack/services/documentation_service.py +704 -0
- crackerjack/services/enhanced_filesystem.py +497 -0
- crackerjack/services/enterprise_optimizer.py +865 -0
- crackerjack/services/error_pattern_analyzer.py +676 -0
- crackerjack/services/file_filter.py +221 -0
- crackerjack/services/file_hasher.py +149 -0
- crackerjack/services/file_io_service.py +361 -0
- crackerjack/services/file_modifier.py +615 -0
- crackerjack/services/filesystem.py +381 -0
- crackerjack/services/git.py +422 -0
- crackerjack/services/health_metrics.py +615 -0
- crackerjack/services/heatmap_generator.py +744 -0
- crackerjack/services/incremental_executor.py +380 -0
- crackerjack/services/initialization.py +823 -0
- crackerjack/services/input_validator.py +668 -0
- crackerjack/services/intelligent_commit.py +327 -0
- crackerjack/services/log_manager.py +289 -0
- crackerjack/services/logging.py +228 -0
- crackerjack/services/lsp_client.py +628 -0
- crackerjack/services/memory_optimizer.py +414 -0
- crackerjack/services/metrics.py +587 -0
- crackerjack/services/monitoring/README.md +30 -0
- crackerjack/services/monitoring/__init__.py +9 -0
- crackerjack/services/monitoring/dependency_monitor.py +678 -0
- crackerjack/services/monitoring/error_pattern_analyzer.py +676 -0
- crackerjack/services/monitoring/health_metrics.py +716 -0
- crackerjack/services/monitoring/metrics.py +587 -0
- crackerjack/services/monitoring/performance_benchmarks.py +410 -0
- crackerjack/services/monitoring/performance_cache.py +388 -0
- crackerjack/services/monitoring/performance_monitor.py +569 -0
- crackerjack/services/parallel_executor.py +527 -0
- crackerjack/services/pattern_cache.py +333 -0
- crackerjack/services/pattern_detector.py +478 -0
- crackerjack/services/patterns/__init__.py +142 -0
- crackerjack/services/patterns/agents.py +107 -0
- crackerjack/services/patterns/code/__init__.py +15 -0
- crackerjack/services/patterns/code/detection.py +118 -0
- crackerjack/services/patterns/code/imports.py +107 -0
- crackerjack/services/patterns/code/paths.py +159 -0
- crackerjack/services/patterns/code/performance.py +119 -0
- crackerjack/services/patterns/code/replacement.py +36 -0
- crackerjack/services/patterns/core.py +212 -0
- crackerjack/services/patterns/documentation/__init__.py +14 -0
- crackerjack/services/patterns/documentation/badges_markdown.py +96 -0
- crackerjack/services/patterns/documentation/comments_blocks.py +83 -0
- crackerjack/services/patterns/documentation/docstrings.py +89 -0
- crackerjack/services/patterns/formatting.py +226 -0
- crackerjack/services/patterns/operations.py +339 -0
- crackerjack/services/patterns/security/__init__.py +23 -0
- crackerjack/services/patterns/security/code_injection.py +122 -0
- crackerjack/services/patterns/security/credentials.py +190 -0
- crackerjack/services/patterns/security/path_traversal.py +221 -0
- crackerjack/services/patterns/security/unsafe_operations.py +216 -0
- crackerjack/services/patterns/templates.py +62 -0
- crackerjack/services/patterns/testing/__init__.py +18 -0
- crackerjack/services/patterns/testing/error_patterns.py +107 -0
- crackerjack/services/patterns/testing/pytest_output.py +126 -0
- crackerjack/services/patterns/tool_output/__init__.py +16 -0
- crackerjack/services/patterns/tool_output/bandit.py +72 -0
- crackerjack/services/patterns/tool_output/other.py +97 -0
- crackerjack/services/patterns/tool_output/pyright.py +67 -0
- crackerjack/services/patterns/tool_output/ruff.py +44 -0
- crackerjack/services/patterns/url_sanitization.py +114 -0
- crackerjack/services/patterns/utilities.py +42 -0
- crackerjack/services/patterns/utils.py +339 -0
- crackerjack/services/patterns/validation.py +46 -0
- crackerjack/services/patterns/versioning.py +62 -0
- crackerjack/services/predictive_analytics.py +523 -0
- crackerjack/services/profiler.py +280 -0
- crackerjack/services/quality/README.md +415 -0
- crackerjack/services/quality/__init__.py +11 -0
- crackerjack/services/quality/anomaly_detector.py +392 -0
- crackerjack/services/quality/pattern_cache.py +333 -0
- crackerjack/services/quality/pattern_detector.py +479 -0
- crackerjack/services/quality/qa_orchestrator.py +491 -0
- crackerjack/services/quality/quality_baseline.py +395 -0
- crackerjack/services/quality/quality_baseline_enhanced.py +649 -0
- crackerjack/services/quality/quality_intelligence.py +949 -0
- crackerjack/services/regex_patterns.py +58 -0
- crackerjack/services/regex_utils.py +483 -0
- crackerjack/services/secure_path_utils.py +524 -0
- crackerjack/services/secure_status_formatter.py +450 -0
- crackerjack/services/secure_subprocess.py +635 -0
- crackerjack/services/security.py +239 -0
- crackerjack/services/security_logger.py +495 -0
- crackerjack/services/server_manager.py +411 -0
- crackerjack/services/smart_scheduling.py +167 -0
- crackerjack/services/status_authentication.py +460 -0
- crackerjack/services/status_security_manager.py +315 -0
- crackerjack/services/terminal_utils.py +0 -0
- crackerjack/services/thread_safe_status_collector.py +441 -0
- crackerjack/services/tool_filter.py +368 -0
- crackerjack/services/tool_version_service.py +43 -0
- crackerjack/services/unified_config.py +115 -0
- crackerjack/services/validation_rate_limiter.py +220 -0
- crackerjack/services/vector_store.py +689 -0
- crackerjack/services/version_analyzer.py +461 -0
- crackerjack/services/version_checker.py +223 -0
- crackerjack/services/websocket_resource_limiter.py +438 -0
- crackerjack/services/zuban_lsp_service.py +391 -0
- crackerjack/slash_commands/README.md +11 -0
- crackerjack/slash_commands/__init__.py +59 -0
- crackerjack/slash_commands/init.md +112 -0
- crackerjack/slash_commands/run.md +197 -0
- crackerjack/slash_commands/status.md +127 -0
- crackerjack/tools/README.md +11 -0
- crackerjack/tools/__init__.py +30 -0
- crackerjack/tools/_git_utils.py +105 -0
- crackerjack/tools/check_added_large_files.py +139 -0
- crackerjack/tools/check_ast.py +105 -0
- crackerjack/tools/check_json.py +103 -0
- crackerjack/tools/check_jsonschema.py +297 -0
- crackerjack/tools/check_toml.py +103 -0
- crackerjack/tools/check_yaml.py +110 -0
- crackerjack/tools/codespell_wrapper.py +72 -0
- crackerjack/tools/end_of_file_fixer.py +202 -0
- crackerjack/tools/format_json.py +128 -0
- crackerjack/tools/mdformat_wrapper.py +114 -0
- crackerjack/tools/trailing_whitespace.py +198 -0
- crackerjack/tools/validate_input_validator_patterns.py +236 -0
- crackerjack/tools/validate_regex_patterns.py +188 -0
- crackerjack/ui/README.md +11 -0
- crackerjack/ui/__init__.py +1 -0
- crackerjack/ui/dashboard_renderer.py +28 -0
- crackerjack/ui/templates/README.md +11 -0
- crackerjack/utils/console_utils.py +13 -0
- crackerjack/utils/dependency_guard.py +230 -0
- crackerjack/utils/retry_utils.py +275 -0
- crackerjack/workflows/README.md +590 -0
- crackerjack/workflows/__init__.py +46 -0
- crackerjack/workflows/actions.py +811 -0
- crackerjack/workflows/auto_fix.py +444 -0
- crackerjack/workflows/container_builder.py +499 -0
- crackerjack/workflows/definitions.py +443 -0
- crackerjack/workflows/engine.py +177 -0
- crackerjack/workflows/event_bridge.py +242 -0
- crackerjack-0.45.2.dist-info/METADATA +1678 -0
- crackerjack-0.45.2.dist-info/RECORD +478 -0
- {crackerjack-0.18.2.dist-info → crackerjack-0.45.2.dist-info}/WHEEL +1 -1
- crackerjack-0.45.2.dist-info/entry_points.txt +2 -0
- crackerjack/.gitignore +0 -14
- crackerjack/.libcst.codemod.yaml +0 -18
- crackerjack/.pdm.toml +0 -1
- crackerjack/.pre-commit-config.yaml +0 -91
- crackerjack/.pytest_cache/.gitignore +0 -2
- crackerjack/.pytest_cache/CACHEDIR.TAG +0 -4
- crackerjack/.pytest_cache/README.md +0 -8
- crackerjack/.pytest_cache/v/cache/nodeids +0 -1
- crackerjack/.pytest_cache/v/cache/stepwise +0 -1
- crackerjack/.ruff_cache/.gitignore +0 -1
- crackerjack/.ruff_cache/0.1.11/3256171999636029978 +0 -0
- crackerjack/.ruff_cache/0.1.14/602324811142551221 +0 -0
- crackerjack/.ruff_cache/0.1.4/10355199064880463147 +0 -0
- crackerjack/.ruff_cache/0.1.6/15140459877605758699 +0 -0
- crackerjack/.ruff_cache/0.1.7/1790508110482614856 +0 -0
- crackerjack/.ruff_cache/0.1.9/17041001205004563469 +0 -0
- crackerjack/.ruff_cache/0.11.2/4070660268492669020 +0 -0
- crackerjack/.ruff_cache/0.11.3/9818742842212983150 +0 -0
- crackerjack/.ruff_cache/0.11.4/9818742842212983150 +0 -0
- crackerjack/.ruff_cache/0.11.6/3557596832929915217 +0 -0
- crackerjack/.ruff_cache/0.11.7/10386934055395314831 +0 -0
- crackerjack/.ruff_cache/0.11.7/3557596832929915217 +0 -0
- crackerjack/.ruff_cache/0.11.8/530407680854991027 +0 -0
- crackerjack/.ruff_cache/0.2.0/10047773857155985907 +0 -0
- crackerjack/.ruff_cache/0.2.1/8522267973936635051 +0 -0
- crackerjack/.ruff_cache/0.2.2/18053836298936336950 +0 -0
- crackerjack/.ruff_cache/0.3.0/12548816621480535786 +0 -0
- crackerjack/.ruff_cache/0.3.3/11081883392474770722 +0 -0
- crackerjack/.ruff_cache/0.3.4/676973378459347183 +0 -0
- crackerjack/.ruff_cache/0.3.5/16311176246009842383 +0 -0
- crackerjack/.ruff_cache/0.5.7/1493622539551733492 +0 -0
- crackerjack/.ruff_cache/0.5.7/6231957614044513175 +0 -0
- crackerjack/.ruff_cache/0.5.7/9932762556785938009 +0 -0
- crackerjack/.ruff_cache/0.6.0/11982804814124138945 +0 -0
- crackerjack/.ruff_cache/0.6.0/12055761203849489982 +0 -0
- crackerjack/.ruff_cache/0.6.2/1206147804896221174 +0 -0
- crackerjack/.ruff_cache/0.6.4/1206147804896221174 +0 -0
- crackerjack/.ruff_cache/0.6.5/1206147804896221174 +0 -0
- crackerjack/.ruff_cache/0.6.7/3657366982708166874 +0 -0
- crackerjack/.ruff_cache/0.6.9/285614542852677309 +0 -0
- crackerjack/.ruff_cache/0.7.1/1024065805990144819 +0 -0
- crackerjack/.ruff_cache/0.7.1/285614542852677309 +0 -0
- crackerjack/.ruff_cache/0.7.3/16061516852537040135 +0 -0
- crackerjack/.ruff_cache/0.8.4/16354268377385700367 +0 -0
- crackerjack/.ruff_cache/0.9.10/12813592349865671909 +0 -0
- crackerjack/.ruff_cache/0.9.10/923908772239632759 +0 -0
- crackerjack/.ruff_cache/0.9.3/13948373885254993391 +0 -0
- crackerjack/.ruff_cache/0.9.9/12813592349865671909 +0 -0
- crackerjack/.ruff_cache/0.9.9/8843823720003377982 +0 -0
- crackerjack/.ruff_cache/CACHEDIR.TAG +0 -1
- crackerjack/crackerjack.py +0 -855
- crackerjack/pyproject.toml +0 -214
- crackerjack-0.18.2.dist-info/METADATA +0 -420
- crackerjack-0.18.2.dist-info/RECORD +0 -59
- crackerjack-0.18.2.dist-info/entry_points.txt +0 -4
- {crackerjack-0.18.2.dist-info → crackerjack-0.45.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
import time
|
|
2
|
+
import typing as t
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from .base import (
|
|
6
|
+
AgentContext,
|
|
7
|
+
FixResult,
|
|
8
|
+
Issue,
|
|
9
|
+
IssueType,
|
|
10
|
+
SubAgent,
|
|
11
|
+
agent_registry,
|
|
12
|
+
)
|
|
13
|
+
from .helpers.performance.performance_ast_analyzer import PerformanceASTAnalyzer
|
|
14
|
+
from .helpers.performance.performance_pattern_detector import PerformancePatternDetector
|
|
15
|
+
from .helpers.performance.performance_recommender import PerformanceRecommender
|
|
16
|
+
from .semantic_helpers import (
|
|
17
|
+
SemanticInsight,
|
|
18
|
+
create_semantic_enhancer,
|
|
19
|
+
get_session_enhanced_recommendations,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class PerformanceAgent(SubAgent):
|
|
24
|
+
"""Agent for detecting and fixing performance issues.
|
|
25
|
+
|
|
26
|
+
Enhanced with semantic context to detect performance patterns across
|
|
27
|
+
the codebase and find similar bottlenecks that may not be immediately visible.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
def __init__(self, context: AgentContext) -> None:
|
|
31
|
+
super().__init__(context)
|
|
32
|
+
self.semantic_enhancer = create_semantic_enhancer(context.project_path)
|
|
33
|
+
self.semantic_insights: dict[str, SemanticInsight] = {}
|
|
34
|
+
self.performance_metrics: dict[str, t.Any] = {}
|
|
35
|
+
|
|
36
|
+
# Initialize helper modules
|
|
37
|
+
self._pattern_detector = PerformancePatternDetector(context)
|
|
38
|
+
self._ast_analyzer = PerformanceASTAnalyzer(context)
|
|
39
|
+
self._recommender = PerformanceRecommender(context)
|
|
40
|
+
|
|
41
|
+
def get_supported_types(self) -> set[IssueType]:
|
|
42
|
+
return {IssueType.PERFORMANCE}
|
|
43
|
+
|
|
44
|
+
async def can_handle(self, issue: Issue) -> float:
|
|
45
|
+
if issue.type != IssueType.PERFORMANCE:
|
|
46
|
+
return 0.0
|
|
47
|
+
|
|
48
|
+
confidence = 0.85
|
|
49
|
+
message_lower = issue.message.lower()
|
|
50
|
+
|
|
51
|
+
if any(
|
|
52
|
+
pattern in message_lower
|
|
53
|
+
for pattern in (
|
|
54
|
+
"nested loop",
|
|
55
|
+
"o(n²)",
|
|
56
|
+
"string concatenation",
|
|
57
|
+
"list[t.Any] concatenation",
|
|
58
|
+
"inefficient",
|
|
59
|
+
"complexity",
|
|
60
|
+
)
|
|
61
|
+
):
|
|
62
|
+
confidence = 0.9
|
|
63
|
+
|
|
64
|
+
return confidence
|
|
65
|
+
|
|
66
|
+
async def analyze_and_fix(self, issue: Issue) -> FixResult:
|
|
67
|
+
self.log(f"Analyzing performance issue: {issue.message}")
|
|
68
|
+
start_time = time.time()
|
|
69
|
+
|
|
70
|
+
validation_result = self._validate_performance_issue(issue)
|
|
71
|
+
if validation_result:
|
|
72
|
+
return validation_result
|
|
73
|
+
|
|
74
|
+
if issue.file_path is None:
|
|
75
|
+
return FixResult(
|
|
76
|
+
success=False,
|
|
77
|
+
confidence=0.0,
|
|
78
|
+
remaining_issues=["No file path provided for performance issue"],
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
file_path = Path(issue.file_path)
|
|
82
|
+
|
|
83
|
+
try:
|
|
84
|
+
result = await self._process_performance_optimization(file_path)
|
|
85
|
+
|
|
86
|
+
analysis_time = time.time() - start_time
|
|
87
|
+
self.performance_metrics[str(file_path)] = {
|
|
88
|
+
"analysis_duration": analysis_time,
|
|
89
|
+
"optimizations_applied": result.fixes_applied,
|
|
90
|
+
"timestamp": time.time(),
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if result.success and result.fixes_applied:
|
|
94
|
+
stats_summary = self._generate_optimization_summary()
|
|
95
|
+
result.recommendations = result.recommendations + [stats_summary]
|
|
96
|
+
|
|
97
|
+
return result
|
|
98
|
+
except Exception as e:
|
|
99
|
+
return self._create_performance_error_result(e)
|
|
100
|
+
|
|
101
|
+
@staticmethod
|
|
102
|
+
def _validate_performance_issue(issue: Issue) -> FixResult | None:
|
|
103
|
+
if not issue.file_path:
|
|
104
|
+
return FixResult(
|
|
105
|
+
success=False,
|
|
106
|
+
confidence=0.0,
|
|
107
|
+
remaining_issues=["No file path specified for performance issue"],
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
file_path = Path(issue.file_path)
|
|
111
|
+
if not file_path.exists():
|
|
112
|
+
return FixResult(
|
|
113
|
+
success=False,
|
|
114
|
+
confidence=0.0,
|
|
115
|
+
remaining_issues=[f"File not found: {file_path}"],
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
return None
|
|
119
|
+
|
|
120
|
+
async def _process_performance_optimization(self, file_path: Path) -> FixResult:
|
|
121
|
+
content = self.context.get_file_content(file_path)
|
|
122
|
+
if not content:
|
|
123
|
+
return FixResult(
|
|
124
|
+
success=False,
|
|
125
|
+
confidence=0.0,
|
|
126
|
+
remaining_issues=[f"Could not read file: {file_path}"],
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
# Detect traditional performance issues using helper
|
|
130
|
+
performance_issues = self._pattern_detector.detect_performance_issues(
|
|
131
|
+
content, file_path
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
# Enhance with semantic performance pattern detection
|
|
135
|
+
semantic_issues = await self._detect_semantic_performance_issues(
|
|
136
|
+
content, file_path
|
|
137
|
+
)
|
|
138
|
+
performance_issues.extend(semantic_issues)
|
|
139
|
+
|
|
140
|
+
if not performance_issues:
|
|
141
|
+
return FixResult(
|
|
142
|
+
success=True,
|
|
143
|
+
confidence=0.7,
|
|
144
|
+
recommendations=["No performance issues detected"],
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
return await self._apply_and_save_optimizations(
|
|
148
|
+
file_path,
|
|
149
|
+
content,
|
|
150
|
+
performance_issues,
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
async def _apply_and_save_optimizations(
|
|
154
|
+
self,
|
|
155
|
+
file_path: Path,
|
|
156
|
+
content: str,
|
|
157
|
+
issues: list[dict[str, t.Any]],
|
|
158
|
+
) -> FixResult:
|
|
159
|
+
# Delegate to recommender helper
|
|
160
|
+
optimized_content = self._recommender.apply_performance_optimizations(
|
|
161
|
+
content, issues
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
if optimized_content == content:
|
|
165
|
+
return self._create_no_optimization_result()
|
|
166
|
+
|
|
167
|
+
success = self.context.write_file_content(file_path, optimized_content)
|
|
168
|
+
if not success:
|
|
169
|
+
return FixResult(
|
|
170
|
+
success=False,
|
|
171
|
+
confidence=0.0,
|
|
172
|
+
remaining_issues=[f"Failed to write optimized file: {file_path}"],
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
# Get summary from recommender
|
|
176
|
+
stats_summary = self._recommender.generate_optimization_summary()
|
|
177
|
+
|
|
178
|
+
return FixResult(
|
|
179
|
+
success=True,
|
|
180
|
+
confidence=0.8,
|
|
181
|
+
fixes_applied=[
|
|
182
|
+
f"Optimized {len(issues)} performance issues",
|
|
183
|
+
"Applied algorithmic improvements",
|
|
184
|
+
stats_summary,
|
|
185
|
+
],
|
|
186
|
+
files_modified=[str(file_path)],
|
|
187
|
+
recommendations=await self._generate_enhanced_recommendations(issues),
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
@staticmethod
|
|
191
|
+
def _create_no_optimization_result() -> FixResult:
|
|
192
|
+
return FixResult(
|
|
193
|
+
success=False,
|
|
194
|
+
confidence=0.6,
|
|
195
|
+
remaining_issues=["Could not automatically optimize performance"],
|
|
196
|
+
recommendations=[
|
|
197
|
+
"Manual optimization required",
|
|
198
|
+
"Consider algorithm complexity improvements",
|
|
199
|
+
"Review data structure choices",
|
|
200
|
+
"Profile code execution for bottlenecks",
|
|
201
|
+
],
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
@staticmethod
|
|
205
|
+
def _create_performance_error_result(error: Exception) -> FixResult:
|
|
206
|
+
return FixResult(
|
|
207
|
+
success=False,
|
|
208
|
+
confidence=0.0,
|
|
209
|
+
remaining_issues=[f"Error processing file: {error}"],
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
async def _detect_semantic_performance_issues(
|
|
213
|
+
self, content: str, file_path: Path
|
|
214
|
+
) -> list[dict[str, t.Any]]:
|
|
215
|
+
"""Detect performance issues using semantic analysis of similar code patterns."""
|
|
216
|
+
issues = []
|
|
217
|
+
|
|
218
|
+
try:
|
|
219
|
+
# Delegate to AST analyzer helper
|
|
220
|
+
critical_functions = (
|
|
221
|
+
self._ast_analyzer.extract_performance_critical_functions(content)
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
for func in critical_functions:
|
|
225
|
+
if (
|
|
226
|
+
func["estimated_complexity"] > 2
|
|
227
|
+
): # Focus on potentially complex functions
|
|
228
|
+
# Search for similar performance patterns
|
|
229
|
+
insight = await self.semantic_enhancer.find_similar_patterns(
|
|
230
|
+
f"performance {func['signature']} {func['body_sample']}",
|
|
231
|
+
current_file=file_path,
|
|
232
|
+
min_similarity=0.6,
|
|
233
|
+
max_results=8,
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
if insight.total_matches > 1:
|
|
237
|
+
# Delegate analysis to AST analyzer helper
|
|
238
|
+
analysis = self._ast_analyzer.analyze_performance_patterns(
|
|
239
|
+
insight, func
|
|
240
|
+
)
|
|
241
|
+
if analysis["issues_found"]:
|
|
242
|
+
issues.append(
|
|
243
|
+
{
|
|
244
|
+
"type": "semantic_performance_pattern",
|
|
245
|
+
"function": func,
|
|
246
|
+
"similar_patterns": insight.related_patterns,
|
|
247
|
+
"performance_analysis": analysis,
|
|
248
|
+
"confidence_score": insight.high_confidence_matches
|
|
249
|
+
/ max(insight.total_matches, 1),
|
|
250
|
+
"suggestion": analysis["optimization_suggestion"],
|
|
251
|
+
}
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
# Store insight for recommendation enhancement
|
|
255
|
+
self.semantic_insights[func["name"]] = insight
|
|
256
|
+
|
|
257
|
+
except Exception as e:
|
|
258
|
+
self.log(f"Warning: Semantic performance analysis failed: {e}")
|
|
259
|
+
|
|
260
|
+
return issues
|
|
261
|
+
|
|
262
|
+
def _generate_optimization_summary(self) -> str:
|
|
263
|
+
"""Generate a summary of optimization results."""
|
|
264
|
+
total_files = len(self.performance_metrics)
|
|
265
|
+
total_optimizations = sum(
|
|
266
|
+
metrics.get("optimizations_applied", 0)
|
|
267
|
+
for metrics in self.performance_metrics.values()
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
total_time = sum(
|
|
271
|
+
metrics.get("analysis_duration", 0)
|
|
272
|
+
for metrics in self.performance_metrics.values()
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
return (
|
|
276
|
+
f"Performance optimization summary: "
|
|
277
|
+
f"{total_optimizations} optimizations applied across {total_files} files "
|
|
278
|
+
f"in {total_time:.2f}s total"
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
async def _generate_enhanced_recommendations(
|
|
282
|
+
self, issues: list[dict[str, t.Any]]
|
|
283
|
+
) -> list[str]:
|
|
284
|
+
"""Generate enhanced recommendations including semantic insights."""
|
|
285
|
+
recommendations = ["Test performance improvements with benchmarks"]
|
|
286
|
+
|
|
287
|
+
# Add semantic insights
|
|
288
|
+
semantic_issues = [
|
|
289
|
+
issue for issue in issues if issue["type"] == "semantic_performance_pattern"
|
|
290
|
+
]
|
|
291
|
+
if semantic_issues:
|
|
292
|
+
recommendations.append(
|
|
293
|
+
f"Semantic analysis found {len(semantic_issues)} similar performance patterns "
|
|
294
|
+
"across codebase - consider applying optimizations consistently"
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
# Store insights for session continuity
|
|
298
|
+
for issue in semantic_issues:
|
|
299
|
+
if "semantic_insight" in issue:
|
|
300
|
+
await self.semantic_enhancer.store_insight_to_session(
|
|
301
|
+
issue["semantic_insight"], "PerformanceAgent"
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
# Enhance with session-stored insights
|
|
305
|
+
recommendations = await get_session_enhanced_recommendations(
|
|
306
|
+
recommendations, "PerformanceAgent", self.context.project_path
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
# Add insights from stored semantic analysis
|
|
310
|
+
for func_name, insight in self.semantic_insights.items():
|
|
311
|
+
if insight.high_confidence_matches > 0:
|
|
312
|
+
enhanced_recs = self.semantic_enhancer.enhance_recommendations(
|
|
313
|
+
[], # Start with empty list to get just semantic recommendations
|
|
314
|
+
insight,
|
|
315
|
+
)
|
|
316
|
+
recommendations.extend(enhanced_recs)
|
|
317
|
+
|
|
318
|
+
# Log semantic context for debugging
|
|
319
|
+
summary = self.semantic_enhancer.get_semantic_context_summary(insight)
|
|
320
|
+
self.log(f"Performance semantic context for {func_name}: {summary}")
|
|
321
|
+
|
|
322
|
+
return recommendations
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
agent_registry.register(PerformanceAgent)
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import ast
|
|
2
|
+
import typing as t
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@dataclass
|
|
7
|
+
class OptimizationResult:
|
|
8
|
+
lines: list[str]
|
|
9
|
+
modified: bool
|
|
10
|
+
optimization_description: str | None = None
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class EnhancedNestedLoopAnalyzer(ast.NodeVisitor):
|
|
14
|
+
def __init__(self) -> None:
|
|
15
|
+
self.loop_stack: list[tuple[str, ast.AST, int]] = []
|
|
16
|
+
self.nested_loops: list[dict[str, t.Any]] = []
|
|
17
|
+
self.complexity_hotspots: list[dict[str, t.Any]] = []
|
|
18
|
+
|
|
19
|
+
def visit_For(self, node: ast.For) -> None:
|
|
20
|
+
self._process_loop_node(node, "nested_for_loop")
|
|
21
|
+
|
|
22
|
+
def visit_While(self, node: ast.While) -> None:
|
|
23
|
+
self._process_loop_node(node, "nested_while_loop")
|
|
24
|
+
|
|
25
|
+
def _process_loop_node(self, node: ast.For | ast.While, loop_type: str) -> None:
|
|
26
|
+
current_depth = len(self.loop_stack) + 1
|
|
27
|
+
self.loop_stack.append((loop_type.split("_")[1], node, current_depth))
|
|
28
|
+
|
|
29
|
+
if current_depth > 1:
|
|
30
|
+
loop_info = self._create_loop_info(node, loop_type, current_depth)
|
|
31
|
+
self.nested_loops.append(loop_info)
|
|
32
|
+
self._check_complexity_hotspot(loop_info, current_depth)
|
|
33
|
+
|
|
34
|
+
self.generic_visit(node)
|
|
35
|
+
self.loop_stack.pop()
|
|
36
|
+
|
|
37
|
+
def _create_loop_info(
|
|
38
|
+
self, node: ast.For | ast.While, loop_type: str, current_depth: int
|
|
39
|
+
) -> dict[str, t.Any]:
|
|
40
|
+
loop_info: dict[str, t.Any] = {
|
|
41
|
+
"line_number": node.lineno,
|
|
42
|
+
"type": loop_type,
|
|
43
|
+
"depth": current_depth,
|
|
44
|
+
"complexity": f"O(n^{current_depth})",
|
|
45
|
+
"complexity_factor": self._calculate_complexity_factor(current_depth),
|
|
46
|
+
"priority": self._get_optimization_priority(current_depth),
|
|
47
|
+
"node": node,
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if isinstance(node, ast.For):
|
|
51
|
+
loop_info["iterable"] = self._extract_iterable_info(node)
|
|
52
|
+
|
|
53
|
+
return loop_info
|
|
54
|
+
|
|
55
|
+
def _check_complexity_hotspot(
|
|
56
|
+
self, loop_info: dict[str, t.Any], current_depth: int
|
|
57
|
+
) -> None:
|
|
58
|
+
if current_depth >= 3:
|
|
59
|
+
self.complexity_hotspots.append(
|
|
60
|
+
loop_info
|
|
61
|
+
| {
|
|
62
|
+
"severity": "high",
|
|
63
|
+
"suggestion": "Critical: Consider algorithmic improvements (memoization, caching, different data structures)",
|
|
64
|
+
}
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
def _calculate_complexity_factor(self, depth: int) -> int:
|
|
68
|
+
return depth**2
|
|
69
|
+
|
|
70
|
+
def _get_optimization_priority(self, depth: int) -> str:
|
|
71
|
+
if depth >= 4:
|
|
72
|
+
return "critical"
|
|
73
|
+
elif depth == 3:
|
|
74
|
+
return "high"
|
|
75
|
+
elif depth == 2:
|
|
76
|
+
return "medium"
|
|
77
|
+
return "low"
|
|
78
|
+
|
|
79
|
+
def _extract_iterable_info(self, node: ast.For) -> dict[str, t.Any]:
|
|
80
|
+
iterable_info = {"type": "unknown", "name": None}
|
|
81
|
+
|
|
82
|
+
if isinstance(node.iter, ast.Name):
|
|
83
|
+
iterable_info = {"type": "variable", "name": node.iter.id}
|
|
84
|
+
elif isinstance(node.iter, ast.Call) and isinstance(node.iter.func, ast.Name):
|
|
85
|
+
iterable_info = {
|
|
86
|
+
"type": "function_call",
|
|
87
|
+
"name": node.iter.func.id,
|
|
88
|
+
}
|
|
89
|
+
if node.iter.func.id == "range":
|
|
90
|
+
iterable_info["optimization_hint"] = (
|
|
91
|
+
"Consider list[t.Any] comprehension or vectorization"
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
return iterable_info
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class EnhancedListOpAnalyzer(ast.NodeVisitor):
|
|
98
|
+
def __init__(self) -> None:
|
|
99
|
+
self.in_loop = False
|
|
100
|
+
self.loop_depth = 0
|
|
101
|
+
self.list_ops: list[dict[str, t.Any]] = []
|
|
102
|
+
self.current_loop_node: ast.For | ast.While | None = None
|
|
103
|
+
|
|
104
|
+
def visit_For(self, node: ast.For) -> None:
|
|
105
|
+
self._enter_loop_context(node)
|
|
106
|
+
self.generic_visit(node)
|
|
107
|
+
self._exit_loop_context()
|
|
108
|
+
|
|
109
|
+
def visit_While(self, node: ast.While) -> None:
|
|
110
|
+
self._enter_loop_context(node)
|
|
111
|
+
self.generic_visit(node)
|
|
112
|
+
self._exit_loop_context()
|
|
113
|
+
|
|
114
|
+
def visit_AugAssign(self, node: ast.AugAssign) -> None:
|
|
115
|
+
if self._should_analyze_aug_assign(node):
|
|
116
|
+
self._analyze_aug_assign_node(node)
|
|
117
|
+
self.generic_visit(node)
|
|
118
|
+
|
|
119
|
+
def _enter_loop_context(self, node: ast.For | ast.While) -> None:
|
|
120
|
+
self._old_state = (self.in_loop, self.loop_depth, self.current_loop_node)
|
|
121
|
+
self.in_loop = True
|
|
122
|
+
self.loop_depth += 1
|
|
123
|
+
self.current_loop_node = node
|
|
124
|
+
|
|
125
|
+
def _exit_loop_context(self) -> None:
|
|
126
|
+
self.in_loop, self.loop_depth, self.current_loop_node = self._old_state
|
|
127
|
+
|
|
128
|
+
def _should_analyze_aug_assign(self, node: ast.AugAssign) -> bool:
|
|
129
|
+
return self.in_loop and isinstance(node.op, ast.Add)
|
|
130
|
+
|
|
131
|
+
def _analyze_aug_assign_node(self, node: ast.AugAssign) -> None:
|
|
132
|
+
impact_factor = self._calculate_performance_impact()
|
|
133
|
+
|
|
134
|
+
if isinstance(node.value, ast.List):
|
|
135
|
+
self._handle_list_concat(node, impact_factor)
|
|
136
|
+
elif isinstance(node.value, ast.Name):
|
|
137
|
+
self._handle_variable_concat(node, impact_factor)
|
|
138
|
+
|
|
139
|
+
def _handle_list_concat(self, node: ast.AugAssign, impact_factor: int) -> None:
|
|
140
|
+
assert isinstance(node.value, ast.List)
|
|
141
|
+
list_size = len(node.value.elts)
|
|
142
|
+
|
|
143
|
+
self.list_ops.append(
|
|
144
|
+
{
|
|
145
|
+
"line_number": node.lineno,
|
|
146
|
+
"type": "list_concat_in_loop",
|
|
147
|
+
"pattern": f"list[t.Any] += [{list_size} items]",
|
|
148
|
+
"loop_depth": self.loop_depth,
|
|
149
|
+
"impact_factor": impact_factor,
|
|
150
|
+
"optimization": "append" if list_size == 1 else "extend",
|
|
151
|
+
"performance_gain": f"{impact_factor * 2}x"
|
|
152
|
+
if list_size > 1
|
|
153
|
+
else "2-3x",
|
|
154
|
+
}
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
def _handle_variable_concat(self, node: ast.AugAssign, impact_factor: int) -> None:
|
|
158
|
+
var_name = getattr(node.value, "id", "unknown")
|
|
159
|
+
self.list_ops.append(
|
|
160
|
+
{
|
|
161
|
+
"line_number": node.lineno,
|
|
162
|
+
"type": "list_concat_variable",
|
|
163
|
+
"pattern": f"list[t.Any] += {var_name}",
|
|
164
|
+
"loop_depth": self.loop_depth,
|
|
165
|
+
"impact_factor": impact_factor,
|
|
166
|
+
"optimization": "extend",
|
|
167
|
+
"performance_gain": f"{impact_factor * 3}x",
|
|
168
|
+
}
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
def _calculate_performance_impact(self) -> int:
|
|
172
|
+
base_impact = 2
|
|
173
|
+
|
|
174
|
+
if self.loop_depth > 1:
|
|
175
|
+
base_impact *= self.loop_depth**2
|
|
176
|
+
|
|
177
|
+
if self._is_hot_loop():
|
|
178
|
+
base_impact *= 5
|
|
179
|
+
|
|
180
|
+
return min(base_impact, 50)
|
|
181
|
+
|
|
182
|
+
def _is_hot_loop(self) -> bool:
|
|
183
|
+
if not (self.current_loop_node and isinstance(self.current_loop_node, ast.For)):
|
|
184
|
+
return False
|
|
185
|
+
|
|
186
|
+
return self._has_large_range_iterator()
|
|
187
|
+
|
|
188
|
+
def _has_large_range_iterator(self) -> bool:
|
|
189
|
+
if not isinstance(self.current_loop_node, ast.For):
|
|
190
|
+
return False
|
|
191
|
+
|
|
192
|
+
iter_node = self.current_loop_node.iter
|
|
193
|
+
if not (
|
|
194
|
+
isinstance(iter_node, ast.Call)
|
|
195
|
+
and isinstance(iter_node.func, ast.Name)
|
|
196
|
+
and iter_node.func.id == "range"
|
|
197
|
+
):
|
|
198
|
+
return False
|
|
199
|
+
|
|
200
|
+
args = iter_node.args
|
|
201
|
+
if not (args and isinstance(args[0], ast.Constant)):
|
|
202
|
+
return False
|
|
203
|
+
|
|
204
|
+
value = args[0].value
|
|
205
|
+
return isinstance(value, int | float) and value > 100
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import typing as t
|
|
2
|
+
from abc import abstractmethod
|
|
3
|
+
|
|
4
|
+
from .base import AgentContext, FixResult, Issue, SubAgent
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ProactiveAgent(SubAgent):
|
|
8
|
+
def __init__(self, context: AgentContext) -> None:
|
|
9
|
+
super().__init__(context)
|
|
10
|
+
self._planning_cache: dict[str, dict[str, t.Any]] = {}
|
|
11
|
+
self._pattern_cache: dict[str, t.Any] = {}
|
|
12
|
+
|
|
13
|
+
@abstractmethod
|
|
14
|
+
async def plan_before_action(self, issue: Issue) -> dict[str, t.Any]:
|
|
15
|
+
pass
|
|
16
|
+
|
|
17
|
+
async def analyze_and_fix_proactively(self, issue: Issue) -> FixResult:
|
|
18
|
+
cache_key = self._get_planning_cache_key(issue)
|
|
19
|
+
if cache_key in self._planning_cache:
|
|
20
|
+
plan = self._planning_cache[cache_key]
|
|
21
|
+
self.log(f"Using cached plan for {cache_key}")
|
|
22
|
+
else:
|
|
23
|
+
plan = await self.plan_before_action(issue)
|
|
24
|
+
self._planning_cache[cache_key] = plan
|
|
25
|
+
self.log(f"Created new plan for {cache_key}")
|
|
26
|
+
|
|
27
|
+
result = await self._execute_with_plan(issue, plan)
|
|
28
|
+
|
|
29
|
+
if result.success and result.confidence >= 0.8:
|
|
30
|
+
self._cache_successful_pattern(issue, plan, result)
|
|
31
|
+
|
|
32
|
+
return result
|
|
33
|
+
|
|
34
|
+
async def _execute_with_plan(
|
|
35
|
+
self, issue: Issue, plan: dict[str, t.Any]
|
|
36
|
+
) -> FixResult:
|
|
37
|
+
return await self.analyze_and_fix(issue)
|
|
38
|
+
|
|
39
|
+
def _get_planning_cache_key(self, issue: Issue) -> str:
|
|
40
|
+
return f"{issue.type.value}: {issue.file_path}: {issue.line_number}"
|
|
41
|
+
|
|
42
|
+
def _cache_successful_pattern(
|
|
43
|
+
self, issue: Issue, plan: dict[str, t.Any], result: FixResult
|
|
44
|
+
) -> None:
|
|
45
|
+
pattern_key = f"{issue.type.value}_{plan.get('strategy', 'default')}"
|
|
46
|
+
self._pattern_cache[pattern_key] = {
|
|
47
|
+
"plan": plan,
|
|
48
|
+
"confidence": result.confidence,
|
|
49
|
+
"files_modified": result.files_modified,
|
|
50
|
+
"fixes_applied": result.fixes_applied,
|
|
51
|
+
}
|
|
52
|
+
self.log(f"Cached successful pattern: {pattern_key}")
|
|
53
|
+
|
|
54
|
+
def get_cached_patterns(self) -> dict[str, t.Any]:
|
|
55
|
+
return self._pattern_cache.copy()
|