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,522 @@
|
|
|
1
|
+
"""Zuban adapter for ACB QA framework - ultra-fast Python type checking.
|
|
2
|
+
|
|
3
|
+
Zuban is a Rust-based type checker for Python, offering 20-200x faster type checking
|
|
4
|
+
compared to traditional tools like pyright or mypy. It provides:
|
|
5
|
+
- Static type analysis
|
|
6
|
+
- Type inference
|
|
7
|
+
- Generic type checking
|
|
8
|
+
- Protocol compliance validation
|
|
9
|
+
|
|
10
|
+
ACB Patterns:
|
|
11
|
+
- MODULE_ID and MODULE_STATUS at module level
|
|
12
|
+
- depends.set() registration after class definition
|
|
13
|
+
- Extends BaseToolAdapter for tool execution
|
|
14
|
+
- Async execution with JSON output parsing
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import logging
|
|
20
|
+
import typing as t
|
|
21
|
+
from contextlib import suppress
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
from uuid import UUID
|
|
24
|
+
|
|
25
|
+
from acb.depends import depends
|
|
26
|
+
|
|
27
|
+
from crackerjack.adapters._tool_adapter_base import (
|
|
28
|
+
BaseToolAdapter,
|
|
29
|
+
ToolAdapterSettings,
|
|
30
|
+
ToolExecutionResult,
|
|
31
|
+
ToolIssue,
|
|
32
|
+
)
|
|
33
|
+
from crackerjack.models.qa_results import QACheckType
|
|
34
|
+
|
|
35
|
+
if t.TYPE_CHECKING:
|
|
36
|
+
from crackerjack.models.qa_config import QACheckConfig
|
|
37
|
+
|
|
38
|
+
# ACB Module Registration (REQUIRED)
|
|
39
|
+
MODULE_ID = UUID(
|
|
40
|
+
"01937d86-6b2c-7d3e-8f4a-b5c6d7e8f9a0"
|
|
41
|
+
) # Static UUID7 for reproducible module identity
|
|
42
|
+
MODULE_STATUS = "stable"
|
|
43
|
+
|
|
44
|
+
# Module-level logger for structured logging
|
|
45
|
+
logger = logging.getLogger(__name__)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class ZubanSettings(ToolAdapterSettings):
|
|
49
|
+
"""Settings for Zuban adapter."""
|
|
50
|
+
|
|
51
|
+
tool_name: str = "zuban"
|
|
52
|
+
use_json_output: bool = False # Zuban doesn't support JSON output
|
|
53
|
+
strict_mode: bool = False
|
|
54
|
+
ignore_missing_imports: bool = False
|
|
55
|
+
follow_imports: str = "normal" # normal, skip, silent
|
|
56
|
+
cache_dir: Path | None = None
|
|
57
|
+
incremental: bool = True
|
|
58
|
+
warn_unused_ignores: bool = False # Not supported by zuban directly
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class ZubanAdapter(BaseToolAdapter):
|
|
62
|
+
"""Adapter for Zuban - ultra-fast Rust-based Python type checker.
|
|
63
|
+
|
|
64
|
+
Performs static type analysis with exceptional performance:
|
|
65
|
+
- Type checking 20-200x faster than pyright
|
|
66
|
+
- Type inference and validation
|
|
67
|
+
- Generic type support
|
|
68
|
+
- Protocol compliance checking
|
|
69
|
+
|
|
70
|
+
Features:
|
|
71
|
+
- JSON output for structured error reporting
|
|
72
|
+
- Incremental type checking with caching
|
|
73
|
+
- Strict mode for enhanced type safety
|
|
74
|
+
- Import following configuration
|
|
75
|
+
- Parallel execution support
|
|
76
|
+
|
|
77
|
+
Example:
|
|
78
|
+
```python
|
|
79
|
+
settings = ZubanSettings(
|
|
80
|
+
strict_mode=True,
|
|
81
|
+
follow_imports="normal",
|
|
82
|
+
incremental=True,
|
|
83
|
+
)
|
|
84
|
+
adapter = ZubanAdapter(settings=settings)
|
|
85
|
+
await adapter.init()
|
|
86
|
+
result = await adapter.check(files=[Path("src/")])
|
|
87
|
+
```
|
|
88
|
+
"""
|
|
89
|
+
|
|
90
|
+
settings: ZubanSettings | None = None
|
|
91
|
+
|
|
92
|
+
def __init__(self, settings: ZubanSettings | None = None) -> None:
|
|
93
|
+
"""Initialize Zuban adapter.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
settings: Optional settings override
|
|
97
|
+
"""
|
|
98
|
+
super().__init__(settings=settings)
|
|
99
|
+
logger.debug(
|
|
100
|
+
"ZubanAdapter initialized", extra={"has_settings": settings is not None}
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
async def init(self) -> None:
|
|
104
|
+
"""Initialize adapter with default settings."""
|
|
105
|
+
if not self.settings:
|
|
106
|
+
self.settings = ZubanSettings()
|
|
107
|
+
logger.info("Using default ZubanSettings")
|
|
108
|
+
await super().init()
|
|
109
|
+
logger.debug(
|
|
110
|
+
"ZubanAdapter initialization complete",
|
|
111
|
+
extra={
|
|
112
|
+
"strict_mode": self.settings.strict_mode,
|
|
113
|
+
"incremental": self.settings.incremental,
|
|
114
|
+
"follow_imports": self.settings.follow_imports,
|
|
115
|
+
"has_cache_dir": self.settings.cache_dir is not None,
|
|
116
|
+
},
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
@property
|
|
120
|
+
def adapter_name(self) -> str:
|
|
121
|
+
"""Human-readable adapter name."""
|
|
122
|
+
return "Zuban (Type Check)"
|
|
123
|
+
|
|
124
|
+
@property
|
|
125
|
+
def module_id(self) -> UUID:
|
|
126
|
+
"""Reference to module-level MODULE_ID."""
|
|
127
|
+
return MODULE_ID
|
|
128
|
+
|
|
129
|
+
@property
|
|
130
|
+
def tool_name(self) -> str:
|
|
131
|
+
"""CLI tool name."""
|
|
132
|
+
return "zuban"
|
|
133
|
+
|
|
134
|
+
def build_command(
|
|
135
|
+
self,
|
|
136
|
+
files: list[Path],
|
|
137
|
+
config: QACheckConfig | None = None,
|
|
138
|
+
) -> list[str]:
|
|
139
|
+
"""Build Zuban command.
|
|
140
|
+
|
|
141
|
+
Args:
|
|
142
|
+
files: Files/directories to type check
|
|
143
|
+
config: Optional configuration override
|
|
144
|
+
|
|
145
|
+
Returns:
|
|
146
|
+
Command as list of strings
|
|
147
|
+
"""
|
|
148
|
+
if not self.settings:
|
|
149
|
+
raise RuntimeError("Settings not initialized")
|
|
150
|
+
|
|
151
|
+
# Use mypy-compatible command as it's more likely to have expected behavior
|
|
152
|
+
cmd = [self.tool_name, "mypy", "--config-file", "mypy.ini"]
|
|
153
|
+
|
|
154
|
+
# Strict mode
|
|
155
|
+
if self.settings.strict_mode:
|
|
156
|
+
cmd.append("--strict")
|
|
157
|
+
|
|
158
|
+
# Ignore missing imports
|
|
159
|
+
if self.settings.ignore_missing_imports:
|
|
160
|
+
cmd.append("--ignore-missing-imports")
|
|
161
|
+
|
|
162
|
+
# Follow imports
|
|
163
|
+
if self.settings.follow_imports == "normal":
|
|
164
|
+
pass # default
|
|
165
|
+
elif self.settings.follow_imports == "skip":
|
|
166
|
+
cmd.append("--follow-untyped-imports")
|
|
167
|
+
elif self.settings.follow_imports == "silent":
|
|
168
|
+
# Doesn't have a direct equivalent, skipping for now
|
|
169
|
+
pass
|
|
170
|
+
|
|
171
|
+
# Cache directory
|
|
172
|
+
if self.settings.cache_dir:
|
|
173
|
+
cmd.extend(["--cache-dir", str(self.settings.cache_dir)])
|
|
174
|
+
|
|
175
|
+
# NOTE: Zuban doesn't support incremental checking with mypy subcommand
|
|
176
|
+
# Skipping --incremental flag to prevent execution errors
|
|
177
|
+
# if self.settings.incremental:
|
|
178
|
+
# cmd.append("--incremental")
|
|
179
|
+
|
|
180
|
+
# Add targets
|
|
181
|
+
cmd.extend([str(f) for f in files])
|
|
182
|
+
|
|
183
|
+
logger.info(
|
|
184
|
+
"Built Zuban command",
|
|
185
|
+
extra={
|
|
186
|
+
"file_count": len(files),
|
|
187
|
+
"strict_mode": self.settings.strict_mode,
|
|
188
|
+
"incremental": self.settings.incremental,
|
|
189
|
+
"follow_imports": self.settings.follow_imports,
|
|
190
|
+
"has_cache_dir": self.settings.cache_dir is not None,
|
|
191
|
+
},
|
|
192
|
+
)
|
|
193
|
+
return cmd
|
|
194
|
+
|
|
195
|
+
async def parse_output(
|
|
196
|
+
self,
|
|
197
|
+
result: ToolExecutionResult,
|
|
198
|
+
) -> list[ToolIssue]:
|
|
199
|
+
"""Parse Zuban text output into standardized issues.
|
|
200
|
+
|
|
201
|
+
Args:
|
|
202
|
+
result: Raw execution result from Zuban
|
|
203
|
+
|
|
204
|
+
Returns:
|
|
205
|
+
List of parsed issues
|
|
206
|
+
"""
|
|
207
|
+
if not result.raw_output:
|
|
208
|
+
logger.debug("No output to parse")
|
|
209
|
+
return []
|
|
210
|
+
|
|
211
|
+
logger.debug(
|
|
212
|
+
"Parsing Zuban text output",
|
|
213
|
+
extra={"output_length": len(result.raw_output)},
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
# Parse text output as zuban doesn't support JSON format
|
|
217
|
+
return self._parse_text_output(result.raw_output)
|
|
218
|
+
|
|
219
|
+
def _check_has_column(self, parts: list[str]) -> tuple[bool, int | None]:
|
|
220
|
+
"""Check if parts[2] is a column number and return it if so."""
|
|
221
|
+
has_column = parts[2].strip().isdigit()
|
|
222
|
+
column_number = int(parts[2].strip()) if has_column else None
|
|
223
|
+
return has_column, column_number
|
|
224
|
+
|
|
225
|
+
def _parse_with_column_format(
|
|
226
|
+
self, file_path_str: str, line_str: str, parts: list[str]
|
|
227
|
+
) -> tuple[Path, int, int | None, str, str] | None:
|
|
228
|
+
"""Parse format: file:line:col: error: message [code]."""
|
|
229
|
+
if not line_str.isdigit():
|
|
230
|
+
return None
|
|
231
|
+
|
|
232
|
+
line_number = int(line_str)
|
|
233
|
+
column_number = int(line_str)
|
|
234
|
+
|
|
235
|
+
# Third part would be the error type
|
|
236
|
+
severity_and_message = parts[2].strip() if len(parts) > 2 else ""
|
|
237
|
+
message_with_code = parts[3].strip() if len(parts) > 3 else severity_and_message
|
|
238
|
+
|
|
239
|
+
# Extract code from message (like [operator])
|
|
240
|
+
message, code = self._extract_message_and_code(message_with_code)
|
|
241
|
+
|
|
242
|
+
return (Path(file_path_str), line_number, column_number, message, code)
|
|
243
|
+
|
|
244
|
+
def _parse_without_column_format(
|
|
245
|
+
self, file_path_str: str, line_str: str, parts: list[str]
|
|
246
|
+
) -> tuple[Path, int, int | None, str, str]:
|
|
247
|
+
"""Parse format: file:line: error: message [code] (no column)."""
|
|
248
|
+
file_path = Path(file_path_str)
|
|
249
|
+
message_with_code = (
|
|
250
|
+
parts[2].strip() + ":" + parts[3].strip()
|
|
251
|
+
if len(parts) > 3
|
|
252
|
+
else parts[2].strip()
|
|
253
|
+
)
|
|
254
|
+
message, code = self._extract_message_and_code(message_with_code)
|
|
255
|
+
# No column number in this format
|
|
256
|
+
return file_path, int(line_str), None, message, code
|
|
257
|
+
|
|
258
|
+
def _parse_standard_format(
|
|
259
|
+
self, file_path_str: str, line_str: str, parts: list[str]
|
|
260
|
+
) -> tuple[Path, int, int | None, str, str]:
|
|
261
|
+
"""Parse standard format: file:line: error: message [code]."""
|
|
262
|
+
file_path = Path(file_path_str)
|
|
263
|
+
line_number = int(line_str)
|
|
264
|
+
|
|
265
|
+
# Second part after colon is severity/error type
|
|
266
|
+
severity_and_message = parts[2].strip()
|
|
267
|
+
message_with_code = parts[3].strip() if len(parts) > 3 else severity_and_message
|
|
268
|
+
|
|
269
|
+
# Extract message and code
|
|
270
|
+
message, code = self._extract_message_and_code(message_with_code)
|
|
271
|
+
|
|
272
|
+
return file_path, line_number, None, message, code
|
|
273
|
+
|
|
274
|
+
def _extract_parts_from_line(
|
|
275
|
+
self, line: str
|
|
276
|
+
) -> tuple[Path, int, int | None, str, str] | None:
|
|
277
|
+
"""Extract path, line, column, severity and message from a line."""
|
|
278
|
+
# Handle zuban output: "file:line: error: message [code]"
|
|
279
|
+
if ":" not in line:
|
|
280
|
+
return None
|
|
281
|
+
|
|
282
|
+
# Split at colons, but be careful with colon positions
|
|
283
|
+
# Format: file:line: error: message [code]
|
|
284
|
+
parts = line.split(":", maxsplit=3)
|
|
285
|
+
if len(parts) < 3:
|
|
286
|
+
return None
|
|
287
|
+
|
|
288
|
+
try:
|
|
289
|
+
file_path_str = parts[0].strip()
|
|
290
|
+
line_str = parts[1].strip()
|
|
291
|
+
|
|
292
|
+
if not line_str:
|
|
293
|
+
# If second part after colon is empty, it might have column info
|
|
294
|
+
# Maybe format is: file:line:col: error: message [code]
|
|
295
|
+
if len(parts) >= 4:
|
|
296
|
+
line_str = parts[1].strip()
|
|
297
|
+
int(line_str)
|
|
298
|
+
|
|
299
|
+
# Check if second part is a column number
|
|
300
|
+
result = self._parse_with_column_format(
|
|
301
|
+
file_path_str, line_str, parts
|
|
302
|
+
)
|
|
303
|
+
if result is not None:
|
|
304
|
+
return result
|
|
305
|
+
|
|
306
|
+
# Not column format, try without column
|
|
307
|
+
return self._parse_without_column_format(
|
|
308
|
+
file_path_str, line_str, parts
|
|
309
|
+
)
|
|
310
|
+
else:
|
|
311
|
+
return None
|
|
312
|
+
else:
|
|
313
|
+
# Format: file:line: error: message [code]
|
|
314
|
+
return self._parse_standard_format(file_path_str, line_str, parts)
|
|
315
|
+
except (ValueError, IndexError):
|
|
316
|
+
return None
|
|
317
|
+
|
|
318
|
+
def _extract_message_and_code(self, message_and_code_str: str) -> tuple[str, str]:
|
|
319
|
+
"""Extract message and code from format like 'error: message [code]'."""
|
|
320
|
+
# Split on first space after "error:" to separate severity from message
|
|
321
|
+
if " error: " in message_and_code_str:
|
|
322
|
+
_, message_part = message_and_code_str.split(" error: ", 1)
|
|
323
|
+
elif " warning: " in message_and_code_str:
|
|
324
|
+
_, message_part = message_and_code_str.split(" warning: ", 1)
|
|
325
|
+
else:
|
|
326
|
+
message_part = message_and_code_str
|
|
327
|
+
|
|
328
|
+
# Extract code from [code] brackets
|
|
329
|
+
code = ""
|
|
330
|
+
if " [" in message_part and "]" in message_part:
|
|
331
|
+
start_bracket = message_part.rfind(" [")
|
|
332
|
+
end_bracket = message_part.rfind("]")
|
|
333
|
+
if (
|
|
334
|
+
start_bracket != -1
|
|
335
|
+
and end_bracket != -1
|
|
336
|
+
and end_bracket > start_bracket
|
|
337
|
+
):
|
|
338
|
+
code = message_part[
|
|
339
|
+
start_bracket + 2 : end_bracket
|
|
340
|
+
] # Extract content between [ and ]
|
|
341
|
+
message_part = message_part[
|
|
342
|
+
:start_bracket
|
|
343
|
+
].strip() # Everything before the bracket
|
|
344
|
+
|
|
345
|
+
return message_part.strip(), code
|
|
346
|
+
|
|
347
|
+
def _determine_severity_and_message(
|
|
348
|
+
self,
|
|
349
|
+
severity_and_message: str,
|
|
350
|
+
has_column: bool,
|
|
351
|
+
parts: list[str],
|
|
352
|
+
original_message: str,
|
|
353
|
+
) -> tuple[str, str]:
|
|
354
|
+
"""Determine severity and clean up message from the severity_and_message part."""
|
|
355
|
+
# Default to error severity
|
|
356
|
+
severity = "error"
|
|
357
|
+
message = original_message
|
|
358
|
+
|
|
359
|
+
if severity_and_message.lower().startswith("warning"):
|
|
360
|
+
severity = "warning"
|
|
361
|
+
message = (
|
|
362
|
+
severity_and_message[len("warning") :].strip()
|
|
363
|
+
if not has_column or len(parts) <= 4
|
|
364
|
+
else original_message
|
|
365
|
+
)
|
|
366
|
+
elif severity_and_message.lower().startswith("error"):
|
|
367
|
+
message = (
|
|
368
|
+
severity_and_message[len("error") :].strip()
|
|
369
|
+
if not has_column or len(parts) <= 4
|
|
370
|
+
else original_message
|
|
371
|
+
)
|
|
372
|
+
|
|
373
|
+
return severity, message
|
|
374
|
+
|
|
375
|
+
def _parse_text_output(self, output: str) -> list[ToolIssue]:
|
|
376
|
+
"""Parse Zuban text output.
|
|
377
|
+
|
|
378
|
+
Args:
|
|
379
|
+
output: Text output from Zuban
|
|
380
|
+
|
|
381
|
+
Returns:
|
|
382
|
+
List of ToolIssue objects
|
|
383
|
+
"""
|
|
384
|
+
issues = []
|
|
385
|
+
lines = output.strip().split("\n")
|
|
386
|
+
|
|
387
|
+
for line in lines:
|
|
388
|
+
# Skip lines that don't contain error information
|
|
389
|
+
if ":" not in line or ("error:" not in line and "warning:" not in line):
|
|
390
|
+
continue
|
|
391
|
+
|
|
392
|
+
# Skip summary lines like "Found X error(s) in Y file(s)"
|
|
393
|
+
if (
|
|
394
|
+
"Found" in line
|
|
395
|
+
and ("error" in line or "warning" in line)
|
|
396
|
+
and "file" in line
|
|
397
|
+
):
|
|
398
|
+
continue
|
|
399
|
+
|
|
400
|
+
# Parse error line in format: "file:line: error: message [code]"
|
|
401
|
+
parts_result = self._extract_parts_from_line(line)
|
|
402
|
+
if parts_result is None:
|
|
403
|
+
continue
|
|
404
|
+
|
|
405
|
+
(
|
|
406
|
+
file_path,
|
|
407
|
+
line_number,
|
|
408
|
+
column_number,
|
|
409
|
+
message,
|
|
410
|
+
code,
|
|
411
|
+
) = parts_result
|
|
412
|
+
|
|
413
|
+
# Determine severity from message content
|
|
414
|
+
severity = "error" if "error:" in line else "warning"
|
|
415
|
+
|
|
416
|
+
issue = ToolIssue(
|
|
417
|
+
file_path=file_path,
|
|
418
|
+
line_number=line_number,
|
|
419
|
+
column_number=column_number,
|
|
420
|
+
message=message,
|
|
421
|
+
code=code,
|
|
422
|
+
severity=severity,
|
|
423
|
+
)
|
|
424
|
+
issues.append(issue)
|
|
425
|
+
|
|
426
|
+
logger.info(
|
|
427
|
+
"Parsed Zuban text output",
|
|
428
|
+
extra={
|
|
429
|
+
"total_issues": len(issues),
|
|
430
|
+
"files_with_issues": len({str(i.file_path) for i in issues}),
|
|
431
|
+
},
|
|
432
|
+
)
|
|
433
|
+
return issues
|
|
434
|
+
|
|
435
|
+
def _get_check_type(self) -> QACheckType:
|
|
436
|
+
"""Return type check type."""
|
|
437
|
+
return QACheckType.TYPE
|
|
438
|
+
|
|
439
|
+
def _detect_package_directory(self) -> str:
|
|
440
|
+
"""Detect the package directory name from pyproject.toml.
|
|
441
|
+
|
|
442
|
+
Returns:
|
|
443
|
+
Package directory name (e.g., 'crackerjack', 'session_mgmt_mcp')
|
|
444
|
+
"""
|
|
445
|
+
from contextlib import suppress
|
|
446
|
+
|
|
447
|
+
current_dir = Path.cwd()
|
|
448
|
+
|
|
449
|
+
# Try to read package name from pyproject.toml
|
|
450
|
+
pyproject_path = current_dir / "pyproject.toml"
|
|
451
|
+
if pyproject_path.exists():
|
|
452
|
+
with suppress(Exception):
|
|
453
|
+
import tomllib
|
|
454
|
+
|
|
455
|
+
with pyproject_path.open("rb") as f:
|
|
456
|
+
data = tomllib.load(f)
|
|
457
|
+
|
|
458
|
+
if "project" in data and "name" in data["project"]:
|
|
459
|
+
# Convert package name to directory name (replace - with _)
|
|
460
|
+
package_name = str(data["project"]["name"]).replace("-", "_")
|
|
461
|
+
|
|
462
|
+
# Verify directory exists
|
|
463
|
+
if (current_dir / package_name).exists():
|
|
464
|
+
return package_name
|
|
465
|
+
|
|
466
|
+
# Fallback to directory name if package dir exists
|
|
467
|
+
if (current_dir / current_dir.name).exists():
|
|
468
|
+
return current_dir.name
|
|
469
|
+
|
|
470
|
+
# Default fallback
|
|
471
|
+
return "src"
|
|
472
|
+
|
|
473
|
+
def get_default_config(self) -> QACheckConfig:
|
|
474
|
+
"""Get default configuration for Zuban adapter.
|
|
475
|
+
|
|
476
|
+
Returns:
|
|
477
|
+
QACheckConfig with sensible defaults
|
|
478
|
+
"""
|
|
479
|
+
from crackerjack.models.qa_config import QACheckConfig
|
|
480
|
+
|
|
481
|
+
# Dynamically detect package directory
|
|
482
|
+
package_dir = self._detect_package_directory()
|
|
483
|
+
|
|
484
|
+
return QACheckConfig(
|
|
485
|
+
check_id=MODULE_ID,
|
|
486
|
+
check_name=self.adapter_name,
|
|
487
|
+
check_type=QACheckType.TYPE,
|
|
488
|
+
enabled=True,
|
|
489
|
+
file_patterns=[
|
|
490
|
+
f"{package_dir}/**/*.py"
|
|
491
|
+
], # Dynamically detected package directory
|
|
492
|
+
exclude_patterns=[
|
|
493
|
+
"**/test_*.py",
|
|
494
|
+
"**/tests/**",
|
|
495
|
+
"**/.venv/**",
|
|
496
|
+
"**/venv/**",
|
|
497
|
+
"**/build/**",
|
|
498
|
+
"**/dist/**",
|
|
499
|
+
"**/__pycache__/**",
|
|
500
|
+
"**/.git/**",
|
|
501
|
+
"**/node_modules/**",
|
|
502
|
+
"**/.tox/**",
|
|
503
|
+
"**/.pytest_cache/**",
|
|
504
|
+
"**/htmlcov/**",
|
|
505
|
+
"**/.coverage*",
|
|
506
|
+
],
|
|
507
|
+
timeout_seconds=180, # Type checking can be slower
|
|
508
|
+
parallel_safe=True,
|
|
509
|
+
stage="comprehensive", # Type checking in comprehensive stage
|
|
510
|
+
settings={
|
|
511
|
+
"strict_mode": False,
|
|
512
|
+
"incremental": False, # Disable to avoid config cache issues
|
|
513
|
+
"follow_imports": "normal",
|
|
514
|
+
"warn_unused_ignores": False, # Disable to avoid config issues
|
|
515
|
+
"ignore_missing_imports": True, # Avoid errors from missing imports
|
|
516
|
+
},
|
|
517
|
+
)
|
|
518
|
+
|
|
519
|
+
|
|
520
|
+
# ACB Registration (REQUIRED at module level)
|
|
521
|
+
with suppress(Exception):
|
|
522
|
+
depends.set(ZubanAdapter)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
> Crackerjack Docs: [Main](<../../../README.md>) | [Adapters](<../README.md>) | [Utility](<./README.md>)
|
|
2
|
+
|
|
3
|
+
# Utility Adapter
|
|
4
|
+
|
|
5
|
+
Configuration-driven utility checks for small, high-signal fixes without external tools.
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
- Enforce EOF newlines, trim trailing whitespace, validate YAML/TOML/JSON
|
|
10
|
+
- Simple file-size limits and dependency lock checks
|
|
11
|
+
- Typed settings and consistent QA results
|
|
12
|
+
|
|
13
|
+
## Supported Check Types
|
|
14
|
+
|
|
15
|
+
- `TEXT_PATTERN` — Regex search (e.g., trailing whitespace), optional auto-fix
|
|
16
|
+
- `EOF_NEWLINE` — Ensure files end with a newline
|
|
17
|
+
- `SYNTAX_VALIDATION` — Parse `yaml`/`toml`/`json` safely
|
|
18
|
+
- `SIZE_CHECK` — Enforce `max_size_bytes`
|
|
19
|
+
- `DEPENDENCY_LOCK` — Run lock command and verify success
|
|
20
|
+
|
|
21
|
+
## Basic Usage
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
from pathlib import Path
|
|
25
|
+
from crackerjack.adapters.utility.checks import (
|
|
26
|
+
UtilityCheckAdapter,
|
|
27
|
+
UtilityCheckSettings,
|
|
28
|
+
UtilityCheckType,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
async def enforce_whitespace() -> None:
|
|
33
|
+
settings = UtilityCheckSettings(
|
|
34
|
+
check_type=UtilityCheckType.TEXT_PATTERN,
|
|
35
|
+
pattern=r"\s+$",
|
|
36
|
+
auto_fix=True,
|
|
37
|
+
)
|
|
38
|
+
adapter = UtilityCheckAdapter(settings=settings)
|
|
39
|
+
await adapter.init()
|
|
40
|
+
result = await adapter.check(files=[Path("src/file.py")])
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Tips
|
|
44
|
+
|
|
45
|
+
- Prefer `CompiledPatternCache`-friendly regexes; settings validate patterns
|
|
46
|
+
- Target specific file globs via `QACheckConfig.file_patterns`
|
|
47
|
+
|
|
48
|
+
## Related
|
|
49
|
+
|
|
50
|
+
- [Format](<../format/README.md>) — For comprehensive Python/Markdown formatting
|
|
51
|
+
- [Lint](<../lint/README.md>) — Codespell for typos and naming issues
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"""Utility adapters for miscellaneous code quality checks.
|
|
2
|
+
|
|
3
|
+
Adapters:
|
|
4
|
+
- checks: Configuration-driven utility checks (text patterns, EOF newlines, syntax validation, size checks, dependency locks)
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
# ACB will auto-discover these adapters via depends.set() in module files
|
|
8
|
+
# No explicit imports needed here
|
|
9
|
+
|
|
10
|
+
__all__ = []
|