crackerjack 0.18.2__py3-none-any.whl → 0.45.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- crackerjack/README.md +19 -0
- crackerjack/__init__.py +96 -2
- crackerjack/__main__.py +637 -138
- crackerjack/adapters/README.md +18 -0
- crackerjack/adapters/__init__.py +39 -0
- crackerjack/adapters/_output_paths.py +167 -0
- crackerjack/adapters/_qa_adapter_base.py +309 -0
- crackerjack/adapters/_tool_adapter_base.py +706 -0
- crackerjack/adapters/ai/README.md +65 -0
- crackerjack/adapters/ai/__init__.py +5 -0
- crackerjack/adapters/ai/claude.py +853 -0
- crackerjack/adapters/complexity/README.md +53 -0
- crackerjack/adapters/complexity/__init__.py +10 -0
- crackerjack/adapters/complexity/complexipy.py +641 -0
- crackerjack/adapters/dependency/__init__.py +22 -0
- crackerjack/adapters/dependency/pip_audit.py +418 -0
- crackerjack/adapters/format/README.md +72 -0
- crackerjack/adapters/format/__init__.py +11 -0
- crackerjack/adapters/format/mdformat.py +313 -0
- crackerjack/adapters/format/ruff.py +516 -0
- crackerjack/adapters/lint/README.md +47 -0
- crackerjack/adapters/lint/__init__.py +11 -0
- crackerjack/adapters/lint/codespell.py +273 -0
- crackerjack/adapters/lsp/README.md +49 -0
- crackerjack/adapters/lsp/__init__.py +27 -0
- crackerjack/adapters/lsp/_base.py +194 -0
- crackerjack/adapters/lsp/_client.py +358 -0
- crackerjack/adapters/lsp/_manager.py +193 -0
- crackerjack/adapters/lsp/skylos.py +283 -0
- crackerjack/adapters/lsp/zuban.py +557 -0
- crackerjack/adapters/refactor/README.md +59 -0
- crackerjack/adapters/refactor/__init__.py +12 -0
- crackerjack/adapters/refactor/creosote.py +318 -0
- crackerjack/adapters/refactor/refurb.py +406 -0
- crackerjack/adapters/refactor/skylos.py +494 -0
- crackerjack/adapters/sast/README.md +132 -0
- crackerjack/adapters/sast/__init__.py +32 -0
- crackerjack/adapters/sast/_base.py +201 -0
- crackerjack/adapters/sast/bandit.py +423 -0
- crackerjack/adapters/sast/pyscn.py +405 -0
- crackerjack/adapters/sast/semgrep.py +241 -0
- crackerjack/adapters/security/README.md +111 -0
- crackerjack/adapters/security/__init__.py +17 -0
- crackerjack/adapters/security/gitleaks.py +339 -0
- crackerjack/adapters/type/README.md +52 -0
- crackerjack/adapters/type/__init__.py +12 -0
- crackerjack/adapters/type/pyrefly.py +402 -0
- crackerjack/adapters/type/ty.py +402 -0
- crackerjack/adapters/type/zuban.py +522 -0
- crackerjack/adapters/utility/README.md +51 -0
- crackerjack/adapters/utility/__init__.py +10 -0
- crackerjack/adapters/utility/checks.py +884 -0
- crackerjack/agents/README.md +264 -0
- crackerjack/agents/__init__.py +66 -0
- crackerjack/agents/architect_agent.py +238 -0
- crackerjack/agents/base.py +167 -0
- crackerjack/agents/claude_code_bridge.py +641 -0
- crackerjack/agents/coordinator.py +600 -0
- crackerjack/agents/documentation_agent.py +520 -0
- crackerjack/agents/dry_agent.py +585 -0
- crackerjack/agents/enhanced_coordinator.py +279 -0
- crackerjack/agents/enhanced_proactive_agent.py +185 -0
- crackerjack/agents/error_middleware.py +53 -0
- crackerjack/agents/formatting_agent.py +230 -0
- crackerjack/agents/helpers/__init__.py +9 -0
- crackerjack/agents/helpers/performance/__init__.py +22 -0
- crackerjack/agents/helpers/performance/performance_ast_analyzer.py +357 -0
- crackerjack/agents/helpers/performance/performance_pattern_detector.py +909 -0
- crackerjack/agents/helpers/performance/performance_recommender.py +572 -0
- crackerjack/agents/helpers/refactoring/__init__.py +22 -0
- crackerjack/agents/helpers/refactoring/code_transformer.py +536 -0
- crackerjack/agents/helpers/refactoring/complexity_analyzer.py +344 -0
- crackerjack/agents/helpers/refactoring/dead_code_detector.py +437 -0
- crackerjack/agents/helpers/test_creation/__init__.py +19 -0
- crackerjack/agents/helpers/test_creation/test_ast_analyzer.py +216 -0
- crackerjack/agents/helpers/test_creation/test_coverage_analyzer.py +643 -0
- crackerjack/agents/helpers/test_creation/test_template_generator.py +1031 -0
- crackerjack/agents/import_optimization_agent.py +1181 -0
- crackerjack/agents/performance_agent.py +325 -0
- crackerjack/agents/performance_helpers.py +205 -0
- crackerjack/agents/proactive_agent.py +55 -0
- crackerjack/agents/refactoring_agent.py +511 -0
- crackerjack/agents/refactoring_helpers.py +247 -0
- crackerjack/agents/security_agent.py +793 -0
- crackerjack/agents/semantic_agent.py +479 -0
- crackerjack/agents/semantic_helpers.py +356 -0
- crackerjack/agents/test_creation_agent.py +570 -0
- crackerjack/agents/test_specialist_agent.py +526 -0
- crackerjack/agents/tracker.py +110 -0
- crackerjack/api.py +647 -0
- crackerjack/cli/README.md +394 -0
- crackerjack/cli/__init__.py +24 -0
- crackerjack/cli/cache_handlers.py +209 -0
- crackerjack/cli/cache_handlers_enhanced.py +680 -0
- crackerjack/cli/facade.py +162 -0
- crackerjack/cli/formatting.py +13 -0
- crackerjack/cli/handlers/__init__.py +85 -0
- crackerjack/cli/handlers/advanced.py +103 -0
- crackerjack/cli/handlers/ai_features.py +62 -0
- crackerjack/cli/handlers/analytics.py +479 -0
- crackerjack/cli/handlers/changelog.py +271 -0
- crackerjack/cli/handlers/config_handlers.py +16 -0
- crackerjack/cli/handlers/coverage.py +84 -0
- crackerjack/cli/handlers/documentation.py +280 -0
- crackerjack/cli/handlers/main_handlers.py +497 -0
- crackerjack/cli/handlers/monitoring.py +371 -0
- crackerjack/cli/handlers.py +700 -0
- crackerjack/cli/interactive.py +488 -0
- crackerjack/cli/options.py +1216 -0
- crackerjack/cli/semantic_handlers.py +292 -0
- crackerjack/cli/utils.py +19 -0
- crackerjack/cli/version.py +19 -0
- crackerjack/code_cleaner.py +1307 -0
- crackerjack/config/README.md +472 -0
- crackerjack/config/__init__.py +275 -0
- crackerjack/config/global_lock_config.py +207 -0
- crackerjack/config/hooks.py +390 -0
- crackerjack/config/loader.py +239 -0
- crackerjack/config/settings.py +141 -0
- crackerjack/config/tool_commands.py +331 -0
- crackerjack/core/README.md +393 -0
- crackerjack/core/__init__.py +0 -0
- crackerjack/core/async_workflow_orchestrator.py +738 -0
- crackerjack/core/autofix_coordinator.py +282 -0
- crackerjack/core/container.py +105 -0
- crackerjack/core/enhanced_container.py +583 -0
- crackerjack/core/file_lifecycle.py +472 -0
- crackerjack/core/performance.py +244 -0
- crackerjack/core/performance_monitor.py +357 -0
- crackerjack/core/phase_coordinator.py +1227 -0
- crackerjack/core/proactive_workflow.py +267 -0
- crackerjack/core/resource_manager.py +425 -0
- crackerjack/core/retry.py +275 -0
- crackerjack/core/service_watchdog.py +601 -0
- crackerjack/core/session_coordinator.py +239 -0
- crackerjack/core/timeout_manager.py +563 -0
- crackerjack/core/websocket_lifecycle.py +410 -0
- crackerjack/core/workflow/__init__.py +21 -0
- crackerjack/core/workflow/workflow_ai_coordinator.py +863 -0
- crackerjack/core/workflow/workflow_event_orchestrator.py +1107 -0
- crackerjack/core/workflow/workflow_issue_parser.py +714 -0
- crackerjack/core/workflow/workflow_phase_executor.py +1158 -0
- crackerjack/core/workflow/workflow_security_gates.py +400 -0
- crackerjack/core/workflow_orchestrator.py +2243 -0
- crackerjack/data/README.md +11 -0
- crackerjack/data/__init__.py +8 -0
- crackerjack/data/models.py +79 -0
- crackerjack/data/repository.py +210 -0
- crackerjack/decorators/README.md +180 -0
- crackerjack/decorators/__init__.py +35 -0
- crackerjack/decorators/error_handling.py +649 -0
- crackerjack/decorators/error_handling_decorators.py +334 -0
- crackerjack/decorators/helpers.py +58 -0
- crackerjack/decorators/patterns.py +281 -0
- crackerjack/decorators/utils.py +58 -0
- crackerjack/docs/INDEX.md +11 -0
- crackerjack/docs/README.md +11 -0
- crackerjack/docs/generated/api/API_REFERENCE.md +10895 -0
- crackerjack/docs/generated/api/CLI_REFERENCE.md +109 -0
- crackerjack/docs/generated/api/CROSS_REFERENCES.md +1755 -0
- crackerjack/docs/generated/api/PROTOCOLS.md +3 -0
- crackerjack/docs/generated/api/SERVICES.md +1252 -0
- crackerjack/documentation/README.md +11 -0
- crackerjack/documentation/__init__.py +31 -0
- crackerjack/documentation/ai_templates.py +756 -0
- crackerjack/documentation/dual_output_generator.py +767 -0
- crackerjack/documentation/mkdocs_integration.py +518 -0
- crackerjack/documentation/reference_generator.py +1065 -0
- crackerjack/dynamic_config.py +678 -0
- crackerjack/errors.py +378 -0
- crackerjack/events/README.md +11 -0
- crackerjack/events/__init__.py +16 -0
- crackerjack/events/telemetry.py +175 -0
- crackerjack/events/workflow_bus.py +346 -0
- crackerjack/exceptions/README.md +301 -0
- crackerjack/exceptions/__init__.py +5 -0
- crackerjack/exceptions/config.py +4 -0
- crackerjack/exceptions/tool_execution_error.py +245 -0
- crackerjack/executors/README.md +591 -0
- crackerjack/executors/__init__.py +13 -0
- crackerjack/executors/async_hook_executor.py +938 -0
- crackerjack/executors/cached_hook_executor.py +316 -0
- crackerjack/executors/hook_executor.py +1295 -0
- crackerjack/executors/hook_lock_manager.py +708 -0
- crackerjack/executors/individual_hook_executor.py +739 -0
- crackerjack/executors/lsp_aware_hook_executor.py +349 -0
- crackerjack/executors/progress_hook_executor.py +282 -0
- crackerjack/executors/tool_proxy.py +433 -0
- crackerjack/hooks/README.md +485 -0
- crackerjack/hooks/lsp_hook.py +93 -0
- crackerjack/intelligence/README.md +557 -0
- crackerjack/intelligence/__init__.py +37 -0
- crackerjack/intelligence/adaptive_learning.py +693 -0
- crackerjack/intelligence/agent_orchestrator.py +485 -0
- crackerjack/intelligence/agent_registry.py +377 -0
- crackerjack/intelligence/agent_selector.py +439 -0
- crackerjack/intelligence/integration.py +250 -0
- crackerjack/interactive.py +719 -0
- crackerjack/managers/README.md +369 -0
- crackerjack/managers/__init__.py +11 -0
- crackerjack/managers/async_hook_manager.py +135 -0
- crackerjack/managers/hook_manager.py +585 -0
- crackerjack/managers/publish_manager.py +631 -0
- crackerjack/managers/test_command_builder.py +391 -0
- crackerjack/managers/test_executor.py +474 -0
- crackerjack/managers/test_manager.py +1357 -0
- crackerjack/managers/test_progress.py +187 -0
- crackerjack/mcp/README.md +374 -0
- crackerjack/mcp/__init__.py +0 -0
- crackerjack/mcp/cache.py +352 -0
- crackerjack/mcp/client_runner.py +121 -0
- crackerjack/mcp/context.py +802 -0
- crackerjack/mcp/dashboard.py +657 -0
- crackerjack/mcp/enhanced_progress_monitor.py +493 -0
- crackerjack/mcp/file_monitor.py +394 -0
- crackerjack/mcp/progress_components.py +607 -0
- crackerjack/mcp/progress_monitor.py +1016 -0
- crackerjack/mcp/rate_limiter.py +336 -0
- crackerjack/mcp/server.py +24 -0
- crackerjack/mcp/server_core.py +526 -0
- crackerjack/mcp/service_watchdog.py +505 -0
- crackerjack/mcp/state.py +407 -0
- crackerjack/mcp/task_manager.py +259 -0
- crackerjack/mcp/tools/README.md +27 -0
- crackerjack/mcp/tools/__init__.py +19 -0
- crackerjack/mcp/tools/core_tools.py +469 -0
- crackerjack/mcp/tools/error_analyzer.py +283 -0
- crackerjack/mcp/tools/execution_tools.py +384 -0
- crackerjack/mcp/tools/intelligence_tool_registry.py +46 -0
- crackerjack/mcp/tools/intelligence_tools.py +264 -0
- crackerjack/mcp/tools/monitoring_tools.py +628 -0
- crackerjack/mcp/tools/proactive_tools.py +367 -0
- crackerjack/mcp/tools/progress_tools.py +222 -0
- crackerjack/mcp/tools/semantic_tools.py +584 -0
- crackerjack/mcp/tools/utility_tools.py +358 -0
- crackerjack/mcp/tools/workflow_executor.py +699 -0
- crackerjack/mcp/websocket/README.md +31 -0
- crackerjack/mcp/websocket/__init__.py +14 -0
- crackerjack/mcp/websocket/app.py +54 -0
- crackerjack/mcp/websocket/endpoints.py +492 -0
- crackerjack/mcp/websocket/event_bridge.py +188 -0
- crackerjack/mcp/websocket/jobs.py +406 -0
- crackerjack/mcp/websocket/monitoring/__init__.py +25 -0
- crackerjack/mcp/websocket/monitoring/api/__init__.py +19 -0
- crackerjack/mcp/websocket/monitoring/api/dependencies.py +141 -0
- crackerjack/mcp/websocket/monitoring/api/heatmap.py +154 -0
- crackerjack/mcp/websocket/monitoring/api/intelligence.py +199 -0
- crackerjack/mcp/websocket/monitoring/api/metrics.py +203 -0
- crackerjack/mcp/websocket/monitoring/api/telemetry.py +101 -0
- crackerjack/mcp/websocket/monitoring/dashboard.py +18 -0
- crackerjack/mcp/websocket/monitoring/factory.py +109 -0
- crackerjack/mcp/websocket/monitoring/filters.py +10 -0
- crackerjack/mcp/websocket/monitoring/metrics.py +64 -0
- crackerjack/mcp/websocket/monitoring/models.py +90 -0
- crackerjack/mcp/websocket/monitoring/utils.py +171 -0
- crackerjack/mcp/websocket/monitoring/websocket_manager.py +78 -0
- crackerjack/mcp/websocket/monitoring/websockets/__init__.py +17 -0
- crackerjack/mcp/websocket/monitoring/websockets/dependencies.py +126 -0
- crackerjack/mcp/websocket/monitoring/websockets/heatmap.py +176 -0
- crackerjack/mcp/websocket/monitoring/websockets/intelligence.py +291 -0
- crackerjack/mcp/websocket/monitoring/websockets/metrics.py +291 -0
- crackerjack/mcp/websocket/monitoring_endpoints.py +21 -0
- crackerjack/mcp/websocket/server.py +174 -0
- crackerjack/mcp/websocket/websocket_handler.py +276 -0
- crackerjack/mcp/websocket_server.py +10 -0
- crackerjack/models/README.md +308 -0
- crackerjack/models/__init__.py +40 -0
- crackerjack/models/config.py +730 -0
- crackerjack/models/config_adapter.py +265 -0
- crackerjack/models/protocols.py +1535 -0
- crackerjack/models/pydantic_models.py +320 -0
- crackerjack/models/qa_config.py +145 -0
- crackerjack/models/qa_results.py +134 -0
- crackerjack/models/resource_protocols.py +299 -0
- crackerjack/models/results.py +35 -0
- crackerjack/models/semantic_models.py +258 -0
- crackerjack/models/task.py +173 -0
- crackerjack/models/test_models.py +60 -0
- crackerjack/monitoring/README.md +11 -0
- crackerjack/monitoring/__init__.py +0 -0
- crackerjack/monitoring/ai_agent_watchdog.py +405 -0
- crackerjack/monitoring/metrics_collector.py +427 -0
- crackerjack/monitoring/regression_prevention.py +580 -0
- crackerjack/monitoring/websocket_server.py +406 -0
- crackerjack/orchestration/README.md +340 -0
- crackerjack/orchestration/__init__.py +43 -0
- crackerjack/orchestration/advanced_orchestrator.py +894 -0
- crackerjack/orchestration/cache/README.md +312 -0
- crackerjack/orchestration/cache/__init__.py +37 -0
- crackerjack/orchestration/cache/memory_cache.py +338 -0
- crackerjack/orchestration/cache/tool_proxy_cache.py +340 -0
- crackerjack/orchestration/config.py +297 -0
- crackerjack/orchestration/coverage_improvement.py +180 -0
- crackerjack/orchestration/execution_strategies.py +361 -0
- crackerjack/orchestration/hook_orchestrator.py +1398 -0
- crackerjack/orchestration/strategies/README.md +401 -0
- crackerjack/orchestration/strategies/__init__.py +39 -0
- crackerjack/orchestration/strategies/adaptive_strategy.py +630 -0
- crackerjack/orchestration/strategies/parallel_strategy.py +237 -0
- crackerjack/orchestration/strategies/sequential_strategy.py +299 -0
- crackerjack/orchestration/test_progress_streamer.py +647 -0
- crackerjack/plugins/README.md +11 -0
- crackerjack/plugins/__init__.py +15 -0
- crackerjack/plugins/base.py +200 -0
- crackerjack/plugins/hooks.py +254 -0
- crackerjack/plugins/loader.py +335 -0
- crackerjack/plugins/managers.py +264 -0
- crackerjack/py313.py +191 -0
- crackerjack/security/README.md +11 -0
- crackerjack/security/__init__.py +0 -0
- crackerjack/security/audit.py +197 -0
- crackerjack/services/README.md +374 -0
- crackerjack/services/__init__.py +9 -0
- crackerjack/services/ai/README.md +295 -0
- crackerjack/services/ai/__init__.py +7 -0
- crackerjack/services/ai/advanced_optimizer.py +878 -0
- crackerjack/services/ai/contextual_ai_assistant.py +542 -0
- crackerjack/services/ai/embeddings.py +444 -0
- crackerjack/services/ai/intelligent_commit.py +328 -0
- crackerjack/services/ai/predictive_analytics.py +510 -0
- crackerjack/services/anomaly_detector.py +392 -0
- crackerjack/services/api_extractor.py +617 -0
- crackerjack/services/backup_service.py +467 -0
- crackerjack/services/bounded_status_operations.py +530 -0
- crackerjack/services/cache.py +369 -0
- crackerjack/services/changelog_automation.py +399 -0
- crackerjack/services/command_execution_service.py +305 -0
- crackerjack/services/config_integrity.py +132 -0
- crackerjack/services/config_merge.py +546 -0
- crackerjack/services/config_service.py +198 -0
- crackerjack/services/config_template.py +493 -0
- crackerjack/services/coverage_badge_service.py +173 -0
- crackerjack/services/coverage_ratchet.py +381 -0
- crackerjack/services/debug.py +733 -0
- crackerjack/services/dependency_analyzer.py +460 -0
- crackerjack/services/dependency_monitor.py +622 -0
- crackerjack/services/documentation_generator.py +493 -0
- crackerjack/services/documentation_service.py +704 -0
- crackerjack/services/enhanced_filesystem.py +497 -0
- crackerjack/services/enterprise_optimizer.py +865 -0
- crackerjack/services/error_pattern_analyzer.py +676 -0
- crackerjack/services/file_filter.py +221 -0
- crackerjack/services/file_hasher.py +149 -0
- crackerjack/services/file_io_service.py +361 -0
- crackerjack/services/file_modifier.py +615 -0
- crackerjack/services/filesystem.py +381 -0
- crackerjack/services/git.py +422 -0
- crackerjack/services/health_metrics.py +615 -0
- crackerjack/services/heatmap_generator.py +744 -0
- crackerjack/services/incremental_executor.py +380 -0
- crackerjack/services/initialization.py +823 -0
- crackerjack/services/input_validator.py +668 -0
- crackerjack/services/intelligent_commit.py +327 -0
- crackerjack/services/log_manager.py +289 -0
- crackerjack/services/logging.py +228 -0
- crackerjack/services/lsp_client.py +628 -0
- crackerjack/services/memory_optimizer.py +414 -0
- crackerjack/services/metrics.py +587 -0
- crackerjack/services/monitoring/README.md +30 -0
- crackerjack/services/monitoring/__init__.py +9 -0
- crackerjack/services/monitoring/dependency_monitor.py +678 -0
- crackerjack/services/monitoring/error_pattern_analyzer.py +676 -0
- crackerjack/services/monitoring/health_metrics.py +716 -0
- crackerjack/services/monitoring/metrics.py +587 -0
- crackerjack/services/monitoring/performance_benchmarks.py +410 -0
- crackerjack/services/monitoring/performance_cache.py +388 -0
- crackerjack/services/monitoring/performance_monitor.py +569 -0
- crackerjack/services/parallel_executor.py +527 -0
- crackerjack/services/pattern_cache.py +333 -0
- crackerjack/services/pattern_detector.py +478 -0
- crackerjack/services/patterns/__init__.py +142 -0
- crackerjack/services/patterns/agents.py +107 -0
- crackerjack/services/patterns/code/__init__.py +15 -0
- crackerjack/services/patterns/code/detection.py +118 -0
- crackerjack/services/patterns/code/imports.py +107 -0
- crackerjack/services/patterns/code/paths.py +159 -0
- crackerjack/services/patterns/code/performance.py +119 -0
- crackerjack/services/patterns/code/replacement.py +36 -0
- crackerjack/services/patterns/core.py +212 -0
- crackerjack/services/patterns/documentation/__init__.py +14 -0
- crackerjack/services/patterns/documentation/badges_markdown.py +96 -0
- crackerjack/services/patterns/documentation/comments_blocks.py +83 -0
- crackerjack/services/patterns/documentation/docstrings.py +89 -0
- crackerjack/services/patterns/formatting.py +226 -0
- crackerjack/services/patterns/operations.py +339 -0
- crackerjack/services/patterns/security/__init__.py +23 -0
- crackerjack/services/patterns/security/code_injection.py +122 -0
- crackerjack/services/patterns/security/credentials.py +190 -0
- crackerjack/services/patterns/security/path_traversal.py +221 -0
- crackerjack/services/patterns/security/unsafe_operations.py +216 -0
- crackerjack/services/patterns/templates.py +62 -0
- crackerjack/services/patterns/testing/__init__.py +18 -0
- crackerjack/services/patterns/testing/error_patterns.py +107 -0
- crackerjack/services/patterns/testing/pytest_output.py +126 -0
- crackerjack/services/patterns/tool_output/__init__.py +16 -0
- crackerjack/services/patterns/tool_output/bandit.py +72 -0
- crackerjack/services/patterns/tool_output/other.py +97 -0
- crackerjack/services/patterns/tool_output/pyright.py +67 -0
- crackerjack/services/patterns/tool_output/ruff.py +44 -0
- crackerjack/services/patterns/url_sanitization.py +114 -0
- crackerjack/services/patterns/utilities.py +42 -0
- crackerjack/services/patterns/utils.py +339 -0
- crackerjack/services/patterns/validation.py +46 -0
- crackerjack/services/patterns/versioning.py +62 -0
- crackerjack/services/predictive_analytics.py +523 -0
- crackerjack/services/profiler.py +280 -0
- crackerjack/services/quality/README.md +415 -0
- crackerjack/services/quality/__init__.py +11 -0
- crackerjack/services/quality/anomaly_detector.py +392 -0
- crackerjack/services/quality/pattern_cache.py +333 -0
- crackerjack/services/quality/pattern_detector.py +479 -0
- crackerjack/services/quality/qa_orchestrator.py +491 -0
- crackerjack/services/quality/quality_baseline.py +395 -0
- crackerjack/services/quality/quality_baseline_enhanced.py +649 -0
- crackerjack/services/quality/quality_intelligence.py +949 -0
- crackerjack/services/regex_patterns.py +58 -0
- crackerjack/services/regex_utils.py +483 -0
- crackerjack/services/secure_path_utils.py +524 -0
- crackerjack/services/secure_status_formatter.py +450 -0
- crackerjack/services/secure_subprocess.py +635 -0
- crackerjack/services/security.py +239 -0
- crackerjack/services/security_logger.py +495 -0
- crackerjack/services/server_manager.py +411 -0
- crackerjack/services/smart_scheduling.py +167 -0
- crackerjack/services/status_authentication.py +460 -0
- crackerjack/services/status_security_manager.py +315 -0
- crackerjack/services/terminal_utils.py +0 -0
- crackerjack/services/thread_safe_status_collector.py +441 -0
- crackerjack/services/tool_filter.py +368 -0
- crackerjack/services/tool_version_service.py +43 -0
- crackerjack/services/unified_config.py +115 -0
- crackerjack/services/validation_rate_limiter.py +220 -0
- crackerjack/services/vector_store.py +689 -0
- crackerjack/services/version_analyzer.py +461 -0
- crackerjack/services/version_checker.py +223 -0
- crackerjack/services/websocket_resource_limiter.py +438 -0
- crackerjack/services/zuban_lsp_service.py +391 -0
- crackerjack/slash_commands/README.md +11 -0
- crackerjack/slash_commands/__init__.py +59 -0
- crackerjack/slash_commands/init.md +112 -0
- crackerjack/slash_commands/run.md +197 -0
- crackerjack/slash_commands/status.md +127 -0
- crackerjack/tools/README.md +11 -0
- crackerjack/tools/__init__.py +30 -0
- crackerjack/tools/_git_utils.py +105 -0
- crackerjack/tools/check_added_large_files.py +139 -0
- crackerjack/tools/check_ast.py +105 -0
- crackerjack/tools/check_json.py +103 -0
- crackerjack/tools/check_jsonschema.py +297 -0
- crackerjack/tools/check_toml.py +103 -0
- crackerjack/tools/check_yaml.py +110 -0
- crackerjack/tools/codespell_wrapper.py +72 -0
- crackerjack/tools/end_of_file_fixer.py +202 -0
- crackerjack/tools/format_json.py +128 -0
- crackerjack/tools/mdformat_wrapper.py +114 -0
- crackerjack/tools/trailing_whitespace.py +198 -0
- crackerjack/tools/validate_input_validator_patterns.py +236 -0
- crackerjack/tools/validate_regex_patterns.py +188 -0
- crackerjack/ui/README.md +11 -0
- crackerjack/ui/__init__.py +1 -0
- crackerjack/ui/dashboard_renderer.py +28 -0
- crackerjack/ui/templates/README.md +11 -0
- crackerjack/utils/console_utils.py +13 -0
- crackerjack/utils/dependency_guard.py +230 -0
- crackerjack/utils/retry_utils.py +275 -0
- crackerjack/workflows/README.md +590 -0
- crackerjack/workflows/__init__.py +46 -0
- crackerjack/workflows/actions.py +811 -0
- crackerjack/workflows/auto_fix.py +444 -0
- crackerjack/workflows/container_builder.py +499 -0
- crackerjack/workflows/definitions.py +443 -0
- crackerjack/workflows/engine.py +177 -0
- crackerjack/workflows/event_bridge.py +242 -0
- crackerjack-0.45.2.dist-info/METADATA +1678 -0
- crackerjack-0.45.2.dist-info/RECORD +478 -0
- {crackerjack-0.18.2.dist-info → crackerjack-0.45.2.dist-info}/WHEEL +1 -1
- crackerjack-0.45.2.dist-info/entry_points.txt +2 -0
- crackerjack/.gitignore +0 -14
- crackerjack/.libcst.codemod.yaml +0 -18
- crackerjack/.pdm.toml +0 -1
- crackerjack/.pre-commit-config.yaml +0 -91
- crackerjack/.pytest_cache/.gitignore +0 -2
- crackerjack/.pytest_cache/CACHEDIR.TAG +0 -4
- crackerjack/.pytest_cache/README.md +0 -8
- crackerjack/.pytest_cache/v/cache/nodeids +0 -1
- crackerjack/.pytest_cache/v/cache/stepwise +0 -1
- crackerjack/.ruff_cache/.gitignore +0 -1
- crackerjack/.ruff_cache/0.1.11/3256171999636029978 +0 -0
- crackerjack/.ruff_cache/0.1.14/602324811142551221 +0 -0
- crackerjack/.ruff_cache/0.1.4/10355199064880463147 +0 -0
- crackerjack/.ruff_cache/0.1.6/15140459877605758699 +0 -0
- crackerjack/.ruff_cache/0.1.7/1790508110482614856 +0 -0
- crackerjack/.ruff_cache/0.1.9/17041001205004563469 +0 -0
- crackerjack/.ruff_cache/0.11.2/4070660268492669020 +0 -0
- crackerjack/.ruff_cache/0.11.3/9818742842212983150 +0 -0
- crackerjack/.ruff_cache/0.11.4/9818742842212983150 +0 -0
- crackerjack/.ruff_cache/0.11.6/3557596832929915217 +0 -0
- crackerjack/.ruff_cache/0.11.7/10386934055395314831 +0 -0
- crackerjack/.ruff_cache/0.11.7/3557596832929915217 +0 -0
- crackerjack/.ruff_cache/0.11.8/530407680854991027 +0 -0
- crackerjack/.ruff_cache/0.2.0/10047773857155985907 +0 -0
- crackerjack/.ruff_cache/0.2.1/8522267973936635051 +0 -0
- crackerjack/.ruff_cache/0.2.2/18053836298936336950 +0 -0
- crackerjack/.ruff_cache/0.3.0/12548816621480535786 +0 -0
- crackerjack/.ruff_cache/0.3.3/11081883392474770722 +0 -0
- crackerjack/.ruff_cache/0.3.4/676973378459347183 +0 -0
- crackerjack/.ruff_cache/0.3.5/16311176246009842383 +0 -0
- crackerjack/.ruff_cache/0.5.7/1493622539551733492 +0 -0
- crackerjack/.ruff_cache/0.5.7/6231957614044513175 +0 -0
- crackerjack/.ruff_cache/0.5.7/9932762556785938009 +0 -0
- crackerjack/.ruff_cache/0.6.0/11982804814124138945 +0 -0
- crackerjack/.ruff_cache/0.6.0/12055761203849489982 +0 -0
- crackerjack/.ruff_cache/0.6.2/1206147804896221174 +0 -0
- crackerjack/.ruff_cache/0.6.4/1206147804896221174 +0 -0
- crackerjack/.ruff_cache/0.6.5/1206147804896221174 +0 -0
- crackerjack/.ruff_cache/0.6.7/3657366982708166874 +0 -0
- crackerjack/.ruff_cache/0.6.9/285614542852677309 +0 -0
- crackerjack/.ruff_cache/0.7.1/1024065805990144819 +0 -0
- crackerjack/.ruff_cache/0.7.1/285614542852677309 +0 -0
- crackerjack/.ruff_cache/0.7.3/16061516852537040135 +0 -0
- crackerjack/.ruff_cache/0.8.4/16354268377385700367 +0 -0
- crackerjack/.ruff_cache/0.9.10/12813592349865671909 +0 -0
- crackerjack/.ruff_cache/0.9.10/923908772239632759 +0 -0
- crackerjack/.ruff_cache/0.9.3/13948373885254993391 +0 -0
- crackerjack/.ruff_cache/0.9.9/12813592349865671909 +0 -0
- crackerjack/.ruff_cache/0.9.9/8843823720003377982 +0 -0
- crackerjack/.ruff_cache/CACHEDIR.TAG +0 -1
- crackerjack/crackerjack.py +0 -855
- crackerjack/pyproject.toml +0 -214
- crackerjack-0.18.2.dist-info/METADATA +0 -420
- crackerjack-0.18.2.dist-info/RECORD +0 -59
- crackerjack-0.18.2.dist-info/entry_points.txt +0 -4
- {crackerjack-0.18.2.dist-info → crackerjack-0.45.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,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"])
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import hashlib
|
|
3
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from .cache import CrackerjackCache
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class FileHasher:
|
|
10
|
+
def __init__(self, cache: CrackerjackCache | None = None) -> None:
|
|
11
|
+
self.cache = cache or CrackerjackCache()
|
|
12
|
+
self._executor = ThreadPoolExecutor(max_workers=4)
|
|
13
|
+
|
|
14
|
+
def get_file_hash(self, file_path: Path, algorithm: str = "md5") -> str:
|
|
15
|
+
if not file_path.exists():
|
|
16
|
+
return ""
|
|
17
|
+
|
|
18
|
+
cached_hash = self.cache.get_file_hash(file_path)
|
|
19
|
+
if cached_hash:
|
|
20
|
+
return cached_hash
|
|
21
|
+
|
|
22
|
+
file_hash = self._compute_file_hash(file_path, algorithm)
|
|
23
|
+
self.cache.set_file_hash(file_path, file_hash)
|
|
24
|
+
return file_hash
|
|
25
|
+
|
|
26
|
+
def get_directory_hash(
|
|
27
|
+
self,
|
|
28
|
+
directory: Path,
|
|
29
|
+
patterns: list[str] | None = None,
|
|
30
|
+
) -> str:
|
|
31
|
+
if patterns is None:
|
|
32
|
+
patterns = ["*.py"]
|
|
33
|
+
|
|
34
|
+
file_hashes: list[str] = []
|
|
35
|
+
for pattern in patterns:
|
|
36
|
+
for file_path in directory.rglob(pattern):
|
|
37
|
+
if file_path.is_file():
|
|
38
|
+
file_hash = self.get_file_hash(file_path)
|
|
39
|
+
file_hashes.append(
|
|
40
|
+
f"{file_path.relative_to(directory)}: {file_hash}",
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
file_hashes.sort()
|
|
44
|
+
combined_content = "\n".join(file_hashes)
|
|
45
|
+
return hashlib.md5(combined_content.encode(), usedforsecurity=False).hexdigest()
|
|
46
|
+
|
|
47
|
+
def get_files_hash_list(self, files: list[Path]) -> list[str]:
|
|
48
|
+
return [
|
|
49
|
+
self.get_file_hash(file_path) for file_path in files if file_path.exists()
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
async def get_files_hash_list_async(self, files: list[Path]) -> list[str]:
|
|
53
|
+
loop = asyncio.get_running_loop()
|
|
54
|
+
tasks = [
|
|
55
|
+
loop.run_in_executor(self._executor, self.get_file_hash, file_path, "md5")
|
|
56
|
+
for file_path in files
|
|
57
|
+
if file_path.exists()
|
|
58
|
+
]
|
|
59
|
+
return await asyncio.gather(*tasks)
|
|
60
|
+
|
|
61
|
+
def has_files_changed(self, files: list[Path], cached_hashes: list[str]) -> bool:
|
|
62
|
+
if len(files) != len(cached_hashes):
|
|
63
|
+
return True
|
|
64
|
+
|
|
65
|
+
current_hashes = self.get_files_hash_list(files)
|
|
66
|
+
return current_hashes != cached_hashes
|
|
67
|
+
|
|
68
|
+
def _compute_file_hash(self, file_path: Path, algorithm: str = "md5") -> str:
|
|
69
|
+
hash_func = hashlib.new(algorithm)
|
|
70
|
+
|
|
71
|
+
try:
|
|
72
|
+
with file_path.open("rb") as f:
|
|
73
|
+
while chunk := f.read(8192):
|
|
74
|
+
hash_func.update(chunk)
|
|
75
|
+
return hash_func.hexdigest()
|
|
76
|
+
except OSError:
|
|
77
|
+
return ""
|
|
78
|
+
|
|
79
|
+
def get_project_files_hash(self, project_path: Path) -> dict[str, str]:
|
|
80
|
+
patterns = ["*.py", "*.toml", "*.cfg", "*.ini", "*.yaml", "*.yml"]
|
|
81
|
+
file_hashes = {}
|
|
82
|
+
|
|
83
|
+
for pattern in patterns:
|
|
84
|
+
for file_path in project_path.rglob(pattern):
|
|
85
|
+
if file_path.is_file() and not self._should_ignore_file(file_path):
|
|
86
|
+
relative_path = str(file_path.relative_to(project_path))
|
|
87
|
+
file_hashes[relative_path] = self.get_file_hash(file_path)
|
|
88
|
+
|
|
89
|
+
return file_hashes
|
|
90
|
+
|
|
91
|
+
def _should_ignore_file(self, file_path: Path) -> bool:
|
|
92
|
+
ignore_patterns = [
|
|
93
|
+
".git",
|
|
94
|
+
".venv",
|
|
95
|
+
"__pycache__",
|
|
96
|
+
".pytest_cache",
|
|
97
|
+
".coverage",
|
|
98
|
+
".crackerjack_cache",
|
|
99
|
+
"node_modules",
|
|
100
|
+
".tox",
|
|
101
|
+
"dist",
|
|
102
|
+
"build",
|
|
103
|
+
"*.egg-info",
|
|
104
|
+
]
|
|
105
|
+
|
|
106
|
+
path_str = str(file_path)
|
|
107
|
+
return any(pattern in path_str for pattern in ignore_patterns)
|
|
108
|
+
|
|
109
|
+
def invalidate_cache(self, file_path: Path | None = None) -> None:
|
|
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
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class SmartFileWatcher:
|
|
118
|
+
def __init__(self, file_hasher: FileHasher) -> None:
|
|
119
|
+
self.file_hasher = file_hasher
|
|
120
|
+
self._watched_files: dict[Path, tuple[float, int]] = {}
|
|
121
|
+
|
|
122
|
+
def register_files(self, files: list[Path]) -> None:
|
|
123
|
+
for file_path in files:
|
|
124
|
+
if file_path.exists():
|
|
125
|
+
stat = file_path.stat()
|
|
126
|
+
self._watched_files[file_path] = (stat.st_mtime, stat.st_size)
|
|
127
|
+
|
|
128
|
+
def check_changes(self) -> list[Path]:
|
|
129
|
+
changed_files: list[Path] = []
|
|
130
|
+
|
|
131
|
+
for file_path, (old_mtime, old_size) in self._watched_files.items():
|
|
132
|
+
if not file_path.exists():
|
|
133
|
+
changed_files.append(file_path)
|
|
134
|
+
continue
|
|
135
|
+
|
|
136
|
+
stat = file_path.stat()
|
|
137
|
+
if stat.st_mtime != old_mtime or stat.st_size != old_size:
|
|
138
|
+
changed_files.append(file_path)
|
|
139
|
+
self._watched_files[file_path] = (stat.st_mtime, stat.st_size)
|
|
140
|
+
|
|
141
|
+
return changed_files
|
|
142
|
+
|
|
143
|
+
def invalidate_changed_files(self) -> int:
|
|
144
|
+
changed_files = self.check_changes()
|
|
145
|
+
|
|
146
|
+
for file_path in changed_files:
|
|
147
|
+
self.file_hasher.invalidate_cache(file_path)
|
|
148
|
+
|
|
149
|
+
return len(changed_files)
|