crackerjack 0.37.9__py3-none-any.whl → 0.45.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- crackerjack/README.md +19 -0
- crackerjack/__init__.py +30 -1
- crackerjack/__main__.py +342 -1263
- crackerjack/adapters/README.md +18 -0
- crackerjack/adapters/__init__.py +27 -5
- crackerjack/adapters/_output_paths.py +167 -0
- crackerjack/adapters/_qa_adapter_base.py +309 -0
- crackerjack/adapters/_tool_adapter_base.py +706 -0
- crackerjack/adapters/ai/README.md +65 -0
- crackerjack/adapters/ai/__init__.py +5 -0
- crackerjack/adapters/ai/claude.py +853 -0
- crackerjack/adapters/complexity/README.md +53 -0
- crackerjack/adapters/complexity/__init__.py +10 -0
- crackerjack/adapters/complexity/complexipy.py +641 -0
- crackerjack/adapters/dependency/__init__.py +22 -0
- crackerjack/adapters/dependency/pip_audit.py +418 -0
- crackerjack/adapters/format/README.md +72 -0
- crackerjack/adapters/format/__init__.py +11 -0
- crackerjack/adapters/format/mdformat.py +313 -0
- crackerjack/adapters/format/ruff.py +516 -0
- crackerjack/adapters/lint/README.md +47 -0
- crackerjack/adapters/lint/__init__.py +11 -0
- crackerjack/adapters/lint/codespell.py +273 -0
- crackerjack/adapters/lsp/README.md +49 -0
- crackerjack/adapters/lsp/__init__.py +27 -0
- crackerjack/adapters/{rust_tool_manager.py → lsp/_manager.py} +3 -3
- crackerjack/adapters/{skylos_adapter.py → lsp/skylos.py} +59 -7
- crackerjack/adapters/{zuban_adapter.py → lsp/zuban.py} +3 -6
- crackerjack/adapters/refactor/README.md +59 -0
- crackerjack/adapters/refactor/__init__.py +12 -0
- crackerjack/adapters/refactor/creosote.py +318 -0
- crackerjack/adapters/refactor/refurb.py +406 -0
- crackerjack/adapters/refactor/skylos.py +494 -0
- crackerjack/adapters/sast/README.md +132 -0
- crackerjack/adapters/sast/__init__.py +32 -0
- crackerjack/adapters/sast/_base.py +201 -0
- crackerjack/adapters/sast/bandit.py +423 -0
- crackerjack/adapters/sast/pyscn.py +405 -0
- crackerjack/adapters/sast/semgrep.py +241 -0
- crackerjack/adapters/security/README.md +111 -0
- crackerjack/adapters/security/__init__.py +17 -0
- crackerjack/adapters/security/gitleaks.py +339 -0
- crackerjack/adapters/type/README.md +52 -0
- crackerjack/adapters/type/__init__.py +12 -0
- crackerjack/adapters/type/pyrefly.py +402 -0
- crackerjack/adapters/type/ty.py +402 -0
- crackerjack/adapters/type/zuban.py +522 -0
- crackerjack/adapters/utility/README.md +51 -0
- crackerjack/adapters/utility/__init__.py +10 -0
- crackerjack/adapters/utility/checks.py +884 -0
- crackerjack/agents/README.md +264 -0
- crackerjack/agents/__init__.py +40 -12
- crackerjack/agents/base.py +1 -0
- crackerjack/agents/claude_code_bridge.py +641 -0
- crackerjack/agents/coordinator.py +49 -53
- crackerjack/agents/dry_agent.py +187 -3
- crackerjack/agents/enhanced_coordinator.py +279 -0
- crackerjack/agents/enhanced_proactive_agent.py +185 -0
- crackerjack/agents/error_middleware.py +53 -0
- crackerjack/agents/formatting_agent.py +6 -8
- crackerjack/agents/helpers/__init__.py +9 -0
- crackerjack/agents/helpers/performance/__init__.py +22 -0
- crackerjack/agents/helpers/performance/performance_ast_analyzer.py +357 -0
- crackerjack/agents/helpers/performance/performance_pattern_detector.py +909 -0
- crackerjack/agents/helpers/performance/performance_recommender.py +572 -0
- crackerjack/agents/helpers/refactoring/__init__.py +22 -0
- crackerjack/agents/helpers/refactoring/code_transformer.py +536 -0
- crackerjack/agents/helpers/refactoring/complexity_analyzer.py +344 -0
- crackerjack/agents/helpers/refactoring/dead_code_detector.py +437 -0
- crackerjack/agents/helpers/test_creation/__init__.py +19 -0
- crackerjack/agents/helpers/test_creation/test_ast_analyzer.py +216 -0
- crackerjack/agents/helpers/test_creation/test_coverage_analyzer.py +643 -0
- crackerjack/agents/helpers/test_creation/test_template_generator.py +1031 -0
- crackerjack/agents/performance_agent.py +121 -1152
- crackerjack/agents/refactoring_agent.py +156 -655
- crackerjack/agents/semantic_agent.py +479 -0
- crackerjack/agents/semantic_helpers.py +356 -0
- crackerjack/agents/test_creation_agent.py +19 -1605
- crackerjack/api.py +5 -7
- crackerjack/cli/README.md +394 -0
- crackerjack/cli/__init__.py +1 -1
- crackerjack/cli/cache_handlers.py +23 -18
- crackerjack/cli/cache_handlers_enhanced.py +1 -4
- crackerjack/cli/facade.py +70 -8
- crackerjack/cli/formatting.py +13 -0
- crackerjack/cli/handlers/__init__.py +85 -0
- crackerjack/cli/handlers/advanced.py +103 -0
- crackerjack/cli/handlers/ai_features.py +62 -0
- crackerjack/cli/handlers/analytics.py +479 -0
- crackerjack/cli/handlers/changelog.py +271 -0
- crackerjack/cli/handlers/config_handlers.py +16 -0
- crackerjack/cli/handlers/coverage.py +84 -0
- crackerjack/cli/handlers/documentation.py +280 -0
- crackerjack/cli/handlers/main_handlers.py +497 -0
- crackerjack/cli/handlers/monitoring.py +371 -0
- crackerjack/cli/handlers.py +249 -49
- crackerjack/cli/interactive.py +8 -5
- crackerjack/cli/options.py +203 -110
- crackerjack/cli/semantic_handlers.py +292 -0
- crackerjack/cli/version.py +19 -0
- crackerjack/code_cleaner.py +60 -24
- crackerjack/config/README.md +472 -0
- crackerjack/config/__init__.py +256 -0
- crackerjack/config/global_lock_config.py +191 -54
- crackerjack/config/hooks.py +188 -16
- crackerjack/config/loader.py +239 -0
- crackerjack/config/settings.py +141 -0
- crackerjack/config/tool_commands.py +331 -0
- crackerjack/core/README.md +393 -0
- crackerjack/core/async_workflow_orchestrator.py +79 -53
- crackerjack/core/autofix_coordinator.py +22 -9
- crackerjack/core/container.py +10 -9
- crackerjack/core/enhanced_container.py +9 -9
- crackerjack/core/performance.py +1 -1
- crackerjack/core/performance_monitor.py +5 -3
- crackerjack/core/phase_coordinator.py +1018 -634
- crackerjack/core/proactive_workflow.py +3 -3
- crackerjack/core/retry.py +275 -0
- crackerjack/core/service_watchdog.py +167 -23
- crackerjack/core/session_coordinator.py +187 -382
- crackerjack/core/timeout_manager.py +161 -44
- crackerjack/core/workflow/__init__.py +21 -0
- crackerjack/core/workflow/workflow_ai_coordinator.py +863 -0
- crackerjack/core/workflow/workflow_event_orchestrator.py +1107 -0
- crackerjack/core/workflow/workflow_issue_parser.py +714 -0
- crackerjack/core/workflow/workflow_phase_executor.py +1158 -0
- crackerjack/core/workflow/workflow_security_gates.py +400 -0
- crackerjack/core/workflow_orchestrator.py +1247 -953
- crackerjack/data/README.md +11 -0
- crackerjack/data/__init__.py +8 -0
- crackerjack/data/models.py +79 -0
- crackerjack/data/repository.py +210 -0
- crackerjack/decorators/README.md +180 -0
- crackerjack/decorators/__init__.py +35 -0
- crackerjack/decorators/error_handling.py +649 -0
- crackerjack/decorators/error_handling_decorators.py +334 -0
- crackerjack/decorators/helpers.py +58 -0
- crackerjack/decorators/patterns.py +281 -0
- crackerjack/decorators/utils.py +58 -0
- crackerjack/docs/README.md +11 -0
- crackerjack/docs/generated/api/CLI_REFERENCE.md +1 -1
- crackerjack/documentation/README.md +11 -0
- crackerjack/documentation/ai_templates.py +1 -1
- crackerjack/documentation/dual_output_generator.py +11 -9
- crackerjack/documentation/reference_generator.py +104 -59
- crackerjack/dynamic_config.py +52 -61
- crackerjack/errors.py +1 -1
- crackerjack/events/README.md +11 -0
- crackerjack/events/__init__.py +16 -0
- crackerjack/events/telemetry.py +175 -0
- crackerjack/events/workflow_bus.py +346 -0
- crackerjack/exceptions/README.md +301 -0
- crackerjack/exceptions/__init__.py +5 -0
- crackerjack/exceptions/config.py +4 -0
- crackerjack/exceptions/tool_execution_error.py +245 -0
- crackerjack/executors/README.md +591 -0
- crackerjack/executors/__init__.py +2 -0
- crackerjack/executors/async_hook_executor.py +539 -77
- crackerjack/executors/cached_hook_executor.py +3 -3
- crackerjack/executors/hook_executor.py +967 -102
- crackerjack/executors/hook_lock_manager.py +31 -22
- crackerjack/executors/individual_hook_executor.py +66 -32
- crackerjack/executors/lsp_aware_hook_executor.py +136 -57
- crackerjack/executors/progress_hook_executor.py +282 -0
- crackerjack/executors/tool_proxy.py +23 -7
- crackerjack/hooks/README.md +485 -0
- crackerjack/hooks/lsp_hook.py +8 -9
- crackerjack/intelligence/README.md +557 -0
- crackerjack/interactive.py +37 -10
- crackerjack/managers/README.md +369 -0
- crackerjack/managers/async_hook_manager.py +41 -57
- crackerjack/managers/hook_manager.py +449 -79
- crackerjack/managers/publish_manager.py +81 -36
- crackerjack/managers/test_command_builder.py +290 -12
- crackerjack/managers/test_executor.py +93 -8
- crackerjack/managers/test_manager.py +1082 -75
- crackerjack/managers/test_progress.py +118 -26
- crackerjack/mcp/README.md +374 -0
- crackerjack/mcp/cache.py +25 -2
- crackerjack/mcp/client_runner.py +35 -18
- crackerjack/mcp/context.py +9 -9
- crackerjack/mcp/dashboard.py +24 -8
- crackerjack/mcp/enhanced_progress_monitor.py +34 -23
- crackerjack/mcp/file_monitor.py +27 -6
- crackerjack/mcp/progress_components.py +45 -34
- crackerjack/mcp/progress_monitor.py +6 -9
- crackerjack/mcp/rate_limiter.py +11 -7
- crackerjack/mcp/server.py +2 -0
- crackerjack/mcp/server_core.py +187 -55
- crackerjack/mcp/service_watchdog.py +12 -9
- crackerjack/mcp/task_manager.py +2 -2
- crackerjack/mcp/tools/README.md +27 -0
- crackerjack/mcp/tools/__init__.py +2 -0
- crackerjack/mcp/tools/core_tools.py +75 -52
- crackerjack/mcp/tools/execution_tools.py +87 -31
- crackerjack/mcp/tools/intelligence_tools.py +2 -2
- crackerjack/mcp/tools/proactive_tools.py +1 -1
- crackerjack/mcp/tools/semantic_tools.py +584 -0
- crackerjack/mcp/tools/utility_tools.py +180 -132
- crackerjack/mcp/tools/workflow_executor.py +87 -46
- crackerjack/mcp/websocket/README.md +31 -0
- crackerjack/mcp/websocket/app.py +11 -1
- crackerjack/mcp/websocket/event_bridge.py +188 -0
- crackerjack/mcp/websocket/jobs.py +27 -4
- crackerjack/mcp/websocket/monitoring/__init__.py +25 -0
- crackerjack/mcp/websocket/monitoring/api/__init__.py +19 -0
- crackerjack/mcp/websocket/monitoring/api/dependencies.py +141 -0
- crackerjack/mcp/websocket/monitoring/api/heatmap.py +154 -0
- crackerjack/mcp/websocket/monitoring/api/intelligence.py +199 -0
- crackerjack/mcp/websocket/monitoring/api/metrics.py +203 -0
- crackerjack/mcp/websocket/monitoring/api/telemetry.py +101 -0
- crackerjack/mcp/websocket/monitoring/dashboard.py +18 -0
- crackerjack/mcp/websocket/monitoring/factory.py +109 -0
- crackerjack/mcp/websocket/monitoring/filters.py +10 -0
- crackerjack/mcp/websocket/monitoring/metrics.py +64 -0
- crackerjack/mcp/websocket/monitoring/models.py +90 -0
- crackerjack/mcp/websocket/monitoring/utils.py +171 -0
- crackerjack/mcp/websocket/monitoring/websocket_manager.py +78 -0
- crackerjack/mcp/websocket/monitoring/websockets/__init__.py +17 -0
- crackerjack/mcp/websocket/monitoring/websockets/dependencies.py +126 -0
- crackerjack/mcp/websocket/monitoring/websockets/heatmap.py +176 -0
- crackerjack/mcp/websocket/monitoring/websockets/intelligence.py +291 -0
- crackerjack/mcp/websocket/monitoring/websockets/metrics.py +291 -0
- crackerjack/mcp/websocket/monitoring_endpoints.py +16 -2930
- crackerjack/mcp/websocket/server.py +1 -3
- crackerjack/mcp/websocket/websocket_handler.py +107 -6
- crackerjack/models/README.md +308 -0
- crackerjack/models/__init__.py +10 -1
- crackerjack/models/config.py +639 -22
- crackerjack/models/config_adapter.py +6 -6
- crackerjack/models/protocols.py +1167 -23
- crackerjack/models/pydantic_models.py +320 -0
- crackerjack/models/qa_config.py +145 -0
- crackerjack/models/qa_results.py +134 -0
- crackerjack/models/results.py +35 -0
- crackerjack/models/semantic_models.py +258 -0
- crackerjack/models/task.py +19 -3
- crackerjack/models/test_models.py +60 -0
- crackerjack/monitoring/README.md +11 -0
- crackerjack/monitoring/ai_agent_watchdog.py +5 -4
- crackerjack/monitoring/metrics_collector.py +4 -3
- crackerjack/monitoring/regression_prevention.py +4 -3
- crackerjack/monitoring/websocket_server.py +4 -241
- crackerjack/orchestration/README.md +340 -0
- crackerjack/orchestration/__init__.py +43 -0
- crackerjack/orchestration/advanced_orchestrator.py +20 -67
- crackerjack/orchestration/cache/README.md +312 -0
- crackerjack/orchestration/cache/__init__.py +37 -0
- crackerjack/orchestration/cache/memory_cache.py +338 -0
- crackerjack/orchestration/cache/tool_proxy_cache.py +340 -0
- crackerjack/orchestration/config.py +297 -0
- crackerjack/orchestration/coverage_improvement.py +13 -6
- crackerjack/orchestration/execution_strategies.py +6 -6
- crackerjack/orchestration/hook_orchestrator.py +1398 -0
- crackerjack/orchestration/strategies/README.md +401 -0
- crackerjack/orchestration/strategies/__init__.py +39 -0
- crackerjack/orchestration/strategies/adaptive_strategy.py +630 -0
- crackerjack/orchestration/strategies/parallel_strategy.py +237 -0
- crackerjack/orchestration/strategies/sequential_strategy.py +299 -0
- crackerjack/orchestration/test_progress_streamer.py +1 -1
- crackerjack/plugins/README.md +11 -0
- crackerjack/plugins/hooks.py +3 -2
- crackerjack/plugins/loader.py +3 -3
- crackerjack/plugins/managers.py +1 -1
- crackerjack/py313.py +191 -0
- crackerjack/security/README.md +11 -0
- crackerjack/services/README.md +374 -0
- crackerjack/services/__init__.py +8 -21
- crackerjack/services/ai/README.md +295 -0
- crackerjack/services/ai/__init__.py +7 -0
- crackerjack/services/ai/advanced_optimizer.py +878 -0
- crackerjack/services/{contextual_ai_assistant.py → ai/contextual_ai_assistant.py} +5 -3
- crackerjack/services/ai/embeddings.py +444 -0
- crackerjack/services/ai/intelligent_commit.py +328 -0
- crackerjack/services/ai/predictive_analytics.py +510 -0
- crackerjack/services/api_extractor.py +5 -3
- crackerjack/services/bounded_status_operations.py +45 -5
- crackerjack/services/cache.py +249 -318
- crackerjack/services/changelog_automation.py +7 -3
- crackerjack/services/command_execution_service.py +305 -0
- crackerjack/services/config_integrity.py +83 -39
- crackerjack/services/config_merge.py +9 -6
- crackerjack/services/config_service.py +198 -0
- crackerjack/services/config_template.py +13 -26
- crackerjack/services/coverage_badge_service.py +6 -4
- crackerjack/services/coverage_ratchet.py +53 -27
- crackerjack/services/debug.py +18 -7
- crackerjack/services/dependency_analyzer.py +4 -4
- crackerjack/services/dependency_monitor.py +13 -13
- crackerjack/services/documentation_generator.py +4 -2
- crackerjack/services/documentation_service.py +62 -33
- crackerjack/services/enhanced_filesystem.py +81 -27
- crackerjack/services/enterprise_optimizer.py +1 -1
- crackerjack/services/error_pattern_analyzer.py +10 -10
- crackerjack/services/file_filter.py +221 -0
- crackerjack/services/file_hasher.py +5 -7
- crackerjack/services/file_io_service.py +361 -0
- crackerjack/services/file_modifier.py +615 -0
- crackerjack/services/filesystem.py +80 -109
- crackerjack/services/git.py +99 -5
- crackerjack/services/health_metrics.py +4 -6
- crackerjack/services/heatmap_generator.py +12 -3
- crackerjack/services/incremental_executor.py +380 -0
- crackerjack/services/initialization.py +101 -49
- crackerjack/services/log_manager.py +2 -2
- crackerjack/services/logging.py +120 -68
- crackerjack/services/lsp_client.py +12 -12
- crackerjack/services/memory_optimizer.py +27 -22
- crackerjack/services/monitoring/README.md +30 -0
- crackerjack/services/monitoring/__init__.py +9 -0
- crackerjack/services/monitoring/dependency_monitor.py +678 -0
- crackerjack/services/monitoring/error_pattern_analyzer.py +676 -0
- crackerjack/services/monitoring/health_metrics.py +716 -0
- crackerjack/services/monitoring/metrics.py +587 -0
- crackerjack/services/{performance_benchmarks.py → monitoring/performance_benchmarks.py} +100 -14
- crackerjack/services/{performance_cache.py → monitoring/performance_cache.py} +21 -15
- crackerjack/services/{performance_monitor.py → monitoring/performance_monitor.py} +10 -6
- crackerjack/services/parallel_executor.py +166 -55
- crackerjack/services/patterns/__init__.py +142 -0
- crackerjack/services/patterns/agents.py +107 -0
- crackerjack/services/patterns/code/__init__.py +15 -0
- crackerjack/services/patterns/code/detection.py +118 -0
- crackerjack/services/patterns/code/imports.py +107 -0
- crackerjack/services/patterns/code/paths.py +159 -0
- crackerjack/services/patterns/code/performance.py +119 -0
- crackerjack/services/patterns/code/replacement.py +36 -0
- crackerjack/services/patterns/core.py +212 -0
- crackerjack/services/patterns/documentation/__init__.py +14 -0
- crackerjack/services/patterns/documentation/badges_markdown.py +96 -0
- crackerjack/services/patterns/documentation/comments_blocks.py +83 -0
- crackerjack/services/patterns/documentation/docstrings.py +89 -0
- crackerjack/services/patterns/formatting.py +226 -0
- crackerjack/services/patterns/operations.py +339 -0
- crackerjack/services/patterns/security/__init__.py +23 -0
- crackerjack/services/patterns/security/code_injection.py +122 -0
- crackerjack/services/patterns/security/credentials.py +190 -0
- crackerjack/services/patterns/security/path_traversal.py +221 -0
- crackerjack/services/patterns/security/unsafe_operations.py +216 -0
- crackerjack/services/patterns/templates.py +62 -0
- crackerjack/services/patterns/testing/__init__.py +18 -0
- crackerjack/services/patterns/testing/error_patterns.py +107 -0
- crackerjack/services/patterns/testing/pytest_output.py +126 -0
- crackerjack/services/patterns/tool_output/__init__.py +16 -0
- crackerjack/services/patterns/tool_output/bandit.py +72 -0
- crackerjack/services/patterns/tool_output/other.py +97 -0
- crackerjack/services/patterns/tool_output/pyright.py +67 -0
- crackerjack/services/patterns/tool_output/ruff.py +44 -0
- crackerjack/services/patterns/url_sanitization.py +114 -0
- crackerjack/services/patterns/utilities.py +42 -0
- crackerjack/services/patterns/utils.py +339 -0
- crackerjack/services/patterns/validation.py +46 -0
- crackerjack/services/patterns/versioning.py +62 -0
- crackerjack/services/predictive_analytics.py +21 -8
- crackerjack/services/profiler.py +280 -0
- crackerjack/services/quality/README.md +415 -0
- crackerjack/services/quality/__init__.py +11 -0
- crackerjack/services/quality/anomaly_detector.py +392 -0
- crackerjack/services/quality/pattern_cache.py +333 -0
- crackerjack/services/quality/pattern_detector.py +479 -0
- crackerjack/services/quality/qa_orchestrator.py +491 -0
- crackerjack/services/{quality_baseline.py → quality/quality_baseline.py} +163 -2
- crackerjack/services/{quality_baseline_enhanced.py → quality/quality_baseline_enhanced.py} +4 -1
- crackerjack/services/{quality_intelligence.py → quality/quality_intelligence.py} +180 -16
- crackerjack/services/regex_patterns.py +58 -2987
- crackerjack/services/regex_utils.py +55 -29
- crackerjack/services/secure_status_formatter.py +42 -15
- crackerjack/services/secure_subprocess.py +35 -2
- crackerjack/services/security.py +16 -8
- crackerjack/services/server_manager.py +40 -51
- crackerjack/services/smart_scheduling.py +46 -6
- crackerjack/services/status_authentication.py +3 -3
- crackerjack/services/thread_safe_status_collector.py +1 -0
- crackerjack/services/tool_filter.py +368 -0
- crackerjack/services/tool_version_service.py +9 -5
- crackerjack/services/unified_config.py +43 -351
- crackerjack/services/vector_store.py +689 -0
- crackerjack/services/version_analyzer.py +6 -4
- crackerjack/services/version_checker.py +14 -8
- crackerjack/services/zuban_lsp_service.py +5 -4
- crackerjack/slash_commands/README.md +11 -0
- crackerjack/slash_commands/init.md +2 -12
- crackerjack/slash_commands/run.md +84 -50
- crackerjack/tools/README.md +11 -0
- crackerjack/tools/__init__.py +30 -0
- crackerjack/tools/_git_utils.py +105 -0
- crackerjack/tools/check_added_large_files.py +139 -0
- crackerjack/tools/check_ast.py +105 -0
- crackerjack/tools/check_json.py +103 -0
- crackerjack/tools/check_jsonschema.py +297 -0
- crackerjack/tools/check_toml.py +103 -0
- crackerjack/tools/check_yaml.py +110 -0
- crackerjack/tools/codespell_wrapper.py +72 -0
- crackerjack/tools/end_of_file_fixer.py +202 -0
- crackerjack/tools/format_json.py +128 -0
- crackerjack/tools/mdformat_wrapper.py +114 -0
- crackerjack/tools/trailing_whitespace.py +198 -0
- crackerjack/tools/validate_regex_patterns.py +7 -3
- crackerjack/ui/README.md +11 -0
- crackerjack/ui/dashboard_renderer.py +28 -0
- crackerjack/ui/templates/README.md +11 -0
- crackerjack/utils/console_utils.py +13 -0
- crackerjack/utils/dependency_guard.py +230 -0
- crackerjack/utils/retry_utils.py +275 -0
- crackerjack/workflows/README.md +590 -0
- crackerjack/workflows/__init__.py +46 -0
- crackerjack/workflows/actions.py +811 -0
- crackerjack/workflows/auto_fix.py +444 -0
- crackerjack/workflows/container_builder.py +499 -0
- crackerjack/workflows/definitions.py +443 -0
- crackerjack/workflows/engine.py +177 -0
- crackerjack/workflows/event_bridge.py +242 -0
- {crackerjack-0.37.9.dist-info → crackerjack-0.45.2.dist-info}/METADATA +678 -98
- crackerjack-0.45.2.dist-info/RECORD +478 -0
- {crackerjack-0.37.9.dist-info → crackerjack-0.45.2.dist-info}/WHEEL +1 -1
- crackerjack/managers/test_manager_backup.py +0 -1075
- crackerjack/mcp/tools/execution_tools_backup.py +0 -1011
- crackerjack/mixins/__init__.py +0 -3
- crackerjack/mixins/error_handling.py +0 -145
- crackerjack/services/config.py +0 -358
- crackerjack/ui/server_panels.py +0 -125
- crackerjack-0.37.9.dist-info/RECORD +0 -231
- /crackerjack/adapters/{rust_tool_adapter.py → lsp/_base.py} +0 -0
- /crackerjack/adapters/{lsp_client.py → lsp/_client.py} +0 -0
- {crackerjack-0.37.9.dist-info → crackerjack-0.45.2.dist-info}/entry_points.txt +0 -0
- {crackerjack-0.37.9.dist-info → crackerjack-0.45.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"""Generic configuration loading and validation service."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
import yaml
|
|
8
|
+
from loguru import logger
|
|
9
|
+
from pydantic import BaseModel, ValidationError
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ConfigService:
|
|
13
|
+
"""Generic configuration loading and validation service."""
|
|
14
|
+
|
|
15
|
+
@staticmethod
|
|
16
|
+
def load_config(path: str | Path) -> dict[str, Any]:
|
|
17
|
+
"""
|
|
18
|
+
Load configuration file based on extension.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
path: Path to the configuration file
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
Dictionary with configuration data
|
|
25
|
+
|
|
26
|
+
Raises:
|
|
27
|
+
ValueError: If file extension is not supported
|
|
28
|
+
FileNotFoundError: If the file doesn't exist
|
|
29
|
+
Exception: For other file loading errors
|
|
30
|
+
"""
|
|
31
|
+
path = Path(path)
|
|
32
|
+
|
|
33
|
+
if not path.exists():
|
|
34
|
+
raise FileNotFoundError(f"Configuration file does not exist: {path}")
|
|
35
|
+
|
|
36
|
+
if path.suffix.lower() == ".json":
|
|
37
|
+
return ConfigService._load_json(path)
|
|
38
|
+
elif path.suffix.lower() in (".yml", ".yaml"):
|
|
39
|
+
return ConfigService._load_yaml(path)
|
|
40
|
+
elif path.suffix.lower() == ".toml":
|
|
41
|
+
return ConfigService._load_toml(path)
|
|
42
|
+
else:
|
|
43
|
+
raise ValueError(f"Unsupported config format: {path.suffix}")
|
|
44
|
+
|
|
45
|
+
@staticmethod
|
|
46
|
+
async def load_config_async(path: str | Path) -> dict[str, Any]:
|
|
47
|
+
"""
|
|
48
|
+
Asynchronously load configuration file based on extension.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
path: Path to the configuration file
|
|
52
|
+
|
|
53
|
+
Returns:
|
|
54
|
+
Dictionary with configuration data
|
|
55
|
+
|
|
56
|
+
Raises:
|
|
57
|
+
ValueError: If file extension is not supported
|
|
58
|
+
FileNotFoundError: If the file doesn't exist
|
|
59
|
+
Exception: For other file loading errors
|
|
60
|
+
"""
|
|
61
|
+
from crackerjack.services.file_io_service import FileIOService
|
|
62
|
+
|
|
63
|
+
path = Path(path)
|
|
64
|
+
|
|
65
|
+
if not path.exists():
|
|
66
|
+
raise FileNotFoundError(f"Configuration file does not exist: {path}")
|
|
67
|
+
|
|
68
|
+
if path.suffix.lower() == ".json":
|
|
69
|
+
content = await FileIOService.read_text_file(path)
|
|
70
|
+
return json.loads(content)
|
|
71
|
+
elif path.suffix.lower() in (".yml", ".yaml"):
|
|
72
|
+
content = await FileIOService.read_text_file(path)
|
|
73
|
+
return yaml.safe_load(content)
|
|
74
|
+
elif path.suffix.lower() == ".toml":
|
|
75
|
+
content = await FileIOService.read_text_file(path)
|
|
76
|
+
import toml
|
|
77
|
+
|
|
78
|
+
return toml.loads(content)
|
|
79
|
+
else:
|
|
80
|
+
raise ValueError(f"Unsupported config format: {path.suffix}")
|
|
81
|
+
|
|
82
|
+
@staticmethod
|
|
83
|
+
def _load_json(path: Path) -> dict[str, Any]:
|
|
84
|
+
"""Load JSON configuration."""
|
|
85
|
+
with path.open(encoding="utf-8") as f:
|
|
86
|
+
return json.load(f)
|
|
87
|
+
|
|
88
|
+
@staticmethod
|
|
89
|
+
def _load_yaml(path: Path) -> dict[str, Any]:
|
|
90
|
+
"""Load YAML configuration."""
|
|
91
|
+
with path.open(encoding="utf-8") as f:
|
|
92
|
+
return yaml.safe_load(f)
|
|
93
|
+
|
|
94
|
+
@staticmethod
|
|
95
|
+
def _load_toml(path: Path) -> dict[str, Any]:
|
|
96
|
+
"""Load TOML configuration."""
|
|
97
|
+
import toml
|
|
98
|
+
|
|
99
|
+
with path.open("r", encoding="utf-8") as f:
|
|
100
|
+
return toml.load(f)
|
|
101
|
+
|
|
102
|
+
@staticmethod
|
|
103
|
+
def validate_config(
|
|
104
|
+
config: dict[str, Any], model_class: type[BaseModel]
|
|
105
|
+
) -> BaseModel:
|
|
106
|
+
"""
|
|
107
|
+
Validate configuration against a Pydantic model.
|
|
108
|
+
|
|
109
|
+
Args:
|
|
110
|
+
config: Configuration dictionary to validate
|
|
111
|
+
model_class: Pydantic model class to validate against
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
Validated Pydantic model instance
|
|
115
|
+
|
|
116
|
+
Raises:
|
|
117
|
+
ValidationError: If the configuration doesn't match the model
|
|
118
|
+
"""
|
|
119
|
+
try:
|
|
120
|
+
return model_class.model_validate(config)
|
|
121
|
+
except ValidationError as e:
|
|
122
|
+
logger.error(f"Config validation failed: {e}")
|
|
123
|
+
raise
|
|
124
|
+
|
|
125
|
+
@staticmethod
|
|
126
|
+
def save_config(
|
|
127
|
+
config: dict[str, Any], path: str | Path, format: str | None = None
|
|
128
|
+
) -> None:
|
|
129
|
+
"""
|
|
130
|
+
Save configuration to file.
|
|
131
|
+
|
|
132
|
+
Args:
|
|
133
|
+
config: Configuration dictionary to save
|
|
134
|
+
path: Path to save the configuration to
|
|
135
|
+
format: Format to save as ('json', 'yaml', 'toml'). If None, inferred from path extension.
|
|
136
|
+
"""
|
|
137
|
+
path = Path(path)
|
|
138
|
+
format = format or path.suffix.lower().lstrip(".")
|
|
139
|
+
|
|
140
|
+
# Create parent directories if they don't exist
|
|
141
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
142
|
+
|
|
143
|
+
if format == "json":
|
|
144
|
+
ConfigService._save_json(config, path)
|
|
145
|
+
elif format in ("yml", "yaml"):
|
|
146
|
+
ConfigService._save_yaml(config, path)
|
|
147
|
+
elif format == "toml":
|
|
148
|
+
ConfigService._save_toml(config, path)
|
|
149
|
+
else:
|
|
150
|
+
raise ValueError(f"Unsupported config format: {format}")
|
|
151
|
+
|
|
152
|
+
@staticmethod
|
|
153
|
+
def _save_json(config: dict[str, Any], path: Path) -> None:
|
|
154
|
+
"""Save configuration as JSON."""
|
|
155
|
+
with path.open("w", encoding="utf-8") as f:
|
|
156
|
+
json.dump(config, f, indent=2, ensure_ascii=False)
|
|
157
|
+
|
|
158
|
+
@staticmethod
|
|
159
|
+
def _save_yaml(config: dict[str, Any], path: Path) -> None:
|
|
160
|
+
"""Save configuration as YAML."""
|
|
161
|
+
with path.open("w", encoding="utf-8") as f:
|
|
162
|
+
yaml.dump(config, f, default_flow_style=False, allow_unicode=True)
|
|
163
|
+
|
|
164
|
+
@staticmethod
|
|
165
|
+
def _save_toml(config: dict[str, Any], path: Path) -> None:
|
|
166
|
+
"""Save configuration as TOML."""
|
|
167
|
+
import toml
|
|
168
|
+
|
|
169
|
+
with path.open("w", encoding="utf-8") as f:
|
|
170
|
+
toml.dump(config, f)
|
|
171
|
+
|
|
172
|
+
@staticmethod
|
|
173
|
+
def merge_configs(
|
|
174
|
+
base_config: dict[str, Any], override_config: dict[str, Any]
|
|
175
|
+
) -> dict[str, Any]:
|
|
176
|
+
"""
|
|
177
|
+
Recursively merge two configuration dictionaries.
|
|
178
|
+
|
|
179
|
+
Args:
|
|
180
|
+
base_config: Base configuration
|
|
181
|
+
override_config: Configuration to merge on top of base
|
|
182
|
+
|
|
183
|
+
Returns:
|
|
184
|
+
Merged configuration dictionary
|
|
185
|
+
"""
|
|
186
|
+
result = base_config.copy()
|
|
187
|
+
|
|
188
|
+
for key, value in override_config.items():
|
|
189
|
+
if (
|
|
190
|
+
key in result
|
|
191
|
+
and isinstance(result[key], dict)
|
|
192
|
+
and isinstance(value, dict)
|
|
193
|
+
):
|
|
194
|
+
result[key] = ConfigService.merge_configs(result[key], value)
|
|
195
|
+
else:
|
|
196
|
+
result[key] = value
|
|
197
|
+
|
|
198
|
+
return result
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import hashlib
|
|
2
|
-
import subprocess
|
|
3
2
|
import typing as t
|
|
4
3
|
from contextlib import suppress
|
|
5
4
|
from dataclasses import dataclass, field
|
|
@@ -8,7 +7,7 @@ from pathlib import Path
|
|
|
8
7
|
|
|
9
8
|
import tomli
|
|
10
9
|
import yaml
|
|
11
|
-
from
|
|
10
|
+
from acb.console import Console
|
|
12
11
|
|
|
13
12
|
|
|
14
13
|
@dataclass
|
|
@@ -95,12 +94,13 @@ class ConfigTemplateService:
|
|
|
95
94
|
"stages": ["pre-push", "manual"],
|
|
96
95
|
},
|
|
97
96
|
{
|
|
98
|
-
"id": "
|
|
99
|
-
"name": "
|
|
100
|
-
"entry": "uv run
|
|
97
|
+
"id": "zuban",
|
|
98
|
+
"name": "zuban-type-checking",
|
|
99
|
+
"entry": "uv run zuban check",
|
|
101
100
|
"language": "system",
|
|
102
|
-
"
|
|
103
|
-
"
|
|
101
|
+
"args": ["--config-file", "mypy.ini", "./crackerjack"],
|
|
102
|
+
"pass_filenames": False,
|
|
103
|
+
"exclude": r"^tests/|^src/",
|
|
104
104
|
"stages": ["pre-push", "manual"],
|
|
105
105
|
},
|
|
106
106
|
]
|
|
@@ -377,7 +377,7 @@ class ConfigTemplateService:
|
|
|
377
377
|
)
|
|
378
378
|
|
|
379
379
|
self._update_version_tracking(project_path, "pre-commit", template.version)
|
|
380
|
-
self.
|
|
380
|
+
self._invalidate_cache(project_path)
|
|
381
381
|
|
|
382
382
|
self.console.print(
|
|
383
383
|
f"[green]✅[/green] Updated {config_file.name} to version {template.version}"
|
|
@@ -452,7 +452,7 @@ class ConfigTemplateService:
|
|
|
452
452
|
"""Update version tracking file."""
|
|
453
453
|
version_file = project_path / ".crackerjack-config.yaml"
|
|
454
454
|
|
|
455
|
-
data = {"version": "1.0.0", "configs": {}}
|
|
455
|
+
data: dict[str, t.Any] = {"version": "1.0.0", "configs": {}}
|
|
456
456
|
if version_file.exists():
|
|
457
457
|
with suppress(Exception):
|
|
458
458
|
with version_file.open() as f:
|
|
@@ -472,23 +472,10 @@ class ConfigTemplateService:
|
|
|
472
472
|
with version_file.open("w") as f:
|
|
473
473
|
yaml.dump(data, f, default_flow_style=False, sort_keys=False)
|
|
474
474
|
|
|
475
|
-
def
|
|
476
|
-
"""Invalidate
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
["pre-commit", "clean"],
|
|
480
|
-
cwd=project_path,
|
|
481
|
-
capture_output=True,
|
|
482
|
-
text=True,
|
|
483
|
-
timeout=30,
|
|
484
|
-
)
|
|
485
|
-
subprocess.run(
|
|
486
|
-
["pre-commit", "install"],
|
|
487
|
-
cwd=project_path,
|
|
488
|
-
capture_output=True,
|
|
489
|
-
text=True,
|
|
490
|
-
timeout=30,
|
|
491
|
-
)
|
|
475
|
+
def _invalidate_cache(self, project_path: Path) -> None:
|
|
476
|
+
"""Invalidate cache to ensure fresh environment."""
|
|
477
|
+
# No-op in the new system - cache invalidation handled differently
|
|
478
|
+
pass
|
|
492
479
|
|
|
493
480
|
def get_config_hash(self, config_path: Path) -> str:
|
|
494
481
|
"""Generate hash of configuration file for cache invalidation."""
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
from contextlib import suppress
|
|
2
2
|
from pathlib import Path
|
|
3
3
|
|
|
4
|
-
from
|
|
4
|
+
from acb.console import Console
|
|
5
|
+
from acb.depends import Inject, depends
|
|
5
6
|
|
|
6
7
|
from .regex_patterns import SAFE_PATTERNS
|
|
7
8
|
|
|
@@ -9,7 +10,8 @@ from .regex_patterns import SAFE_PATTERNS
|
|
|
9
10
|
class CoverageBadgeService:
|
|
10
11
|
"""Service for managing coverage badges in README.md files."""
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
@depends.inject
|
|
14
|
+
def __init__(self, console: Inject[Console], project_root: Path) -> None:
|
|
13
15
|
self.console = console
|
|
14
16
|
self.project_root = project_root
|
|
15
17
|
self.readme_path = project_root / "README.md"
|
|
@@ -154,8 +156,8 @@ class CoverageBadgeService:
|
|
|
154
156
|
if current_coverage is None:
|
|
155
157
|
return True # No badge exists, should add one
|
|
156
158
|
|
|
157
|
-
# Only update if coverage changed by at least 0.
|
|
158
|
-
return abs(coverage_percent - current_coverage) >= 0.
|
|
159
|
+
# Only update if coverage changed by at least 0.01% (more accurate reporting)
|
|
160
|
+
return abs(coverage_percent - current_coverage) >= 0.01
|
|
159
161
|
|
|
160
162
|
except Exception:
|
|
161
163
|
return True # On error, attempt update
|
|
@@ -3,20 +3,66 @@ import typing as t
|
|
|
3
3
|
from datetime import datetime
|
|
4
4
|
from pathlib import Path
|
|
5
5
|
|
|
6
|
-
from
|
|
6
|
+
from acb.console import Console
|
|
7
|
+
from acb.depends import Inject, depends
|
|
7
8
|
from rich.progress import BarColumn, Progress, SpinnerColumn, TextColumn
|
|
8
9
|
|
|
10
|
+
from crackerjack.models.protocols import CoverageRatchetProtocol
|
|
11
|
+
from crackerjack.services.filesystem import FileSystemService
|
|
12
|
+
from crackerjack.services.regex_patterns import update_coverage_requirement
|
|
9
13
|
|
|
10
|
-
|
|
14
|
+
|
|
15
|
+
class CoverageRatchetService(CoverageRatchetProtocol):
|
|
11
16
|
MILESTONES = [15, 20, 25, 30, 40, 50, 60, 70, 80, 90, 95, 100]
|
|
12
17
|
|
|
13
18
|
TOLERANCE_MARGIN = 2.0
|
|
14
19
|
|
|
15
|
-
|
|
16
|
-
|
|
20
|
+
@depends.inject
|
|
21
|
+
def __init__(self, pkg_path: Path, console: Inject[Console]) -> None:
|
|
22
|
+
# Normalize to pathlib.Path to avoid async path behaviors
|
|
23
|
+
try:
|
|
24
|
+
self.pkg_path = Path(str(pkg_path))
|
|
25
|
+
except Exception:
|
|
26
|
+
self.pkg_path = Path(pkg_path)
|
|
17
27
|
self.console = console
|
|
18
|
-
self.ratchet_file = pkg_path / ".coverage-ratchet.json"
|
|
19
|
-
self.pyproject_file = pkg_path / "pyproject.toml"
|
|
28
|
+
self.ratchet_file = self.pkg_path / ".coverage-ratchet.json"
|
|
29
|
+
self.pyproject_file = self.pkg_path / "pyproject.toml"
|
|
30
|
+
|
|
31
|
+
def initialize(self) -> None:
|
|
32
|
+
pass
|
|
33
|
+
|
|
34
|
+
def cleanup(self) -> None:
|
|
35
|
+
pass
|
|
36
|
+
|
|
37
|
+
def health_check(self) -> bool:
|
|
38
|
+
return True
|
|
39
|
+
|
|
40
|
+
def shutdown(self) -> None:
|
|
41
|
+
pass
|
|
42
|
+
|
|
43
|
+
def metrics(self) -> dict[str, t.Any]:
|
|
44
|
+
return {}
|
|
45
|
+
|
|
46
|
+
def is_healthy(self) -> bool:
|
|
47
|
+
return True
|
|
48
|
+
|
|
49
|
+
def register_resource(self, resource: t.Any) -> None:
|
|
50
|
+
pass
|
|
51
|
+
|
|
52
|
+
def cleanup_resource(self, resource: t.Any) -> None:
|
|
53
|
+
pass
|
|
54
|
+
|
|
55
|
+
def record_error(self, error: Exception) -> None:
|
|
56
|
+
pass
|
|
57
|
+
|
|
58
|
+
def increment_requests(self) -> None:
|
|
59
|
+
pass
|
|
60
|
+
|
|
61
|
+
def get_custom_metric(self, name: str) -> t.Any:
|
|
62
|
+
return None
|
|
63
|
+
|
|
64
|
+
def set_custom_metric(self, name: str, value: t.Any) -> None:
|
|
65
|
+
pass
|
|
20
66
|
|
|
21
67
|
def initialize_baseline(self, initial_coverage: float) -> None:
|
|
22
68
|
if self.ratchet_file.exists():
|
|
@@ -136,7 +182,7 @@ class CoverageRatchetService:
|
|
|
136
182
|
def _check_milestones(
|
|
137
183
|
self, old_coverage: float, new_coverage: float, data: dict[str, t.Any]
|
|
138
184
|
) -> list[float]:
|
|
139
|
-
achieved_milestones = set
|
|
185
|
+
achieved_milestones = set(data.get("milestones_achieved", []))
|
|
140
186
|
return [
|
|
141
187
|
milestone
|
|
142
188
|
for milestone in self.MILESTONES
|
|
@@ -184,13 +230,9 @@ class CoverageRatchetService:
|
|
|
184
230
|
try:
|
|
185
231
|
content = self.pyproject_file.read_text()
|
|
186
232
|
|
|
187
|
-
from crackerjack.services.regex_patterns import update_coverage_requirement
|
|
188
|
-
|
|
189
233
|
updated_content = update_coverage_requirement(content, new_coverage)
|
|
190
234
|
|
|
191
235
|
if updated_content != content:
|
|
192
|
-
from crackerjack.services.filesystem import FileSystemService
|
|
193
|
-
|
|
194
236
|
updated_content = (
|
|
195
237
|
FileSystemService.clean_trailing_whitespace_and_newlines(
|
|
196
238
|
updated_content
|
|
@@ -236,22 +278,6 @@ class CoverageRatchetService:
|
|
|
236
278
|
needed = milestone - current
|
|
237
279
|
return max(0.0, needed)
|
|
238
280
|
return 0.0
|
|
239
|
-
data = self.get_ratchet_data()
|
|
240
|
-
if not data:
|
|
241
|
-
return {"status": "not_initialized"}
|
|
242
|
-
|
|
243
|
-
return {
|
|
244
|
-
"status": "active",
|
|
245
|
-
"current_coverage": data["baseline"],
|
|
246
|
-
"target_coverage": data["target"],
|
|
247
|
-
"next_milestone": data.get("next_milestone"),
|
|
248
|
-
"milestones_achieved": data.get("milestones_achieved", []),
|
|
249
|
-
"total_milestones": len(self.MILESTONES),
|
|
250
|
-
"progress_percent": (data["baseline"] / data["target"]) * 100,
|
|
251
|
-
"last_updated": data["last_updated"],
|
|
252
|
-
"history_count": len(data.get("history", [])),
|
|
253
|
-
"improvement_trend": self._calculate_trend(data),
|
|
254
|
-
}
|
|
255
281
|
|
|
256
282
|
def _calculate_trend(self, data: dict[str, t.Any]) -> str:
|
|
257
283
|
history = data.get("history", [])
|
crackerjack/services/debug.py
CHANGED
|
@@ -8,7 +8,8 @@ from datetime import datetime
|
|
|
8
8
|
from pathlib import Path
|
|
9
9
|
from typing import Any
|
|
10
10
|
|
|
11
|
-
from
|
|
11
|
+
from acb.console import Console
|
|
12
|
+
from acb.depends import depends
|
|
12
13
|
from rich.panel import Panel
|
|
13
14
|
from rich.table import Table
|
|
14
15
|
|
|
@@ -20,7 +21,7 @@ class AIAgentDebugger:
|
|
|
20
21
|
def __init__(self, enabled: bool = False, verbose: bool = False) -> None:
|
|
21
22
|
self.enabled = enabled
|
|
22
23
|
self.verbose = verbose
|
|
23
|
-
self.console = Console
|
|
24
|
+
self.console = depends.get_sync(Console)
|
|
24
25
|
self.logger = get_logger("crackerjack.ai_agent.debug")
|
|
25
26
|
self.session_id = f"debug_{int(time.time())}"
|
|
26
27
|
|
|
@@ -351,7 +352,9 @@ class AIAgentDebugger:
|
|
|
351
352
|
f"Total test fixes: {self.total_test_fixes}, hook fixes: {self.total_hook_fixes}",
|
|
352
353
|
)
|
|
353
354
|
|
|
354
|
-
self.console.print(
|
|
355
|
+
self.console.print(
|
|
356
|
+
Panel(table, title="AI Agent Debug Summary", border_style=border_style)
|
|
357
|
+
)
|
|
355
358
|
|
|
356
359
|
if self.iteration_stats:
|
|
357
360
|
self._print_iteration_breakdown(border_style)
|
|
@@ -397,7 +400,9 @@ class AIAgentDebugger:
|
|
|
397
400
|
else "N / A",
|
|
398
401
|
)
|
|
399
402
|
|
|
400
|
-
self.console.print(
|
|
403
|
+
self.console.print(
|
|
404
|
+
Panel(table, title="Iteration Breakdown", border_style=border_style)
|
|
405
|
+
)
|
|
401
406
|
|
|
402
407
|
def _print_agent_activity_breakdown(self, border_style: str = "red") -> None:
|
|
403
408
|
agent_stats: dict[str, dict[str, t.Any]] = {}
|
|
@@ -436,7 +441,9 @@ class AIAgentDebugger:
|
|
|
436
441
|
)
|
|
437
442
|
table.add_row(agent, str(stats["activities"]), confidence_text)
|
|
438
443
|
|
|
439
|
-
self.console.print(
|
|
444
|
+
self.console.print(
|
|
445
|
+
Panel(table, title="Agent Activity Breakdown", border_style=border_style)
|
|
446
|
+
)
|
|
440
447
|
|
|
441
448
|
def _print_total_statistics(self, border_style: str = "red") -> None:
|
|
442
449
|
success_icon = "✅" if self.workflow_success else "❌"
|
|
@@ -475,7 +482,9 @@ class AIAgentDebugger:
|
|
|
475
482
|
f"{total_fixes}/{total_issues} issues resolved",
|
|
476
483
|
)
|
|
477
484
|
|
|
478
|
-
self.console.print(
|
|
485
|
+
self.console.print(
|
|
486
|
+
Panel(table, title="Total Workflow Statistics", border_style=border_style)
|
|
487
|
+
)
|
|
479
488
|
|
|
480
489
|
def _print_mcp_operation_breakdown(self, border_style: str = "red") -> None:
|
|
481
490
|
tool_stats = {}
|
|
@@ -510,7 +519,9 @@ class AIAgentDebugger:
|
|
|
510
519
|
f"{avg_duration: .2f}s" if avg_duration > 0 else "N / A",
|
|
511
520
|
)
|
|
512
521
|
|
|
513
|
-
self.console.print(
|
|
522
|
+
self.console.print(
|
|
523
|
+
Panel(table, title="MCP Tool Usage", border_style=border_style)
|
|
524
|
+
)
|
|
514
525
|
|
|
515
526
|
def log_iteration_start(self, iteration_number: int) -> None:
|
|
516
527
|
if not self.enabled:
|
|
@@ -67,10 +67,10 @@ class DependencyEdge:
|
|
|
67
67
|
class DependencyGraph:
|
|
68
68
|
"""Complete dependency graph data structure."""
|
|
69
69
|
|
|
70
|
-
nodes: dict[str, DependencyNode] = field(default_factory=dict
|
|
70
|
+
nodes: dict[str, DependencyNode] = field(default_factory=dict)
|
|
71
71
|
edges: list[DependencyEdge] = field(default_factory=list)
|
|
72
|
-
clusters: dict[str, list[str]] = field(default_factory=dict
|
|
73
|
-
metrics: dict[str, t.Any] = field(default_factory=dict
|
|
72
|
+
clusters: dict[str, list[str]] = field(default_factory=dict)
|
|
73
|
+
metrics: dict[str, t.Any] = field(default_factory=dict)
|
|
74
74
|
generated_at: datetime = field(default_factory=datetime.now)
|
|
75
75
|
|
|
76
76
|
def to_dict(self) -> dict[str, t.Any]:
|
|
@@ -193,7 +193,7 @@ class DependencyAnalyzer:
|
|
|
193
193
|
edges = self.dependency_graph.edges
|
|
194
194
|
|
|
195
195
|
# Basic metrics
|
|
196
|
-
metrics = {
|
|
196
|
+
metrics: dict[str, t.Any] = {
|
|
197
197
|
"total_nodes": len(nodes),
|
|
198
198
|
"total_edges": len(edges),
|
|
199
199
|
"total_clusters": len(self.dependency_graph.clusters),
|
|
@@ -68,8 +68,12 @@ class DependencyMonitorService:
|
|
|
68
68
|
|
|
69
69
|
def _parse_dependencies(self) -> dict[str, str]:
|
|
70
70
|
try:
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
content = self.filesystem.read_file(self.pyproject_path)
|
|
72
|
+
if isinstance(content, bytes):
|
|
73
|
+
content_str = content.decode("utf-8")
|
|
74
|
+
else:
|
|
75
|
+
content_str = content
|
|
76
|
+
data = tomllib.loads(content_str)
|
|
73
77
|
|
|
74
78
|
dependencies: dict[str, str] = {}
|
|
75
79
|
project_data = data.get("project", {})
|
|
@@ -357,8 +361,7 @@ class DependencyMonitorService:
|
|
|
357
361
|
|
|
358
362
|
cached_data = cache[cache_key]
|
|
359
363
|
cache_age = current_time - cached_data["timestamp"]
|
|
360
|
-
|
|
361
|
-
return is_fresh
|
|
364
|
+
return cache_age < 86400
|
|
362
365
|
|
|
363
366
|
def _create_major_update_from_cache(
|
|
364
367
|
self,
|
|
@@ -452,13 +455,13 @@ class DependencyMonitorService:
|
|
|
452
455
|
|
|
453
456
|
import requests
|
|
454
457
|
|
|
455
|
-
url = f"https
|
|
458
|
+
url = f"https: //pypi.org/pypi/{package}/json"
|
|
456
459
|
self._validate_pypi_url(url)
|
|
457
460
|
|
|
458
461
|
parsed = urlparse(url)
|
|
459
462
|
|
|
460
463
|
if parsed.scheme != "https" or parsed.netloc != "pypi.org":
|
|
461
|
-
msg = f"Invalid URL: only https
|
|
464
|
+
msg = f"Invalid URL: only https: //pypi.org URLs are allowed, got {url}"
|
|
462
465
|
raise ValueError(msg)
|
|
463
466
|
|
|
464
467
|
response = requests.get(url, timeout=10, verify=True)
|
|
@@ -502,8 +505,7 @@ class DependencyMonitorService:
|
|
|
502
505
|
def _get_release_date(self, releases: dict[str, t.Any], version: str) -> str:
|
|
503
506
|
release_info = releases.get(version, [])
|
|
504
507
|
if release_info:
|
|
505
|
-
|
|
506
|
-
return upload_time
|
|
508
|
+
return release_info[0].get("upload_time", "")
|
|
507
509
|
return ""
|
|
508
510
|
|
|
509
511
|
def _has_breaking_changes(self, version: str) -> bool:
|
|
@@ -536,15 +538,13 @@ class DependencyMonitorService:
|
|
|
536
538
|
def _load_update_cache(self) -> dict[str, t.Any]:
|
|
537
539
|
with suppress(Exception):
|
|
538
540
|
if self.cache_file.exists():
|
|
539
|
-
|
|
540
|
-
|
|
541
|
+
content = self.filesystem.read_file(self.cache_file)
|
|
542
|
+
return t.cast(dict[str, t.Any], json.loads(content))
|
|
541
543
|
return {}
|
|
542
544
|
|
|
543
545
|
def _save_update_cache(self, cache: dict[str, t.Any]) -> None:
|
|
544
546
|
with suppress(Exception):
|
|
545
|
-
self.cache_file.
|
|
546
|
-
with self.cache_file.open("w") as f:
|
|
547
|
-
json.dump(cache, f, indent=2)
|
|
547
|
+
self.filesystem.write_file(self.cache_file, json.dumps(cache))
|
|
548
548
|
|
|
549
549
|
def _report_vulnerabilities(
|
|
550
550
|
self,
|
|
@@ -4,7 +4,8 @@ import typing as t
|
|
|
4
4
|
from pathlib import Path
|
|
5
5
|
from string import Template
|
|
6
6
|
|
|
7
|
-
from
|
|
7
|
+
from acb.console import Console
|
|
8
|
+
from acb.depends import Inject, depends
|
|
8
9
|
|
|
9
10
|
from ..models.protocols import DocumentationGeneratorProtocol
|
|
10
11
|
|
|
@@ -125,7 +126,8 @@ $functions
|
|
|
125
126
|
class DocumentationGeneratorImpl(DocumentationGeneratorProtocol):
|
|
126
127
|
"""Implementation of documentation generation from extracted API data."""
|
|
127
128
|
|
|
128
|
-
|
|
129
|
+
@depends.inject
|
|
130
|
+
def __init__(self, console: Inject[Console]) -> None:
|
|
129
131
|
self.console = console
|
|
130
132
|
self.renderer = MarkdownTemplateRenderer()
|
|
131
133
|
|