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,391 @@
|
|
|
1
|
+
"""Zuban Language Server Protocol (LSP) service for real-time type checking."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import json
|
|
5
|
+
import logging
|
|
6
|
+
import subprocess
|
|
7
|
+
import time
|
|
8
|
+
import typing as t
|
|
9
|
+
from contextlib import suppress
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
from acb.console import Console
|
|
13
|
+
from acb.depends import depends
|
|
14
|
+
|
|
15
|
+
from .security_logger import get_security_logger
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger("crackerjack.zuban_lsp")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ZubanLSPService:
|
|
21
|
+
"""Manages zuban language server lifecycle and communication."""
|
|
22
|
+
|
|
23
|
+
def __init__(
|
|
24
|
+
self,
|
|
25
|
+
port: int = 8677,
|
|
26
|
+
mode: str = "tcp",
|
|
27
|
+
console: Console | None = None,
|
|
28
|
+
) -> None:
|
|
29
|
+
"""Initialize Zuban LSP service.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
port: TCP port for server (default: 8677)
|
|
33
|
+
mode: Transport mode, "tcp" or "stdio" (default: "tcp")
|
|
34
|
+
console: Rich console for output (optional)
|
|
35
|
+
"""
|
|
36
|
+
self.port = port
|
|
37
|
+
self.mode = mode
|
|
38
|
+
self.console = console or depends.get_sync(Console)
|
|
39
|
+
self.process: subprocess.Popen[bytes] | None = None
|
|
40
|
+
self.start_time: float = 0.0
|
|
41
|
+
self.security_logger = get_security_logger()
|
|
42
|
+
self._health_check_failures = 0
|
|
43
|
+
self._max_health_failures = 3
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def is_running(self) -> bool:
|
|
47
|
+
"""Check if LSP server process is running."""
|
|
48
|
+
return self.process is not None and self.process.poll() is None
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
def uptime(self) -> float:
|
|
52
|
+
"""Get server uptime in seconds."""
|
|
53
|
+
if self.is_running and self.start_time > 0:
|
|
54
|
+
return time.time() - self.start_time
|
|
55
|
+
return 0.0
|
|
56
|
+
|
|
57
|
+
async def start(self) -> bool:
|
|
58
|
+
"""Start the zuban LSP server.
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
True if started successfully, False otherwise
|
|
62
|
+
"""
|
|
63
|
+
if self.is_running:
|
|
64
|
+
logger.info("Zuban LSP server already running")
|
|
65
|
+
return True
|
|
66
|
+
|
|
67
|
+
try:
|
|
68
|
+
self.console.print("[cyan]🚀 Starting Zuban LSP server...[/cyan]")
|
|
69
|
+
|
|
70
|
+
# Build command based on transport mode
|
|
71
|
+
if self.mode == "tcp":
|
|
72
|
+
# For TCP mode, we'll need to configure zuban to listen on port
|
|
73
|
+
# Currently zuban server only supports stdio, so we use stdio mode
|
|
74
|
+
cmd = ["uv", "run", "zuban", "server"]
|
|
75
|
+
else:
|
|
76
|
+
cmd = ["uv", "run", "zuban", "server"]
|
|
77
|
+
|
|
78
|
+
# Start the process
|
|
79
|
+
self.process = subprocess.Popen(
|
|
80
|
+
cmd,
|
|
81
|
+
stdin=subprocess.PIPE,
|
|
82
|
+
stdout=subprocess.PIPE,
|
|
83
|
+
stderr=subprocess.PIPE,
|
|
84
|
+
cwd=Path.cwd(),
|
|
85
|
+
start_new_session=True,
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
self.start_time = time.time()
|
|
89
|
+
self._health_check_failures = 0
|
|
90
|
+
|
|
91
|
+
# Log the startup
|
|
92
|
+
self.security_logger.log_subprocess_execution(
|
|
93
|
+
command=cmd,
|
|
94
|
+
purpose="zuban_lsp_server_start",
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
# Wait a moment for startup
|
|
98
|
+
await asyncio.sleep(1.0)
|
|
99
|
+
|
|
100
|
+
# Verify it started successfully
|
|
101
|
+
if not self.is_running:
|
|
102
|
+
error_output = ""
|
|
103
|
+
if self.process and self.process.stderr:
|
|
104
|
+
with suppress(Exception):
|
|
105
|
+
error_output = self.process.stderr.read().decode()
|
|
106
|
+
|
|
107
|
+
self.console.print("[red]❌ Failed to start Zuban LSP server[/red]")
|
|
108
|
+
if error_output:
|
|
109
|
+
logger.error(f"Zuban LSP startup error: {error_output}")
|
|
110
|
+
return False
|
|
111
|
+
|
|
112
|
+
self.console.print(
|
|
113
|
+
f"[green]✅ Zuban LSP server started (PID: {self.process.pid})[/green]"
|
|
114
|
+
)
|
|
115
|
+
logger.info(f"Zuban LSP server started with PID {self.process.pid}")
|
|
116
|
+
return True
|
|
117
|
+
|
|
118
|
+
except Exception as e:
|
|
119
|
+
self.console.print(f"[red]❌ Error starting Zuban LSP server: {e}[/red]")
|
|
120
|
+
logger.error(f"Failed to start Zuban LSP server: {e}")
|
|
121
|
+
return False
|
|
122
|
+
|
|
123
|
+
async def stop(self) -> None:
|
|
124
|
+
"""Gracefully stop the LSP server."""
|
|
125
|
+
if not self.process:
|
|
126
|
+
return
|
|
127
|
+
|
|
128
|
+
self.console.print("[yellow]🛑 Stopping Zuban LSP server...[/yellow]")
|
|
129
|
+
|
|
130
|
+
try:
|
|
131
|
+
# Try graceful shutdown first
|
|
132
|
+
self.process.terminate()
|
|
133
|
+
|
|
134
|
+
# Wait for graceful shutdown
|
|
135
|
+
try:
|
|
136
|
+
self.process.wait(timeout=5.0)
|
|
137
|
+
self.console.print(
|
|
138
|
+
"[green]✅ Zuban LSP server stopped gracefully[/green]"
|
|
139
|
+
)
|
|
140
|
+
except subprocess.TimeoutExpired:
|
|
141
|
+
# Force kill if graceful shutdown fails
|
|
142
|
+
self.process.kill()
|
|
143
|
+
self.process.wait(timeout=2.0)
|
|
144
|
+
self.console.print("[yellow]⚠️ Zuban LSP server force stopped[/yellow]")
|
|
145
|
+
|
|
146
|
+
except Exception as e:
|
|
147
|
+
logger.error(f"Error stopping Zuban LSP server: {e}")
|
|
148
|
+
|
|
149
|
+
finally:
|
|
150
|
+
self.process = None
|
|
151
|
+
self.start_time = 0.0
|
|
152
|
+
self._health_check_failures = 0
|
|
153
|
+
|
|
154
|
+
async def health_check(self) -> bool:
|
|
155
|
+
"""Check if LSP server is responsive.
|
|
156
|
+
|
|
157
|
+
Returns:
|
|
158
|
+
True if server is healthy, False otherwise
|
|
159
|
+
"""
|
|
160
|
+
if not self.is_running:
|
|
161
|
+
return False
|
|
162
|
+
|
|
163
|
+
try:
|
|
164
|
+
# For stdio mode, we check if process is alive and responsive
|
|
165
|
+
if self.mode == "stdio":
|
|
166
|
+
return self._check_stdio_health()
|
|
167
|
+
else:
|
|
168
|
+
# For TCP mode, we would check port connectivity
|
|
169
|
+
return self._check_tcp_health()
|
|
170
|
+
|
|
171
|
+
except Exception as e:
|
|
172
|
+
logger.warning(f"Health check failed: {e}")
|
|
173
|
+
self._health_check_failures += 1
|
|
174
|
+
return False
|
|
175
|
+
|
|
176
|
+
def _check_stdio_health(self) -> bool:
|
|
177
|
+
"""Check health for stdio mode server."""
|
|
178
|
+
if not self.process:
|
|
179
|
+
return False
|
|
180
|
+
|
|
181
|
+
# Simple check - is process still alive?
|
|
182
|
+
return self.process.poll() is None
|
|
183
|
+
|
|
184
|
+
def _check_tcp_health(self) -> bool:
|
|
185
|
+
"""Check health for TCP mode server."""
|
|
186
|
+
# TODO: Implement TCP health check when zuban supports TCP mode
|
|
187
|
+
# For now, fall back to process check
|
|
188
|
+
return self._check_stdio_health()
|
|
189
|
+
|
|
190
|
+
async def restart(self) -> bool:
|
|
191
|
+
"""Restart the LSP server.
|
|
192
|
+
|
|
193
|
+
Returns:
|
|
194
|
+
True if restarted successfully, False otherwise
|
|
195
|
+
"""
|
|
196
|
+
self.console.print("[cyan]🔄 Restarting Zuban LSP server...[/cyan]")
|
|
197
|
+
|
|
198
|
+
await self.stop()
|
|
199
|
+
await asyncio.sleep(2.0) # Brief pause between stop and start
|
|
200
|
+
|
|
201
|
+
success = await self.start()
|
|
202
|
+
if success:
|
|
203
|
+
self.console.print(
|
|
204
|
+
"[green]✅ Zuban LSP server restarted successfully[/green]"
|
|
205
|
+
)
|
|
206
|
+
else:
|
|
207
|
+
self.console.print("[red]❌ Failed to restart Zuban LSP server[/red]")
|
|
208
|
+
|
|
209
|
+
return success
|
|
210
|
+
|
|
211
|
+
def get_status(self) -> dict[str, t.Any]:
|
|
212
|
+
"""Get current status of the LSP server.
|
|
213
|
+
|
|
214
|
+
Returns:
|
|
215
|
+
Dictionary with server status information
|
|
216
|
+
"""
|
|
217
|
+
return {
|
|
218
|
+
"running": self.is_running,
|
|
219
|
+
"pid": self.process.pid if self.process else None,
|
|
220
|
+
"uptime": self.uptime,
|
|
221
|
+
"port": self.port,
|
|
222
|
+
"mode": self.mode,
|
|
223
|
+
"health_failures": self._health_check_failures,
|
|
224
|
+
"max_health_failures": self._max_health_failures,
|
|
225
|
+
"healthy": self.is_running
|
|
226
|
+
and self._health_check_failures < self._max_health_failures,
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
async def send_lsp_request(
|
|
230
|
+
self, method: str, params: dict[str, t.Any] | None = None
|
|
231
|
+
) -> dict[str, t.Any] | None:
|
|
232
|
+
"""Send an LSP request to the server.
|
|
233
|
+
|
|
234
|
+
Args:
|
|
235
|
+
method: LSP method name (e.g., "initialize", "textDocument/didOpen")
|
|
236
|
+
params: Request parameters (optional)
|
|
237
|
+
|
|
238
|
+
Returns:
|
|
239
|
+
LSP response or None if failed
|
|
240
|
+
"""
|
|
241
|
+
if not self.is_running or not self.process or not self.process.stdin:
|
|
242
|
+
return None
|
|
243
|
+
|
|
244
|
+
try:
|
|
245
|
+
request_id = int(time.time() * 1000)
|
|
246
|
+
request = {
|
|
247
|
+
"jsonrpc": "2.0",
|
|
248
|
+
"id": request_id,
|
|
249
|
+
"method": method,
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if params is not None:
|
|
253
|
+
request["params"] = params
|
|
254
|
+
|
|
255
|
+
request_json = json.dumps(request)
|
|
256
|
+
content_length = len(request_json.encode())
|
|
257
|
+
|
|
258
|
+
# LSP protocol: Content-Length header + \r\n\r\n + JSON
|
|
259
|
+
message = f"Content-Length: {content_length}\r\n\r\n{request_json}"
|
|
260
|
+
|
|
261
|
+
self.process.stdin.write(message.encode())
|
|
262
|
+
self.process.stdin.flush()
|
|
263
|
+
|
|
264
|
+
# For notifications (no response expected), return success
|
|
265
|
+
if method.startswith("textDocument/did"):
|
|
266
|
+
return {"status": "notification_sent", "id": request_id}
|
|
267
|
+
|
|
268
|
+
# For requests that expect responses, attempt to read response
|
|
269
|
+
try:
|
|
270
|
+
response = await self._read_lsp_response(request_id, timeout=5.0)
|
|
271
|
+
return response
|
|
272
|
+
except TimeoutError:
|
|
273
|
+
logger.warning(f"LSP request {method} timed out")
|
|
274
|
+
return {"status": "timeout", "id": request_id}
|
|
275
|
+
|
|
276
|
+
except Exception as e:
|
|
277
|
+
logger.error(f"Failed to send LSP request: {e}")
|
|
278
|
+
return None
|
|
279
|
+
|
|
280
|
+
async def _read_lsp_response(
|
|
281
|
+
self, expected_id: int, timeout: float = 5.0
|
|
282
|
+
) -> dict[str, t.Any] | None:
|
|
283
|
+
"""Read LSP response from server with timeout.
|
|
284
|
+
|
|
285
|
+
Args:
|
|
286
|
+
expected_id: Expected request ID for the response
|
|
287
|
+
timeout: Timeout in seconds
|
|
288
|
+
|
|
289
|
+
Returns:
|
|
290
|
+
LSP response dictionary or None if failed
|
|
291
|
+
"""
|
|
292
|
+
if not self.process or not self.process.stdout:
|
|
293
|
+
return None
|
|
294
|
+
|
|
295
|
+
try:
|
|
296
|
+
# Read with timeout
|
|
297
|
+
response_data = await asyncio.wait_for(
|
|
298
|
+
self._read_message_from_stdout(), timeout=timeout
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
if not response_data:
|
|
302
|
+
return None
|
|
303
|
+
|
|
304
|
+
response = json.loads(response_data)
|
|
305
|
+
typed_response = t.cast(dict[str, t.Any], response)
|
|
306
|
+
|
|
307
|
+
# Check if this is the response we're looking for
|
|
308
|
+
if typed_response.get("id") == expected_id:
|
|
309
|
+
return typed_response
|
|
310
|
+
|
|
311
|
+
# Log if we got a different response
|
|
312
|
+
logger.debug(
|
|
313
|
+
f"Received response for ID {typed_response.get('id')}, expected {expected_id}"
|
|
314
|
+
)
|
|
315
|
+
return typed_response
|
|
316
|
+
|
|
317
|
+
except TimeoutError:
|
|
318
|
+
raise
|
|
319
|
+
except Exception as e:
|
|
320
|
+
logger.error(f"Failed to read LSP response: {e}")
|
|
321
|
+
return None
|
|
322
|
+
|
|
323
|
+
async def _read_message_from_stdout(self) -> str | None:
|
|
324
|
+
"""Read a complete LSP message from stdout.
|
|
325
|
+
|
|
326
|
+
Returns:
|
|
327
|
+
Message content as string, or None if failed
|
|
328
|
+
"""
|
|
329
|
+
if not self.process or not self.process.stdout:
|
|
330
|
+
return None
|
|
331
|
+
|
|
332
|
+
try:
|
|
333
|
+
# Read the Content-Length header
|
|
334
|
+
header_line = await self._read_line_async()
|
|
335
|
+
if not header_line or not header_line.startswith("Content-Length:"):
|
|
336
|
+
return None
|
|
337
|
+
|
|
338
|
+
# Extract content length
|
|
339
|
+
content_length = int(header_line.split(":", 1)[1].strip())
|
|
340
|
+
|
|
341
|
+
# Read the empty line separator
|
|
342
|
+
empty_line = await self._read_line_async()
|
|
343
|
+
if empty_line.strip(): # Should be empty
|
|
344
|
+
logger.warning("Expected empty line after Content-Length header")
|
|
345
|
+
|
|
346
|
+
# Read the JSON content
|
|
347
|
+
content_bytes = await self._read_bytes_async(content_length)
|
|
348
|
+
return content_bytes.decode("utf-8")
|
|
349
|
+
|
|
350
|
+
except Exception as e:
|
|
351
|
+
logger.error(f"Failed to read LSP message: {e}")
|
|
352
|
+
return None
|
|
353
|
+
|
|
354
|
+
async def _read_line_async(self) -> str:
|
|
355
|
+
"""Read a line from stdout asynchronously."""
|
|
356
|
+
if not self.process or not self.process.stdout:
|
|
357
|
+
return ""
|
|
358
|
+
|
|
359
|
+
# This is a simplified implementation
|
|
360
|
+
# In a production system, you'd want to use proper async I/O
|
|
361
|
+
loop = asyncio.get_event_loop()
|
|
362
|
+
line = await loop.run_in_executor(None, self.process.stdout.readline) # type: ignore[call-arg]
|
|
363
|
+
return line.decode("utf-8").rstrip("\r\n")
|
|
364
|
+
|
|
365
|
+
async def _read_bytes_async(self, count: int) -> bytes:
|
|
366
|
+
"""Read specified number of bytes from stdout asynchronously."""
|
|
367
|
+
if not self.process or not self.process.stdout:
|
|
368
|
+
return b""
|
|
369
|
+
|
|
370
|
+
loop = asyncio.get_event_loop()
|
|
371
|
+
data = await loop.run_in_executor(None, self.process.stdout.read, count) # type: ignore[call-arg]
|
|
372
|
+
return data
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
async def create_zuban_lsp_service(
|
|
376
|
+
port: int = 8677,
|
|
377
|
+
mode: str = "tcp",
|
|
378
|
+
console: Console | None = None,
|
|
379
|
+
) -> ZubanLSPService:
|
|
380
|
+
"""Factory function to create and optionally start Zuban LSP service.
|
|
381
|
+
|
|
382
|
+
Args:
|
|
383
|
+
port: TCP port for server (default: 8677)
|
|
384
|
+
mode: Transport mode, "tcp" or "stdio" (default: "tcp")
|
|
385
|
+
console: Rich console for output (optional)
|
|
386
|
+
|
|
387
|
+
Returns:
|
|
388
|
+
Configured ZubanLSPService instance
|
|
389
|
+
"""
|
|
390
|
+
service = ZubanLSPService(port=port, mode=mode, console=console)
|
|
391
|
+
return service
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
> Crackerjack Docs: [Main](<../../README.md>) | [Crackerjack Package](<../README.md>) | [Slash Commands](<./README.md>)
|
|
2
|
+
|
|
3
|
+
# Slash Commands
|
|
4
|
+
|
|
5
|
+
Slash command handlers and related routing.
|
|
6
|
+
|
|
7
|
+
## Related
|
|
8
|
+
|
|
9
|
+
- [Crackerjack Package](<../README.md>) - Parent package
|
|
10
|
+
- [MCP](<../mcp/README.md>) - MCP server slash command integration
|
|
11
|
+
- [CLI](<../cli/README.md>) - Command-line interface handlers
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
from ..errors import ErrorCode, ExecutionError
|
|
4
|
+
from ..services.input_validator import validate_and_sanitize_string
|
|
5
|
+
|
|
6
|
+
SLASH_COMMANDS_DIR = Path(__file__).parent
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def get_slash_command_path(command_name: str) -> Path:
|
|
10
|
+
try:
|
|
11
|
+
sanitized_name = validate_and_sanitize_string(
|
|
12
|
+
command_name, max_length=50, strict_alphanumeric=True
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
command_path = SLASH_COMMANDS_DIR / f"{sanitized_name}.md"
|
|
16
|
+
|
|
17
|
+
if not str(command_path.resolve()).startswith(
|
|
18
|
+
str(SLASH_COMMANDS_DIR.resolve())
|
|
19
|
+
):
|
|
20
|
+
raise ExecutionError(
|
|
21
|
+
message=f"Command path outside allowed directory: {command_name}",
|
|
22
|
+
error_code=ErrorCode.VALIDATION_ERROR,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
return command_path
|
|
26
|
+
|
|
27
|
+
except Exception as e:
|
|
28
|
+
if isinstance(e, ExecutionError):
|
|
29
|
+
raise
|
|
30
|
+
raise ExecutionError(
|
|
31
|
+
message=f"Invalid command name: {command_name}",
|
|
32
|
+
error_code=ErrorCode.VALIDATION_ERROR,
|
|
33
|
+
) from e
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def list_available_commands() -> list[str]:
|
|
37
|
+
try:
|
|
38
|
+
commands = []
|
|
39
|
+
for file_path in SLASH_COMMANDS_DIR.glob("*.md"):
|
|
40
|
+
command_name = file_path.stem
|
|
41
|
+
|
|
42
|
+
try:
|
|
43
|
+
validate_and_sanitize_string(
|
|
44
|
+
command_name, max_length=50, strict_alphanumeric=True
|
|
45
|
+
)
|
|
46
|
+
commands.append(command_name)
|
|
47
|
+
except ExecutionError:
|
|
48
|
+
continue
|
|
49
|
+
|
|
50
|
+
return sorted(commands)
|
|
51
|
+
|
|
52
|
+
except Exception as e:
|
|
53
|
+
raise ExecutionError(
|
|
54
|
+
message="Failed to list[t.Any] available commands",
|
|
55
|
+
error_code=ErrorCode.FILE_READ_ERROR,
|
|
56
|
+
) from e
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
__all__ = ["SLASH_COMMANDS_DIR", "get_slash_command_path", "list_available_commands"]
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
______________________________________________________________________
|
|
2
|
+
|
|
3
|
+
## description: Initialize or update crackerjack configuration for a Python project with best practices, quality hooks, and AI guidelines.
|
|
4
|
+
|
|
5
|
+
# /crackerjack:init
|
|
6
|
+
|
|
7
|
+
Initialize or update crackerjack configuration for a Python project.
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
/crackerjack:init
|
|
13
|
+
/crackerjack:init --force
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Description
|
|
17
|
+
|
|
18
|
+
This slash command initializes a new Python project with crackerjack's best practices or updates an existing project's configuration to the latest standards.
|
|
19
|
+
|
|
20
|
+
## What It Does
|
|
21
|
+
|
|
22
|
+
1. **Checks Project State**: Verifies which configuration files exist
|
|
23
|
+
1. **Smart Merge Configuration**:
|
|
24
|
+
- `pyproject.toml` - Intelligently merges tool configurations, preserves higher coverage requirements
|
|
25
|
+
- `CLAUDE.md` - Appends crackerjack guidelines without overwriting existing content
|
|
26
|
+
- `RULES.md` - Copies only if missing, preserves existing coding standards
|
|
27
|
+
1. **Preserves Project Identity**: Never overwrites existing project metadata, dependencies, or configurations
|
|
28
|
+
|
|
29
|
+
## When to Use /crackerjack:init
|
|
30
|
+
|
|
31
|
+
### Automatic Detection
|
|
32
|
+
|
|
33
|
+
The MCP server can detect when initialization is needed:
|
|
34
|
+
|
|
35
|
+
- **Missing Core Files**: No pyproject.toml
|
|
36
|
+
- **New Project**: Git repository just initialized
|
|
37
|
+
- **Manual Request**: User explicitly asks for initialization
|
|
38
|
+
|
|
39
|
+
### Recommended Frequency
|
|
40
|
+
|
|
41
|
+
- **New Projects**: Always run on project creation
|
|
42
|
+
- **Weekly**: For active development projects
|
|
43
|
+
- **After Tool Updates**: When crackerjack or dependencies update
|
|
44
|
+
- **Team Onboarding**: When new developers join
|
|
45
|
+
|
|
46
|
+
## Options
|
|
47
|
+
|
|
48
|
+
- `--force`: Force reinitialization even if configuration exists
|
|
49
|
+
|
|
50
|
+
## Example
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
User: Set up this Python project with best practices
|
|
54
|
+
AI: I'll initialize crackerjack configuration for your project.
|
|
55
|
+
|
|
56
|
+
/crackerjack:init
|
|
57
|
+
|
|
58
|
+
[AI executes initialization and reports results]
|
|
59
|
+
|
|
60
|
+
The project has been initialized with:
|
|
61
|
+
✅ pyproject.toml - Project configuration
|
|
62
|
+
✅ CLAUDE.md - AI guidelines
|
|
63
|
+
✅ RULES.md - Coding standards
|
|
64
|
+
|
|
65
|
+
Your project now follows Python best practices!
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Auto-Init Behavior
|
|
69
|
+
|
|
70
|
+
When connected via MCP, crackerjack can automatically suggest initialization when:
|
|
71
|
+
|
|
72
|
+
1. Running `/crackerjack:run` in an uninitialized project
|
|
73
|
+
1. Detecting missing critical configuration files
|
|
74
|
+
1. Finding configuration files that need updates
|
|
75
|
+
|
|
76
|
+
This ensures projects always have up-to-date quality standards without manual intervention.
|
|
77
|
+
|
|
78
|
+
## Smart Merge Behavior
|
|
79
|
+
|
|
80
|
+
**Crackerjack uses intelligent smart merging instead of destructive overwrites:**
|
|
81
|
+
|
|
82
|
+
### pyproject.toml Smart Merge
|
|
83
|
+
|
|
84
|
+
- **Preserves Project Identity**: Project name, version, description, dependencies remain untouched
|
|
85
|
+
- **Ensures Crackerjack Dependency**: Adds `crackerjack` to `[dependency-groups].dev` if missing
|
|
86
|
+
- **Merges Tool Configurations**: Adds missing tool sections (`[tool.ruff]`, `[tool.pyright]`, etc.)
|
|
87
|
+
- **Preserves Higher Coverage**: If target has higher `--cov-fail-under` than source, keeps the higher value
|
|
88
|
+
- **Adds Missing Pytest Markers**: Appends new test markers while preserving existing ones
|
|
89
|
+
|
|
90
|
+
### CLAUDE.md Smart Append
|
|
91
|
+
|
|
92
|
+
- **Non-Destructive**: Appends crackerjack guidelines with clear markers
|
|
93
|
+
- **Prevents Duplicates**: Skips if crackerjack section already exists
|
|
94
|
+
- **Clear Boundaries**: Uses `<!-- CRACKERJACK_START -->` and `<!-- CRACKERJACK_END -->` markers
|
|
95
|
+
|
|
96
|
+
### Universal Compatibility
|
|
97
|
+
|
|
98
|
+
This smart merge approach works with **any Python package**, not just specific projects:
|
|
99
|
+
|
|
100
|
+
- ✅ **MCP Servers** (session-mgmt-mcp, excalidraw-mcp)
|
|
101
|
+
- ✅ **Django Projects** with existing configurations
|
|
102
|
+
- ✅ **Flask Applications** with established tooling
|
|
103
|
+
- ✅ **Data Science Projects** with Jupyter-specific settings
|
|
104
|
+
- ✅ **CLI Tools** with complex pyproject.toml configurations
|
|
105
|
+
|
|
106
|
+
### Example Smart Merge Results
|
|
107
|
+
|
|
108
|
+
**Before**: Project with 85% coverage requirement
|
|
109
|
+
**After**: Keeps 85% coverage, adds all crackerjack tools, preserves project identity
|
|
110
|
+
|
|
111
|
+
**Before**: CLAUDE.md with project-specific guidelines
|
|
112
|
+
**After**: Original content + crackerjack section appended with clear markers
|