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
@@ -7,10 +7,18 @@ from dataclasses import dataclass, field
7
7
  from datetime import datetime
8
8
  from pathlib import Path
9
9
 
10
- from crackerjack.services.logging import get_logger
11
- from crackerjack.services.memory_optimizer import get_memory_optimizer
12
- from crackerjack.services.performance_cache import get_performance_cache
13
- from crackerjack.services.performance_monitor import get_performance_monitor
10
+ from acb.console import Console
11
+ from acb.depends import Inject, depends
12
+ from acb.logger import Logger
13
+
14
+ from crackerjack.models.protocols import (
15
+ PerformanceBenchmarkProtocol,
16
+ PerformanceBenchmarkServiceProtocol,
17
+ ServiceProtocol,
18
+ )
19
+ from crackerjack.services.memory_optimizer import LazyLoader, MemoryOptimizer
20
+ from crackerjack.services.monitoring.performance_cache import get_performance_cache
21
+ from crackerjack.services.monitoring.performance_monitor import get_performance_monitor
14
22
 
15
23
 
16
24
  @dataclass
@@ -88,10 +96,11 @@ class BenchmarkSuite:
88
96
 
89
97
 
90
98
  class PerformanceBenchmarker:
91
- def __init__(self) -> None:
92
- self._logger = get_logger("crackerjack.benchmarker")
99
+ @depends.inject
100
+ def __init__(self, logger: Inject[Logger]) -> None:
101
+ self._logger = logger
93
102
  self._monitor = get_performance_monitor()
94
- self._memory_optimizer = get_memory_optimizer()
103
+ self._memory_optimizer = MemoryOptimizer.get_instance()
95
104
  self._cache = get_performance_cache()
96
105
 
97
106
  self._test_iterations = 3
@@ -144,8 +153,6 @@ class PerformanceBenchmarker:
144
153
  "optimized_start"
145
154
  )
146
155
 
147
- from crackerjack.services.memory_optimizer import LazyLoader
148
-
149
156
  lazy_objects = []
150
157
  for i in range(50):
151
158
 
@@ -298,15 +305,94 @@ class PerformanceBenchmarker:
298
305
  self._logger.info(f"Exported benchmark results to {output_path}")
299
306
 
300
307
 
301
- class PerformanceBenchmarkService:
308
+ class PerformanceBenchmarkService(
309
+ PerformanceBenchmarkProtocol, PerformanceBenchmarkServiceProtocol, ServiceProtocol
310
+ ):
302
311
  """Service wrapper for performance benchmarking in workflow orchestration."""
303
312
 
304
- def __init__(self, console, pkg_path):
313
+ @depends.inject
314
+ def __init__(
315
+ self, console: Console, logger: Inject[Logger], pkg_path: Path
316
+ ) -> None:
305
317
  self._console = console
306
318
  self._pkg_path = pkg_path
307
- self._benchmarker = PerformanceBenchmarker()
308
- self._logger = get_logger("crackerjack.benchmark_service")
319
+ self._benchmarker = PerformanceBenchmarker(logger=logger)
320
+ self._logger = logger
321
+
322
+ def initialize(self) -> None:
323
+ pass
324
+
325
+ def cleanup(self) -> None:
326
+ pass
327
+
328
+ def health_check(self) -> bool:
329
+ return True
330
+
331
+ def shutdown(self) -> None:
332
+ pass
333
+
334
+ def metrics(self) -> dict[str, t.Any]:
335
+ return {}
336
+
337
+ def is_healthy(self) -> bool:
338
+ return True
339
+
340
+ def register_resource(self, resource: t.Any) -> None:
341
+ pass
342
+
343
+ def cleanup_resource(self, resource: t.Any) -> None:
344
+ pass
345
+
346
+ def record_error(self, error: Exception) -> None:
347
+ pass
348
+
349
+ def increment_requests(self) -> None:
350
+ pass
351
+
352
+ def get_custom_metric(self, name: str) -> t.Any:
353
+ return None
354
+
355
+ def set_custom_metric(self, name: str, value: t.Any) -> None:
356
+ pass
357
+
358
+ # Methods for PerformanceBenchmarkProtocol
359
+ def run_benchmark(self, operation: str) -> dict[str, t.Any]:
360
+ """Run a specific benchmark operation."""
361
+ start_time = time.time()
362
+ # Since we don't have operation-specific benchmark methods,
363
+ # we'll return basic timing information
364
+ return {
365
+ "operation": operation,
366
+ "start_time": start_time,
367
+ "end_time": time.time(),
368
+ "duration": time.time() - start_time,
369
+ "status": "completed",
370
+ }
371
+
372
+ def get_report(self) -> dict[str, t.Any]:
373
+ """Get performance report."""
374
+ # Return a basic report based on workflow metrics
375
+ return {
376
+ "timestamp": datetime.now().isoformat(),
377
+ "report_type": "performance_summary",
378
+ "total_benchmarks": 0, # This would be updated with actual values from the benchmarker
379
+ "summary": "Performance benchmark service operational",
380
+ }
381
+
382
+ def compare_benchmarks(
383
+ self,
384
+ baseline: dict[str, t.Any],
385
+ current: dict[str, t.Any],
386
+ ) -> dict[str, t.Any]:
387
+ """Compare two benchmark results."""
388
+ return {
389
+ "comparison_type": "basic_comparison",
390
+ "baseline": baseline,
391
+ "current": current,
392
+ "differences": {},
393
+ }
309
394
 
