crackerjack 0.37.9__py3-none-any.whl → 0.45.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (425) hide show
  1. crackerjack/README.md +19 -0
  2. crackerjack/__init__.py +30 -1
  3. crackerjack/__main__.py +342 -1263
  4. crackerjack/adapters/README.md +18 -0
  5. crackerjack/adapters/__init__.py +27 -5
  6. crackerjack/adapters/_output_paths.py +167 -0
  7. crackerjack/adapters/_qa_adapter_base.py +309 -0
  8. crackerjack/adapters/_tool_adapter_base.py +706 -0
  9. crackerjack/adapters/ai/README.md +65 -0
  10. crackerjack/adapters/ai/__init__.py +5 -0
  11. crackerjack/adapters/ai/claude.py +853 -0
  12. crackerjack/adapters/complexity/README.md +53 -0
  13. crackerjack/adapters/complexity/__init__.py +10 -0
  14. crackerjack/adapters/complexity/complexipy.py +641 -0
  15. crackerjack/adapters/dependency/__init__.py +22 -0
  16. crackerjack/adapters/dependency/pip_audit.py +418 -0
  17. crackerjack/adapters/format/README.md +72 -0
  18. crackerjack/adapters/format/__init__.py +11 -0
  19. crackerjack/adapters/format/mdformat.py +313 -0
  20. crackerjack/adapters/format/ruff.py +516 -0
  21. crackerjack/adapters/lint/README.md +47 -0
  22. crackerjack/adapters/lint/__init__.py +11 -0
  23. crackerjack/adapters/lint/codespell.py +273 -0
  24. crackerjack/adapters/lsp/README.md +49 -0
  25. crackerjack/adapters/lsp/__init__.py +27 -0
  26. crackerjack/adapters/{rust_tool_manager.py → lsp/_manager.py} +3 -3
  27. crackerjack/adapters/{skylos_adapter.py → lsp/skylos.py} +59 -7
  28. crackerjack/adapters/{zuban_adapter.py → lsp/zuban.py} +3 -6
  29. crackerjack/adapters/refactor/README.md +59 -0
  30. crackerjack/adapters/refactor/__init__.py +12 -0
  31. crackerjack/adapters/refactor/creosote.py +318 -0
  32. crackerjack/adapters/refactor/refurb.py +406 -0
  33. crackerjack/adapters/refactor/skylos.py +494 -0
  34. crackerjack/adapters/sast/README.md +132 -0
  35. crackerjack/adapters/sast/__init__.py +32 -0
  36. crackerjack/adapters/sast/_base.py +201 -0
  37. crackerjack/adapters/sast/bandit.py +423 -0
  38. crackerjack/adapters/sast/pyscn.py +405 -0
  39. crackerjack/adapters/sast/semgrep.py +241 -0
  40. crackerjack/adapters/security/README.md +111 -0
  41. crackerjack/adapters/security/__init__.py +17 -0
  42. crackerjack/adapters/security/gitleaks.py +339 -0
  43. crackerjack/adapters/type/README.md +52 -0
  44. crackerjack/adapters/type/__init__.py +12 -0
  45. crackerjack/adapters/type/pyrefly.py +402 -0
  46. crackerjack/adapters/type/ty.py +402 -0
  47. crackerjack/adapters/type/zuban.py +522 -0
  48. crackerjack/adapters/utility/README.md +51 -0
  49. crackerjack/adapters/utility/__init__.py +10 -0
  50. crackerjack/adapters/utility/checks.py +884 -0
  51. crackerjack/agents/README.md +264 -0
  52. crackerjack/agents/__init__.py +40 -12
  53. crackerjack/agents/base.py +1 -0
  54. crackerjack/agents/claude_code_bridge.py +641 -0
  55. crackerjack/agents/coordinator.py +49 -53
  56. crackerjack/agents/dry_agent.py +187 -3
  57. crackerjack/agents/enhanced_coordinator.py +279 -0
  58. crackerjack/agents/enhanced_proactive_agent.py +185 -0
  59. crackerjack/agents/error_middleware.py +53 -0
  60. crackerjack/agents/formatting_agent.py +6 -8
  61. crackerjack/agents/helpers/__init__.py +9 -0
  62. crackerjack/agents/helpers/performance/__init__.py +22 -0
  63. crackerjack/agents/helpers/performance/performance_ast_analyzer.py +357 -0
  64. crackerjack/agents/helpers/performance/performance_pattern_detector.py +909 -0
  65. crackerjack/agents/helpers/performance/performance_recommender.py +572 -0
  66. crackerjack/agents/helpers/refactoring/__init__.py +22 -0
  67. crackerjack/agents/helpers/refactoring/code_transformer.py +536 -0
  68. crackerjack/agents/helpers/refactoring/complexity_analyzer.py +344 -0
  69. crackerjack/agents/helpers/refactoring/dead_code_detector.py +437 -0
  70. crackerjack/agents/helpers/test_creation/__init__.py +19 -0
  71. crackerjack/agents/helpers/test_creation/test_ast_analyzer.py +216 -0
  72. crackerjack/agents/helpers/test_creation/test_coverage_analyzer.py +643 -0
  73. crackerjack/agents/helpers/test_creation/test_template_generator.py +1031 -0
  74. crackerjack/agents/performance_agent.py +121 -1152
  75. crackerjack/agents/refactoring_agent.py +156 -655
  76. crackerjack/agents/semantic_agent.py +479 -0
  77. crackerjack/agents/semantic_helpers.py +356 -0
  78. crackerjack/agents/test_creation_agent.py +19 -1605
  79. crackerjack/api.py +5 -7
  80. crackerjack/cli/README.md +394 -0
  81. crackerjack/cli/__init__.py +1 -1
  82. crackerjack/cli/cache_handlers.py +23 -18
  83. crackerjack/cli/cache_handlers_enhanced.py +1 -4
  84. crackerjack/cli/facade.py +70 -8
  85. crackerjack/cli/formatting.py +13 -0
  86. crackerjack/cli/handlers/__init__.py +85 -0
  87. crackerjack/cli/handlers/advanced.py +103 -0
  88. crackerjack/cli/handlers/ai_features.py +62 -0
  89. crackerjack/cli/handlers/analytics.py +479 -0
  90. crackerjack/cli/handlers/changelog.py +271 -0
  91. crackerjack/cli/handlers/config_handlers.py +16 -0
  92. crackerjack/cli/handlers/coverage.py +84 -0
  93. crackerjack/cli/handlers/documentation.py +280 -0
  94. crackerjack/cli/handlers/main_handlers.py +497 -0
  95. crackerjack/cli/handlers/monitoring.py +371 -0
  96. crackerjack/cli/handlers.py +249 -49
  97. crackerjack/cli/interactive.py +8 -5
  98. crackerjack/cli/options.py +203 -110
  99. crackerjack/cli/semantic_handlers.py +292 -0
  100. crackerjack/cli/version.py +19 -0
  101. crackerjack/code_cleaner.py +60 -24
  102. crackerjack/config/README.md +472 -0
  103. crackerjack/config/__init__.py +256 -0
  104. crackerjack/config/global_lock_config.py +191 -54
  105. crackerjack/config/hooks.py +188 -16
  106. crackerjack/config/loader.py +239 -0
  107. crackerjack/config/settings.py +141 -0
  108. crackerjack/config/tool_commands.py +331 -0
  109. crackerjack/core/README.md +393 -0
  110. crackerjack/core/async_workflow_orchestrator.py +79 -53
  111. crackerjack/core/autofix_coordinator.py +22 -9
  112. crackerjack/core/container.py +10 -9
  113. crackerjack/core/enhanced_container.py +9 -9
  114. crackerjack/core/performance.py +1 -1
  115. crackerjack/core/performance_monitor.py +5 -3
  116. crackerjack/core/phase_coordinator.py +1018 -634
  117. crackerjack/core/proactive_workflow.py +3 -3
  118. crackerjack/core/retry.py +275 -0
  119. crackerjack/core/service_watchdog.py +167 -23
  120. crackerjack/core/session_coordinator.py +187 -382
  121. crackerjack/core/timeout_manager.py +161 -44
  122. crackerjack/core/workflow/__init__.py +21 -0
  123. crackerjack/core/workflow/workflow_ai_coordinator.py +863 -0
  124. crackerjack/core/workflow/workflow_event_orchestrator.py +1107 -0
  125. crackerjack/core/workflow/workflow_issue_parser.py +714 -0
  126. crackerjack/core/workflow/workflow_phase_executor.py +1158 -0
  127. crackerjack/core/workflow/workflow_security_gates.py +400 -0
  128. crackerjack/core/workflow_orchestrator.py +1247 -953
  129. crackerjack/data/README.md +11 -0
  130. crackerjack/data/__init__.py +8 -0
  131. crackerjack/data/models.py +79 -0
  132. crackerjack/data/repository.py +210 -0
  133. crackerjack/decorators/README.md +180 -0
  134. crackerjack/decorators/__init__.py +35 -0
  135. crackerjack/decorators/error_handling.py +649 -0
  136. crackerjack/decorators/error_handling_decorators.py +334 -0
  137. crackerjack/decorators/helpers.py +58 -0
  138. crackerjack/decorators/patterns.py +281 -0
  139. crackerjack/decorators/utils.py +58 -0
  140. crackerjack/docs/README.md +11 -0
  141. crackerjack/docs/generated/api/CLI_REFERENCE.md +1 -1
  142. crackerjack/documentation/README.md +11 -0
  143. crackerjack/documentation/ai_templates.py +1 -1
  144. crackerjack/documentation/dual_output_generator.py +11 -9
  145. crackerjack/documentation/reference_generator.py +104 -59
  146. crackerjack/dynamic_config.py +52 -61
  147. crackerjack/errors.py +1 -1
  148. crackerjack/events/README.md +11 -0
  149. crackerjack/events/__init__.py +16 -0
  150. crackerjack/events/telemetry.py +175 -0
  151. crackerjack/events/workflow_bus.py +346 -0
  152. crackerjack/exceptions/README.md +301 -0
  153. crackerjack/exceptions/__init__.py +5 -0
  154. crackerjack/exceptions/config.py +4 -0
  155. crackerjack/exceptions/tool_execution_error.py +245 -0
  156. crackerjack/executors/README.md +591 -0
  157. crackerjack/executors/__init__.py +2 -0
  158. crackerjack/executors/async_hook_executor.py +539 -77
  159. crackerjack/executors/cached_hook_executor.py +3 -3
  160. crackerjack/executors/hook_executor.py +967 -102
  161. crackerjack/executors/hook_lock_manager.py +31 -22
  162. crackerjack/executors/individual_hook_executor.py +66 -32
  163. crackerjack/executors/lsp_aware_hook_executor.py +136 -57
  164. crackerjack/executors/progress_hook_executor.py +282 -0
  165. crackerjack/executors/tool_proxy.py +23 -7
  166. crackerjack/hooks/README.md +485 -0
  167. crackerjack/hooks/lsp_hook.py +8 -9
  168. crackerjack/intelligence/README.md +557 -0
  169. crackerjack/interactive.py +37 -10
  170. crackerjack/managers/README.md +369 -0
  171. crackerjack/managers/async_hook_manager.py +41 -57
  172. crackerjack/managers/hook_manager.py +449 -79
  173. crackerjack/managers/publish_manager.py +81 -36
  174. crackerjack/managers/test_command_builder.py +290 -12
  175. crackerjack/managers/test_executor.py +93 -8
  176. crackerjack/managers/test_manager.py +1082 -75
  177. crackerjack/managers/test_progress.py +118 -26
  178. crackerjack/mcp/README.md +374 -0
  179. crackerjack/mcp/cache.py +25 -2
  180. crackerjack/mcp/client_runner.py +35 -18
  181. crackerjack/mcp/context.py +9 -9
  182. crackerjack/mcp/dashboard.py +24 -8
  183. crackerjack/mcp/enhanced_progress_monitor.py +34 -23
  184. crackerjack/mcp/file_monitor.py +27 -6
  185. crackerjack/mcp/progress_components.py +45 -34
  186. crackerjack/mcp/progress_monitor.py +6 -9
  187. crackerjack/mcp/rate_limiter.py +11 -7
  188. crackerjack/mcp/server.py +2 -0
  189. crackerjack/mcp/server_core.py +187 -55
  190. crackerjack/mcp/service_watchdog.py +12 -9
  191. crackerjack/mcp/task_manager.py +2 -2
  192. crackerjack/mcp/tools/README.md +27 -0
  193. crackerjack/mcp/tools/__init__.py +2 -0
  194. crackerjack/mcp/tools/core_tools.py +75 -52
  195. crackerjack/mcp/tools/execution_tools.py +87 -31
  196. crackerjack/mcp/tools/intelligence_tools.py +2 -2
  197. crackerjack/mcp/tools/proactive_tools.py +1 -1
  198. crackerjack/mcp/tools/semantic_tools.py +584 -0
  199. crackerjack/mcp/tools/utility_tools.py +180 -132
  200. crackerjack/mcp/tools/workflow_executor.py +87 -46
  201. crackerjack/mcp/websocket/README.md +31 -0
  202. crackerjack/mcp/websocket/app.py +11 -1
  203. crackerjack/mcp/websocket/event_bridge.py +188 -0
  204. crackerjack/mcp/websocket/jobs.py +27 -4
  205. crackerjack/mcp/websocket/monitoring/__init__.py +25 -0
  206. crackerjack/mcp/websocket/monitoring/api/__init__.py +19 -0
  207. crackerjack/mcp/websocket/monitoring/api/dependencies.py +141 -0
  208. crackerjack/mcp/websocket/monitoring/api/heatmap.py +154 -0
  209. crackerjack/mcp/websocket/monitoring/api/intelligence.py +199 -0
  210. crackerjack/mcp/websocket/monitoring/api/metrics.py +203 -0
  211. crackerjack/mcp/websocket/monitoring/api/telemetry.py +101 -0
  212. crackerjack/mcp/websocket/monitoring/dashboard.py +18 -0
  213. crackerjack/mcp/websocket/monitoring/factory.py +109 -0
  214. crackerjack/mcp/websocket/monitoring/filters.py +10 -0
  215. crackerjack/mcp/websocket/monitoring/metrics.py +64 -0
  216. crackerjack/mcp/websocket/monitoring/models.py +90 -0
  217. crackerjack/mcp/websocket/monitoring/utils.py +171 -0
  218. crackerjack/mcp/websocket/monitoring/websocket_manager.py +78 -0
  219. crackerjack/mcp/websocket/monitoring/websockets/__init__.py +17 -0
  220. crackerjack/mcp/websocket/monitoring/websockets/dependencies.py +126 -0
  221. crackerjack/mcp/websocket/monitoring/websockets/heatmap.py +176 -0
  222. crackerjack/mcp/websocket/monitoring/websockets/intelligence.py +291 -0
  223. crackerjack/mcp/websocket/monitoring/websockets/metrics.py +291 -0
  224. crackerjack/mcp/websocket/monitoring_endpoints.py +16 -2930
  225. crackerjack/mcp/websocket/server.py +1 -3
  226. crackerjack/mcp/websocket/websocket_handler.py +107 -6
  227. crackerjack/models/README.md +308 -0
  228. crackerjack/models/__init__.py +10 -1
  229. crackerjack/models/config.py +639 -22
  230. crackerjack/models/config_adapter.py +6 -6
  231. crackerjack/models/protocols.py +1167 -23
  232. crackerjack/models/pydantic_models.py +320 -0
  233. crackerjack/models/qa_config.py +145 -0
  234. crackerjack/models/qa_results.py +134 -0
  235. crackerjack/models/results.py +35 -0
  236. crackerjack/models/semantic_models.py +258 -0
  237. crackerjack/models/task.py +19 -3
  238. crackerjack/models/test_models.py +60 -0
  239. crackerjack/monitoring/README.md +11 -0
  240. crackerjack/monitoring/ai_agent_watchdog.py +5 -4
  241. crackerjack/monitoring/metrics_collector.py +4 -3
  242. crackerjack/monitoring/regression_prevention.py +4 -3
  243. crackerjack/monitoring/websocket_server.py +4 -241
  244. crackerjack/orchestration/README.md +340 -0
  245. crackerjack/orchestration/__init__.py +43 -0
  246. crackerjack/orchestration/advanced_orchestrator.py +20 -67
  247. crackerjack/orchestration/cache/README.md +312 -0
  248. crackerjack/orchestration/cache/__init__.py +37 -0
  249. crackerjack/orchestration/cache/memory_cache.py +338 -0
  250. crackerjack/orchestration/cache/tool_proxy_cache.py +340 -0
  251. crackerjack/orchestration/config.py +297 -0
  252. crackerjack/orchestration/coverage_improvement.py +13 -6
  253. crackerjack/orchestration/execution_strategies.py +6 -6
  254. crackerjack/orchestration/hook_orchestrator.py +1398 -0
  255. crackerjack/orchestration/strategies/README.md +401 -0
  256. crackerjack/orchestration/strategies/__init__.py +39 -0
  257. crackerjack/orchestration/strategies/adaptive_strategy.py +630 -0
  258. crackerjack/orchestration/strategies/parallel_strategy.py +237 -0
  259. crackerjack/orchestration/strategies/sequential_strategy.py +299 -0
  260. crackerjack/orchestration/test_progress_streamer.py +1 -1
  261. crackerjack/plugins/README.md +11 -0
  262. crackerjack/plugins/hooks.py +3 -2
  263. crackerjack/plugins/loader.py +3 -3
  264. crackerjack/plugins/managers.py +1 -1
  265. crackerjack/py313.py +191 -0
  266. crackerjack/security/README.md +11 -0
  267. crackerjack/services/README.md +374 -0
  268. crackerjack/services/__init__.py +8 -21
  269. crackerjack/services/ai/README.md +295 -0
  270. crackerjack/services/ai/__init__.py +7 -0
  271. crackerjack/services/ai/advanced_optimizer.py +878 -0
  272. crackerjack/services/{contextual_ai_assistant.py → ai/contextual_ai_assistant.py} +5 -3
  273. crackerjack/services/ai/embeddings.py +444 -0
  274. crackerjack/services/ai/intelligent_commit.py +328 -0
  275. crackerjack/services/ai/predictive_analytics.py +510 -0
  276. crackerjack/services/api_extractor.py +5 -3
  277. crackerjack/services/bounded_status_operations.py +45 -5
  278. crackerjack/services/cache.py +249 -318
  279. crackerjack/services/changelog_automation.py +7 -3
  280. crackerjack/services/command_execution_service.py +305 -0
  281. crackerjack/services/config_integrity.py +83 -39
  282. crackerjack/services/config_merge.py +9 -6
  283. crackerjack/services/config_service.py +198 -0
  284. crackerjack/services/config_template.py +13 -26
  285. crackerjack/services/coverage_badge_service.py +6 -4
  286. crackerjack/services/coverage_ratchet.py +53 -27
  287. crackerjack/services/debug.py +18 -7
  288. crackerjack/services/dependency_analyzer.py +4 -4
  289. crackerjack/services/dependency_monitor.py +13 -13
  290. crackerjack/services/documentation_generator.py +4 -2
  291. crackerjack/services/documentation_service.py +62 -33
  292. crackerjack/services/enhanced_filesystem.py +81 -27
  293. crackerjack/services/enterprise_optimizer.py +1 -1
  294. crackerjack/services/error_pattern_analyzer.py +10 -10
  295. crackerjack/services/file_filter.py +221 -0
  296. crackerjack/services/file_hasher.py +5 -7
  297. crackerjack/services/file_io_service.py +361 -0
  298. crackerjack/services/file_modifier.py +615 -0
  299. crackerjack/services/filesystem.py +80 -109
  300. crackerjack/services/git.py +99 -5
  301. crackerjack/services/health_metrics.py +4 -6
  302. crackerjack/services/heatmap_generator.py +12 -3
  303. crackerjack/services/incremental_executor.py +380 -0
  304. crackerjack/services/initialization.py +101 -49
  305. crackerjack/services/log_manager.py +2 -2
  306. crackerjack/services/logging.py +120 -68
  307. crackerjack/services/lsp_client.py +12 -12
  308. crackerjack/services/memory_optimizer.py +27 -22
  309. crackerjack/services/monitoring/README.md +30 -0
  310. crackerjack/services/monitoring/__init__.py +9 -0
  311. crackerjack/services/monitoring/dependency_monitor.py +678 -0
  312. crackerjack/services/monitoring/error_pattern_analyzer.py +676 -0
  313. crackerjack/services/monitoring/health_metrics.py +716 -0
  314. crackerjack/services/monitoring/metrics.py +587 -0
  315. crackerjack/services/{performance_benchmarks.py → monitoring/performance_benchmarks.py} +100 -14
  316. crackerjack/services/{performance_cache.py → monitoring/performance_cache.py} +21 -15
  317. crackerjack/services/{performance_monitor.py → monitoring/performance_monitor.py} +10 -6
  318. crackerjack/services/parallel_executor.py +166 -55
  319. crackerjack/services/patterns/__init__.py +142 -0
  320. crackerjack/services/patterns/agents.py +107 -0
  321. crackerjack/services/patterns/code/__init__.py +15 -0
  322. crackerjack/services/patterns/code/detection.py +118 -0
  323. crackerjack/services/patterns/code/imports.py +107 -0
  324. crackerjack/services/patterns/code/paths.py +159 -0
  325. crackerjack/services/patterns/code/performance.py +119 -0
  326. crackerjack/services/patterns/code/replacement.py +36 -0
  327. crackerjack/services/patterns/core.py +212 -0
  328. crackerjack/services/patterns/documentation/__init__.py +14 -0
  329. crackerjack/services/patterns/documentation/badges_markdown.py +96 -0
  330. crackerjack/services/patterns/documentation/comments_blocks.py +83 -0
  331. crackerjack/services/patterns/documentation/docstrings.py +89 -0
  332. crackerjack/services/patterns/formatting.py +226 -0
  333. crackerjack/services/patterns/operations.py +339 -0
  334. crackerjack/services/patterns/security/__init__.py +23 -0
  335. crackerjack/services/patterns/security/code_injection.py +122 -0
  336. crackerjack/services/patterns/security/credentials.py +190 -0
  337. crackerjack/services/patterns/security/path_traversal.py +221 -0
  338. crackerjack/services/patterns/security/unsafe_operations.py +216 -0
  339. crackerjack/services/patterns/templates.py +62 -0
  340. crackerjack/services/patterns/testing/__init__.py +18 -0
  341. crackerjack/services/patterns/testing/error_patterns.py +107 -0
  342. crackerjack/services/patterns/testing/pytest_output.py +126 -0
  343. crackerjack/services/patterns/tool_output/__init__.py +16 -0
  344. crackerjack/services/patterns/tool_output/bandit.py +72 -0
  345. crackerjack/services/patterns/tool_output/other.py +97 -0
  346. crackerjack/services/patterns/tool_output/pyright.py +67 -0
  347. crackerjack/services/patterns/tool_output/ruff.py +44 -0
  348. crackerjack/services/patterns/url_sanitization.py +114 -0
  349. crackerjack/services/patterns/utilities.py +42 -0
  350. crackerjack/services/patterns/utils.py +339 -0
  351. crackerjack/services/patterns/validation.py +46 -0
  352. crackerjack/services/patterns/versioning.py +62 -0
  353. crackerjack/services/predictive_analytics.py +21 -8
  354. crackerjack/services/profiler.py +280 -0
  355. crackerjack/services/quality/README.md +415 -0
  356. crackerjack/services/quality/__init__.py +11 -0
  357. crackerjack/services/quality/anomaly_detector.py +392 -0
  358. crackerjack/services/quality/pattern_cache.py +333 -0
  359. crackerjack/services/quality/pattern_detector.py +479 -0
  360. crackerjack/services/quality/qa_orchestrator.py +491 -0
  361. crackerjack/services/{quality_baseline.py → quality/quality_baseline.py} +163 -2
  362. crackerjack/services/{quality_baseline_enhanced.py → quality/quality_baseline_enhanced.py} +4 -1
  363. crackerjack/services/{quality_intelligence.py → quality/quality_intelligence.py} +180 -16
  364. crackerjack/services/regex_patterns.py +58 -2987
  365. crackerjack/services/regex_utils.py +55 -29
  366. crackerjack/services/secure_status_formatter.py +42 -15
  367. crackerjack/services/secure_subprocess.py +35 -2
  368. crackerjack/services/security.py +16 -8
  369. crackerjack/services/server_manager.py +40 -51
  370. crackerjack/services/smart_scheduling.py +46 -6
  371. crackerjack/services/status_authentication.py +3 -3
  372. crackerjack/services/thread_safe_status_collector.py +1 -0
  373. crackerjack/services/tool_filter.py +368 -0
  374. crackerjack/services/tool_version_service.py +9 -5
  375. crackerjack/services/unified_config.py +43 -351
  376. crackerjack/services/vector_store.py +689 -0
  377. crackerjack/services/version_analyzer.py +6 -4
  378. crackerjack/services/version_checker.py +14 -8
  379. crackerjack/services/zuban_lsp_service.py +5 -4
  380. crackerjack/slash_commands/README.md +11 -0
  381. crackerjack/slash_commands/init.md +2 -12
  382. crackerjack/slash_commands/run.md +84 -50
  383. crackerjack/tools/README.md +11 -0
  384. crackerjack/tools/__init__.py +30 -0
  385. crackerjack/tools/_git_utils.py +105 -0
  386. crackerjack/tools/check_added_large_files.py +139 -0
  387. crackerjack/tools/check_ast.py +105 -0
  388. crackerjack/tools/check_json.py +103 -0
  389. crackerjack/tools/check_jsonschema.py +297 -0
  390. crackerjack/tools/check_toml.py +103 -0
  391. crackerjack/tools/check_yaml.py +110 -0
  392. crackerjack/tools/codespell_wrapper.py +72 -0
  393. crackerjack/tools/end_of_file_fixer.py +202 -0
  394. crackerjack/tools/format_json.py +128 -0
  395. crackerjack/tools/mdformat_wrapper.py +114 -0
  396. crackerjack/tools/trailing_whitespace.py +198 -0
  397. crackerjack/tools/validate_regex_patterns.py +7 -3
  398. crackerjack/ui/README.md +11 -0
  399. crackerjack/ui/dashboard_renderer.py +28 -0
  400. crackerjack/ui/templates/README.md +11 -0
  401. crackerjack/utils/console_utils.py +13 -0
  402. crackerjack/utils/dependency_guard.py +230 -0
  403. crackerjack/utils/retry_utils.py +275 -0
  404. crackerjack/workflows/README.md +590 -0
  405. crackerjack/workflows/__init__.py +46 -0
  406. crackerjack/workflows/actions.py +811 -0
  407. crackerjack/workflows/auto_fix.py +444 -0
  408. crackerjack/workflows/container_builder.py +499 -0
  409. crackerjack/workflows/definitions.py +443 -0
  410. crackerjack/workflows/engine.py +177 -0
  411. crackerjack/workflows/event_bridge.py +242 -0
  412. {crackerjack-0.37.9.dist-info → crackerjack-0.45.2.dist-info}/METADATA +678 -98
  413. crackerjack-0.45.2.dist-info/RECORD +478 -0
  414. {crackerjack-0.37.9.dist-info → crackerjack-0.45.2.dist-info}/WHEEL +1 -1
  415. crackerjack/managers/test_manager_backup.py +0 -1075
  416. crackerjack/mcp/tools/execution_tools_backup.py +0 -1011
  417. crackerjack/mixins/__init__.py +0 -3
  418. crackerjack/mixins/error_handling.py +0 -145
  419. crackerjack/services/config.py +0 -358
  420. crackerjack/ui/server_panels.py +0 -125
  421. crackerjack-0.37.9.dist-info/RECORD +0 -231
  422. /crackerjack/adapters/{rust_tool_adapter.py → lsp/_base.py} +0 -0
  423. /crackerjack/adapters/{lsp_client.py → lsp/_client.py} +0 -0
  424. {crackerjack-0.37.9.dist-info → crackerjack-0.45.2.dist-info}/entry_points.txt +0 -0
  425. {crackerjack-0.37.9.dist-info → crackerjack-0.45.2.dist-info}/licenses/LICENSE +0 -0
