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
crackerjack/errors.py CHANGED
@@ -3,7 +3,7 @@ import typing as t
3
3
  from enum import Enum
4
4
  from pathlib import Path
5
5
 
6
- from rich.console import Console
6
+ from acb.console import Console
7
7
  from rich.panel import Panel
8
8
 
9
9
 
@@ -0,0 +1,11 @@
1
+ > Crackerjack Docs: [Main](<../../README.md>) | [Crackerjack Package](<../README.md>) | [Events](<./README.md>)
2
+
3
+ # Events
4
+
5
+ Event types, signals, and dispatch-related helpers.
6
+
7
+ ## Related
8
+
9
+ - [Crackerjack Package](<../README.md>) - Parent package
10
+ - [Monitoring](<../monitoring/README.md>) - Observability and metrics
11
+ - [Coordinators](../coordinators/README.md) - Event coordination and orchestration
@@ -0,0 +1,16 @@
1
+ """Event bus utilities for Crackerjack."""
2
+
3
+ from .telemetry import WorkflowEventTelemetry, register_default_subscribers
4
+ from .workflow_bus import (
5
+ WorkflowEvent,
6
+ WorkflowEventBus,
7
+ WorkflowEventDispatchResult,
8
+ )
9
+
10
+ __all__ = [
11
+ "WorkflowEvent",
12
+ "WorkflowEventBus",
13
+ "WorkflowEventDispatchResult",
14
+ "WorkflowEventTelemetry",
15
+ "register_default_subscribers",
16
+ ]
@@ -0,0 +1,175 @@
1
+ """Telemetry collection for workflow events."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ import json
7
+ import typing as t
8
+ from collections import Counter, deque
9
+ from contextlib import suppress
10
+ from dataclasses import dataclass, field
11
+ from datetime import datetime
12
+ from pathlib import Path
13
+ from typing import TYPE_CHECKING
14
+
15
+ from acb.events import Event, EventHandlerResult
16
+
17
+ from .workflow_bus import WorkflowEvent
18
+
19
+ if TYPE_CHECKING: # pragma: no cover - typing helper
20
+ from .workflow_bus import WorkflowEventBus
21
+
22
+ HistoryEntry = dict[str, t.Any]
23
+
24
+
25
+ @dataclass
26
+ class WorkflowEventTelemetry:
27
+ """Collects lightweight metrics about workflow events."""
28
+
29
+ max_history: int = 100
30
+ state_file: Path | None = None
31
+ rollup_interval_seconds: float = 3600.0
32
+ rollup_file: Path | None = None
33
+ _lock: asyncio.Lock = field(default_factory=asyncio.Lock, init=False)
34
+ _counts: Counter[str] = field(default_factory=Counter, init=False)
35
+ _history: deque[HistoryEntry] = field(init=False)
36
+ _last_error: HistoryEntry | None = field(default=None, init=False)
37
+ _persist_task: asyncio.Task[None] | None = field(
38
+ default=None, init=False, repr=False
39
+ )
40
+ _rollup_task: asyncio.Task[None] | None = field(
41
+ default=None, init=False, repr=False
42
+ )
43
+
44
+ def __post_init__(self) -> None:
45
+ self._history = deque(maxlen=self.max_history)
46
+ if self.rollup_file is None and self.state_file is not None:
47
+ self.rollup_file = self.state_file.with_name(
48
+ f"{self.state_file.stem}_rollups.jsonl"
49
+ )
50
+
51
+ async def handle_event(self, event: Event) -> EventHandlerResult:
52
+ """Event bus subscriber that records event metadata."""
53
+ entry: HistoryEntry = {
54
+ "event_type": event.metadata.event_type,
55
+ "timestamp": event.metadata.timestamp.isoformat(),
56
+ "source": event.metadata.source,
57
+ "payload": event.payload,
58
+ }
59
+
60
+ async with self._lock:
61
+ self._counts[event.metadata.event_type] += 1
62
+ self._history.append(entry)
63
+ if event.metadata.event_type == WorkflowEvent.WORKFLOW_FAILED.value:
64
+ self._last_error = entry
65
+
66
+ if self.state_file is not None:
67
+ await self._schedule_persist()
68
+ await self._ensure_rollup_task()
69
+
70
+ return EventHandlerResult(success=True)
71
+
72
+ async def snapshot(self) -> dict[str, t.Any]:
73
+ """Return a snapshot of the telemetry counters and history."""
74
+ async with self._lock:
75
+ return {
76
+ "counts": dict(self._counts),
77
+ "recent_events": list(self._history),
78
+ "last_error": self._last_error,
79
+ }
80
+
81
+ async def reset(self) -> None:
82
+ """Reset telemetry counters."""
83
+ async with self._lock:
84
+ self._counts.clear()
85
+ self._history.clear()
86
+ self._last_error = None
87
+ if self.state_file and self.state_file.exists():
88
+ with suppress(Exception):
89
+ self.state_file.unlink()
90
+
91
+ async def shutdown(self) -> None:
92
+ """Shutdown background persistence tasks."""
93
+ if self._persist_task and not self._persist_task.done():
94
+ self._persist_task.cancel()
95
+ with suppress(asyncio.CancelledError):
96
+ await self._persist_task
97
+ if self._rollup_task and not self._rollup_task.done():
98
+ self._rollup_task.cancel()
99
+ with suppress(asyncio.CancelledError):
100
+ await self._rollup_task
101
+
102
+ async def _schedule_persist(self) -> None:
103
+ if self.state_file is None:
104
+ return
105
+
106
+ if self._persist_task and not self._persist_task.done():
107
+ return
108
+
109
+ async def _persist() -> None:
110
+ snapshot = await self.snapshot()
111
+ state_file = self.state_file
112
+ if state_file is None:
113
+ return
114
+ with suppress(Exception):
115
+ state_file.parent.mkdir(parents=True, exist_ok=True)
116
+ await asyncio.to_thread(
117
+ state_file.write_text,
118
+ json.dumps(snapshot, indent=2),
119
+ )
120
+
121
+ self._persist_task = asyncio.create_task(_persist())
122
+
123
+ async def _ensure_rollup_task(self) -> None:
124
+ if self.rollup_file is None or self.rollup_interval_seconds <= 0:
125
+ return
126
+ loop = asyncio.get_running_loop()
127
+ if self._rollup_task and not self._rollup_task.done():
128
+ return
129
+
130
+ async def _rollup_loop() -> None:
131
+ try:
132
+ while True:
133
+ await asyncio.sleep(self.rollup_interval_seconds)
134
+ await self._persist_rollup()
135
+ except asyncio.CancelledError: # pragma: no cover - loop cancellation
136
+ raise
137
+
138
+ self._rollup_task = loop.create_task(_rollup_loop())
139
+
140
+ async def _persist_rollup(self) -> None:
141
+ if self.rollup_file is None:
142
+ return
143
+ snapshot = await self.snapshot()
144
+ rollup_entry = {
145
+ "timestamp": datetime.now().isoformat(),
146
+ "counts": snapshot["counts"],
147
+ "total_events": sum(snapshot["counts"].values()),
148
+ "last_error": snapshot["last_error"],
149
+ }
150
+
151
+ rollup_file = self.rollup_file
152
+
153
+ def _write() -> None:
154
+ if rollup_file is None:
155
+ return
156
+ rollup_file.parent.mkdir(parents=True, exist_ok=True)
157
+ with rollup_file.open("a", encoding="utf-8") as fh:
158
+ fh.write(json.dumps(rollup_entry))
159
+ fh.write("\n")
160
+
161
+ await asyncio.to_thread(_write)
162
+
163
+
164
+ def register_default_subscribers(
165
+ event_bus: WorkflowEventBus,
166
+ telemetry: WorkflowEventTelemetry,
167
+ ) -> None:
168
+ """Attach default subscribers to the workflow event bus."""
169
+ event_bus.register_logging_handler()
170
+ event_bus.subscribe(
171
+ event_type=None,
172
+ handler=telemetry.handle_event,
173
+ description="workflow.telemetry",
174
+ max_concurrent=1,
175
+ )
@@ -0,0 +1,346 @@
1
+ """Workflow event bus built on top of ACB event primitives.
2
+
3
+ Provides a lightweight in-process event bus that uses ``acb.events`` data
4
+ structures so the rest of the codebase can adopt the forthcoming ACB EventBus
5
+ without waiting on external messaging infrastructure. Subscribers register
6
+ handlers for workflow event types and publishers emit events that are dispatched
7
+ asynchronously.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import asyncio
13
+ import logging
14
+ import threading
15
+ import typing as t
16
+ from dataclasses import dataclass, field
17
+ from enum import Enum
18
+
19
+ from acb.events import (
20
+ Event,
21
+ EventHandlerResult,
22
+ FunctionalEventHandler,
23
+ create_event,
24
+ )
25
+ from acb.events._base import EventSubscription
26
+
27
+ logger = logging.getLogger(__name__)
28
+
29
+ HandlerCallable = t.Callable[
30
+ [Event], t.Awaitable[EventHandlerResult] | EventHandlerResult
31
+ ]
32
+
33
+
34
+ class WorkflowEvent(str, Enum):
35
+ """Standard workflow events emitted inside Crackerjack."""
36
+
37
+ WORKFLOW_STARTED = "workflow.started"
38
+ WORKFLOW_SESSION_INITIALIZING = "workflow.session.initializing"
39
+ WORKFLOW_SESSION_READY = "workflow.session.ready"
40
+ CONFIG_PHASE_STARTED = "workflow.config.started"
41
+ CONFIG_PHASE_COMPLETED = "workflow.config.completed"
42
+ WORKFLOW_COMPLETED = "workflow.completed"
43
+ WORKFLOW_FAILED = "workflow.failed"
44
+ WORKFLOW_INTERRUPTED = "workflow.interrupted"
45
+
46
+ QUALITY_PHASE_STARTED = "workflow.quality.started"
47
+ QUALITY_PHASE_COMPLETED = "workflow.quality.completed"
48
+
49
+ PUBLISH_PHASE_STARTED = "workflow.publish.started"
50
+ PUBLISH_PHASE_COMPLETED = "workflow.publish.completed"
51
+
52
+ COMMIT_PHASE_STARTED = "workflow.commit.started"
53
+ COMMIT_PHASE_COMPLETED = "workflow.commit.completed"
54
+
55
+ HOOK_STRATEGY_STARTED = "hooks.strategy.started"
56
+ HOOK_STRATEGY_COMPLETED = "hooks.strategy.completed"
57
+ HOOK_STRATEGY_FAILED = "hooks.strategy.failed"
58
+
59
+ HOOK_EXECUTION_STARTED = "hooks.execution.started"
60
+ HOOK_EXECUTION_COMPLETED = "hooks.execution.completed"
61
+ HOOK_EXECUTION_FAILED = "hooks.execution.failed"
62
+
63
+ def __str__(self) -> str: # pragma: no cover - trivial
64
+ return str(self.value)
65
+
66
+
67
+ @dataclass
68
+ class WorkflowEventDispatchResult:
69
+ """Result returned from publishing an event."""
70
+
71
+ event: Event
72
+ results: list[EventHandlerResult] = field(default_factory=list)
73
+
74
+
75
+ @dataclass
76
+ class _SubscriptionEntry:
77
+ """Internal representation of a subscription with concurrency control."""
78
+
79
+ subscription: EventSubscription
80
+ description: str | None = None
81
+ semaphore: asyncio.Semaphore = field(default_factory=lambda: asyncio.Semaphore(1))
82
+ max_retries: int = 0
83
+ retry_backoff: float = 0.5
84
+
85
+ def __post_init__(self) -> None:
86
+ max_concurrent = self.subscription.max_concurrent or 1
87
+ self.semaphore = asyncio.Semaphore(max_concurrent)
88
+
89
+
90
+ class WorkflowEventBus:
91
+ """In-process event bus compatible with ACB event handlers."""
92
+
93
+ def __init__(self) -> None:
94
+ self._subscriptions: dict[str | None, dict[str, _SubscriptionEntry]] = {}
95
+ self._lock = threading.RLock()
96
+ self._default_handlers_registered = False
97
+
98
+ def subscribe(
99
+ self,
100
+ event_type: WorkflowEvent | str | None,
101
+ handler: HandlerCallable,
102
+ *,
103
+ predicate: t.Callable[[Event], bool] | None = None,
104
+ max_concurrent: int | None = None,
105
+ description: str | None = None,
106
+ max_retries: int = 0,
107
+ retry_backoff: float = 0.5,
108
+ ) -> str:
109
+ """Register a handler for an event type.
110
+
111
+ Args:
112
+ event_type: WorkflowEvent enum value, string, or ``None`` for wildcard.
113
+ handler: Callable invoked when the event is published.
114
+ predicate: Optional additional filter predicate.
115
+ max_concurrent: Maximum concurrent invocations for this handler.
116
+ description: Optional human readable identifier.
117
+ max_retries: Number of retry attempts when a handler raises.
118
+ retry_backoff: Initial backoff delay (seconds) between retries; doubles each attempt.
119
+
120
+ Returns:
121
+ Subscription ID string.
122
+ """
123
+ event_type_value = (
124
+ event_type.value if isinstance(event_type, WorkflowEvent) else event_type
125
+ )
126
+
127
+ event_handler = FunctionalEventHandler(
128
+ handler,
129
+ event_type=event_type_value,
130
+ predicate=predicate,
131
+ )
132
+ subscription = EventSubscription(
133
+ handler=event_handler,
134
+ event_type=event_type_value,
135
+ predicate=predicate,
136
+ max_concurrent=max_concurrent or 1,
137
+ )
138
+ entry = _SubscriptionEntry(
139
+ subscription=subscription,
140
+ description=description,
141
+ max_retries=max_retries,
142
+ retry_backoff=retry_backoff,
143
+ )
144
+
145
+ key = event_type_value
146
+
147
+ with self._lock:
148
+ bucket = self._subscriptions.setdefault(key, {})
149
+ bucket[str(subscription.subscription_id)] = entry
150
+
151
+ logger.debug(
152
+ "Registered workflow event subscription",
153
+ extra={
154
+ "event_type": event_type_value or "*",
155
+ "subscription_id": str(subscription.subscription_id),
156
+ "description": description,
157
+ "max_concurrent": max_concurrent or 1,
158
+ "max_retries": max_retries,
159
+ "retry_backoff": retry_backoff,
160
+ },
161
+ )
162
+
163
+ return str(subscription.subscription_id)
164
+
165
+ def unsubscribe(self, subscription_id: str) -> bool:
166
+ """Remove a subscription by ID."""
167
+ with self._lock:
168
+ for bucket in self._subscriptions.values():
169
+ if subscription_id in bucket:
170
+ del bucket[subscription_id]
171
+ logger.debug(
172
+ "Removed workflow event subscription",
173
+ extra={"subscription_id": subscription_id},
174
+ )
175
+ return True
176
+ return False
177
+
178
+ def list_subscriptions(self) -> list[dict[str, t.Any]]:
179
+ """Return summary information for registered subscriptions."""
180
+ data: list[dict[str, t.Any]] = []
181
+ with self._lock:
182
+ for event_type, bucket in self._subscriptions.items():
183
+ for subscription_id, entry in bucket.items():
184
+ data.append(
185
+ {
186
+ "subscription_id": subscription_id,
187
+ "event_type": event_type or "*",
188
+ "description": entry.description,
189
+ "max_concurrent": entry.subscription.max_concurrent,
190
+ }
191
+ )
192
+ return data
193
+
194
+ async def publish(
195
+ self,
196
+ event_type: WorkflowEvent | str,
197
+ payload: dict[str, t.Any] | None = None,
198
+ *,
199
+ source: str = "crackerjack.workflow",
200
+ **metadata: t.Any,
201
+ ) -> WorkflowEventDispatchResult:
202
+ """Publish an event to subscribed handlers."""
203
+ event_type_value = (
204
+ event_type.value if isinstance(event_type, WorkflowEvent) else event_type
205
+ )
206
+ payload = payload or {}
207
+ event = create_event(event_type_value, source, payload, **metadata)
208
+
209
+ entries = self._collect_subscriptions(event)
210
+ if not entries:
211
+ logger.debug(
212
+ "Workflow event published with no subscribers",
213
+ extra={"event_type": event_type_value},
214
+ )
215
+ return WorkflowEventDispatchResult(event=event, results=[])
216
+
217
+ tasks = [self._invoke_subscription(entry, event) for entry in entries]
218
+ raw_results = await asyncio.gather(*tasks, return_exceptions=True)
219
+
220
+ results: list[EventHandlerResult] = []
221
+ for entry, result in zip(entries, raw_results, strict=False):
222
+ if isinstance(result, EventHandlerResult):
223
+ results.append(result)
224
+ continue
225
+
226
+ if isinstance(result, Exception):
227
+ logger.exception(
228
+ "Workflow event handler raised an exception",
229
+ extra={
230
+ "event_type": event_type_value,
231
+ "subscription_id": entry.subscription.subscription_id,
232
+ "description": entry.description,
233
+ },
234
+ exc_info=result,
235
+ )
236
+ results.append(
237
+ EventHandlerResult(
238
+ success=False,
239
+ error_message=str(result),
240
+ metadata={
241
+ "subscription_id": str(entry.subscription.subscription_id)
242
+ },
243
+ )
244
+ )
245
+ continue
246
+
247
+ # Allow handlers to return truthy values instead of EventHandlerResult
248
+ success = True if result is None else bool(result)
249
+ results.append(
250
+ EventHandlerResult(
251
+ success=success,
252
+ metadata={
253
+ "subscription_id": str(entry.subscription.subscription_id)
254
+ },
255
+ )
256
+ )
257
+
258
+ return WorkflowEventDispatchResult(event=event, results=results)
259
+
260
+ def register_logging_handler(self) -> None:
261
+ """Install a default debug logging handler (idempotent)."""
262
+ if self._default_handlers_registered:
263
+ return
264
+
265
+ async def _log_event(event: Event) -> EventHandlerResult:
266
+ logger.debug(
267
+ "Workflow event dispatched",
268
+ extra={
269
+ "event_type": event.metadata.event_type,
270
+ "source": event.metadata.source,
271
+ "payload": event.payload,
272
+ },
273
+ )
274
+ return EventHandlerResult(success=True)
275
+
276
+ self.subscribe(
277
+ event_type=None,
278
+ handler=_log_event,
279
+ description="workflow.logging",
280
+ )
281
+ self._default_handlers_registered = True
282
+
283
+ def _collect_subscriptions(self, event: Event) -> list[_SubscriptionEntry]:
284
+ with self._lock:
285
+ specific = list(
286
+ self._subscriptions.get(event.metadata.event_type, {}).values()
287
+ )
288
+ wildcard = list(self._subscriptions.get(None, {}).values())
289
+ return specific + wildcard
290
+
291
+ async def _invoke_subscription(
292
+ self,
293
+ entry: _SubscriptionEntry,
294
+ event: Event,
295
+ ) -> EventHandlerResult:
296
+ handler = entry.subscription.handler
297
+ if not handler.can_handle(event):
298
+ return EventHandlerResult(
299
+ success=True,
300
+ metadata={
301
+ "subscription_id": str(entry.subscription.subscription_id),
302
+ "skipped": True,
303
+ },
304
+ )
305
+
306
+ async with entry.semaphore:
307
+ attempt = 0
308
+ delay = max(entry.retry_backoff, 0.0)
309
+ while True:
310
+ try:
311
+ return await handler.handle(event)
312
+ except Exception as exc:
313
+ attempt += 1
314
+ if attempt > entry.max_retries:
315
+ logger.exception(
316
+ "Workflow event handler failed after retries",
317
+ extra={
318
+ "subscription_id": str(
319
+ entry.subscription.subscription_id
320
+ ),
321
+ "description": entry.description,
322
+ "event_type": event.metadata.event_type,
323
+ "attempts": attempt,
324
+ },
325
+ exc_info=exc,
326
+ )
327
+ raise
328
+
329
+ logger.warning(
330
+ "Workflow event handler raised; retrying",
331
+ extra={
332
+ "subscription_id": str(entry.subscription.subscription_id),
333
+ "description": entry.description,
334
+ "event_type": event.metadata.event_type,
335
+ "attempt": attempt,
336
+ "max_retries": entry.max_retries,
337
+ "retry_delay": delay,
338
+ },
339
+ exc_info=exc,
340
+ )
341
+ if delay > 0:
342
+ await asyncio.sleep(delay)
343
+ delay *= 2
344
+
345
+
346
+ __all__ = ["WorkflowEventBus", "WorkflowEvent", "WorkflowEventDispatchResult"]