395
+ # Methods for PerformanceBenchmarkServiceProtocol
310
396
  async def run_benchmark_suite(self) -> BenchmarkSuite | None:
311
397
  """Run comprehensive benchmark suite and return results."""
312
398
  try:
@@ -321,4 +407,4 @@ class PerformanceBenchmarkService:
321
407
 
322
408
 
323
409
  def get_benchmarker() -> PerformanceBenchmarker:
324
- return PerformanceBenchmarker()
410
+ return PerformanceBenchmarker(logger=depends.get_sync(Logger))
@@ -8,7 +8,8 @@ from pathlib import Path
8
8
  from threading import Lock
9
9
  from weakref import WeakValueDictionary
10
10
 
11
- from crackerjack.services.logging import get_logger
11
+ from acb.depends import Inject, depends
12
+ from acb.logger import Logger
12
13
 
13
14
 
14
15
  @dataclass
@@ -45,8 +46,10 @@ class CacheStats:
45
46
 
46
47
 
47
48
  class PerformanceCache:
49
+ @depends.inject
48
50
  def __init__(
49
51
  self,
52
+ logger: Inject[Logger],
50
53
  max_memory_mb: int = 50,
51
54
  default_ttl_seconds: int = 300,
52
55
  cleanup_interval_seconds: int = 60,
@@ -58,7 +61,7 @@ class PerformanceCache:
58
61
  self._cache: dict[str, CacheEntry] = {}
59
62
  self._lock = Lock()
60
63
  self._stats = CacheStats()
61
- self._logger = get_logger("crackerjack.performance_cache")
64
+ self._logger = logger
62
65
  self._cleanup_task: asyncio.Task[None] | None = None
63
66
  self._invalidation_map: dict[str, set[str]] = {}
64
67
 
@@ -241,9 +244,9 @@ class PerformanceCache:
241
244
 
242
245
 
243
246
  class GitOperationCache:
244
- def __init__(self, cache: PerformanceCache):
247
+ def __init__(self, cache: PerformanceCache, logger: Logger):
245
248
  self.cache = cache
246
- self._logger = get_logger("crackerjack.git_cache")
249
+ self._logger = logger
247
250
 
248
251
  def _make_repo_key(self, repo_path: Path, operation: str, params: str = "") -> str:
249
252
  repo_hash = hashlib.md5(
@@ -268,7 +271,7 @@ class GitOperationCache:
268
271
  ) -> None:
269
272
  key = self._make_repo_key(repo_path, "branch_info")
270
273
  invalidation_keys = {f"git_repo: {repo_path}"}
271
- self.cache.set[t.Any](key, branch_info, ttl_seconds, invalidation_keys)
274
+ self.cache.set(key, branch_info, ttl_seconds, invalidation_keys)
272
275
 
273
276
  def get_file_status(self, repo_path: Path) -> t.Any:
274
277
  key = self._make_repo_key(repo_path, "file_status")
@@ -282,7 +285,7 @@ class GitOperationCache:
282
285
  ) -> None:
283
286
  key = self._make_repo_key(repo_path, "file_status")
284
287
  invalidation_keys = {f"git_repo: {repo_path}", "git_files"}
