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
|
@@ -1,434 +1,239 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
3
|
import time
|
|
4
4
|
import typing as t
|
|
5
|
-
|
|
5
|
+
import uuid
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
|
|
8
|
-
from
|
|
8
|
+
from acb.console import Console
|
|
9
|
+
from acb.depends import depends
|
|
9
10
|
|
|
10
|
-
from crackerjack.models.protocols import OptionsProtocol
|
|
11
11
|
from crackerjack.models.task import SessionTracker
|
|
12
12
|
|
|
13
|
+
if t.TYPE_CHECKING:
|
|
14
|
+
from crackerjack.core.workflow_orchestrator import WorkflowPipeline
|
|
15
|
+
from crackerjack.models.protocols import OptionsProtocol
|
|
16
|
+
|
|
13
17
|
|
|
14
18
|
class SessionCoordinator:
|
|
19
|
+
"""Lightweight session tracking and cleanup coordinator."""
|
|
20
|
+
|
|
15
21
|
def __init__(
|
|
16
22
|
self,
|
|
17
|
-
console: Console,
|
|
18
|
-
pkg_path: Path,
|
|
23
|
+
console: Console | None = None,
|
|
24
|
+
pkg_path: Path | None = None,
|
|
19
25
|
web_job_id: str | None = None,
|
|
20
26
|
) -> None:
|
|
21
|
-
self.console = console
|
|
22
|
-
self.pkg_path = pkg_path
|
|
23
|
-
self.session_tracker: SessionTracker | None = None
|
|
24
|
-
self._cleanup_handlers: list[t.Callable[[], None]] = []
|
|
25
|
-
self._thread_pool = None
|
|
26
|
-
self._lock_files: set[Path] = set()
|
|
27
|
-
|
|
28
|
-
import uuid
|
|
29
|
-
|
|
30
|
-
self.session_id = web_job_id or str(uuid.uuid4())
|
|
27
|
+
self.console = console or depends.get_sync(Console)
|
|
28
|
+
self.pkg_path = pkg_path or Path.cwd()
|
|
31
29
|
self.web_job_id = web_job_id
|
|
30
|
+
self.session_id = web_job_id or uuid.uuid4().hex[:8]
|
|
32
31
|
self.start_time = time.time()
|
|
33
|
-
self.
|
|
32
|
+
self.cleanup_config: t.Any = None
|
|
33
|
+
self.cleanup_handlers: list[t.Callable[[], None]] = []
|
|
34
|
+
self.lock_files: set[Path] = set()
|
|
34
35
|
self.current_task: str | None = None
|
|
35
|
-
self.success: bool = False
|
|
36
36
|
|
|
37
|
-
self.
|
|
37
|
+
self.session_tracker: SessionTracker | None = None
|
|
38
|
+
self.tasks: dict[str, t.Any] = {}
|
|
39
|
+
|
|
40
|
+
def initialize_session_tracking(self, options: OptionsProtocol) -> None:
|
|
41
|
+
"""Initialize session metadata and baseline tracking."""
|
|
42
|
+
self.session_tracker = SessionTracker(
|
|
43
|
+
session_id=self.session_id, start_time=self.start_time
|
|
44
|
+
)
|
|
38
45
|
|
|
39
|
-
|
|
40
|
-
|
|
46
|
+
self.session_tracker.metadata.update(
|
|
47
|
+
{
|
|
48
|
+
"options": getattr(options, "__dict__", {}),
|
|
49
|
+
"pkg_path": str(self.pkg_path),
|
|
50
|
+
"initialized_at": time.time(),
|
|
51
|
+
},
|
|
52
|
+
)
|
|
53
|
+
self.tasks = self.session_tracker.tasks
|
|
54
|
+
self.start_session("workflow")
|
|
41
55
|
|
|
42
56
|
def start_session(self, task_name: str) -> None:
|
|
57
|
+
"""Record the start of a high-level session task."""
|
|
43
58
|
self.current_task = task_name
|
|
59
|
+
# Lazily initialize session tracker if not already set
|
|
60
|
+
if self.session_tracker is None:
|
|
61
|
+
self.session_tracker = SessionTracker(
|
|
62
|
+
session_id=self.session_id, start_time=self.start_time
|
|
63
|
+
)
|
|
64
|
+
self.tasks = self.session_tracker.tasks
|
|
65
|
+
self.session_tracker.metadata.update({"pkg_path": str(self.pkg_path)})
|
|
66
|
+
self.session_tracker.metadata["current_session"] = task_name
|
|
44
67
|
|
|
45
|
-
def end_session(self, success: bool
|
|
46
|
-
|
|
68
|
+
def end_session(self, success: bool) -> None:
|
|
69
|
+
"""Mark session completion."""
|
|
70
|
+
# Record wall-clock end time for tests and summaries
|
|
47
71
|
self.end_time = time.time()
|
|
72
|
+
if self.session_tracker:
|
|
73
|
+
self.session_tracker.metadata["completed_at"] = self.end_time
|
|
74
|
+
self.session_tracker.metadata["success"] = success
|
|
75
|
+
self.current_task = None
|
|
48
76
|
|
|
49
|
-
|
|
50
|
-
self
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
def initialize_session_tracking(self, options: OptionsProtocol) -> None:
|
|
58
|
-
if hasattr(options, "track_progress") and options.track_progress:
|
|
59
|
-
import uuid
|
|
60
|
-
|
|
77
|
+
def track_task(
|
|
78
|
+
self,
|
|
79
|
+
task_id: str,
|
|
80
|
+
task_name: str,
|
|
81
|
+
details: str | None = None,
|
|
82
|
+
) -> str:
|
|
83
|
+
"""Track a task within the session."""
|
|
84
|
+
if self.session_tracker is None:
|
|
61
85
|
self.session_tracker = SessionTracker(
|
|
62
|
-
|
|
63
|
-
session_id=str(uuid.uuid4()),
|
|
64
|
-
start_time=time.time(),
|
|
86
|
+
session_id=self.session_id, start_time=self.start_time
|
|
65
87
|
)
|
|
88
|
+
self.tasks = self.session_tracker.tasks
|
|
89
|
+
self.session_tracker.metadata.update({"pkg_path": str(self.pkg_path)})
|
|
90
|
+
self.session_tracker.start_task(task_id, task_name, details)
|
|
91
|
+
return task_id
|
|
66
92
|
|
|
67
|
-
def
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
"task_id": task_id,
|
|
75
|
-
"description": task_name,
|
|
76
|
-
"start_time": time.time(),
|
|
77
|
-
"status": "in_progress",
|
|
78
|
-
"details": None,
|
|
79
|
-
"end_time": None,
|
|
80
|
-
"progress": 0,
|
|
81
|
-
},
|
|
82
|
-
)()
|
|
83
|
-
|
|
84
|
-
self.tasks[task_id] = task_obj
|
|
85
|
-
|
|
93
|
+
def complete_task(
|
|
94
|
+
self,
|
|
95
|
+
task_id: str,
|
|
96
|
+
details: str | None = None,
|
|
97
|
+
files_changed: list[str] | None = None,
|
|
98
|
+
) -> None:
|
|
99
|
+
"""Mark task as completed."""
|
|
86
100
|
if self.session_tracker:
|
|
87
|
-
self.session_tracker.
|
|
88
|
-
|
|
89
|
-
return task_id
|
|
101
|
+
self.session_tracker.complete_task(task_id, details, files_changed)
|
|
90
102
|
|
|
91
103
|
def update_task(
|
|
92
104
|
self,
|
|
93
105
|
task_id: str,
|
|
94
106
|
status: str,
|
|
107
|
+
*,
|
|
95
108
|
details: str | None = None,
|
|
96
|
-
|
|
109
|
+
files_changed: list[str] | None = None,
|
|
110
|
+
error_message: str | None = None,
|
|
97
111
|
) -> None:
|
|
98
|
-
|
|
99
|
-
task = self.tasks[task_id]
|
|
100
|
-
task.status = status
|
|
101
|
-
if details:
|
|
102
|
-
task.details = details
|
|
103
|
-
if progress is not None:
|
|
104
|
-
task.progress = progress
|
|
105
|
-
|
|
106
|
-
if status in ("completed", "failed"):
|
|
107
|
-
task.end_time = time.time()
|
|
108
|
-
|
|
109
|
-
def complete_task(self, task_id: str, details: str | None = None) -> None:
|
|
110
|
-
if self.session_tracker:
|
|
111
|
-
self.session_tracker.complete_task(task_id, details=details)
|
|
112
|
-
|
|
113
|
-
def fail_task(self, task_id: str, error: str) -> None:
|
|
114
|
-
if self.session_tracker:
|
|
115
|
-
self.session_tracker.fail_task(task_id, error)
|
|
116
|
-
|
|
117
|
-
def get_session_summary(self) -> dict[str, int] | None:
|
|
118
|
-
if self.session_tracker:
|
|
119
|
-
return self.session_tracker.get_summary()
|
|
120
|
-
return None
|
|
121
|
-
|
|
122
|
-
def get_summary(self) -> dict[str, t.Any]:
|
|
123
|
-
duration = getattr(self, "end_time", time.time()) - self.start_time
|
|
124
|
-
tasks_count = len(self.tasks)
|
|
112
|
+
"""Update a task's status in the current session.
|
|
125
113
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
"success": self.success,
|
|
134
|
-
"tasks": [
|
|
135
|
-
{
|
|
136
|
-
"task_id": task.task_id,
|
|
137
|
-
"description": task.description,
|
|
138
|
-
"status": task.status,
|
|
139
|
-
"details": task.details,
|
|
140
|
-
"start_time": task.start_time,
|
|
141
|
-
"end_time": task.end_time,
|
|
142
|
-
"progress": task.progress,
|
|
143
|
-
}
|
|
144
|
-
for task in self.tasks.values()
|
|
145
|
-
],
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
def finalize_session(self, start_time: float, success: bool) -> None:
|
|
149
|
-
total_time = time.time() - start_time
|
|
150
|
-
if success:
|
|
151
|
-
self.complete_task(
|
|
152
|
-
"workflow",
|
|
153
|
-
f"Completed successfully in {total_time: .1f}s",
|
|
154
|
-
)
|
|
155
|
-
else:
|
|
156
|
-
self.complete_task(
|
|
157
|
-
"workflow",
|
|
158
|
-
f"Completed with issues in {total_time: .1f}s",
|
|
159
|
-
)
|
|
160
|
-
|
|
161
|
-
def register_cleanup(self, cleanup_handler: t.Callable[[], None]) -> None:
|
|
162
|
-
self._cleanup_handlers.append(cleanup_handler)
|
|
163
|
-
|
|
164
|
-
def track_lock_file(self, lock_file_path: Path) -> None:
|
|
165
|
-
self._lock_files.add(lock_file_path)
|
|
166
|
-
|
|
167
|
-
def cleanup_resources(self) -> None:
|
|
168
|
-
for cleanup_handler in self._cleanup_handlers:
|
|
169
|
-
with suppress(Exception):
|
|
170
|
-
cleanup_handler()
|
|
171
|
-
|
|
172
|
-
self._cleanup_temporary_files()
|
|
173
|
-
|
|
174
|
-
def _cleanup_temporary_files(self) -> None:
|
|
175
|
-
if not hasattr(self, "_cleanup_config") or self._cleanup_config is None:
|
|
176
|
-
self._cleanup_debug_logs()
|
|
177
|
-
self._cleanup_coverage_files()
|
|
178
|
-
self._cleanup_pycache_directories()
|
|
179
|
-
elif self._cleanup_config.auto_cleanup:
|
|
180
|
-
self._cleanup_debug_logs(keep_recent=self._cleanup_config.keep_debug_logs)
|
|
181
|
-
self._cleanup_coverage_files(
|
|
182
|
-
keep_recent=self._cleanup_config.keep_coverage_files,
|
|
183
|
-
)
|
|
184
|
-
self._cleanup_pycache_directories()
|
|
185
|
-
|
|
186
|
-
def set_cleanup_config(self, cleanup_config: t.Any) -> None:
|
|
187
|
-
self._cleanup_config = cleanup_config
|
|
188
|
-
|
|
189
|
-
def _cleanup_debug_logs(self, keep_recent: int = 5) -> None:
|
|
190
|
-
with suppress(Exception):
|
|
191
|
-
from crackerjack.services.log_manager import get_log_manager
|
|
192
|
-
|
|
193
|
-
log_manager = get_log_manager()
|
|
194
|
-
|
|
195
|
-
log_manager.rotate_logs(
|
|
196
|
-
log_manager.debug_dir,
|
|
197
|
-
"debug-*.log",
|
|
198
|
-
max_files=keep_recent,
|
|
199
|
-
max_age_days=7,
|
|
200
|
-
)
|
|
201
|
-
|
|
202
|
-
legacy_pattern = "crackerjack-debug-*.log"
|
|
203
|
-
legacy_files = sorted(
|
|
204
|
-
self.pkg_path.glob(legacy_pattern),
|
|
205
|
-
key=lambda p: p.stat().st_mtime,
|
|
206
|
-
)
|
|
207
|
-
|
|
208
|
-
for old_file in legacy_files[:-keep_recent]:
|
|
209
|
-
with suppress(FileNotFoundError, PermissionError):
|
|
210
|
-
old_file.unlink()
|
|
211
|
-
|
|
212
|
-
def _cleanup_coverage_files(self, keep_recent: int = 10) -> None:
|
|
213
|
-
with suppress(Exception):
|
|
214
|
-
cache_dir = Path.home() / ".cache" / "crackerjack" / "coverage"
|
|
215
|
-
if cache_dir.exists():
|
|
216
|
-
pattern = ".coverage *"
|
|
217
|
-
coverage_files = sorted(
|
|
218
|
-
cache_dir.glob(pattern),
|
|
219
|
-
key=lambda p: p.stat().st_mtime,
|
|
220
|
-
)
|
|
221
|
-
|
|
222
|
-
for old_file in coverage_files[:-keep_recent]:
|
|
223
|
-
with suppress(FileNotFoundError, PermissionError):
|
|
224
|
-
old_file.unlink()
|
|
225
|
-
|
|
226
|
-
pattern = ".coverage.*"
|
|
227
|
-
coverage_files = sorted(
|
|
228
|
-
self.pkg_path.glob(pattern),
|
|
229
|
-
key=lambda p: p.stat().st_mtime,
|
|
114
|
+
Supports 'completed', 'failed', and 'in_progress' states. Unknown statuses
|
|
115
|
+
are set directly on the TaskStatusData if present.
|
|
116
|
+
"""
|
|
117
|
+
if self.session_tracker is None:
|
|
118
|
+
# Initialize tracker lazily to ensure tasks dict exists
|
|
119
|
+
self.session_tracker = SessionTracker(
|
|
120
|
+
session_id=self.session_id, start_time=self.start_time
|
|
230
121
|
)
|
|
122
|
+
self.tasks = self.session_tracker.tasks
|
|
123
|
+
self.session_tracker.metadata.update({"pkg_path": str(self.pkg_path)})
|
|
231
124
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
def _cleanup_pycache_directories(self) -> None:
|
|
237
|
-
with suppress(Exception):
|
|
238
|
-
import shutil
|
|
239
|
-
|
|
240
|
-
for pycache_dir in self.pkg_path.rglob("__pycache__"):
|
|
241
|
-
if pycache_dir.is_dir():
|
|
242
|
-
with suppress(FileNotFoundError, PermissionError):
|
|
243
|
-
shutil.rmtree(pycache_dir)
|
|
244
|
-
|
|
245
|
-
def _setup_logging(self) -> None:
|
|
246
|
-
logger = logging.getLogger("crackerjack")
|
|
247
|
-
if not logger.handlers:
|
|
248
|
-
handler = logging.StreamHandler()
|
|
249
|
-
handler.setLevel(logging.WARNING)
|
|
250
|
-
logger.addHandler(handler)
|
|
251
|
-
logger.setLevel(logging.WARNING)
|
|
252
|
-
|
|
253
|
-
def _setup_websocket_progress_file(self) -> None:
|
|
254
|
-
import tempfile
|
|
255
|
-
|
|
256
|
-
self.progress_dir = Path(tempfile.gettempdir()) / "crackerjack-mcp-progress"
|
|
257
|
-
self.progress_file = self.progress_dir / f"job-{self.web_job_id}.json"
|
|
258
|
-
|
|
259
|
-
if self.progress_file.exists():
|
|
260
|
-
self._update_websocket_progress("running", "Crackerjack process started")
|
|
261
|
-
|
|
262
|
-
def _update_websocket_progress(self, status: str, message: str) -> None:
|
|
263
|
-
if not hasattr(self, "progress_file") or not self.progress_file:
|
|
125
|
+
normalized = status.lower()
|
|
126
|
+
if normalized == "completed":
|
|
127
|
+
self.session_tracker.complete_task(task_id, details, files_changed)
|
|
264
128
|
return
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
if self.progress_file.exists():
|
|
269
|
-
progress_data = json.loads(self.progress_file.read_text())
|
|
270
|
-
|
|
271
|
-
progress_data.update(
|
|
272
|
-
{
|
|
273
|
-
"status": status,
|
|
274
|
-
"message": message,
|
|
275
|
-
"updated_at": time.time(),
|
|
276
|
-
"current_stage": message,
|
|
277
|
-
},
|
|
278
|
-
)
|
|
279
|
-
|
|
280
|
-
self.progress_file.write_text(json.dumps(progress_data, indent=2))
|
|
281
|
-
|
|
282
|
-
except Exception as e:
|
|
283
|
-
self.console.print(
|
|
284
|
-
f"[dim yellow]Warning: Could not update progress file: {e}[/ dim yellow]",
|
|
129
|
+
if normalized == "failed":
|
|
130
|
+
self.session_tracker.fail_task(
|
|
131
|
+
task_id, error_message or "Task failed", details
|
|
285
132
|
)
|
|
133
|
+
return
|
|
134
|
+
if normalized == "in_progress":
|
|
135
|
+
# Ensure task exists; if not, create it as in-progress
|
|
136
|
+
if task_id not in self.session_tracker.tasks:
|
|
137
|
+
self.session_tracker.start_task(task_id, task_id, details)
|
|
138
|
+
else:
|
|
139
|
+
task = self.session_tracker.tasks[task_id]
|
|
140
|
+
task.status = "in_progress"
|
|
141
|
+
if details:
|
|
142
|
+
task.details = details
|
|
143
|
+
return
|
|
286
144
|
|
|
287
|
-
|
|
288
|
-
if self.
|
|
289
|
-
self.
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
try:
|
|
294
|
-
quality_service = self._initialize_quality_service()
|
|
295
|
-
metrics = self._extract_session_metrics()
|
|
296
|
-
|
|
297
|
-
if metrics:
|
|
298
|
-
self._record_quality_baseline(quality_service, metrics)
|
|
299
|
-
report = quality_service.generate_comprehensive_report(metrics)
|
|
300
|
-
self._display_quality_report(report)
|
|
301
|
-
except Exception as e:
|
|
302
|
-
self._handle_quality_tracking_error(e)
|
|
303
|
-
|
|
304
|
-
def _initialize_quality_service(self) -> t.Any:
|
|
305
|
-
"""Initialize the quality baseline service."""
|
|
306
|
-
from crackerjack.services.quality_baseline_enhanced import (
|
|
307
|
-
EnhancedQualityBaselineService,
|
|
308
|
-
)
|
|
309
|
-
|
|
310
|
-
return EnhancedQualityBaselineService()
|
|
145
|
+
# Fallback: set arbitrary status value if task exists
|
|
146
|
+
if task_id in self.session_tracker.tasks:
|
|
147
|
+
task = self.session_tracker.tasks[task_id]
|
|
148
|
+
task.status = normalized or task.status
|
|
149
|
+
if details:
|
|
150
|
+
task.details = details
|
|
311
151
|
|
|
312
|
-
def
|
|
313
|
-
self,
|
|
152
|
+
def fail_task(
|
|
153
|
+
self,
|
|
154
|
+
task_id: str,
|
|
155
|
+
error_message: str,
|
|
156
|
+
details: str | None = None,
|
|
314
157
|
) -> None:
|
|
315
|
-
"""
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
test_count=metrics.get("test_count", 0),
|
|
319
|
-
test_pass_rate=metrics.get("test_pass_rate", 100.0),
|
|
320
|
-
hook_failures=metrics.get("hook_failures", 0),
|
|
321
|
-
complexity_violations=metrics.get("complexity_violations", 0),
|
|
322
|
-
security_issues=metrics.get("security_issues", 0),
|
|
323
|
-
type_errors=metrics.get("type_errors", 0),
|
|
324
|
-
linting_issues=metrics.get("linting_issues", 0),
|
|
325
|
-
)
|
|
326
|
-
|
|
327
|
-
def _handle_quality_tracking_error(self, error: Exception) -> None:
|
|
328
|
-
"""Handle quality tracking errors without failing the session."""
|
|
329
|
-
self.console.print(
|
|
330
|
-
f"[dim yellow]Warning: Quality tracking failed: {error}[/dim yellow]"
|
|
331
|
-
)
|
|
332
|
-
|
|
333
|
-
def _extract_session_metrics(self) -> dict[str, t.Any] | None:
|
|
334
|
-
"""Extract quality metrics from the current session."""
|
|
335
|
-
with suppress(Exception):
|
|
336
|
-
metrics: dict[str, t.Any] = {}
|
|
337
|
-
self._extract_test_metrics(metrics)
|
|
338
|
-
self._extract_hook_metrics(metrics)
|
|
339
|
-
self._set_default_metrics(metrics)
|
|
340
|
-
return metrics or None
|
|
341
|
-
return None
|
|
342
|
-
|
|
343
|
-
def _extract_test_metrics(self, metrics: dict[str, t.Any]) -> None:
|
|
344
|
-
"""Extract test-related metrics from tasks."""
|
|
345
|
-
if "testing" not in self.tasks:
|
|
346
|
-
return
|
|
347
|
-
|
|
348
|
-
test_task = self.tasks["testing"]
|
|
158
|
+
"""Mark task as failed."""
|
|
159
|
+
if self.session_tracker:
|
|
160
|
+
self.session_tracker.fail_task(task_id, error_message, details)
|
|
349
161
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
162
|
+
def finalize_session(self, start_time: float, success: bool) -> None:
|
|
163
|
+
"""Finalize session bookkeeping."""
|
|
164
|
+
duration = time.time() - start_time
|
|
165
|
+
if self.session_tracker:
|
|
166
|
+
self.session_tracker.metadata["duration"] = duration
|
|
167
|
+
self.session_tracker.metadata["success"] = success
|
|
168
|
+
if success and self.current_task:
|
|
169
|
+
self.session_tracker.complete_task(self.current_task)
|
|
170
|
+
elif not success and self.current_task:
|
|
171
|
+
self.session_tracker.fail_task(self.current_task, "Session failed")
|
|
172
|
+
self.current_task = None
|
|
356
173
|
|
|
357
|
-
def
|
|
358
|
-
"""
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
174
|
+
def cleanup_resources(self) -> None:
|
|
175
|
+
"""Execute registered cleanup handlers and release tracked resources."""
|
|
176
|
+
for handler in self.cleanup_handlers.copy():
|
|
177
|
+
try:
|
|
178
|
+
handler()
|
|
179
|
+
except Exception as exc: # pragma: no cover - defensive
|
|
180
|
+
self.console.print(
|
|
181
|
+
f"[red]Cleanup handler error:[/ red] {type(exc).__name__}: {exc}",
|
|
182
|
+
)
|
|
365
183
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
184
|
+
for lock_path in list(self.lock_files):
|
|
185
|
+
try:
|
|
186
|
+
if lock_path.exists():
|
|
187
|
+
lock_path.unlink()
|
|
188
|
+
except OSError:
|
|
189
|
+
pass
|
|
190
|
+
finally:
|
|
191
|
+
self.lock_files.discard(lock_path)
|
|
192
|
+
|
|
193
|
+
def register_cleanup(self, handler: t.Callable[[], None]) -> None:
|
|
194
|
+
"""Register cleanup handler to execute when session completes."""
|
|
195
|
+
self.cleanup_handlers.append(handler)
|
|
196
|
+
|
|
197
|
+
def track_lock_file(self, path: Path) -> None:
|
|
198
|
+
"""Track lock file for cleanup."""
|
|
199
|
+
self.lock_files.add(path)
|
|
200
|
+
|
|
201
|
+
def set_cleanup_config(self, config: t.Any) -> None:
|
|
202
|
+
"""Store cleanup configuration from options."""
|
|
203
|
+
self.cleanup_config = config
|
|
204
|
+
|
|
205
|
+
def get_session_summary(self) -> dict[str, t.Any]:
|
|
206
|
+
"""Return high-level session summary."""
|
|
207
|
+
if self.session_tracker:
|
|
208
|
+
summary = self.session_tracker.get_summary()
|
|
209
|
+
# Backward compatible alias
|
|
210
|
+
if "tasks_count" not in summary:
|
|
211
|
+
summary["tasks_count"] = summary.get("total_tasks", 0)
|
|
212
|
+
return summary
|
|
213
|
+
return {
|
|
214
|
+
"session_id": self.session_id,
|
|
215
|
+
"metadata": {"pkg_path": str(self.pkg_path)},
|
|
216
|
+
"tasks": {},
|
|
217
|
+
"tasks_count": 0,
|
|
376
218
|
}
|
|
377
|
-
for key, default_value in defaults.items():
|
|
378
|
-
metrics.setdefault(key, default_value)
|
|
379
219
|
|
|
380
|
-
def
|
|
381
|
-
"""
|
|
382
|
-
|
|
383
|
-
if not report.current_metrics:
|
|
384
|
-
return
|
|
385
|
-
|
|
386
|
-
self._display_quality_score(report)
|
|
387
|
-
self._display_quality_trend(report)
|
|
388
|
-
self._display_critical_alerts(report)
|
|
389
|
-
self._display_top_recommendations(report)
|
|
390
|
-
|
|
391
|
-
def _display_quality_score(self, report: t.Any) -> None:
|
|
392
|
-
"""Display the quality score."""
|
|
393
|
-
score = report.current_metrics.quality_score
|
|
394
|
-
self.console.print(f"\n[cyan]📊 Quality Score: {score}/100[/cyan]")
|
|
395
|
-
|
|
396
|
-
def _display_quality_trend(self, report: t.Any) -> None:
|
|
397
|
-
"""Display quality trend information."""
|
|
398
|
-
if not report.trend:
|
|
399
|
-
return
|
|
400
|
-
|
|
401
|
-
trend_emoji = self._get_trend_emoji(report.trend.direction.value)
|
|
402
|
-
self.console.print(
|
|
403
|
-
f"[dim]{trend_emoji} Trend: {report.trend.direction.value} "
|
|
404
|
-
f"({report.trend.confidence:.1%} confidence)[/dim]"
|
|
405
|
-
)
|
|
406
|
-
|
|
407
|
-
def _get_trend_emoji(self, direction: str) -> str:
|
|
408
|
-
"""Get emoji for trend direction."""
|
|
409
|
-
trend_emojis = {
|
|
410
|
-
"improving": "📈",
|
|
411
|
-
"declining": "📉",
|
|
412
|
-
"stable": "📊",
|
|
413
|
-
"volatile": "⚠️",
|
|
414
|
-
}
|
|
415
|
-
return trend_emojis.get(direction, "📊")
|
|
220
|
+
def get_summary(self) -> dict[str, t.Any]:
|
|
221
|
+
"""Alias for get_session_summary."""
|
|
222
|
+
return self.get_session_summary()
|
|
416
223
|
|
|
417
|
-
def _display_critical_alerts(self, report: t.Any) -> None:
|
|
418
|
-
"""Display critical quality alerts."""
|
|
419
|
-
critical_alerts = [a for a in report.alerts if a.severity.value == "critical"]
|
|
420
|
-
if critical_alerts:
|
|
421
|
-
self.console.print(
|
|
422
|
-
f"[red]🚨 {len(critical_alerts)} critical quality issues[/red]"
|
|
423
|
-
)
|
|
424
224
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
if not report.recommendations:
|
|
428
|
-
return
|
|
225
|
+
class SessionController:
|
|
226
|
+
"""Coordinates session setup for the workflow pipeline."""
|
|
429
227
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
self.console.print(f" {rec}")
|
|
228
|
+
def __init__(self, pipeline: WorkflowPipeline) -> None:
|
|
229
|
+
self._pipeline = pipeline
|
|
433
230
|
|
|
434
|
-
|
|
231
|
+
def initialize(self, options: OptionsProtocol) -> None:
|
|
232
|
+
"""Initialize session state and ancillary services."""
|
|
233
|
+
pipeline = self._pipeline
|
|
234
|
+
pipeline.session.initialize_session_tracking(options)
|
|
235
|
+
pipeline._configure_session_cleanup(options)
|
|
236
|
+
pipeline._initialize_zuban_lsp(options)
|
|
237
|
+
pipeline._configure_hook_manager_lsp(options)
|
|
238
|
+
pipeline._register_lsp_cleanup_handler(options)
|
|
239
|
+
pipeline._log_workflow_startup_info(options)
|