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,823 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import subprocess
|
|
3
|
+
import typing as t
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
import tomli
|
|
7
|
+
import yaml
|
|
8
|
+
from acb.console import Console
|
|
9
|
+
from acb.depends import Inject, depends
|
|
10
|
+
|
|
11
|
+
from crackerjack.models.protocols import ConfigMergeServiceProtocol
|
|
12
|
+
|
|
13
|
+
from .config_merge import ConfigMergeService
|
|
14
|
+
from .filesystem import FileSystemService
|
|
15
|
+
from .git import GitService
|
|
16
|
+
from .input_validator import get_input_validator, validate_and_sanitize_path
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class InitializationService:
|
|
20
|
+
@depends.inject
|
|
21
|
+
def __init__(
|
|
22
|
+
self,
|
|
23
|
+
console: Inject[Console],
|
|
24
|
+
filesystem: FileSystemService,
|
|
25
|
+
git_service: GitService,
|
|
26
|
+
pkg_path: Path,
|
|
27
|
+
config_merge_service: ConfigMergeServiceProtocol | None = None,
|
|
28
|
+
) -> None:
|
|
29
|
+
self.console = console
|
|
30
|
+
self.filesystem = filesystem
|
|
31
|
+
self.git_service = git_service
|
|
32
|
+
self.pkg_path = pkg_path
|
|
33
|
+
|
|
34
|
+
self.config_merge_service = config_merge_service or ConfigMergeService(
|
|
35
|
+
filesystem, git_service
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
def initialize_project(self, project_path: str | Path) -> bool:
|
|
39
|
+
try:
|
|
40
|
+
result = self.initialize_project_full(Path(project_path))
|
|
41
|
+
success = result.get("success", False)
|
|
42
|
+
return bool(success)
|
|
43
|
+
except Exception:
|
|
44
|
+
return False
|
|
45
|
+
|
|
46
|
+
def setup_git_hooks(self) -> bool:
|
|
47
|
+
try:
|
|
48
|
+
return True
|
|
49
|
+
except Exception:
|
|
50
|
+
return False
|
|
51
|
+
|
|
52
|
+
def validate_project_structure(self) -> bool:
|
|
53
|
+
try:
|
|
54
|
+
return True
|
|
55
|
+
except Exception:
|
|
56
|
+
return False
|
|
57
|
+
|
|
58
|
+
def initialize_project_full(
|
|
59
|
+
self,
|
|
60
|
+
target_path: Path | None = None,
|
|
61
|
+
force: bool = False,
|
|
62
|
+
) -> dict[str, t.Any]:
|
|
63
|
+
if target_path is None:
|
|
64
|
+
target_path = Path.cwd()
|
|
65
|
+
|
|
66
|
+
try:
|
|
67
|
+
target_path = validate_and_sanitize_path(target_path, allow_absolute=True)
|
|
68
|
+
except Exception as e:
|
|
69
|
+
return {
|
|
70
|
+
"target_path": str(target_path),
|
|
71
|
+
"files_copied": [],
|
|
72
|
+
"files_skipped": [],
|
|
73
|
+
"errors": [f"Invalid target path: {e}"],
|
|
74
|
+
"success": False,
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
results = self._create_results_dict(target_path)
|
|
78
|
+
|
|
79
|
+
try:
|
|
80
|
+
config_files = self._get_config_files()
|
|
81
|
+
project_name = target_path.name
|
|
82
|
+
|
|
83
|
+
validator = get_input_validator()
|
|
84
|
+
name_result = validator.validate_project_name(project_name)
|
|
85
|
+
if not name_result.valid:
|
|
86
|
+
results["errors"].append(
|
|
87
|
+
f"Invalid project name: {name_result.error_message}"
|
|
88
|
+
)
|
|
89
|
+
results["success"] = False
|
|
90
|
+
return results
|
|
91
|
+
|
|
92
|
+
sanitized_project_name = name_result.sanitized_value
|
|
93
|
+
|
|
94
|
+
for file_name, merge_strategy in config_files.items():
|
|
95
|
+
self._process_config_file(
|
|
96
|
+
file_name,
|
|
97
|
+
merge_strategy,
|
|
98
|
+
sanitized_project_name,
|
|
99
|
+
target_path,
|
|
100
|
+
force,
|
|
101
|
+
results,
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
self._print_summary(results)
|
|
105
|
+
|
|
106
|
+
except Exception as e:
|
|
107
|
+
self._handle_initialization_error(results, e)
|
|
108
|
+
|
|
109
|
+
return results
|
|
110
|
+
|
|
111
|
+
def _create_results_dict(self, target_path: Path) -> dict[str, t.Any]:
|
|
112
|
+
return {
|
|
113
|
+
"target_path": str(target_path),
|
|
114
|
+
"files_copied": [],
|
|
115
|
+
"files_skipped": [],
|
|
116
|
+
"errors": [],
|
|
117
|
+
"success": True,
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
def _get_config_files(self) -> dict[str, str]:
|
|
121
|
+
# Skip pre-commit configuration to prevent hook installation
|
|
122
|
+
return {
|
|
123
|
+
"pyproject.toml": "smart_merge",
|
|
124
|
+
".gitignore": "smart_merge_gitignore",
|
|
125
|
+
"CLAUDE.md": "smart_append",
|
|
126
|
+
"RULES.md": "replace_if_missing",
|
|
127
|
+
"example.mcp.json": "special",
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
def _apply_merge_strategy(
|
|
131
|
+
self,
|
|
132
|
+
merge_strategy: str,
|
|
133
|
+
source_file: Path,
|
|
134
|
+
target_file: Path,
|
|
135
|
+
file_name: str,
|
|
136
|
+
project_name: str,
|
|
137
|
+
force: bool,
|
|
138
|
+
results: dict[str, t.Any],
|
|
139
|
+
) -> None:
|
|
140
|
+
"""Apply the appropriate merge strategy for the config file."""
|
|
141
|
+
if merge_strategy == "smart_merge":
|
|
142
|
+
self._smart_merge_config(
|
|
143
|
+
source_file,
|
|
144
|
+
target_file,
|
|
145
|
+
file_name,
|
|
146
|
+
project_name,
|
|
147
|
+
force,
|
|
148
|
+
results,
|
|
149
|
+
)
|
|
150
|
+
elif merge_strategy == "smart_merge_gitignore":
|
|
151
|
+
self._smart_merge_gitignore(
|
|
152
|
+
target_file,
|
|
153
|
+
project_name,
|
|
154
|
+
force,
|
|
155
|
+
results,
|
|
156
|
+
)
|
|
157
|
+
elif merge_strategy == "smart_append":
|
|
158
|
+
self._smart_append_config(
|
|
159
|
+
source_file,
|
|
160
|
+
target_file,
|
|
161
|
+
file_name,
|
|
162
|
+
project_name,
|
|
163
|
+
force,
|
|
164
|
+
results,
|
|
165
|
+
)
|
|
166
|
+
elif merge_strategy == "replace_if_missing":
|
|
167
|
+
self._handle_replace_if_missing(
|
|
168
|
+
source_file,
|
|
169
|
+
target_file,
|
|
170
|
+
file_name,
|
|
171
|
+
project_name,
|
|
172
|
+
force,
|
|
173
|
+
results,
|
|
174
|
+
)
|
|
175
|
+
else:
|
|
176
|
+
self._handle_default_strategy(
|
|
177
|
+
source_file,
|
|
178
|
+
target_file,
|
|
179
|
+
file_name,
|
|
180
|
+
project_name,
|
|
181
|
+
force,
|
|
182
|
+
results,
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
def _handle_replace_if_missing(
|
|
186
|
+
self,
|
|
187
|
+
source_file: Path,
|
|
188
|
+
target_file: Path,
|
|
189
|
+
file_name: str,
|
|
190
|
+
project_name: str,
|
|
191
|
+
force: bool,
|
|
192
|
+
results: dict[str, t.Any],
|
|
193
|
+
) -> None:
|
|
194
|
+
"""Handle replace_if_missing strategy."""
|
|
195
|
+
if not target_file.exists() or force:
|
|
196
|
+
content = self._read_and_process_content(source_file, True, project_name)
|
|
197
|
+
self._write_file_and_track(target_file, content, file_name, results)
|
|
198
|
+
else:
|
|
199
|
+
self._skip_existing_file(file_name, results)
|
|
200
|
+
|
|
201
|
+
def _handle_default_strategy(
|
|
202
|
+
self,
|
|
203
|
+
source_file: Path,
|
|
204
|
+
target_file: Path,
|
|
205
|
+
file_name: str,
|
|
206
|
+
project_name: str,
|
|
207
|
+
force: bool,
|
|
208
|
+
results: dict[str, t.Any],
|
|
209
|
+
) -> None:
|
|
210
|
+
"""Handle default copy strategy."""
|
|
211
|
+
if not self._should_copy_file(target_file, force, file_name, results):
|
|
212
|
+
return
|
|
213
|
+
content = self._read_and_process_content(source_file, True, project_name)
|
|
214
|
+
self._write_file_and_track(target_file, content, file_name, results)
|
|
215
|
+
|
|
216
|
+
def _process_config_file(
|
|
217
|
+
self,
|
|
218
|
+
file_name: str,
|
|
219
|
+
merge_strategy: str,
|
|
220
|
+
project_name: str,
|
|
221
|
+
target_path: Path,
|
|
222
|
+
force: bool,
|
|
223
|
+
results: dict[str, t.Any],
|
|
224
|
+
) -> None:
|
|
225
|
+
if file_name == "example.mcp.json":
|
|
226
|
+
self._process_mcp_config(target_path, force, results)
|
|
227
|
+
return
|
|
228
|
+
|
|
229
|
+
# Use crackerjack's project root for template files
|
|
230
|
+
crackerjack_project_root = Path(__file__).parent.parent.parent
|
|
231
|
+
source_file = crackerjack_project_root / file_name
|
|
232
|
+
target_file = target_path / file_name
|
|
233
|
+
|
|
234
|
+
if not source_file.exists():
|
|
235
|
+
self._handle_missing_source_file(file_name, results)
|
|
236
|
+
return
|
|
237
|
+
|
|
238
|
+
try:
|
|
239
|
+
self._apply_merge_strategy(
|
|
240
|
+
merge_strategy,
|
|
241
|
+
source_file,
|
|
242
|
+
target_file,
|
|
243
|
+
file_name,
|
|
244
|
+
project_name,
|
|
245
|
+
force,
|
|
246
|
+
results,
|
|
247
|
+
)
|
|
248
|
+
except Exception as e:
|
|
249
|
+
self._handle_file_processing_error(file_name, e, results)
|
|
250
|
+
|
|
251
|
+
def _should_copy_file(
|
|
252
|
+
self,
|
|
253
|
+
target_file: Path,
|
|
254
|
+
force: bool,
|
|
255
|
+
file_name: str,
|
|
256
|
+
results: dict[str, t.Any],
|
|
257
|
+
) -> bool:
|
|
258
|
+
if target_file.exists() and not force:
|
|
259
|
+
t.cast("list[str]", results["files_skipped"]).append(file_name)
|
|
260
|
+
self.console.print(
|
|
261
|
+
f"[yellow]⚠️[/ yellow] Skipped {file_name} (already exists)",
|
|
262
|
+
)
|
|
263
|
+
return False
|
|
264
|
+
return True
|
|
265
|
+
|
|
266
|
+
def _read_and_process_content(
|
|
267
|
+
self,
|
|
268
|
+
source_file: Path,
|
|
269
|
+
should_replace: bool,
|
|
270
|
+
project_name: str,
|
|
271
|
+
) -> str:
|
|
272
|
+
content = source_file.read_text()
|
|
273
|
+
|
|
274
|
+
if should_replace and project_name != "crackerjack":
|
|
275
|
+
content = content.replace("crackerjack", project_name)
|
|
276
|
+
|
|
277
|
+
return content
|
|
278
|
+
|
|
279
|
+
def _write_file_and_track(
|
|
280
|
+
self,
|
|
281
|
+
target_file: Path,
|
|
282
|
+
content: str,
|
|
283
|
+
file_name: str,
|
|
284
|
+
results: dict[str, t.Any],
|
|
285
|
+
) -> None:
|
|
286
|
+
target_file.write_text(content)
|
|
287
|
+
t.cast("list[str]", results["files_copied"]).append(file_name)
|
|
288
|
+
|
|
289
|
+
try:
|
|
290
|
+
self.git_service.add_files([str(target_file)])
|
|
291
|
+
except Exception as e:
|
|
292
|
+
self.console.print(
|
|
293
|
+
f"[yellow]⚠️[/ yellow] Could not git add {file_name}: {e}"
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
self.console.print(f"[green]✅[/ green] Copied {file_name}")
|
|
297
|
+
|
|
298
|
+
def _skip_existing_file(self, file_name: str, results: dict[str, t.Any]) -> None:
|
|
299
|
+
t.cast("list[str]", results["files_skipped"]).append(file_name)
|
|
300
|
+
self.console.print(f"[yellow]⚠️[/ yellow] Skipped {file_name} (already exists)")
|
|
301
|
+
|
|
302
|
+
def _handle_missing_source_file(
|
|
303
|
+
self,
|
|
304
|
+
file_name: str,
|
|
305
|
+
results: dict[str, t.Any],
|
|
306
|
+
) -> None:
|
|
307
|
+
error_msg = f"Source file not found: {file_name}"
|
|
308
|
+
t.cast("list[str]", results["errors"]).append(error_msg)
|
|
309
|
+
self.console.print(f"[yellow]⚠️[/ yellow] {error_msg}")
|
|
310
|
+
|
|
311
|
+
def _handle_file_processing_error(
|
|
312
|
+
self,
|
|
313
|
+
file_name: str,
|
|
314
|
+
error: Exception,
|
|
315
|
+
results: dict[str, t.Any],
|
|
316
|
+
) -> None:
|
|
317
|
+
error_msg = f"Failed to copy {file_name}: {error}"
|
|
318
|
+
t.cast("list[str]", results["errors"]).append(error_msg)
|
|
319
|
+
results["success"] = False
|
|
320
|
+
self.console.print(f"[red]❌[/ red] {error_msg}")
|
|
321
|
+
|
|
322
|
+
def _print_summary(self, results: dict[str, t.Any]) -> None:
|
|
323
|
+
if results["success"]:
|
|
324
|
+
self.console.print(
|
|
325
|
+
f"[green]🎉 Project initialized successfully ! [/ green] "
|
|
326
|
+
f"Copied {len(t.cast('list[str]', results['files_copied']))} files",
|
|
327
|
+
)
|
|
328
|
+
else:
|
|
329
|
+
self.console.print(
|
|
330
|
+
"[red]❌ Project initialization completed with errors[/ red]",
|
|
331
|
+
)
|
|
332
|
+
|
|
333
|
+
def _handle_initialization_error(
|
|
334
|
+
self,
|
|
335
|
+
results: dict[str, t.Any],
|
|
336
|
+
error: Exception,
|
|
337
|
+
) -> None:
|
|
338
|
+
results["success"] = False
|
|
339
|
+
t.cast("list[str]", results["errors"]).append(f"Initialization failed: {error}")
|
|
340
|
+
self.console.print(f"[red]❌[/ red] Initialization failed: {error}")
|
|
341
|
+
|
|
342
|
+
def check_uv_installed(self) -> bool:
|
|
343
|
+
try:
|
|
344
|
+
result = subprocess.run(
|
|
345
|
+
["uv", "--version"],
|
|
346
|
+
capture_output=True,
|
|
347
|
+
text=True,
|
|
348
|
+
timeout=10,
|
|
349
|
+
check=False,
|
|
350
|
+
)
|
|
351
|
+
return result.returncode == 0
|
|
352
|
+
except (FileNotFoundError, subprocess.TimeoutExpired):
|
|
353
|
+
return False
|
|
354
|
+
|
|
355
|
+
def _process_mcp_config(
|
|
356
|
+
self,
|
|
357
|
+
target_path: Path,
|
|
358
|
+
force: bool,
|
|
359
|
+
results: dict[str, t.Any],
|
|
360
|
+
) -> None:
|
|
361
|
+
# Use crackerjack's project root for template files
|
|
362
|
+
crackerjack_project_root = Path(__file__).parent.parent.parent
|
|
363
|
+
source_file = crackerjack_project_root / "example.mcp.json"
|
|
364
|
+
|
|
365
|
+
target_file = target_path / ".mcp.json"
|
|
366
|
+
|
|
367
|
+
if not source_file.exists():
|
|
368
|
+
self._handle_missing_source_file("example.mcp.json", results)
|
|
369
|
+
return
|
|
370
|
+
|
|
371
|
+
try:
|
|
372
|
+
with source_file.open() as f:
|
|
373
|
+
source_config = json.load(f)
|
|
374
|
+
|
|
375
|
+
if not isinstance(source_config.get("mcpServers"), dict):
|
|
376
|
+
self._handle_file_processing_error(
|
|
377
|
+
"example.mcp.json",
|
|
378
|
+
ValueError("Invalid example.mcp.json format: missing mcpServers"),
|
|
379
|
+
results,
|
|
380
|
+
)
|
|
381
|
+
return
|
|
382
|
+
|
|
383
|
+
crackerjack_servers = source_config["mcpServers"]
|
|
384
|
+
|
|
385
|
+
if not target_file.exists():
|
|
386
|
+
target_config = {"mcpServers": crackerjack_servers}
|
|
387
|
+
self._write_mcp_config_and_track(target_file, target_config, results)
|
|
388
|
+
self.console.print(
|
|
389
|
+
"[green]✅[/ green] Created .mcp.json with crackerjack MCP servers",
|
|
390
|
+
)
|
|
391
|
+
return
|
|
392
|
+
|
|
393
|
+
if target_file.exists() and not force:
|
|
394
|
+
self._merge_mcp_config(target_file, crackerjack_servers, results)
|
|
395
|
+
return
|
|
396
|
+
|
|
397
|
+
target_config = {"mcpServers": crackerjack_servers}
|
|
398
|
+
self._write_mcp_config_and_track(target_file, target_config, results)
|
|
399
|
+
self.console.print(
|
|
400
|
+
"[green]✅[/ green] Updated .mcp.json with crackerjack MCP servers",
|
|
401
|
+
)
|
|
402
|
+
|
|
403
|
+
except Exception as e:
|
|
404
|
+
self._handle_file_processing_error(".mcp.json", e, results)
|
|
405
|
+
|
|
406
|
+
def _merge_mcp_config(
|
|
407
|
+
self,
|
|
408
|
+
target_file: Path,
|
|
409
|
+
crackerjack_servers: dict[str, t.Any],
|
|
410
|
+
results: dict[str, t.Any],
|
|
411
|
+
) -> None:
|
|
412
|
+
try:
|
|
413
|
+
with target_file.open() as f:
|
|
414
|
+
existing_config = json.load(f)
|
|
415
|
+
|
|
416
|
+
if not isinstance(existing_config.get("mcpServers"), dict):
|
|
417
|
+
existing_config["mcpServers"] = {}
|
|
418
|
+
|
|
419
|
+
existing_servers = existing_config["mcpServers"]
|
|
420
|
+
updated_servers = {}
|
|
421
|
+
|
|
422
|
+
for name, config in crackerjack_servers.items():
|
|
423
|
+
if name in existing_servers:
|
|
424
|
+
self.console.print(
|
|
425
|
+
f"[yellow]🔄[/ yellow] Updating existing MCP server: {name}",
|
|
426
|
+
)
|
|
427
|
+
else:
|
|
428
|
+
self.console.print(
|
|
429
|
+
f"[green]➕[/ green] Adding new MCP server: {name}",
|
|
430
|
+
)
|
|
431
|
+
updated_servers[name] = config
|
|
432
|
+
|
|
433
|
+
existing_servers.update(updated_servers)
|
|
434
|
+
|
|
435
|
+
self._write_mcp_config_and_track(target_file, existing_config, results)
|
|
436
|
+
|
|
437
|
+
t.cast("list[str]", results["files_copied"]).append(".mcp.json (merged)")
|
|
438
|
+
|
|
439
|
+
except Exception as e:
|
|
440
|
+
self._handle_file_processing_error(".mcp.json (merge)", e, results)
|
|
441
|
+
|
|
442
|
+
def _write_mcp_config_and_track(
|
|
443
|
+
self,
|
|
444
|
+
target_file: Path,
|
|
445
|
+
config: dict[str, t.Any],
|
|
446
|
+
results: dict[str, t.Any],
|
|
447
|
+
) -> None:
|
|
448
|
+
with target_file.open("w") as f:
|
|
449
|
+
json.dump(config, f, indent=2)
|
|
450
|
+
|
|
451
|
+
t.cast("list[str]", results["files_copied"]).append(".mcp.json")
|
|
452
|
+
|
|
453
|
+
try:
|
|
454
|
+
self.git_service.add_files([str(target_file)])
|
|
455
|
+
except Exception as e:
|
|
456
|
+
self.console.print(f"[yellow]⚠️[/ yellow] Could not git add .mcp.json: {e}")
|
|
457
|
+
|
|
458
|
+
def _generate_project_claude_content(self, project_name: str) -> str:
|
|
459
|
+
return """
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
This project uses crackerjack for Python project management and quality assurance.
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
For optimal development experience with this crackerjack - enabled project, use these specialized agents:
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
- **🏗️ crackerjack-architect**: Expert in crackerjack's modular architecture and Python project management patterns. **Use PROACTIVELY** for all feature development, architectural decisions, and ensuring code follows crackerjack standards from the start.
|
|
469
|
+
|
|
470
|
+
- **🐍 python-pro**: Modern Python development with type hints, async/await patterns, and clean architecture
|
|
471
|
+
|
|
472
|
+
- **🧪 pytest-hypothesis-specialist**: Advanced testing patterns, property-based testing, and test optimization
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
- **🧪 crackerjack-test-specialist**: Advanced testing specialist for complex testing scenarios and coverage optimization
|
|
476
|
+
- **🏗️ backend-architect**: System design, API architecture, and service integration patterns
|
|
477
|
+
- **🔒 security-auditor**: Security analysis, vulnerability detection, and secure coding practices
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
```bash
|
|
481
|
+
|
|
482
|
+
Task tool with subagent_type ="crackerjack-architect" for feature planning
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
Task tool with subagent_type ="python-pro" for code implementation
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
Task tool with subagent_type ="pytest-hypothesis-specialist" for test development
|
|
489
|
+
|
|
490
|
+
|
|
491
|
+
Task tool with subagent_type ="security-auditor" for security analysis
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
**💡 Pro Tip**: The crackerjack-architect agent automatically ensures code follows crackerjack patterns from the start, eliminating the need for retrofitting and quality fixes.
|
|
495
|
+
|
|
496
|
+
|
|
497
|
+
This project follows crackerjack's clean code philosophy:
|
|
498
|
+
|
|
499
|
+
|
|
500
|
+
- **EVERY LINE OF CODE IS A LIABILITY**: The best code is no code
|
|
501
|
+
- **DRY (Don't Repeat Yourself)**: If you write it twice, you're doing it wrong
|
|
502
|
+
- **YAGNI (You Ain't Gonna Need It)**: Build only what's needed NOW
|
|
503
|
+
- **KISS (Keep It Simple, Stupid)**: Complexity is the enemy of maintainability
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
- **Cognitive complexity ≤15 **per function (automatically enforced)
|
|
507
|
+
- **Coverage ratchet system**: Never decrease coverage, always improve toward 100%
|
|
508
|
+
- **Type annotations required**: All functions must have return type hints
|
|
509
|
+
- **Security patterns**: No hardcoded paths, proper temp file handling
|
|
510
|
+
- **Python 3.13+ modern patterns**: Use `|` unions, pathlib over os.path
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
```bash
|
|
514
|
+
|
|
515
|
+
python -m crackerjack
|
|
516
|
+
|
|
517
|
+
|
|
518
|
+
python -m crackerjack - t
|
|
519
|
+
|
|
520
|
+
|
|
521
|
+
python -m crackerjack - - ai - agent - t
|
|
522
|
+
|
|
523
|
+
|
|
524
|
+
python -m crackerjack - a patch
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
|
|
528
|
+
1. **Plan with crackerjack-architect**: Ensure proper architecture from the start
|
|
529
|
+
2. **Implement with python-pro**: Follow modern Python patterns
|
|
530
|
+
3. **Test comprehensively**: Use pytest-hypothesis-specialist for robust testing
|
|
531
|
+
4. **Run quality checks**: `python -m crackerjack -t` before committing
|
|
532
|
+
5. **Security review**: Use security-auditor for final validation
|
|
533
|
+
|
|
534
|
+
|
|
535
|
+
- **Use crackerjack-architect agent proactively** for all significant code changes
|
|
536
|
+
- **Never reduce test coverage** - the ratchet system only allows improvements
|
|
537
|
+
- **Follow crackerjack patterns** - the tools will enforce quality automatically
|
|
538
|
+
- **Leverage AI agent auto-fixing** - `python -m crackerjack --ai-agent -t` for autonomous quality fixes
|
|
539
|
+
|
|
540
|
+
- --
|
|
541
|
+
* This project is enhanced by crackerjack's intelligent Python project management.*"""
|
|
542
|
+
|
|
543
|
+
def _smart_append_config(
|
|
544
|
+
self,
|
|
545
|
+
source_file: Path,
|
|
546
|
+
target_file: Path,
|
|
547
|
+
file_name: str,
|
|
548
|
+
project_name: str,
|
|
549
|
+
force: bool,
|
|
550
|
+
results: dict[str, t.Any],
|
|
551
|
+
) -> None:
|
|
552
|
+
try:
|
|
553
|
+
if file_name == "CLAUDE.md" and project_name != "crackerjack":
|
|
554
|
+
source_content = self._generate_project_claude_content(project_name)
|
|
555
|
+
else:
|
|
556
|
+
source_content = self._read_and_process_content(
|
|
557
|
+
source_file, True, project_name
|
|
558
|
+
)
|
|
559
|
+
|
|
560
|
+
crackerjack_start_marker = "<!-- CRACKERJACK INTEGRATION START -->"
|
|
561
|
+
crackerjack_end_marker = "<!-- CRACKERJACK INTEGRATION END -->"
|
|
562
|
+
|
|
563
|
+
merged_content = self.config_merge_service.smart_append_file(
|
|
564
|
+
source_content,
|
|
565
|
+
target_file,
|
|
566
|
+
crackerjack_start_marker,
|
|
567
|
+
crackerjack_end_marker,
|
|
568
|
+
force,
|
|
569
|
+
)
|
|
570
|
+
|
|
571
|
+
if target_file.exists():
|
|
572
|
+
existing_content = target_file.read_text()
|
|
573
|
+
if crackerjack_start_marker in existing_content and not force:
|
|
574
|
+
self._skip_existing_file(
|
|
575
|
+
f"{file_name} (crackerjack section)", results
|
|
576
|
+
)
|
|
577
|
+
return
|
|
578
|
+
|
|
579
|
+
target_file.write_text(merged_content)
|
|
580
|
+
t.cast("list[str]", results["files_copied"]).append(
|
|
581
|
+
f"{file_name} (appended)"
|
|
582
|
+
)
|
|
583
|
+
|
|
584
|
+
try:
|
|
585
|
+
self.git_service.add_files([str(target_file)])
|
|
586
|
+
except Exception as e:
|
|
587
|
+
self.console.print(
|
|
588
|
+
f"[yellow]⚠️[/ yellow] Could not git add {file_name}: {e}"
|
|
589
|
+
)
|
|
590
|
+
|
|
591
|
+
self.console.print(f"[green]✅[/ green] Appended to {file_name}")
|
|
592
|
+
|
|
593
|
+
except Exception as e:
|
|
594
|
+
self._handle_file_processing_error(file_name, e, results)
|
|
595
|
+
|
|
596
|
+
def _smart_merge_gitignore(
|
|
597
|
+
self,
|
|
598
|
+
target_file: Path,
|
|
599
|
+
project_name: str,
|
|
600
|
+
force: bool,
|
|
601
|
+
results: dict[str, t.Any],
|
|
602
|
+
) -> None:
|
|
603
|
+
gitignore_patterns = [
|
|
604
|
+
"# Build/Distribution",
|
|
605
|
+
"/build/",
|
|
606
|
+
"/dist/",
|
|
607
|
+
"*.egg-info/",
|
|
608
|
+
"",
|
|
609
|
+
"# Caches",
|
|
610
|
+
"__pycache__/",
|
|
611
|
+
".mypy_cache/",
|
|
612
|
+
".ruff_cache/",
|
|
613
|
+
".pytest_cache/",
|
|
614
|
+
"",
|
|
615
|
+
"# Coverage",
|
|
616
|
+
".coverage*",
|
|
617
|
+
"htmlcov/",
|
|
618
|
+
"",
|
|
619
|
+
"# Development",
|
|
620
|
+
".venv/",
|
|
621
|
+
".DS_STORE",
|
|
622
|
+
"*.pyc",
|
|
623
|
+
"",
|
|
624
|
+
"# Crackerjack specific",
|
|
625
|
+
"crackerjack-debug-*.log",
|
|
626
|
+
"crackerjack-ai-debug-*.log",
|
|
627
|
+
".crackerjack-*",
|
|
628
|
+
]
|
|
629
|
+
|
|
630
|
+
try:
|
|
631
|
+
merged_content = self.config_merge_service.smart_merge_gitignore(
|
|
632
|
+
gitignore_patterns, target_file
|
|
633
|
+
)
|
|
634
|
+
|
|
635
|
+
target_file.write_text(merged_content)
|
|
636
|
+
t.cast("list[str]", results["files_copied"]).append(".gitignore (merged)")
|
|
637
|
+
|
|
638
|
+
try:
|
|
639
|
+
self.git_service.add_files([str(target_file)])
|
|
640
|
+
except Exception as e:
|
|
641
|
+
self.console.print(
|
|
642
|
+
f"[yellow]⚠️[/ yellow] Could not git add .gitignore: {e}"
|
|
643
|
+
)
|
|
644
|
+
|
|
645
|
+
self.console.print("[green]✅[/ green] Smart merged .gitignore")
|
|
646
|
+
|
|
647
|
+
except Exception as e:
|
|
648
|
+
self._handle_file_processing_error(".gitignore", e, results)
|
|
649
|
+
|
|
650
|
+
def _smart_merge_config(
|
|
651
|
+
self,
|
|
652
|
+
source_file: Path,
|
|
653
|
+
target_file: Path,
|
|
654
|
+
file_name: str,
|
|
655
|
+
project_name: str,
|
|
656
|
+
force: bool,
|
|
657
|
+
results: dict[str, t.Any],
|
|
658
|
+
) -> None:
|
|
659
|
+
if file_name == "pyproject.toml":
|
|
660
|
+
self._smart_merge_pyproject(
|
|
661
|
+
source_file,
|
|
662
|
+
target_file,
|
|
663
|
+
project_name,
|
|
664
|
+
force,
|
|
665
|
+
results,
|
|
666
|
+
)
|
|
667
|
+
elif file_name == ".pre-commit-config.yaml":
|
|
668
|
+
self._smart_merge_pre_commit_config(
|
|
669
|
+
source_file,
|
|
670
|
+
target_file,
|
|
671
|
+
project_name,
|
|
672
|
+
force,
|
|
673
|
+
results,
|
|
674
|
+
)
|
|
675
|
+
elif not target_file.exists() or force:
|
|
676
|
+
content = self._read_and_process_content(
|
|
677
|
+
source_file,
|
|
678
|
+
True,
|
|
679
|
+
project_name,
|
|
680
|
+
)
|
|
681
|
+
self._write_file_and_track(target_file, content, file_name, results)
|
|
682
|
+
else:
|
|
683
|
+
self._skip_existing_file(file_name, results)
|
|
684
|
+
|
|
685
|
+
def _smart_merge_pyproject(
|
|
686
|
+
self,
|
|
687
|
+
source_file: Path,
|
|
688
|
+
target_file: Path,
|
|
689
|
+
project_name: str,
|
|
690
|
+
force: bool,
|
|
691
|
+
results: dict[str, t.Any],
|
|
692
|
+
) -> None:
|
|
693
|
+
try:
|
|
694
|
+
with source_file.open("rb") as f:
|
|
695
|
+
source_config = tomli.load(f)
|
|
696
|
+
|
|
697
|
+
merged_config = self.config_merge_service.smart_merge_pyproject(
|
|
698
|
+
source_config, target_file, project_name
|
|
699
|
+
)
|
|
700
|
+
|
|
701
|
+
self.config_merge_service.write_pyproject_config(merged_config, target_file)
|
|
702
|
+
|
|
703
|
+
t.cast("list[str]", results["files_copied"]).append(
|
|
704
|
+
"pyproject.toml (merged)"
|
|
705
|
+
)
|
|
706
|
+
|
|
707
|
+
try:
|
|
708
|
+
self.git_service.add_files([str(target_file)])
|
|
709
|
+
except Exception as e:
|
|
710
|
+
self.console.print(
|
|
711
|
+
f"[yellow]⚠️[/ yellow] Could not git add pyproject.toml: {e}",
|
|
712
|
+
)
|
|
713
|
+
|
|
714
|
+
self.console.print("[green]✅[/ green] Smart merged pyproject.toml")
|
|
715
|
+
|
|
716
|
+
except Exception as e:
|
|
717
|
+
self._handle_file_processing_error("pyproject.toml", e, results)
|
|
718
|
+
|
|
719
|
+
def _smart_merge_pre_commit_config(
|
|
720
|
+
self,
|
|
721
|
+
source_file: Path,
|
|
722
|
+
target_file: Path,
|
|
723
|
+
project_name: str,
|
|
724
|
+
force: bool,
|
|
725
|
+
results: dict[str, t.Any],
|
|
726
|
+
) -> None:
|
|
727
|
+
try:
|
|
728
|
+
source_config = self._load_source_config(source_file)
|
|
729
|
+
if source_config is None:
|
|
730
|
+
return
|
|
731
|
+
|
|
732
|
+
merged_config = self._perform_config_merge(
|
|
733
|
+
source_config, target_file, project_name
|
|
734
|
+
)
|
|
735
|
+
|
|
736
|
+
if self._should_skip_merge(target_file, merged_config, results):
|
|
737
|
+
return
|
|
738
|
+
|
|
739
|
+
self._write_and_finalize_config(
|
|
740
|
+
merged_config, target_file, source_config, results
|
|
741
|
+
)
|
|
742
|
+
|
|
743
|
+
except Exception as e:
|
|
744
|
+
self._handle_file_processing_error(".pre-commit-config.yaml", e, results)
|
|
745
|
+
|
|
746
|
+
def _load_source_config(self, source_file: Path) -> dict[str, t.Any] | None:
|
|
747
|
+
with source_file.open() as f:
|
|
748
|
+
loaded_config = yaml.safe_load(f)
|
|
749
|
+
source_config: dict[str, t.Any] = (
|
|
750
|
+
loaded_config if isinstance(loaded_config, dict) else {}
|
|
751
|
+
)
|
|
752
|
+
|
|
753
|
+
if not isinstance(source_config, dict):
|
|
754
|
+
self.console.print(
|
|
755
|
+
"[yellow]⚠️[/yellow] Source .pre-commit-config.yaml is not a dictionary, skipping merge"
|
|
756
|
+
)
|
|
757
|
+
return None
|
|
758
|
+
|
|
759
|
+
return source_config
|
|
760
|
+
|
|
761
|
+
def _perform_config_merge(
|
|
762
|
+
self, source_config: dict[str, t.Any], target_file: Path, project_name: str
|
|
763
|
+
) -> dict[str, t.Any]:
|
|
764
|
+
return self.config_merge_service.smart_merge_pre_commit_config(
|
|
765
|
+
source_config, target_file, project_name
|
|
766
|
+
)
|
|
767
|
+
|
|
768
|
+
def _should_skip_merge(
|
|
769
|
+
self,
|
|
770
|
+
target_file: Path,
|
|
771
|
+
merged_config: dict[str, t.Any],
|
|
772
|
+
results: dict[str, t.Any],
|
|
773
|
+
) -> bool:
|
|
774
|
+
if not target_file.exists():
|
|
775
|
+
return False
|
|
776
|
+
|
|
777
|
+
with target_file.open() as f:
|
|
778
|
+
loaded_config = yaml.safe_load(f)
|
|
779
|
+
old_config: dict[str, t.Any] = (
|
|
780
|
+
loaded_config if isinstance(loaded_config, dict) else {}
|
|
781
|
+
)
|
|
782
|
+
|
|
783
|
+
if not isinstance(old_config, dict):
|
|
784
|
+
old_config = {}
|
|
785
|
+
|
|
786
|
+
old_repo_count = len(old_config.get("repos", []))
|
|
787
|
+
new_repo_count = len(merged_config.get("repos", []))
|
|
788
|
+
|
|
789
|
+
if new_repo_count == old_repo_count:
|
|
790
|
+
self._skip_existing_file(".pre-commit-config.yaml (no new repos)", results)
|
|
791
|
+
return True
|
|
792
|
+
|
|
793
|
+
return False
|
|
794
|
+
|
|
795
|
+
def _write_and_finalize_config(
|
|
796
|
+
self,
|
|
797
|
+
merged_config: dict[str, t.Any],
|
|
798
|
+
target_file: Path,
|
|
799
|
+
source_config: dict[str, t.Any],
|
|
800
|
+
results: dict[str, t.Any],
|
|
801
|
+
) -> None:
|
|
802
|
+
self.config_merge_service.write_pre_commit_config(merged_config, target_file)
|
|
803
|
+
|
|
804
|
+
t.cast("list[str]", results["files_copied"]).append(
|
|
805
|
+
".pre-commit-config.yaml (merged)"
|
|
806
|
+
)
|
|
807
|
+
|
|
808
|
+
self._git_add_config_file(target_file)
|
|
809
|
+
self._display_merge_success(source_config)
|
|
810
|
+
|
|
811
|
+
def _git_add_config_file(self, target_file: Path) -> None:
|
|
812
|
+
try:
|
|
813
|
+
self.git_service.add_files([str(target_file)])
|
|
814
|
+
except Exception as e:
|
|
815
|
+
self.console.print(
|
|
816
|
+
f"[yellow]⚠️[/ yellow] Could not git add .pre-commit-config.yaml: {e}"
|
|
817
|
+
)
|
|
818
|
+
|
|
819
|
+
def _display_merge_success(self, source_config: dict[str, t.Any]) -> None:
|
|
820
|
+
source_repo_count = len(source_config.get("repos", []))
|
|
821
|
+
self.console.print(
|
|
822
|
+
f"[green]✅[/ green] Merged .pre-commit-config.yaml ({source_repo_count} repos processed)"
|
|
823
|
+
)
|