@@ -1,1011 +0,0 @@
1
- import asyncio
2
- import json
3
- import time
4
- import typing as t
5
- import uuid
6
- from contextlib import suppress
7
-
8
- from crackerjack.mcp.context import get_context
9
-
10
- from .progress_tools import _update_progress
11
-
12
-
13
- def register_execution_tools(mcp_app: t.Any) -> None:
14
- _register_execute_crackerjack_tool(mcp_app)
15
- _register_smart_error_analysis_tool(mcp_app)
16
- _register_init_crackerjack_tool(mcp_app)
17
- _register_agent_suggestions_tool(mcp_app)
18
-
19
-
20
- def _register_execute_crackerjack_tool(mcp_app: t.Any) -> None:
21
- @mcp_app.tool()
22
- async def execute_crackerjack(args: str, kwargs: str) -> str:
23
- context = get_context()
24
- validation_error = await _validate_context_and_rate_limit(context)
25
- if validation_error:
26
- return validation_error
27
-
28
- job_id = str(uuid.uuid4())[:8]
29
-
30
- kwargs_result = _parse_kwargs(kwargs)
31
- if "error" in kwargs_result:
32
- return json.dumps(kwargs_result)
33
-
34
- extra_kwargs = kwargs_result["kwargs"]
35
-
36
- try:
37
- result = await _execute_crackerjack_sync(
38
- job_id,
39
- args,
40
- extra_kwargs,
41
- context,
42
- )
43
- return json.dumps(result, indent=2)
44
- except Exception as e:
45
- return json.dumps(
46
- {
47
- "job_id": job_id,
48
- "status": "failed",
49
- "error": f"Execution failed: {e}",
50
- },
51
- indent=2,
52
- )
53
-
54
-
55
- def _register_smart_error_analysis_tool(mcp_app: t.Any) -> None:
56
- @mcp_app.tool()
57
- async def smart_error_analysis(use_cache: bool = True) -> str:
58
- context = get_context()
59
- if not context:
60
- return '{"error": "Server context not available"}'
61
-
62
- try:
63
- from crackerjack.services.debug import get_ai_agent_debugger
64
-
65
- get_ai_agent_debugger()
66
-
67
- cached_patterns = _get_cached_patterns(context, use_cache)
68
- analysis = _build_error_analysis(use_cache, cached_patterns)
69
-
70
- return json.dumps(analysis, indent=2)
71
-
72
- except Exception as e:
73
- return f'{{"error": "Smart error analysis failed: {e}"}}'
74
-
75
-
76
- async def _validate_context_and_rate_limit(context: t.Any) -> str | None:
77
- if not context:
78
- return '{"error": "Server context not available"}'
79
-
80
- if context.rate_limiter:
81
- allowed, details = await context.rate_limiter.check_request_allowed("default")
82
- if not allowed:
83
- return f'{{"error": "Rate limit exceeded: {details.get("reason", "unknown")}", "success": false}}'
84
-
85
- return None
86
-
87
-
88
- def _handle_task_exception(job_id: str, task: asyncio.Task[t.Any]) -> None:
89
- import tempfile
90
- from pathlib import Path
91
-
92
- try:
93
- exception = task.exception()
94
- if exception:
95
- debug_file = (
96
- Path(tempfile.gettempdir()) / f"crackerjack - task-error -{job_id}.log"
97
- )
98
- with debug_file.open("w") as f:
99
- f.write(
100
- f"Background task {job_id} failed with exception: {exception}\n",
101
- )
102
- f.write(f"Exception type: {type(exception)}\n")
103
- import traceback
104
-
105
- f.write(
106
- f"Traceback: \n{traceback.format_exception(type(exception), exception, exception.__traceback__)}\n",
107
- )
108
- except Exception as e:
109
- with suppress(Exception):
110
- debug_file = (
111
- Path(tempfile.gettempdir())
112
- / f"crackerjack - logging-error -{job_id}.log"
113
- )
114
- with debug_file.open("w") as f:
115
- f.write(f"Failed to log task exception: {e}\n")
116
-
117
-
118
- def _parse_kwargs(kwargs: str) -> dict[str, t.Any]:
119
- try:
120
- return {"kwargs": json.loads(kwargs) if kwargs.strip() else {}}
121
- except json.JSONDecodeError as e:
122
- return {"error": f"Invalid JSON in kwargs: {e}"}
123
-
124
-
125
- def _get_cached_patterns(context: t.Any, use_cache: bool) -> list[t.Any]:
126
- if use_cache and hasattr(context, "error_cache"):
127
- return getattr(context.error_cache, "patterns", [])
128
- return []
129
-
130
-
131
- def _build_error_analysis(
132
- use_cache: bool,
133
- cached_patterns: list[t.Any],
134
- ) -> dict[str, t.Any]:
135
- analysis = {
136
- "analysis_type": "smart_error_analysis",
137
- "use_cache": use_cache,
138
- "cached_patterns_count": len(cached_patterns),
139
- "common_patterns": [
140
- {
141
- "type": "import_error",
142
- "frequency": "high",
143
- "typical_fix": "Check import paths and dependencies",
144
- },
145
- {
146
- "type": "type_annotation_missing",
147
- "frequency": "medium",
148
- "typical_fix": "Add proper type hints to functions and methods",
149
- },
150
- {
151
- "type": "test_failure",
152
- "frequency": "medium",
153
- "typical_fix": "Review test expectations and implementation",
154
- },
155
- ],
156
- "recommendations": [
157
- "Run fast hooks first to fix formatting issues",
158
- "Execute tests to identify functional problems",
159
- "Run comprehensive hooks for quality analysis",
160
- ],
161
- }
162
-
163
- if cached_patterns:
164
- analysis["cached_patterns"] = cached_patterns[:5]
165
-
166
- return analysis
167
-
168
-
169
- async def _execute_crackerjack_sync(
170
- job_id: str,
171
- args: str,
172
- kwargs: dict[str, t.Any],
173
- context: t.Any,
174
- ) -> dict[str, t.Any]:
175
- if not context:
176
- return {"job_id": job_id, "status": "failed", "error": "No context available"}
177
-
178
- max_iterations = kwargs.get("max_iterations", 10)
179
- current_iteration = 1
180
-
181
- try:
182
- await _initialize_execution(job_id, max_iterations, current_iteration, context)
183
-
184
- orchestrator, use_advanced_orchestrator = await _setup_orchestrator(
185
- job_id,
186
- max_iterations,
187
- current_iteration,
188
- kwargs,
189
- context,
190
- )
191
-
192
- return await _run_workflow_iterations(
193
- job_id,
194
- max_iterations,
195
- orchestrator,
196
- use_advanced_orchestrator,
197
- kwargs,
198
- )
199
-
200
- except Exception as e:
201
- _update_progress(
202
- job_id=job_id,
203
- status="failed",
204
- iteration=current_iteration,
205
- max_iterations=max_iterations,
206
- current_stage="error",
207
- message=f"Execution failed: {e}",
208
- )
209
- context.safe_print(f"Execution failed: {e}")
210
- return {"job_id": job_id, "status": "failed", "error": str(e)}
211
-
212
-
213
- async def _initialize_execution(
214
- job_id: str,
215
- max_iterations: int,
216
- current_iteration: int,
217
- context: t.Any,
218
- ) -> None:
219
- _update_progress(
220
- job_id=job_id,
221
- iteration=current_iteration,
222
- max_iterations=max_iterations,
223
- overall_progress=2,
224
- message="Initializing crackerjack execution",
225
- )
226
-
227
- status_result = await _check_status_and_prepare(job_id, context)
228
- if status_result.get("should_abort", False):
229
- msg = f"Execution aborted: {status_result['reason']}"
230
- raise RuntimeError(msg)
231
-
232
- _update_progress(
233
- job_id=job_id,
234
- iteration=current_iteration,
235
- max_iterations=max_iterations,
236
- overall_progress=5,
237
- current_stage="status_verified",
238
- message="Status check complete-no conflicts detected",
239
- )
240
-
241
- await _cleanup_stale_jobs(context)
242
-
243
- await _ensure_services_running(job_id, context)
244
-
245
- _update_progress(
246
- job_id=job_id,
247
- iteration=current_iteration,
248
- max_iterations=max_iterations,
249
- overall_progress=10,
250
- current_stage="services_ready",
251
- message="Services initialized successfully",
252
- )
253
-
254
-
255
- async def _setup_orchestrator(
256
- job_id: str,
257
- max_iterations: int,
258
- current_iteration: int,
259
- kwargs: dict[str, t.Any],
260
- context: t.Any,
261
- ) -> tuple[t.Any, bool]:
262
- context.safe_print("Using Standard WorkflowOrchestrator for MCP compatibility")
263
- orchestrator = _create_standard_orchestrator(job_id, kwargs, context)
264
- use_advanced_orchestrator = False
265
-
266
- orchestrator_type = "Standard Orchestrator (MCP Compatible)"
267
- _update_progress(
268
- job_id=job_id,
269
- iteration=current_iteration,
270
- max_iterations=max_iterations,
271
- overall_progress=15,
272
- current_stage="orchestrator_ready",
273
- message=f"Initialized {orchestrator_type}",
274
- )
275
-
276
- return orchestrator, use_advanced_orchestrator
277
-
278
-
279
- async def _create_advanced_orchestrator(
280
- job_id: str,
281
- kwargs: dict[str, t.Any],
282
- context: t.Any,
283
- ) -> t.Any:
284
- from crackerjack.core.session_coordinator import SessionCoordinator
285
- from crackerjack.orchestration.advanced_orchestrator import (
286
- AdvancedWorkflowOrchestrator,
287
- )
288
- from crackerjack.orchestration.execution_strategies import (
289
- AICoordinationMode,
290
- AIIntelligence,
291
- ExecutionStrategy,
292
- OrchestrationConfig,
293
- ProgressLevel,
294
- StreamingMode,
295
- )
296
-
297
- optimal_config = OrchestrationConfig(
298
- execution_strategy=ExecutionStrategy.ADAPTIVE,
299
- progress_level=ProgressLevel.DETAILED,
300
- streaming_mode=StreamingMode.WEBSOCKET,
301
- ai_coordination_mode=AICoordinationMode.COORDINATOR,
302
- ai_intelligence=AIIntelligence.ADAPTIVE,
303
- correlation_tracking=True,
304
- failure_analysis=True,
305
- intelligent_retry=True,
306
- max_parallel_hooks=3,
307
- max_parallel_tests=4,
308
- timeout_multiplier=1.0,
309
- debug_level="standard",
310
- log_individual_outputs=False,
311
- preserve_temp_files=False,
312
- )
313
-
314
- session = SessionCoordinator(
315
- context.console,
316
- context.config.project_path,
317
- web_job_id=job_id,
318
- )
319
- orchestrator = AdvancedWorkflowOrchestrator(
320
- console=context.console,
321
- pkg_path=context.config.project_path,
322
- session=session,
323
- config=optimal_config,
324
- )
325
-
326
- if kwargs.get("debug", False):
327
- orchestrator.individual_executor.set_mcp_mode(False)
328
- context.safe_print("🐛 Debug mode enabled-full output mode")
329
-
330
- return orchestrator
331
-
332
-
333
- def _create_standard_orchestrator(
334
- job_id: str,
335
- kwargs: dict[str, t.Any],
336
- context: t.Any,
337
- ) -> t.Any:
338
- from crackerjack.core.workflow_orchestrator import WorkflowOrchestrator
339
-
340
- return WorkflowOrchestrator(
341
- console=context.console,
342
- pkg_path=context.config.project_path,
343
- dry_run=kwargs.get("dry_run", False),
344
- web_job_id=job_id,
345
- )
346
-
347
-
348
- async def _run_workflow_iterations(
349
- job_id: str,
350
- max_iterations: int,
351
- orchestrator: t.Any,
352
- use_advanced_orchestrator: bool,
353
- kwargs: dict[str, t.Any],
354
- ) -> dict[str, t.Any]:
355
- success = False
356
- current_iteration = 1
357
-
358
- for iteration in range(1, max_iterations + 1):
359
- current_iteration = iteration
360
-
361
- _update_progress(
362
- job_id=job_id,
363
- iteration=current_iteration,
364
- max_iterations=max_iterations,
365
- overall_progress=int((iteration / max_iterations) * 80),
366
- current_stage=f"iteration_{iteration}",
367
- message=f"Running iteration {iteration} / {max_iterations}",
368
- )
369
-
370
- options = _create_workflow_options(kwargs)
371
-
372
- try:
373
- success = await _execute_single_iteration(
374
- orchestrator,
375
- use_advanced_orchestrator,
376
- options,
377
- )
378
-
379
- if success:
380
- return _create_success_result(
381
- job_id,
382
- current_iteration,
383
- max_iterations,
384
- iteration,
385
- )
386
-
387
- if iteration < max_iterations:
388
- await _handle_iteration_retry(
389
- job_id,
390
- current_iteration,
391
- max_iterations,
392
- iteration,
393
- )
394
- continue
395
-
396
- except Exception as e:
397
- if not await _handle_iteration_error(iteration, max_iterations, e):
398
- break
399
-
400
- return _create_failure_result(job_id, current_iteration, max_iterations)
401
-
402
-
403
- def _create_workflow_options(kwargs: dict[str, t.Any]) -> t.Any:
404
- from crackerjack.models.config import WorkflowOptions
405
-
406
- options = WorkflowOptions()
407
- options.testing.test = kwargs.get("test", True)
408
- options.ai.ai_agent = kwargs.get("ai_agent", True)
409
- options.hooks.skip_hooks = kwargs.get("skip_hooks", False)
410
-
411
- return options
412
-
413
-
414
- async def _execute_single_iteration(
415
- orchestrator: t.Any,
416
- use_advanced_orchestrator: bool,
417
- options: t.Any,
418
- ) -> bool:
419
- if use_advanced_orchestrator:
420
- result = await orchestrator.execute_orchestrated_workflow(options)
421
- return bool(result)
422
- result = await orchestrator.run_complete_workflow(options)
423
- return bool(result)
424
-
425
-
426
- def _create_success_result(
427
- job_id: str,
428
- current_iteration: int,
429
- max_iterations: int,
430
- iteration: int,
431
- ) -> dict[str, t.Any]:
432
- _update_progress(
433
- job_id=job_id,
434
- status="completed",
435
- iteration=current_iteration,
436
- max_iterations=max_iterations,
437
- overall_progress=100,
438
- current_stage="completed",
439
- message=f"Successfully completed after {iteration} iterations",
440
- )
441
- return {
442
- "job_id": job_id,
443
- "status": "completed",
444
- "iteration": current_iteration,
445
- "message": f"Successfully completed after {iteration} iterations",
446
- }
447
-
448
-
449
- async def _handle_iteration_retry(
450
- job_id: str,
451
- current_iteration: int,
452
- max_iterations: int,
453
- iteration: int,
454
- ) -> None:
455
- _update_progress(
456
- job_id=job_id,
457
- iteration=current_iteration,
458
- max_iterations=max_iterations,
459
- overall_progress=int((iteration / max_iterations) * 80),
460
- current_stage="retrying",
461
- message=f"Iteration {iteration} failed, retrying...",
462
- )
463
- await asyncio.sleep(1)
464
-
465
-
466
- async def _handle_iteration_error(
467
- iteration: int,
468
- max_iterations: int,
469
- error: Exception,
470
- ) -> bool:
471
- if iteration >= max_iterations:
472
- return False
473
- await asyncio.sleep(1)
474
- return True
475
-
476
-
477
- def _create_failure_result(
478
- job_id: str,
479
- current_iteration: int,
480
- max_iterations: int,
481
- ) -> dict[str, t.Any]:
482
- _update_progress(
483
- job_id=job_id,
484
- status="failed",
485
- iteration=current_iteration,
486
- max_iterations=max_iterations,
487
- overall_progress=80,
488
- current_stage="failed",
489
- message=f"Failed after {max_iterations} iterations",
490
- )
491
- return {
492
- "job_id": job_id,
493
- "status": "failed",
494
- "iteration": current_iteration,
495
- "message": f"Failed after {max_iterations} iterations",
496
- }
497
-
498
-
499
- async def _ensure_services_running(job_id: str, context: t.Any) -> None:
500
- import subprocess
501
-
502
- _update_progress(
503
- job_id=job_id,
504
- current_stage="service_startup",
505
- message="Checking required services...",
506
- )
507
-
508
- websocket_running = False
509
- with suppress(Exception):
510
- from crackerjack.services.server_manager import find_websocket_server_processes
511
-
512
- websocket_processes = find_websocket_server_processes()
513
- websocket_running = len(websocket_processes) > 0
514
-
515
- if not websocket_running:
516
- _update_progress(
517
- job_id=job_id,
518
- current_stage="service_startup",
519
- message="Starting WebSocket server...",
520
- )
521
-
522
- try:
523
- subprocess.Popen(
524
- ["python", "- m", "crackerjack", "- - start - websocket-server"],
525
- cwd=context.config.project_path,
526
- stdout=subprocess.DEVNULL,
527
- stderr=subprocess.DEVNULL,
528
- start_new_session=True,
529
- )
530
-
531
- for _i in range(10):
532
- with suppress(Exception):
533
- websocket_processes = find_websocket_server_processes()
534
- if websocket_processes:
535
- context.safe_print("✅ WebSocket server started successfully")
536
- break
537
- await asyncio.sleep(0.5)
538
- else:
539
- context.safe_print("⚠️ WebSocket server may not have started properly")
540
-
541
- except Exception as e:
542
- context.safe_print(f"⚠️ Failed to start WebSocket server: {e}")
543
- else:
544
- context.safe_print("✅ WebSocket server already running")
545
-
546
-
547
- async def _check_status_and_prepare(job_id: str, context: t.Any) -> dict[str, t.Any]:
548
- _update_progress(
549
- job_id=job_id,
550
- current_stage="status_check",
551
- message="🔍 Checking system status to prevent conflicts...",
552
- )
553
-
554
- try:
555
- status_info = await _get_status_info()
556
- if "error" in status_info:
557
- return _handle_status_error(status_info, context)
558
-
559
- cleanup_performed = []
560
-
561
- _check_active_jobs(status_info, context)
562
-
563
- cleanup_performed.extend(_check_resource_cleanup(status_info, context))
564
-
565
- _check_service_health(status_info, context)
566
-
567
- context.safe_print("✅ Status check complete-ready to proceed")
568
-
569
- return {
570
- "should_abort": False,
571
- "reason": "",
572
- "status_info": status_info,
573
- "cleanup_performed": cleanup_performed,
574
- }
575
-
576
- except Exception as e:
577
- return _handle_status_exception(e, context)
578
-
579
-
580
- async def _get_status_info() -> dict[str, t.Any]:
581
- from .monitoring_tools import _get_comprehensive_status
582
-
583
- return await _get_comprehensive_status()
584
-
585
-
586
- def _handle_status_error(
587
- status_info: dict[str, t.Any],
588
- context: t.Any,
589
- ) -> dict[str, t.Any]:
590
- context.safe_print(f"⚠️ Status check failed: {status_info['error']}")
591
- return {
592
- "should_abort": False,
593
- "reason": "",
594
- "status_info": status_info,
595
- "cleanup_performed": [],
596
- }
597
-
598
-
599
- def _check_active_jobs(status_info: dict[str, t.Any], context: t.Any) -> None:
600
- active_jobs = [
601
- j
602
- for j in status_info.get("jobs", {}).get("details", [])
603
- if j.get("status") == "running"
604
- ]
605
-
606
- if active_jobs:
607
- _handle_conflicting_jobs(active_jobs, context)
608
- else:
609
- context.safe_print("✅ No active jobs detected-safe to proceed")
610
-
611
-
612
- def _handle_conflicting_jobs(
613
- active_jobs: list[dict[str, t.Any]],
614
- context: t.Any,
615
- ) -> None:
616
- conflicting_jobs = active_jobs
617
-
618
- if conflicting_jobs:
619
- job_ids = [j.get("job_id", "unknown") for j in conflicting_jobs]
620
- context.safe_print(
621
- f"⚠️ Found {len(conflicting_jobs)} active job(s): {', '.join(job_ids[:3])}",
622
- )
623
- context.safe_print(
624
- " Running concurrent crackerjack instances may cause file conflicts",
625
- )
626
- context.safe_print(" Proceeding with caution...")
627
-
628
-
629
- def _check_resource_cleanup(status_info: dict[str, t.Any], context: t.Any) -> list[str]:
630
- cleanup_performed = []
631
-
632
- temp_files_count = (
633
- status_info.get("server_stats", {})
634
- .get("resource_usage", {})
635
- .get("temp_files_count", 0)
636
- )
637
-
638
- if temp_files_count > 50:
639
- context.safe_print(
640
- f"🗑️ Found {temp_files_count} temporary files-cleanup recommended",
641
- )
642
- cleanup_performed.append("temp_files_flagged")
643
-
644
- return cleanup_performed
645
-
646
-
647
- def _check_service_health(status_info: dict[str, t.Any], context: t.Any) -> None:
648
- services = status_info.get("services", {})
649
- mcp_running = services.get("mcp_server", {}).get("running", False)
650
- websocket_running = services.get("websocket_server", {}).get("running", False)
651
-
652
- if not mcp_running:
653
- context.safe_print("⚠️ MCP server not running - will auto-start if needed")
654
-
655
- if not websocket_running:
656
- context.safe_print("📡 WebSocket server not running - will auto-start")
657
-
658
-
659
- def _handle_status_exception(error: Exception, context: t.Any) -> dict[str, t.Any]:
660
- context.safe_print(f"⚠️ Status check encountered error: {error}")
661
- return {
662
- "should_abort": False,
663
- "reason": "",
664
- "status_info": {"error": str(error)},
665
- "cleanup_performed": [],
666
- }
667
-
668
-
669
- async def _cleanup_stale_jobs(context: t.Any) -> None:
670
- if not context.progress_dir.exists():
671
- return
672
-
673
- current_time = time.time()
674
- cleaned_count = 0
675
-
676
- with suppress(Exception):
677
- for progress_file in context.progress_dir.glob("job-*.json"):
678
- try:
679
- import json
680
-
681
- progress_data = json.loads(progress_file.read_text())
682
-
683
- last_update = progress_data.get("updated_at", 0)
684
- age_minutes = (current_time - last_update) / 60
685
-
686
- is_stale = (
687
- age_minutes > 30
688
- or progress_data.get("job_id") == "unknown"
689
- or "analyzing_failures: processing"
690
- in progress_data.get("status", "")
691
- )
692
-
693
- if is_stale:
694
- progress_file.unlink()
695
- cleaned_count += 1
696
-
697
- except (json.JSONDecodeError, OSError):
698
- with suppress(OSError):
699
- progress_file.unlink()
700
- cleaned_count += 1
701
-
702
- if cleaned_count > 0:
703
- context.safe_print(f"🗑️ Cleaned up {cleaned_count} stale job files")
704
-
705
-
706
- def _register_init_crackerjack_tool(mcp_app: t.Any) -> None:
707
- @mcp_app.tool()
708
- async def init_crackerjack(args: str = "", kwargs: str = "{}") -> str:
709
- context = get_context()
710
- if not context:
711
- return _create_init_error_response("Server context not available")
712
-
713
- target_path, force, parse_error = _parse_init_arguments(args, kwargs)
714
- if parse_error:
715
- return parse_error
716
-
717
- try:
718
- results = _execute_initialization(context, target_path, force)
719
- if isinstance(results, bool):
720
- return json.dumps({"success": results})
721
- return _create_init_success_response(results, target_path, force)
722
- except Exception as e:
723
- return _create_init_exception_response(e, target_path)
724
-
725
-
726
- def _create_init_error_response(message: str) -> str:
727
- return json.dumps({"error": message, "success": False}, indent=2)
728
-
729
-
730
- def _parse_init_arguments(args: str, kwargs: str) -> tuple[t.Any, bool, str | None]:
731
- from pathlib import Path
732
-
733
- target_path = args.strip() or None
734
-
735
- try:
736
- extra_kwargs: dict[str, t.Any] = json.loads(kwargs) if kwargs.strip() else {}
737
- except json.JSONDecodeError as e:
738
- return None, False, _create_init_error_response(f"Invalid JSON in kwargs: {e}")
739
-
740
- force = extra_kwargs.get("force", False)
741
-
742
- if target_path:
743
- target_path_obj = Path(target_path).resolve()
744
- target_path = str(target_path_obj)
745
- else:
746
- target_path_obj = Path.cwd()
747
- target_path = str(target_path_obj)
748
-
749
- if not Path(target_path).exists():
750
- return (
751
- None,
752
- False,
753
- _create_init_error_response(f"Target path does not exist: {target_path}"),
754
- )
755
-
756
- return target_path, force, None
757
-
758
-
759
- def _execute_initialization(context: t.Any, target_path: t.Any, force: bool) -> bool:
760
- from crackerjack.services.filesystem import FileSystemService
761
- from crackerjack.services.git import GitService
762
- from crackerjack.services.initialization import InitializationService
763
-
764
- filesystem = FileSystemService()
765
- git_service = GitService(context.console, context.config.project_path)
766
-
767
- return InitializationService(
768
- context.console, filesystem, git_service, context.config.project_path
769
- ).initialize_project(target_path=target_path, force=force)
770
-
771
-
772
- def _create_init_success_response(
773
- results: dict[str, t.Any], target_path: t.Any, force: bool
774
- ) -> str:
775
- results["command"] = "init_crackerjack"
776
- results["target_path"] = str(target_path)
777
- results["force"] = force
778
- return json.dumps(results, indent=2)
779
-
780
-
781
- def _create_init_exception_response(error: Exception, target_path: t.Any) -> str:
782
- error_result = {
783
- "error": f"Initialization failed: {error}",
784
- "success": False,
785
- "command": "init_crackerjack",
786
- "target_path": str(target_path) if target_path else "current_directory",
787
- }
788
- return json.dumps(error_result, indent=2)
789
-
790
-
791
- def _register_agent_suggestions_tool(mcp_app: t.Any) -> None:
792
- @mcp_app.tool()
793
- async def suggest_agents(
794
- task_description: str = "",
795
- project_type: str = "python",
796
- current_context: str = "",
797
- ) -> str:
798
- suggestions: dict[str, list[dict[str, str]] | list[str] | str] = {
799
- "primary_agents": t.cast(list[dict[str, str]], []),
800
- "task_specific_agents": t.cast(list[dict[str, str]], []),
801
- "usage_patterns": t.cast(list[str], []),
802
- "rationale": "",
803
- }
804
-
805
- # Type cast the lists to ensure proper typing
806
- primary_agents: list[dict[str, str]] = t.cast(
807
- list[dict[str, str]], suggestions["primary_agents"]
808
- )
809
- task_specific_agents: list[dict[str, str]] = t.cast(
810
- list[dict[str, str]], suggestions["task_specific_agents"]
811
- )
812
- t.cast(list[str], suggestions["usage_patterns"])
813
-
814
- if project_type.lower() == "python" or "python" in task_description.lower():
815
- primary_agents.extend(
816
- (
817
- {
818
- "name": "crackerjack-architect",
819
- "emoji": "🏗️",
820
- "description": "Expert in crackerjack's modular architecture and Python project management patterns",
821
- "usage": "Use PROACTIVELY for all feature development, architectural decisions, and ensuring code follows crackerjack standards",
822
- "priority": "HIGH",
823
- },
824
- {
825
- "name": "python-pro",
826
- "emoji": "🐍",
827
- "description": "Modern Python development with type hints, async/await patterns, and clean architecture",
828
- "usage": "Use for implementing Python code with best practices",
829
- "priority": "HIGH",
830
- },
831
- )
832
- )
833
-
834
- task_lower = task_description.lower()
835
- context_lower = current_context.lower()
836
-
837
- if any(
838
- word in task_lower + context_lower
839
- for word in ("test", "testing", "coverage", "pytest")
840
- ):
841
- task_specific_agents.extend(
842
- (
843
- {
844
- "name": "crackerjack-test-specialist",
845
- "emoji": "🧪",
846
- "description": "Advanced testing specialist for complex scenarios and coverage optimization",
847
- "usage": "Use for test creation, debugging test failures, and coverage improvements",
848
- "priority": "HIGH",
849
- },
850
- {
851
- "name": "pytest-hypothesis-specialist",
852
- "emoji": "🧪",
853
- "description": "Advanced testing patterns and property-based testing",
854
- "usage": "Use for comprehensive test development and optimization",
855
- "priority": "MEDIUM",
856
- },
857
- )
858
- )
859
-
860
- if any(
861
- word in task_lower + context_lower
862
- for word in ("security", "vulnerability", "auth", "permission")
863
- ):
864
- task_specific_agents.append(
865
- {
866
- "name": "security-auditor",
867
- "emoji": "🔒",
868
- "description": "Security auditing and vulnerability detection specialist",
869
- "usage": "Use for identifying and mitigating security vulnerabilities",
870
- "priority": "HIGH",
871
- }
872
- )
873
-
874
- if any(
875
- word in task_lower + context_lower
876
- for word in ("architecture", "design", "api", "backend")
877
- ):
878
- task_specific_agents.append(
879
- {
880
- "name": "backend-architect",
881
- "emoji": "🏗️",
882
- "description": "Backend architecture and system design specialist",
883
- "usage": "Use for complex backend design decisions and system architecture",
884
- "priority": "MEDIUM",
885
- }
886
- )
887
-
888
- suggestions["usage_patterns"] = [
889
- 'Task tool with subagent_type ="crackerjack-architect" for feature planning and architecture',
890
- 'Task tool with subagent_type ="python-pro" for implementation with best practices',
891
- 'Task tool with subagent_type ="crackerjack - test-specialist" for comprehensive testing',
892
- 'Task tool with subagent_type ="security-auditor" for security validation',
893
- ]
894
-
895
- if "crackerjack-architect" in [
896
- agent["name"] for agent in suggestions["primary_agents"]
897
- ]:
898
- suggestions["rationale"] = (
899
- "The crackerjack-architect agent is essential for this Python project as it ensures "
900
- "code follows crackerjack patterns from the start, eliminating retrofitting needs. "
901
- "Combined with python - pro for implementation and task-specific agents for specialized "
902
- "work, this provides comprehensive development support with built-in quality assurance."
903
- )
904
-
905
- return json.dumps(suggestions, indent=2)
906
-
907
- @mcp_app.tool()
908
- async def detect_agent_needs(
909
- error_context: str = "",
910
- file_patterns: str = "",
911
- recent_changes: str = "",
912
- ) -> str:
913
- recommendations = {
914
- "urgent_agents": [],
915
- "suggested_agents": [],
916
- "workflow_recommendations": [],
917
- "detection_reasoning": "",
918
- }
919
-
920
- _add_urgent_agents_for_errors(recommendations, error_context)
921
-
922
- _add_python_project_suggestions(recommendations, file_patterns)
923
-
924
- _set_workflow_recommendations(recommendations)
925
-
926
- _generate_detection_reasoning(recommendations)
927
-
928
- return json.dumps(recommendations, indent=2)
929
-
930
-
931
- def _add_urgent_agents_for_errors(
932
- recommendations: dict[str, t.Any], error_context: str
933
- ) -> None:
934
- if any(
935
- word in error_context.lower()
936
- for word in ("test fail", "coverage", "pytest", "assertion")
937
- ):
938
- recommendations["urgent_agents"].append(
939
- {
940
- "agent": "crackerjack - test-specialist",
941
- "reason": "Test failures detected-specialist needed for debugging and fixes",
942
- "action": 'Task tool with subagent_type ="crackerjack - test-specialist" to analyze and fix test issues',
943
- }
944
- )
945
-
946
- if any(
947
- word in error_context.lower()
948
- for word in ("security", "vulnerability", "bandit", "unsafe")
949
- ):
950
- recommendations["urgent_agents"].append(
951
- {
952
- "agent": "security-auditor",
953
- "reason": "Security issues detected-immediate audit required",
954
- "action": 'Task tool with subagent_type ="security-auditor" to review and fix security vulnerabilities',
955
- }
956
- )
957
-
958
- if any(
959
- word in error_context.lower()
960
- for word in ("complexity", "refactor", "too complex")
961
- ):
962
- recommendations["urgent_agents"].append(
963
- {
964
- "agent": "crackerjack-architect",
965
- "reason": "Complexity issues detected-architectural review needed",
966
- "action": 'Task tool with subagent_type ="crackerjack-architect" to simplify and restructure code',
967
- }
968
- )
969
-
970
-
971
- def _add_python_project_suggestions(
972
- recommendations: dict[str, t.Any], file_patterns: str
973
- ) -> None:
974
- if "python" in file_patterns.lower() or ".py" in file_patterns:
975
- recommendations["suggested_agents"].extend(
976
- [
977
- {
978
- "agent": "crackerjack-architect",
979
- "reason": "Python project detected-ensure crackerjack compliance",
980
- "priority": "HIGH",
981
- },
982
- {
983
- "agent": "python-pro",
984
- "reason": "Python development best practices",
985
- "priority": "HIGH",
986
- },
987
- ]
988
- )
989
-
990
-
991
- def _set_workflow_recommendations(recommendations: dict[str, t.Any]) -> None:
992
- if recommendations["urgent_agents"]:
993
- recommendations["workflow_recommendations"] = [
994
- "Address urgent issues first with specialized agents",
995
- "Run crackerjack quality checks after fixes: python - m crackerjack-t",
996
- "Use crackerjack-architect for ongoing compliance",
997
- ]
998
- else:
999
- recommendations["workflow_recommendations"] = [
1000
- "Start with crackerjack-architect for proper planning",
1001
- "Use python-pro for implementation",
1002
- "Run continuous quality checks: python-m crackerjack",
1003
- ]
1004
-
1005
-
1006
- def _generate_detection_reasoning(recommendations: dict[str, t.Any]) -> None:
1007
- recommendations["detection_reasoning"] = (
1008
- f"Analysis of context revealed {len(recommendations['urgent_agents'])} urgent issues "
1009
- f"and {len(recommendations['suggested_agents'])} general recommendations. "
1010
- "Prioritize urgent agents first, then follow standard workflow patterns."
1011
- )