285
- self.cache.set[t.Any](key, file_status, ttl_seconds, invalidation_keys)
288
+ self.cache.set(key, file_status, ttl_seconds, invalidation_keys)
286
289
 
287
290
  def invalidate_repo(self, repo_path: Path) -> None:
288
291
  self.cache.invalidate(f"git_repo: {repo_path}")
@@ -290,9 +293,9 @@ class GitOperationCache:
290
293
 
291
294
 
292
295
  class FileSystemCache:
293
- def __init__(self, cache: PerformanceCache):
296
+ def __init__(self, cache: PerformanceCache, logger: Logger):
294
297
  self.cache = cache
295
- self._logger = get_logger("crackerjack.filesystem_cache")
298
+ self._logger = logger
296
299
 
297
300
  def _make_file_key(self, file_path: Path, operation: str) -> str:
298
301
  file_hash = hashlib.md5(
@@ -312,16 +315,16 @@ class FileSystemCache:
312
315
  ) -> None:
313
316
  key = self._make_file_key(file_path, "stats")
314
317
  invalidation_keys = {f"file: {file_path}"}
315
- self.cache.set[t.Any](key, stats, ttl_seconds, invalidation_keys)
318
+ self.cache.set(key, stats, ttl_seconds, invalidation_keys)
316
319
 
317
320
  def invalidate_file(self, file_path: Path) -> None:
318
321
  self.cache.invalidate(f"file: {file_path}")
319
322
 
320
323
 
321
324
  class CommandResultCache:
322
- def __init__(self, cache: PerformanceCache):
325
+ def __init__(self, cache: PerformanceCache, logger: Logger):
323
326
  self.cache = cache
324
- self._logger = get_logger("crackerjack.command_cache")
327
+ self._logger = logger
325
328
 
326
329
  def _make_command_key(self, command: list[str], cwd: Path | None = None) -> str:
327
330
  cmd_str = " ".join(command)
@@ -352,7 +355,7 @@ class CommandResultCache:
352
355
  if cwd:
353
356
  invalidation_keys.add(f"cwd: {cwd}")
354
357
 
355
- self.cache.set[t.Any](key, result, ttl_seconds, invalidation_keys)
358
+ self.cache.set(key, result, ttl_seconds, invalidation_keys)
356
359
 
357
360
  def invalidate_commands(self) -> None:
358
361
  self.cache.invalidate("commands")
@@ -371,12 +374,15 @@ def get_performance_cache() -> PerformanceCache:
371
374
 
372
375
 
373
376
  def get_git_cache() -> GitOperationCache:
374
- return GitOperationCache(get_performance_cache())
377
+ performance_cache = get_performance_cache()
378
+ return GitOperationCache(performance_cache, logger=performance_cache._logger)
375
379
 
376
380
 
377
381
  def get_filesystem_cache() -> FileSystemCache:
378
- return FileSystemCache(get_performance_cache())
382
+ performance_cache = get_performance_cache()
383
+ return FileSystemCache(performance_cache, logger=performance_cache._logger)
379
384
 
380
385
 
381
386
  def get_command_cache() -> CommandResultCache:
382
- return CommandResultCache(get_performance_cache())
387
+ performance_cache = get_performance_cache()
388
+ return CommandResultCache(performance_cache, logger=performance_cache._logger)
@@ -7,9 +7,11 @@ from pathlib import Path
7
7
  from threading import Lock
8
8
  from typing import Any
9
9
 
10
- from crackerjack.services.logging import get_logger
10
+ from acb.depends import Inject, depends
11
+ from acb.logger import Logger
12
+
11
13
  from crackerjack.services.memory_optimizer import MemoryOptimizer
12
- from crackerjack.services.performance_cache import get_performance_cache
14
+ from crackerjack.services.monitoring.performance_cache import get_performance_cache
13
15
 
14
16
 
15
17
  @dataclass
@@ -119,15 +121,17 @@ class PerformanceBenchmark:
119
121
 
120
122
 
121
123
  class PerformanceMonitor:
124
+ @depends.inject
122
125
  def __init__(
123
126
  self,
127
+ logger: Inject[Logger],
124
128
  data_retention_days: int = 30,
125
129
  benchmark_history_size: int = 100,
126
130
  ):
127
131
  self.data_retention_days = data_retention_days
128
132
  self.benchmark_history_size = benchmark_history_size
129
133
  self._initialize_data_structures(benchmark_history_size)
