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
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
import typing as t
|
|
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
|
|
|
8
9
|
from ..models.protocols import (
|
|
9
10
|
APIExtractorProtocol,
|
|
@@ -17,17 +18,18 @@ from .documentation_generator import DocumentationGeneratorImpl
|
|
|
17
18
|
class DocumentationServiceImpl(DocumentationServiceProtocol):
|
|
18
19
|
"""Main service for automated documentation generation and maintenance."""
|
|
19
20
|
|
|
21
|
+
@depends.inject
|
|
20
22
|
def __init__(
|
|
21
23
|
self,
|
|
22
|
-
console: Console,
|
|
24
|
+
console: Inject[Console],
|
|
23
25
|
pkg_path: Path,
|
|
24
26
|
api_extractor: APIExtractorProtocol | None = None,
|
|
25
27
|
doc_generator: DocumentationGeneratorProtocol | None = None,
|
|
26
28
|
) -> None:
|
|
27
29
|
self.console = console
|
|
28
30
|
self.pkg_path = pkg_path
|
|
29
|
-
self.api_extractor = api_extractor or APIExtractorImpl(
|
|
30
|
-
self.doc_generator = doc_generator or DocumentationGeneratorImpl(
|
|
31
|
+
self.api_extractor = api_extractor or APIExtractorImpl()
|
|
32
|
+
self.doc_generator = doc_generator or DocumentationGeneratorImpl()
|
|
31
33
|
|
|
32
34
|
# Define standard paths
|
|
33
35
|
self.docs_dir = pkg_path / "docs"
|
|
@@ -38,58 +40,85 @@ class DocumentationServiceImpl(DocumentationServiceProtocol):
|
|
|
38
40
|
# Ensure directories exist
|
|
39
41
|
self._ensure_directories()
|
|
40
42
|
|
|
41
|
-
def
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
)
|
|
46
|
-
|
|
47
|
-
# Categorize source files
|
|
43
|
+
def _categorize_source_files(
|
|
44
|
+
self, source_paths: list[Path]
|
|
45
|
+
) -> dict[str, list[Path]]:
|
|
46
|
+
"""Categorize source files by type."""
|
|
48
47
|
python_files = [p for p in source_paths if p.suffix == ".py"]
|
|
49
|
-
protocol_files = [p for p in python_files if p.name == "protocols.py"]
|
|
50
|
-
service_files = [p for p in python_files if "/services/" in str(p)]
|
|
51
|
-
manager_files = [p for p in python_files if "/managers/" in str(p)]
|
|
52
|
-
cli_files = [p for p in python_files if "/cli/" in str(p)]
|
|
53
|
-
mcp_files = [
|
|
54
|
-
p for p in source_paths if "/mcp/" in str(p) or p.suffix in (".py", ".md")
|
|
55
|
-
]
|
|
56
48
|
|
|
57
|
-
|
|
49
|
+
return {
|
|
50
|
+
"python": python_files,
|
|
51
|
+
"protocol": [p for p in python_files if p.name == "protocols.py"],
|
|
52
|
+
"service": [p for p in python_files if "/services/" in str(p)],
|
|
53
|
+
"manager": [p for p in python_files if "/managers/" in str(p)],
|
|
54
|
+
"cli": [p for p in python_files if "/cli/" in str(p)],
|
|
55
|
+
"mcp": [
|
|
56
|
+
p
|
|
57
|
+
for p in source_paths
|
|
58
|
+
if "/mcp/" in str(p) or p.suffix in (".py", ".md")
|
|
59
|
+
],
|
|
60
|
+
}
|
|
58
61
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
62
|
+
def _extract_specialized_apis(
|
|
63
|
+
self, categorized_files: dict[str, list[Path]]
|
|
64
|
+
) -> dict[str, t.Any]:
|
|
65
|
+
"""Extract specialized API documentation."""
|
|
66
|
+
api_data = {}
|
|
63
67
|
|
|
64
68
|
# Extract protocol definitions
|
|
65
|
-
if
|
|
66
|
-
for protocol_file in
|
|
69
|
+
if categorized_files["protocol"]:
|
|
70
|
+
for protocol_file in categorized_files["protocol"]:
|
|
67
71
|
protocol_data = self.api_extractor.extract_protocol_definitions(
|
|
68
72
|
protocol_file
|
|
69
73
|
)
|
|
70
74
|
api_data.update(protocol_data)
|
|
71
75
|
|
|
72
76
|
# Extract service interfaces
|
|
73
|
-
if
|
|
74
|
-
service_data = self.api_extractor.extract_service_interfaces(
|
|
77
|
+
if categorized_files["service"]:
|
|
78
|
+
service_data = self.api_extractor.extract_service_interfaces(
|
|
79
|
+
categorized_files["service"]
|
|
80
|
+
)
|
|
75
81
|
api_data.update(service_data)
|
|
76
82
|
|
|
77
83
|
# Extract manager interfaces
|
|
78
|
-
if
|
|
79
|
-
manager_data = self.api_extractor.extract_service_interfaces(
|
|
84
|
+
if categorized_files["manager"]:
|
|
85
|
+
manager_data = self.api_extractor.extract_service_interfaces(
|
|
86
|
+
categorized_files["manager"]
|
|
87
|
+
)
|
|
80
88
|
if "services" in manager_data:
|
|
81
89
|
api_data["managers"] = manager_data["services"]
|
|
82
90
|
|
|
83
91
|
# Extract CLI commands
|
|
84
|
-
if
|
|
85
|
-
cli_data = self.api_extractor.extract_cli_commands(
|
|
92
|
+
if categorized_files["cli"]:
|
|
93
|
+
cli_data = self.api_extractor.extract_cli_commands(categorized_files["cli"])
|
|
86
94
|
api_data.update(cli_data)
|
|
87
95
|
|
|
88
96
|
# Extract MCP tools
|
|
89
|
-
if
|
|
90
|
-
mcp_data = self.api_extractor.extract_mcp_tools(
|
|
97
|
+
if categorized_files["mcp"]:
|
|
98
|
+
mcp_data = self.api_extractor.extract_mcp_tools(categorized_files["mcp"])
|
|
91
99
|
api_data.update(mcp_data)
|
|
92
100
|
|
|
101
|
+
return api_data
|
|
102
|
+
|
|
103
|
+
def extract_api_documentation(self, source_paths: list[Path]) -> dict[str, t.Any]:
|
|
104
|
+
"""Extract API documentation from source code files."""
|
|
105
|
+
self.console.print(
|
|
106
|
+
"[cyan]📖[/cyan] Extracting API documentation from source files..."
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
categorized_files = self._categorize_source_files(source_paths)
|
|
110
|
+
api_data = {}
|
|
111
|
+
|
|
112
|
+
# Extract from Python files
|
|
113
|
+
if categorized_files["python"]:
|
|
114
|
+
python_data = self.api_extractor.extract_from_python_files(
|
|
115
|
+
categorized_files["python"]
|
|
116
|
+
)
|
|
117
|
+
api_data.update(python_data)
|
|
118
|
+
|
|
119
|
+
# Extract specialized APIs
|
|
120
|
+
api_data.update(self._extract_specialized_apis(categorized_files))
|
|
121
|
+
|
|
93
122
|
self.console.print(
|
|
94
123
|
f"[green]✅[/green] Extracted documentation from {len(source_paths)} files"
|
|
95
124
|
)
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import asyncio
|
|
2
4
|
import hashlib
|
|
3
5
|
import time
|
|
@@ -6,19 +8,30 @@ from pathlib import Path
|
|
|
6
8
|
from typing import Any
|
|
7
9
|
|
|
8
10
|
import aiofiles
|
|
11
|
+
from acb.depends import Inject, depends
|
|
12
|
+
from acb.logger import Logger
|
|
9
13
|
|
|
10
14
|
from crackerjack.errors import FileError
|
|
11
|
-
from crackerjack.models.protocols import
|
|
12
|
-
|
|
15
|
+
from crackerjack.models.protocols import (
|
|
16
|
+
EnhancedFileSystemServiceProtocol,
|
|
17
|
+
ServiceProtocol,
|
|
18
|
+
)
|
|
19
|
+
from crackerjack.services.logging import LoggingContext
|
|
13
20
|
|
|
14
21
|
|
|
15
22
|
class FileCache:
|
|
16
|
-
|
|
23
|
+
@depends.inject
|
|
24
|
+
def __init__(
|
|
25
|
+
self,
|
|
26
|
+
logger: Inject[Logger],
|
|
27
|
+
max_size: int = 1000,
|
|
28
|
+
default_ttl: float = 300.0,
|
|
29
|
+
) -> None:
|
|
17
30
|
self.max_size = max_size
|
|
18
31
|
self.default_ttl = default_ttl
|
|
19
32
|
self._cache: dict[str, dict[str, Any]] = {}
|
|
20
33
|
self._access_times: dict[str, float] = {}
|
|
21
|
-
self.logger =
|
|
34
|
+
self.logger = logger
|
|
22
35
|
|
|
23
36
|
def get(self, key: str) -> str | None:
|
|
24
37
|
if key not in self._cache:
|
|
@@ -78,11 +91,16 @@ class FileCache:
|
|
|
78
91
|
|
|
79
92
|
|
|
80
93
|
class BatchFileOperations:
|
|
81
|
-
|
|
94
|
+
@depends.inject
|
|
95
|
+
def __init__(
|
|
96
|
+
self,
|
|
97
|
+
logger: Inject[Logger],
|
|
98
|
+
batch_size: int = 10,
|
|
99
|
+
) -> None:
|
|
82
100
|
self.batch_size = batch_size
|
|
83
101
|
self.read_queue: list[tuple[Path, asyncio.Future[str]]] = []
|
|
84
102
|
self.write_queue: list[tuple[Path, str, asyncio.Future[None]]] = []
|
|
85
|
-
self.logger =
|
|
103
|
+
self.logger = logger
|
|
86
104
|
|
|
87
105
|
async def queue_read(self, path: Path) -> str:
|
|
88
106
|
future: asyncio.Future[str] = asyncio.Future()
|
|
@@ -161,18 +179,21 @@ class BatchFileOperations:
|
|
|
161
179
|
future.set_exception(e)
|
|
162
180
|
|
|
163
181
|
|
|
164
|
-
class EnhancedFileSystemService(
|
|
182
|
+
class EnhancedFileSystemService(EnhancedFileSystemServiceProtocol, ServiceProtocol):
|
|
183
|
+
@depends.inject
|
|
165
184
|
def __init__(
|
|
166
185
|
self,
|
|
186
|
+
logger: Inject[Logger],
|
|
167
187
|
cache_size: int = 1000,
|
|
168
188
|
cache_ttl: float = 300.0,
|
|
169
189
|
batch_size: int = 10,
|
|
170
190
|
enable_async: bool = True,
|
|
171
191
|
) -> None:
|
|
172
|
-
|
|
192
|
+
# Use keyword args to avoid DI/positional ambiguity
|
|
193
|
+
self.cache = FileCache(max_size=cache_size, default_ttl=cache_ttl)
|
|
173
194
|
self.batch_ops = BatchFileOperations(batch_size) if enable_async else None
|
|
174
195
|
self.enable_async = enable_async
|
|
175
|
-
self.logger =
|
|
196
|
+
self.logger = logger
|
|
176
197
|
|
|
177
198
|
self._file_timestamps: dict[str, float] = {}
|
|
178
199
|
|
|
@@ -195,6 +216,9 @@ class EnhancedFileSystemService(FileSystemInterface):
|
|
|
195
216
|
|
|
196
217
|
def write_file(self, path: str | Path, content: str) -> None:
|
|
197
218
|
path_obj = Path(path) if isinstance(path, str) else path
|
|
219
|
+
# Validate content type before logging/length computation
|
|
220
|
+
if not isinstance(content, str):
|
|
221
|
+
raise TypeError("Content must be a string")
|
|
198
222
|
|
|
199
223
|
with LoggingContext("write_file", path=str(path_obj), size=len(content)):
|
|
200
224
|
self._write_file_direct(path_obj, content)
|
|
@@ -307,33 +331,45 @@ class EnhancedFileSystemService(FileSystemInterface):
|
|
|
307
331
|
return self.cache.get(cache_key)
|
|
308
332
|
|
|
309
333
|
@staticmethod
|
|
310
|
-
def
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
334
|
+
def _validate_file_exists(path: Path) -> None:
|
|
335
|
+
"""Validate that a file exists."""
|
|
336
|
+
if not path.exists():
|
|
337
|
+
raise FileError(
|
|
338
|
+
message=f"File does not exist: {path}",
|
|
339
|
+
details=f"Attempted to read file at {path.absolute()}",
|
|
340
|
+
recovery="Check file path and ensure file exists",
|
|
341
|
+
)
|
|
342
|
+
|
|
343
|
+
@staticmethod
|
|
344
|
+
def _handle_read_error(error: Exception, path: Path) -> None:
|
|
345
|
+
"""Handle file read errors."""
|
|
346
|
+
if isinstance(error, PermissionError):
|
|
320
347
|
raise FileError(
|
|
321
348
|
message=f"Permission denied reading file: {path}",
|
|
322
|
-
details=str(
|
|
349
|
+
details=str(error),
|
|
323
350
|
recovery="Check file permissions and user access rights",
|
|
324
|
-
) from
|
|
325
|
-
|
|
351
|
+
) from error
|
|
352
|
+
elif isinstance(error, UnicodeDecodeError):
|
|
326
353
|
raise FileError(
|
|
327
354
|
message=f"Unable to decode file as UTF-8: {path}",
|
|
328
|
-
details=str(
|
|
355
|
+
details=str(error),
|
|
329
356
|
recovery="Ensure file is text - based and UTF-8 encoded",
|
|
330
|
-
) from
|
|
331
|
-
|
|
357
|
+
) from error
|
|
358
|
+
elif isinstance(error, OSError):
|
|
332
359
|
raise FileError(
|
|
333
360
|
message=f"System error reading file: {path}",
|
|
334
|
-
details=str(
|
|
361
|
+
details=str(error),
|
|
335
362
|
recovery="Check disk space and file system integrity",
|
|
336
|
-
) from
|
|
363
|
+
) from error
|
|
364
|
+
|
|
365
|
+
@staticmethod
|
|
366
|
+
def _read_file_direct(path: Path) -> str:
|
|
367
|
+
try:
|
|
368
|
+
EnhancedFileSystemService._validate_file_exists(path)
|
|
369
|
+
return path.read_text(encoding="utf-8")
|
|
370
|
+
except (PermissionError, UnicodeDecodeError, OSError) as e:
|
|
371
|
+
EnhancedFileSystemService._handle_read_error(e, path)
|
|
372
|
+
raise # Ensure type checker knows this doesn't return
|
|
337
373
|
|
|
338
374
|
@staticmethod
|
|
339
375
|
def _write_file_direct(path: Path, content: str) -> None:
|
|
@@ -441,3 +477,21 @@ class EnhancedFileSystemService(FileSystemInterface):
|
|
|
441
477
|
details=str(e),
|
|
442
478
|
recovery="Check parent directory permissions",
|
|
443
479
|
) from e
|
|
480
|
+
|
|
481
|
+
async def _on_start(self) -> None:
|
|
482
|
+
"""
|
|
483
|
+
Lifecycle method called when the service is started.
|
|
484
|
+
"""
|
|
485
|
+
self.logger.debug("EnhancedFileSystemService started")
|
|
486
|
+
|
|
487
|
+
async def _on_stop(self) -> None:
|
|
488
|
+
"""
|
|
489
|
+
Lifecycle method called when the service is stopped.
|
|
490
|
+
"""
|
|
491
|
+
self.logger.debug("EnhancedFileSystemService stopped")
|
|
492
|
+
|
|
493
|
+
async def _on_reload(self) -> None:
|
|
494
|
+
"""
|
|
495
|
+
Lifecycle method called when the service is reloaded.
|
|
496
|
+
"""
|
|
497
|
+
self.logger.debug("EnhancedFileSystemService reloaded")
|
|
@@ -313,7 +313,7 @@ class DataCompactionManager:
|
|
|
313
313
|
return file_mtime < cutoff_date
|
|
314
314
|
|
|
315
315
|
def _build_compaction_result(
|
|
316
|
-
self, data_type: str, rules: dict[str, t.Any], stats: dict[str,
|
|
316
|
+
self, data_type: str, rules: dict[str, t.Any], stats: dict[str, t.Any]
|
|
317
317
|
) -> dict[str, t.Any]:
|
|
318
318
|
"""Build the compaction result dictionary."""
|
|
319
319
|
return {
|
|
@@ -157,7 +157,7 @@ class ErrorPatternAnalyzer:
|
|
|
157
157
|
error_type = pattern.error_type
|
|
158
158
|
count = pattern.count
|
|
159
159
|
|
|
160
|
-
file_error_counts[file_path][error_type] += count
|
|
160
|
+
file_error_counts[file_path][error_type] += float(count)
|
|
161
161
|
max_value = max(max_value, file_error_counts[file_path][error_type])
|
|
162
162
|
|
|
163
163
|
# Create heat map cells
|
|
@@ -173,21 +173,21 @@ class ErrorPatternAnalyzer:
|
|
|
173
173
|
|
|
174
174
|
for file_path in files:
|
|
175
175
|
for error_type in error_types:
|
|
176
|
-
|
|
177
|
-
if
|
|
178
|
-
intensity
|
|
176
|
+
count_val = float(file_error_counts[file_path].get(error_type, 0))
|
|
177
|
+
if count_val > 0:
|
|
178
|
+
intensity = count_val / max_value if max_value > 0 else 0.0 # type: ignore[assignment]
|
|
179
179
|
severity = self._get_severity_for_type(error_type)
|
|
180
180
|
|
|
181
181
|
cells.append(
|
|
182
182
|
HeatMapCell(
|
|
183
183
|
x=file_path,
|
|
184
184
|
y=error_type,
|
|
185
|
-
value=
|
|
185
|
+
value=count_val,
|
|
186
186
|
color_intensity=intensity,
|
|
187
187
|
tooltip_data={
|
|
188
188
|
"file": file_path,
|
|
189
189
|
"error_type": error_type,
|
|
190
|
-
"count":
|
|
190
|
+
"count": int(count_val),
|
|
191
191
|
"severity": severity,
|
|
192
192
|
},
|
|
193
193
|
severity=severity,
|
|
@@ -300,7 +300,7 @@ class ErrorPatternAnalyzer:
|
|
|
300
300
|
cells = []
|
|
301
301
|
for time_label in time_labels:
|
|
302
302
|
for error_type in error_types:
|
|
303
|
-
count = temporal_counts[time_label].get(error_type, 0)
|
|
303
|
+
count = float(temporal_counts[time_label].get(error_type, 0))
|
|
304
304
|
if count > 0:
|
|
305
305
|
cell = self._create_temporal_cell(
|
|
306
306
|
time_label, error_type, count, max_value
|
|
@@ -313,7 +313,7 @@ class ErrorPatternAnalyzer:
|
|
|
313
313
|
self, time_label: str, error_type: str, count: float, max_value: float
|
|
314
314
|
) -> HeatMapCell:
|
|
315
315
|
"""Create a single temporal heatmap cell."""
|
|
316
|
-
intensity
|
|
316
|
+
intensity = count / max_value if max_value > 0 else 0.0 # type: ignore[assignment]
|
|
317
317
|
severity = self._get_severity_for_type(error_type)
|
|
318
318
|
|
|
319
319
|
return HeatMapCell(
|
|
@@ -392,7 +392,7 @@ class ErrorPatternAnalyzer:
|
|
|
392
392
|
cells = []
|
|
393
393
|
for function_id in functions:
|
|
394
394
|
for error_type in error_types:
|
|
395
|
-
count = function_error_counts[function_id].get(error_type, 0)
|
|
395
|
+
count = float(function_error_counts[function_id].get(error_type, 0))
|
|
396
396
|
if count > 0:
|
|
397
397
|
cell = self._create_function_cell(
|
|
398
398
|
function_id, error_type, count, max_value
|
|
@@ -405,7 +405,7 @@ class ErrorPatternAnalyzer:
|
|
|
405
405
|
self, function_id: str, error_type: str, count: float, max_value: float
|
|
406
406
|
) -> HeatMapCell:
|
|
407
407
|
"""Create a single function heatmap cell."""
|
|
408
|
-
intensity
|
|
408
|
+
intensity = count / max_value if max_value > 0 else 0.0 # type: ignore[assignment]
|
|
409
409
|
severity = self._get_severity_for_type(error_type)
|
|
410
410
|
|
|
411
411
|
return HeatMapCell(
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
"""Smart file filtering for incremental tool execution.
|
|
2
|
+
|
|
3
|
+
Filters files based on git changes, patterns, and tool requirements.
|
|
4
|
+
Part of Phase 10.2: Development Velocity Improvements.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import typing as t
|
|
8
|
+
from fnmatch import fnmatch
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
from crackerjack.models.protocols import (
|
|
12
|
+
GitServiceProtocol,
|
|
13
|
+
ServiceProtocol,
|
|
14
|
+
SmartFileFilterProtocol,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class SmartFileFilter(SmartFileFilterProtocol, ServiceProtocol):
|
|
19
|
+
"""Filter files for tool execution based on git changes and patterns.
|
|
20
|
+
|
|
21
|
+
Provides intelligent file filtering to enable incremental execution,
|
|
22
|
+
reducing unnecessary tool runs and improving feedback loops.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(
|
|
26
|
+
self,
|
|
27
|
+
git_service: GitServiceProtocol,
|
|
28
|
+
project_root: Path | None = None,
|
|
29
|
+
):
|
|
30
|
+
"""Initialize file filter.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
git_service: Git service for repository operations
|
|
34
|
+
project_root: Project root directory (defaults to cwd)
|
|
35
|
+
"""
|
|
36
|
+
self._git_service = git_service
|
|
37
|
+
self.project_root = project_root or Path.cwd()
|
|
38
|
+
|
|
39
|
+
def initialize(self) -> None:
|
|
40
|
+
pass
|
|
41
|
+
|
|
42
|
+
def cleanup(self) -> None:
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
def health_check(self) -> bool:
|
|
46
|
+
return True
|
|
47
|
+
|
|
48
|
+
def shutdown(self) -> None:
|
|
49
|
+
pass
|
|
50
|
+
|
|
51
|
+
def metrics(self) -> dict[str, t.Any]:
|
|
52
|
+
return {}
|
|
53
|
+
|
|
54
|
+
def is_healthy(self) -> bool:
|
|
55
|
+
return True
|
|
56
|
+
|
|
57
|
+
def register_resource(self, resource: t.Any) -> None:
|
|
58
|
+
pass
|
|
59
|
+
|
|
60
|
+
def cleanup_resource(self, resource: t.Any) -> None:
|
|
61
|
+
pass
|
|
62
|
+
|
|
63
|
+
def record_error(self, error: Exception) -> None:
|
|
64
|
+
pass
|
|
65
|
+
|
|
66
|
+
def increment_requests(self) -> None:
|
|
67
|
+
pass
|
|
68
|
+
|
|
69
|
+
def get_custom_metric(self, name: str) -> t.Any:
|
|
70
|
+
return None
|
|
71
|
+
|
|
72
|
+
def set_custom_metric(self, name: str, value: t.Any) -> None:
|
|
73
|
+
pass
|
|
74
|
+
|
|
75
|
+
def get_changed_files(self, since: str = "HEAD") -> list[Path]:
|
|
76
|
+
"""Get files changed since a git reference.
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
since: Git reference (commit, branch, tag, or "HEAD")
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
List of changed file paths relative to project root
|
|
83
|
+
"""
|
|
84
|
+
return self._git_service.get_changed_files_since(since, self.project_root)
|
|
85
|
+
|
|
86
|
+
def get_staged_files(self) -> list[Path]:
|
|
87
|
+
"""Get currently staged files (in git index).
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
List of staged file paths relative to project root
|
|
91
|
+
"""
|
|
92
|
+
return self._git_service.get_staged_files(self.project_root)
|
|
93
|
+
|
|
94
|
+
def get_unstaged_files(self) -> list[Path]:
|
|
95
|
+
"""Get unstaged modified files (working tree changes).
|
|
96
|
+
|
|
97
|
+
Returns:
|
|
98
|
+
List of unstaged file paths relative to project root
|
|
99
|
+
"""
|
|
100
|
+
return self._git_service.get_unstaged_files(self.project_root)
|
|
101
|
+
|
|
102
|
+
def filter_by_pattern(self, files: list[Path], pattern: str) -> list[Path]:
|
|
103
|
+
"""Filter files by glob pattern.
|
|
104
|
+
|
|
105
|
+
Args:
|
|
106
|
+
files: List of file paths to filter
|
|
107
|
+
pattern: Glob pattern (e.g., '*.py', '**/*.ts')
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
List of files matching the pattern
|
|
111
|
+
"""
|
|
112
|
+
return [
|
|
113
|
+
file_path
|
|
114
|
+
for file_path in files
|
|
115
|
+
if fnmatch(str(file_path), pattern) or fnmatch(file_path.name, pattern)
|
|
116
|
+
]
|
|
117
|
+
|
|
118
|
+
def filter_by_tool(self, files: list[Path], tool: str) -> list[Path]:
|
|
119
|
+
"""Filter files relevant to a specific tool.
|
|
120
|
+
|
|
121
|
+
Args:
|
|
122
|
+
files: List of file paths to filter
|
|
123
|
+
tool: Tool name (e.g., 'ruff-check', 'zuban', 'skylos')
|
|
124
|
+
|
|
125
|
+
Returns:
|
|
126
|
+
List of files applicable to the tool
|
|
127
|
+
"""
|
|
128
|
+
# Tool-specific file type mappings
|
|
129
|
+
tool_patterns = {
|
|
130
|
+
# Python tools
|
|
131
|
+
"ruff-check": ["*.py"],
|
|
132
|
+
"ruff-format": ["*.py"],
|
|
133
|
+
"zuban": ["*.py"],
|
|
134
|
+
"skylos": ["*.py"],
|
|
135
|
+
"bandit": ["*.py"],
|
|
136
|
+
"refurb": ["*.py"],
|
|
137
|
+
"complexipy": ["*.py"],
|
|
138
|
+
"creosote": ["*.py"],
|
|
139
|
+
# Markdown tools
|
|
140
|
+
"mdformat": ["*.md"],
|
|
141
|
+
# YAML/TOML tools
|
|
142
|
+
"check-yaml": ["*.yaml", "*.yml"],
|
|
143
|
+
"check-toml": ["*.toml"],
|
|
144
|
+
# Text tools (apply to most files)
|
|
145
|
+
"trailing-whitespace": ["*"],
|
|
146
|
+
"end-of-file-fixer": ["*"],
|
|
147
|
+
"codespell": ["*"],
|
|
148
|
+
# Special tools
|
|
149
|
+
"validate-regex-patterns": ["*.py"],
|
|
150
|
+
"gitleaks": ["*"],
|
|
151
|
+
"uv-lock": ["pyproject.toml"],
|
|
152
|
+
"check-added-large-files": ["*"],
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
patterns = tool_patterns.get(tool, ["*"])
|
|
156
|
+
|
|
157
|
+
# Apply all patterns for the tool
|
|
158
|
+
filtered = []
|
|
159
|
+
for pattern in patterns:
|
|
160
|
+
filtered.extend(self.filter_by_pattern(files, pattern))
|
|
161
|
+
|
|
162
|
+
# Remove duplicates while preserving order
|
|
163
|
+
seen = set()
|
|
164
|
+
result = []
|
|
165
|
+
for file_path in filtered:
|
|
166
|
+
if file_path not in seen:
|
|
167
|
+
seen.add(file_path)
|
|
168
|
+
result.append(file_path)
|
|
169
|
+
|
|
170
|
+
return result
|
|
171
|
+
|
|
172
|
+
def get_all_modified_files(self) -> list[Path]:
|
|
173
|
+
"""Get all modified files (staged + unstaged).
|
|
174
|
+
|
|
175
|
+
Returns:
|
|
176
|
+
Combined list of staged and unstaged files
|
|
177
|
+
"""
|
|
178
|
+
staged = set(self.get_staged_files())
|
|
179
|
+
unstaged = set(self.get_unstaged_files())
|
|
180
|
+
all_modified = staged | unstaged
|
|
181
|
+
|
|
182
|
+
return sorted(all_modified)
|
|
183
|
+
|
|
184
|
+
def filter_by_extensions(
|
|
185
|
+
self, files: list[Path], extensions: list[str]
|
|
186
|
+
) -> list[Path]:
|
|
187
|
+
"""Filter files by file extensions.
|
|
188
|
+
|
|
189
|
+
Args:
|
|
190
|
+
files: List of file paths to filter
|
|
191
|
+
extensions: List of extensions (e.g., ['.py', '.md'])
|
|
192
|
+
|
|
193
|
+
Returns:
|
|
194
|
+
List of files with matching extensions
|
|
195
|
+
"""
|
|
196
|
+
# Normalize extensions to include leading dot
|
|
197
|
+
normalized = [ext if ext.startswith(".") else f".{ext}" for ext in extensions]
|
|
198
|
+
|
|
199
|
+
return [file_path for file_path in files if file_path.suffix in normalized]
|
|
200
|
+
|
|
201
|
+
def get_python_files(self, files: list[Path]) -> list[Path]:
|
|
202
|
+
"""Convenience method to filter Python files.
|
|
203
|
+
|
|
204
|
+
Args:
|
|
205
|
+
files: List of file paths to filter
|
|
206
|
+
|
|
207
|
+
Returns:
|
|
208
|
+
List of Python files (.py)
|
|
209
|
+
"""
|
|
210
|
+
return self.filter_by_extensions(files, [".py"])
|
|
211
|
+
|
|
212
|
+
def get_markdown_files(self, files: list[Path]) -> list[Path]:
|
|
213
|
+
"""Convenience method to filter Markdown files.
|
|
214
|
+
|
|
215
|
+
Args:
|
|
216
|
+
files: List of file paths to filter
|
|
217
|
+
|
|
218
|
+
Returns:
|
|
219
|
+
List of Markdown files (.md)
|
|
220
|
+
"""
|
|
221
|
+
return self.filter_by_extensions(files, [".md"])
|
|
@@ -107,13 +107,11 @@ class FileHasher:
|
|
|
107
107
|
return any(pattern in path_str for pattern in ignore_patterns)
|
|
108
108
|
|
|
109
109
|
def invalidate_cache(self, file_path: Path | None = None) -> None:
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
else:
|
|
116
|
-
self.cache.file_hash_cache.clear()
|
|
110
|
+
# CrackerjackCache doesn't have direct access to its underlying cache,
|
|
111
|
+
# so for targeted invalidation we would need to clear all file hashes
|
|
112
|
+
# For a specific file, we can't directly invalidate just that entry
|
|
113
|
+
# since the cache key contains mtime and size that would trigger invalidation naturally
|
|
114
|
+
pass # No direct way to clear individual cache entries in CrackerjackCache
|
|
117
115
|
|
|
118
116
|
|
|
119
117
|
class SmartFileWatcher:
|