130
- self._initialize_services()
134
+ self._initialize_services(logger)
131
135
  self._initialize_thresholds()
132
136
 
133
137
  def _initialize_data_structures(self, history_size: int) -> None:
@@ -140,9 +144,9 @@ class PerformanceMonitor:
140
144
  lambda: deque(maxlen=history_size) # type: ignore[arg-type]
141
145
  )
142
146
 
143
- def _initialize_services(self) -> None:
147
+ def _initialize_services(self, logger: Logger) -> None:
144
148
  self._lock = Lock()
145
- self._logger = get_logger("crackerjack.performance_monitor")
149
+ self._logger = logger
146
150
  self._memory_optimizer = MemoryOptimizer.get_instance()
147
151
  self._cache = get_performance_cache()
148
152
 
@@ -532,7 +536,7 @@ def get_performance_monitor() -> PerformanceMonitor:
532
536
  global _global_monitor
533
537
  with _monitor_lock:
534
538
  if _global_monitor is None:
535
- _global_monitor = PerformanceMonitor()
539
+ _global_monitor = PerformanceMonitor(logger=depends.get_sync(Logger))
536
540
  return _global_monitor
537
541
 
538
542
 
@@ -1,14 +1,23 @@
1
1
  import asyncio
2
+ import subprocess
2
3
  import time
3
4
  import typing as t
4
- from concurrent.futures import ThreadPoolExecutor
5
+ from contextlib import suppress
5
6
  from dataclasses import dataclass, field
6
7
  from enum import Enum
7
8
  from pathlib import Path
8
9
 
10
+ from acb.depends import Inject, depends
11
+ from acb.logger import Logger
12
+
9
13
  from crackerjack.config.hooks import HookDefinition, SecurityLevel
10
- from crackerjack.services.logging import get_logger
11
- from crackerjack.services.performance_cache import get_performance_cache
14
+ from crackerjack.models.protocols import (
15
+ AsyncCommandExecutorProtocol,
16
+ ParallelHookExecutorProtocol,
17
+ PerformanceCacheProtocol,
18
+ ServiceProtocol,
19
+ )
20
+ from crackerjack.models.results import ExecutionResult, ParallelExecutionResult
12
21
 
13
22
 
14
23
  class ExecutionStrategy(Enum):
@@ -27,42 +36,19 @@ class ExecutionGroup:
27
36
  security_level: SecurityLevel = SecurityLevel.MEDIUM
28
37
 
29
38
 
30
- @dataclass
31
- class ExecutionResult:
32
- operation_id: str
33
- success: bool
34
- duration_seconds: float
35
- output: str = ""
36
- error: str = ""
37
- exit_code: int = 0
38
- metadata: dict[str, t.Any] = field(default_factory=dict[str, t.Any])
39
-
39
+ class ParallelHookExecutor(ParallelHookExecutorProtocol, ServiceProtocol):
40
+ """Executes hooks in parallel or sequentially based on defined strategies.
40
41
 
41
- @dataclass
42
- class ParallelExecutionResult:
43
- group_name: str
44
- total_operations: int
45
- successful_operations: int
46
- failed_operations: int
47
- total_duration_seconds: float
48
- results: list[ExecutionResult]
49
-
50
- @property
51
- def success_rate(self) -> float:
52
- return (
53
- self.successful_operations / self.total_operations
54
- if self.total_operations > 0
55
- else 0.0
56
- )
42
+ This service manages the concurrent execution of various hooks (e.g., linting, formatting)
43
+ to optimize performance and provide faster feedback loops. It supports different execution
44
+ strategies and handles dependencies between hooks.
45
+ """
57
46
 
58
- @property
59
- def overall_success(self) -> bool:
60
- return self.failed_operations == 0
61
-
62
-
63
- class ParallelHookExecutor:
47
+ @depends.inject
64
48
  def __init__(
65
49
  self,
50
+ logger: Inject[Logger],
51
+ cache: Inject[PerformanceCacheProtocol],
66
52
  max_workers: int = 3,
67
53
  timeout_seconds: int = 300,
68
54
  strategy: ExecutionStrategy = ExecutionStrategy.PARALLEL_SAFE,
@@ -70,8 +56,68 @@ class ParallelHookExecutor:
70
56
  self.max_workers = max_workers
71
57
  self.timeout_seconds = timeout_seconds
72
58
  self.strategy = strategy
73
- self._logger = get_logger("crackerjack.parallel_executor")
74
- self._cache = get_performance_cache()
59
+ self._logger = logger
60
+ self._cache = cache
61
+
62
+ def initialize(self) -> None:
63
+ pass
64
+
65
+ def cleanup(self) -> None:
66
+ pass
67
+
68
+ async def async_cleanup(self) -> None:
69
+ """Async cleanup for any remaining tasks."""
70
+ with suppress(RuntimeError):
71
+ loop = asyncio.get_running_loop()
72
+ pending_tasks = (
73
+ task
74
+ for task in asyncio.all_tasks(loop)
75
+ if not task.done()
76
+ and ("hook" in str(task).lower() or "parallel" in str(task).lower())
77
+ )
78
+
79
+ for task in pending_tasks:
80
+ if not task.done():
81
+ try:
82
+ task.cancel()
83
+ await asyncio.wait_for(task, timeout=0.1)
84
+ except (TimeoutError, asyncio.CancelledError):
85
+ pass
86
+ except RuntimeError as e:
87
+ if "Event loop is closed" in str(e):
88
+ return
89
+ else:
90
+ raise
91
+
92
+ def health_check(self) -> bool:
93
+ return True
94
+
95
+ def shutdown(self) -> None:
96
+ pass
97
+
98
+ def metrics(self) -> dict[str, t.Any]:
99
+ return {}
100
+
101
+ def is_healthy(self) -> bool:
102
+ return True
103
+
104
+ def register_resource(self, resource: t.Any) -> None:
105
+ pass
106
+
107
+ def cleanup_resource(self, resource: t.Any) -> None:
108
+ pass
109
+
110
+ def record_error(self, error: Exception) -> None:
111
+ pass
112
+
113
+ def increment_requests(self) -> None:
114
+ pass
115
+
116
+ def get_custom_metric(self, name: str) -> t.Any:
117
+ return None
118
+
119
+ def set_custom_metric(self, name: str, value: t.Any) -> None:
120
+ pass
75
121
 
76
122
  def analyze_hook_dependencies(
77
123
  self,
@@ -239,7 +285,7 @@ class ParallelHookExecutor:
239
285
  f"Hook {hooks[i].name} failed with exception: {result}"
240
286
  )
241
287
  else:
242
- processed_results.append(result)
288
+ processed_results.append(t.cast(ExecutionResult, result))
243
289
 
244
290
  successful = sum(1 for r in processed_results if r.success)
245
291
  self._logger.info(
@@ -249,18 +295,82 @@ class ParallelHookExecutor:
249
295
  return processed_results
250
296
 
251
297
 
252
- class AsyncCommandExecutor:
298
+ class AsyncCommandExecutor(AsyncCommandExecutorProtocol, ServiceProtocol):
299
+ """Executes shell commands asynchronously, with caching capabilities.
300
+
301
+ This service provides a robust way to run external commands without blocking
302
+ the main event loop, supporting parallel execution and caching of results
303
+ to improve performance and responsiveness.
304
+ """
305
+
306
+ @depends.inject
253
307
  def __init__(
254
308
  self,
309
+ logger: Inject[Logger],
310
+ cache: Inject[PerformanceCacheProtocol],
255
311
  max_workers: int = 4,
256
312
  cache_results: bool = True,
257
313
  ):
258
314
  self.max_workers = max_workers
259
315
  self.cache_results = cache_results
260
- self._logger = get_logger("crackerjack.async_executor")
261
- self._cache = get_performance_cache()
316
+ self._logger = logger
317
+ self._cache = cache
318
+ from concurrent.futures import ThreadPoolExecutor
319
+
262
320
  self._thread_pool = ThreadPoolExecutor(max_workers=max_workers)
263
321
 
322
+ def shutdown(self) -> None:
323
+ if hasattr(self, "_thread_pool"):
324
+ self._thread_pool.shutdown(wait=True)
325
+
326
+ def metrics(self) -> dict[str, t.Any]:
327
+ return {}
328
+
329
+ def is_healthy(self) -> bool:
330
+ return True
331
+
332
+ def register_resource(self, resource: t.Any) -> None:
333
+ pass
334
+
335
+ def cleanup_resource(self, resource: t.Any) -> None:
336
+ pass
337
+
338
+ def record_error(self, error: Exception) -> None:
339
+ pass
340
+
341
+ def increment_requests(self) -> None:
342
+ pass
343
+
344
+ def get_custom_metric(self, name: str) -> t.Any:
345
+ return None
346
+
347
+ def set_custom_metric(self, name: str, value: t.Any) -> None:
348
+ pass
349
+
350
+ async def async_cleanup(self) -> None:
351
+ """Async cleanup for any remaining command executor tasks."""
352
+ with suppress(RuntimeError):
353
+ loop = asyncio.get_running_loop()
354
+ pending_tasks = (
355
+ task
356
+ for task in asyncio.all_tasks(loop)
357
+ if not task.done()
358
+ and ("command" in str(task).lower() or "async" in str(task).lower())
359
+ )
360
+
361
+ for task in pending_tasks:
362
+ if not task.done():
363
+ try:
364
+ task.cancel()
365
+ await asyncio.wait_for(task, timeout=0.1)
366
+ except (TimeoutError, asyncio.CancelledError):
367
+ pass
368
+ except RuntimeError as e:
369
+ if "Event loop is closed" in str(e):
370
+ return
371
+ else:
372
+ raise
373
+
264
374
  async def execute_command(
265
375
  self,
266
376
  command: list[str],
@@ -307,7 +417,7 @@ class AsyncCommandExecutor:
307
417
  )
308
418
  processed_results.append(error_result)
309
419
  else:
310
- processed_results.append(result)
420
+ processed_results.append(t.cast(ExecutionResult, result))
311
421
 
312
422
  successful = sum(1 for r in processed_results if r.success)
313
423
  self._logger.info(
@@ -325,8 +435,6 @@ class AsyncCommandExecutor:
325
435
  loop = asyncio.get_event_loop()
326
436
 
327
437
  def run_sync_command() -> ExecutionResult:
328
- import subprocess
329
-
330
438
  try:
331
439
  result = subprocess.run(
332
440
  command,
@@ -370,9 +478,7 @@ class AsyncCommandExecutor:
370
478
  command: list[str],
371
479
  cwd: Path | None = None,
372
480
  ) -> ExecutionResult | None:
373
- from crackerjack.services.performance_cache import get_command_cache
374
-
375
- cache_result = get_command_cache().get_command_result(command, cwd)
481
+ cache_result = self._cache.get(self._get_cache_key(command, cwd))
376
482
  return t.cast(ExecutionResult | None, cache_result)
377
483
 
378
484
  async def _cache_result(
@@ -382,14 +488,13 @@ class AsyncCommandExecutor:
382
488
  ttl_seconds: int,
383
489
  cwd: Path | None = None,
384
490
  ) -> None:
385
- from crackerjack.services.performance_cache import get_command_cache
491
+ self._cache.set(self._get_cache_key(command, cwd), result, ttl_seconds)
386
492
 
387
- command_cache = get_command_cache()
388
- command_cache.set_command_result(command, result, cwd, ttl_seconds)
389
-
390
- def __del__(self) -> None:
391
- if hasattr(self, "_thread_pool"):
392
- self._thread_pool.shutdown(wait=False)
493
+ def _get_cache_key(self, command: list[str], cwd: Path | None) -> str:
494
+ key_parts = [" ".join(command)]
495
+ if cwd:
496
+ key_parts.append(str(cwd))
497
+ return ":".join(key_parts)
393
498
 
394
499
 
395
500
  _parallel_executor: ParallelHookExecutor | None = None
@@ -403,6 +508,8 @@ def get_parallel_executor(
403
508
  global _parallel_executor
404
509
  if _parallel_executor is None:
405
510
  _parallel_executor = ParallelHookExecutor(
511
+ logger=depends.get_sync(Logger),
512
+ cache=depends.get_sync(PerformanceCacheProtocol),
406
513
  max_workers=max_workers,
407
514
  strategy=strategy,
408
515
  )
@@ -412,5 +519,9 @@ def get_parallel_executor(
412
519
  def get_async_executor(max_workers: int = 4) -> AsyncCommandExecutor:
413
520
  global _async_executor
414
521
  if _async_executor is None:
415
- _async_executor = AsyncCommandExecutor(max_workers=max_workers)
522
+ _async_executor = AsyncCommandExecutor(
523
+ logger=depends.get_sync(Logger),
524
+ cache=depends.get_sync(PerformanceCacheProtocol),
525
+ max_workers=max_workers,
526
+ )
416
527
  return _async_executor