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
@@ -3,9 +3,10 @@ from collections.abc import Iterator
3
3
  from pathlib import Path
4
4
 
5
5
  from crackerjack.errors import ErrorCode, FileError, ResourceError
6
+ from crackerjack.models.protocols import FileSystemInterface
6
7
 
7
8
 
8
- class FileSystemService:
9
+ class FileSystemService(FileSystemInterface):
9
10
  @staticmethod
10
11
  def clean_trailing_whitespace_and_newlines(content: str) -> str:
11
12
  lines = content.splitlines()
@@ -17,37 +18,79 @@ class FileSystemService:
17
18
 
18
19
  return result
19
20
 
21
+ def _validate_path_exists(self, path_obj: Path, operation: str) -> None:
22
+ """Validate that a path exists."""
23
+ if not path_obj.exists():
24
+ raise FileError(
25
+ message=f"File does not exist: {path_obj}",
26
+ details=f"Attempted to {operation} file at {path_obj.absolute()}",
27
+ recovery="Check file path and ensure file exists",
28
+ )
29
+
30
+ def _handle_permission_error(
31
+ self, error: PermissionError, path: str | Path, operation: str
32
+ ) -> None:
33
+ """Handle permission errors."""
34
+ raise FileError(
35
+ message=f"Permission denied {operation}: {path}",
36
+ error_code=ErrorCode.PERMISSION_ERROR,
37
+ details=str(error),
38
+ recovery="Check file permissions and user access rights",
39
+ ) from error
40
+
41
+ def _handle_unicode_error(
42
+ self, error: UnicodeDecodeError, path: str | Path
43
+ ) -> None:
44
+ """Handle unicode decode errors."""
45
+ raise FileError(
46
+ message=f"Unable to decode file as UTF-8: {path}",
47
+ error_code=ErrorCode.FILE_READ_ERROR,
48
+ details=str(error),
49
+ recovery="Ensure file is text - based and UTF-8 encoded",
50
+ ) from error
51
+
52
+ def _handle_os_error(
53
+ self, error: OSError, path: str | Path, operation: str
54
+ ) -> None:
55
+ """Handle OS errors."""
56
+ raise FileError(
57
+ message=f"System error {operation}: {path}",
58
+ error_code=ErrorCode.FILE_READ_ERROR,
59
+ details=str(error),
60
+ recovery="Check disk space and file system integrity",
61
+ ) from error
62
+
63
+ def _handle_disk_space_error(
64
+ self, error: OSError, path: str | Path, operation: str
65
+ ) -> None:
66
+ """Handle disk space errors."""
67
+ if "No space left on device" in str(error):
68
+ raise ResourceError(
69
+ message=f"Insufficient disk space to {operation}: {path}",
70
+ details=str(error),
71
+ recovery="Free up disk space and try again",
72
+ ) from error
73
+ raise FileError(
74
+ message=f"System error {operation}: {path}",
75
+ error_code=ErrorCode.FILE_WRITE_ERROR,
76
+ details=str(error),
77
+ recovery="Check disk space and file system integrity",
78
+ ) from error
79
+
20
80
  def read_file(self, path: str | Path) -> str:
21
81
  try:
22
82
  path_obj = Path(path) if isinstance(path, str) else path
23
- if not path_obj.exists():
24
- raise FileError(
25
- message=f"File does not exist: {path_obj}",
26
- details=f"Attempted to read file at {path_obj.absolute()}",
27
- recovery="Check file path and ensure file exists",
28
- )
83
+ self._validate_path_exists(path_obj, "read")
29
84
  return path_obj.read_text(encoding="utf-8")
30
85
  except PermissionError as e:
31
- raise FileError(
32
- message=f"Permission denied reading file: {path}",
33
- error_code=ErrorCode.PERMISSION_ERROR,
34
- details=str(e),
35
- recovery="Check file permissions and user access rights",
36
- ) from e
86
+ self._handle_permission_error(e, path, "reading file")
87
+ raise # Ensure type checker knows this doesn't return
37
88
  except UnicodeDecodeError as e:
38
- raise FileError(
39
- message=f"Unable to decode file as UTF-8: {path}",
40
- error_code=ErrorCode.FILE_READ_ERROR,
41
- details=str(e),
42
- recovery="Ensure file is text - based and UTF-8 encoded",
43
- ) from e
89
+ self._handle_unicode_error(e, path)
90
+ raise # Ensure type checker knows this doesn't return
44
91
  except OSError as e:
45
- raise FileError(
46
- message=f"System error reading file: {path}",
47
- error_code=ErrorCode.FILE_READ_ERROR,
48
- details=str(e),
49
- recovery="Check disk space and file system integrity",
50
- ) from e
92
+ self._handle_os_error(e, path, "reading file")
93
+ raise # Ensure type checker knows this doesn't return
51
94
 
52
95
  def write_file(self, path: str | Path, content: str) -> None:
53
96
  try:
@@ -99,12 +142,7 @@ class FileSystemService:
99
142
  path_obj = Path(path) if isinstance(path, str) else path
100
143
  path_obj.mkdir(parents=parents, exist_ok=True)
101
144
  except PermissionError as e:
102
- raise FileError(
103
- message=f"Permission denied creating directory: {path}",
104
- error_code=ErrorCode.PERMISSION_ERROR,
105
- details=str(e),
106
- recovery="Check parent directory permissions",
107
- ) from e
145
+ self._handle_permission_error(e, path, "creating directory")
108
146
  except FileExistsError as e:
109
147
  if not parents:
110
148
  raise FileError(
@@ -113,18 +151,7 @@ class FileSystemService:
113
151
  recovery="Use exist_ok=True or check if directory exists first",
114
152
  ) from e
115
153
  except OSError as e:
116
- if "No space left on device" in str(e):
117
- raise ResourceError(
118
- message=f"Insufficient disk space to create directory: {path}",
119
- details=str(e),
120
- recovery="Free up disk space and try again",
121
- ) from e
122
- raise FileError(
123
- message=f"System error creating directory: {path}",
124
- error_code=ErrorCode.FILE_WRITE_ERROR,
125
- details=str(e),
126
- recovery="Check disk space and file system integrity",
127
- ) from e
154
+ self._handle_disk_space_error(e, path, "create directory")
128
155
 
129
156
  def glob(self, pattern: str, path: str | Path | None = None) -> list[Path]:
130
157
  base_path = Path(path) if path else Path.cwd()
@@ -220,12 +247,7 @@ class FileSystemService:
220
247
  try:
221
248
  shutil.copy2(src_path, dst_path)
222
249
  except PermissionError as e:
223
- raise FileError(
224
- message=f"Permission denied copying file: {src} -> {dst}",
225
- error_code=ErrorCode.PERMISSION_ERROR,
226
- details=str(e),
227
- recovery="Check file and directory permissions",
228
- ) from e
250
+ self._handle_permission_error(e, f"{src} -> {dst}", "copying file")
229
251
  except shutil.SameFileError as e:
230
252
  raise FileError(
231
253
  message=f"Source and destination are the same file: {src}",
@@ -234,18 +256,7 @@ class FileSystemService:
234
256
  recovery="Ensure source and destination paths are different",
235
257
  ) from e
236
258
  except OSError as e:
237
- if "No space left on device" in str(e):
238
- raise ResourceError(
239
- message=f"Insufficient disk space to copy file: {src} -> {dst}",
240
- details=str(e),
241
- recovery="Free up disk space and try again",
242
- ) from e
243
- raise FileError(
244
- message=f"System error copying file: {src} -> {dst}",
245
- error_code=ErrorCode.FILE_WRITE_ERROR,
246
- details=str(e),
247
- recovery="Check disk space and file system integrity",
248
- ) from e
259
+ self._handle_disk_space_error(e, f"{src} -> {dst}", "copy file")
249
260
 
250
261
  def remove_file(self, path: str | Path) -> None:
251
262
  try:
@@ -342,69 +353,29 @@ class FileSystemService:
342
353
  ) -> Iterator[str]:
343
354
  try:
344
355
  path_obj = Path(path) if isinstance(path, str) else path
345
- if not path_obj.exists():
346
- raise FileError(
347
- message=f"File does not exist: {path_obj}",
348
- details=f"Attempted to read file at {path_obj.absolute()}",
349
- recovery="Check file path and ensure file exists",
350
- )
356
+ self._validate_path_exists(path_obj, "read")
351
357
 
352
358
  with path_obj.open(encoding="utf-8") as file:
353
359
  while chunk := file.read(chunk_size):
354
360
  yield chunk
355
361
 
356
362
  except PermissionError as e:
357
- raise FileError(
358
- message=f"Permission denied reading file: {path}",
359
- error_code=ErrorCode.PERMISSION_ERROR,
360
- details=str(e),
361
- recovery="Check file permissions",
362
- ) from e
363
+ self._handle_permission_error(e, path, "reading file")
363
364
  except UnicodeDecodeError as e:
364
- raise FileError(
365
- message=f"File encoding error: {path}",
366
- error_code=ErrorCode.FILE_READ_ERROR,
367
- details=str(e),
368
- recovery="Ensure file is encoded in UTF-8",
369
- ) from e
365
+ self._handle_unicode_error(e, path)
370
366
  except OSError as e:
371
- raise FileError(
372
- message=f"System error reading file: {path}",
373
- error_code=ErrorCode.FILE_READ_ERROR,
374
- details=str(e),
375
- recovery="Check file system integrity",
376
- ) from e
367
+ self._handle_os_error(e, path, "reading file")
377
368
 
378
369
  def read_lines_streaming(self, path: str | Path) -> Iterator[str]:
379
370
  try:
380
371
  path_obj = Path(path) if isinstance(path, str) else path
381
- if not path_obj.exists():
382
- raise FileError(
383
- message=f"File does not exist: {path_obj}",
384
- details=f"Attempted to read file at {path_obj.absolute()}",
385
- recovery="Check file path and ensure file exists",
386
- )
372
+ self._validate_path_exists(path_obj, "read")
387
373
  with path_obj.open(encoding="utf-8") as file:
388
374
  for line in file:
389
375
  yield line.rstrip("\n\r")
390
376
  except PermissionError as e:
391
- raise FileError(
392
- message=f"Permission denied reading file: {path}",
393
- error_code=ErrorCode.PERMISSION_ERROR,
394
- details=str(e),
395
- recovery="Check file permissions",
396
- ) from e
377
+ self._handle_permission_error(e, path, "reading file")
397
378
  except UnicodeDecodeError as e:
398
- raise FileError(
399
- message=f"File encoding error: {path}",
400
- error_code=ErrorCode.FILE_READ_ERROR,
401
- details=str(e),
402
- recovery="Ensure file is encoded in UTF-8",
403
- ) from e
379
+ self._handle_unicode_error(e, path)
404
380
  except OSError as e:
405
- raise FileError(
406
- message=f"System error reading file: {path}",
407
- error_code=ErrorCode.FILE_READ_ERROR,
408
- details=str(e),
409
- recovery="Check file system integrity",
410
- ) from e
381
+ self._handle_os_error(e, path, "reading file")
@@ -1,8 +1,11 @@
1
- import subprocess
1
+ import subprocess # nosec B404
2
2
  import typing as t
3
3
  from pathlib import Path
4
4
 
5
- from rich.console import Console
5
+ from acb.console import Console
6
+ from acb.depends import Inject, depends
7
+
8
+ from crackerjack.models.protocols import GitInterface
6
9
 
7
10
  from .secure_subprocess import execute_secure_subprocess
8
11
  from .security_logger import get_security_logger
@@ -18,6 +21,7 @@ GIT_COMMANDS = {
18
21
  "commit": ["commit", "-m"],
19
22
  "add_updated": ["add", "-u"],
20
23
  "push_porcelain": ["push", "--porcelain"],
24
+ "push_with_tags": ["push", "--porcelain", "--follow-tags"],
21
25
  "current_branch": ["branch", "--show-current"],
22
26
  "commits_ahead": ["rev-list", "--count", "@{u}..HEAD"],
23
27
  }
@@ -31,8 +35,9 @@ class FailedGitResult:
31
35
  self.stderr = f"Git security validation failed: {error}"
32
36
 
33
37
 
34
- class GitService:
35
- def __init__(self, console: Console, pkg_path: Path | None = None) -> None:
38
+ class GitService(GitInterface):
39
+ @depends.inject
40
+ def __init__(self, console: Inject[Console], pkg_path: Path | None = None) -> None:
36
41
  self.console = console
37
42
  self.pkg_path = pkg_path or Path.cwd()
38
43
 
@@ -156,7 +161,7 @@ class GitService:
156
161
 
157
162
  def _retry_commit_after_restage(self, message: str) -> bool:
158
163
  self.console.print(
159
- "[yellow]🔄[/ yellow] Pre - commit hooks modified files - attempting to re-stage and retry commit"
164
+ "[yellow]🔄[/yellow] Pre-commit hooks modified files - attempting to re-stage and retry commit"
160
165
  )
161
166
 
162
167
  add_result = self._run_git_command(GIT_COMMANDS["add_updated"])
@@ -204,6 +209,19 @@ class GitService:
204
209
  self.console.print(f"[red]❌[/ red] Error pushing: {e}")
205
210
  return False
206
211
 
212
+ def push_with_tags(self) -> bool:
213
+ """Push commits and any tags to remote using --follow-tags."""
214
+ try:
215
+ result = self._run_git_command(GIT_COMMANDS["push_with_tags"])
216
+ if result.returncode == 0:
217
+ self._display_push_success(result.stdout)
218
+ return True
219
+ self.console.print(f"[red]❌[/ red] Push failed: {result.stderr}")
220
+ return False
221
+ except Exception as e:
222
+ self.console.print(f"[red]❌[/ red] Error pushing: {e}")
223
+ return False
224
+
207
225
  def _display_push_success(self, push_output: str) -> None:
208
226
  lines = push_output.strip().split("\n") if push_output.strip() else []
209
227
 
@@ -326,3 +344,79 @@ class GitService:
326
344
  if result.returncode == 0 and result.stdout.strip().isdigit():
327
345
  return int(result.stdout.strip())
328
346
  return 0
347
+
348
+ def get_changed_files_by_extension(
349
+ self,
350
+ extensions: list[str],
351
+ include_staged: bool = True,
352
+ include_unstaged: bool = True,
353
+ ) -> list[Path]:
354
+ """Get changed files filtered by file extensions.
355
+
356
+ Args:
357
+ extensions: List of extensions to filter by (e.g., [".py", ".md"])
358
+ include_staged: Include staged files in results
359
+ include_unstaged: Include unstaged files in results
360
+
361
+ Returns:
362
+ List of Path objects for changed files matching the extensions
363
+
364
+ Example:
365
+ >>> git_service.get_changed_files_by_extension([".py"])
366
+ [Path("crackerjack/services/git.py"), Path("tests/test_git.py")]
367
+ """
368
+ try:
369
+ all_changed: set[str] = set()
370
+
371
+ if include_staged:
372
+ staged_result = self._run_git_command(GIT_COMMANDS["staged_files"])
373
+ if staged_result.stdout.strip():
374
+ all_changed.update(staged_result.stdout.strip().split("\n"))
375
+
376
+ if include_unstaged:
377
+ unstaged_result = self._run_git_command(GIT_COMMANDS["unstaged_files"])
378
+ if unstaged_result.stdout.strip():
379
+ all_changed.update(unstaged_result.stdout.strip().split("\n"))
380
+
381
+ # Filter by extensions
382
+ filtered = [
383
+ self.pkg_path / f
384
+ for f in all_changed
385
+ if f and any(f.endswith(ext) for ext in extensions)
386
+ ]
387
+
388
+ # Only return files that actually exist
389
+ return [f for f in filtered if f.exists()]
390
+
391
+ except Exception as e:
392
+ self.console.print(
393
+ f"[yellow]⚠️[/yellow] Error getting changed files by extension: {e}"
394
+ )
395
+ return []
396
+
397
+ def get_current_commit_hash(self) -> str | None:
398
+ """Get the hash of the current commit (HEAD)."""
399
+ try:
400
+ result = self._run_git_command(["rev-parse", "HEAD"])
401
+ if result.returncode == 0 and result.stdout.strip():
402
+ return result.stdout.strip()
403
+ return None
404
+ except Exception:
405
+ self.console.print("[red]❌[/red] Error getting current commit hash")
406
+ return None
407
+
408
+ def reset_hard(self, commit_hash: str) -> bool:
409
+ """Reset the repository to a specific commit hash (hard reset)."""
410
+ try:
411
+ result = self._run_git_command(["reset", "--hard", commit_hash])
412
+ if result.returncode == 0:
413
+ self.console.print(
414
+ f"[green]✅[/green] Repository reset to {commit_hash[:8]}"
415
+ )
416
+ return True
417
+ else:
418
+ self.console.print(f"[red]❌[/red] Reset failed: {result.stderr}")
419
+ return False
420
+ except Exception as e:
421
+ self.console.print(f"[red]❌[/red] Error during reset: {e}")
422
+ return False
@@ -347,11 +347,11 @@ class HealthMetricsService:
347
347
  try:
348
348
  from urllib.parse import urlparse
349
349
 
350
- url = f"https://pypi.org/pypi/{package_name}/json"
350
+ url = f"https: //pypi.org/pypi/{package_name}/json"
351
351
 
352
352
  parsed = urlparse(url)
353
353
  if parsed.scheme != "https" or parsed.netloc != "pypi.org":
354
- msg = f"Invalid URL: only https://pypi.org URLs are allowed, got {url}"
354
+ msg = f"Invalid URL: only https: //pypi.org URLs are allowed, got {url}"
355
355
  raise ValueError(msg)
356
356
 
357
357
  if not parsed.path.startswith("/pypi/") or not parsed.path.endswith(
@@ -362,8 +362,7 @@ class HealthMetricsService:
362
362
 
363
363
  response = requests.get(url, timeout=10, verify=True)
364
364
  response.raise_for_status()
365
- json_result = response.json()
366
- return t.cast(dict[str, t.Any] | None, json_result)
365
+ return response.json()
367
366
  except Exception:
368
367
  return None
369
368
 
@@ -379,8 +378,7 @@ class HealthMetricsService:
379
378
  if not release_info:
380
379
  return None
381
380
 
382
- upload_time_raw = release_info[0].get("upload_time", "")
383
- return t.cast(str | None, upload_time_raw)
381
+ return release_info[0].get("upload_time", "")
384
382
 
385
383
  def _calculate_days_since_upload(self, upload_time: str) -> int | None:
386
384
  try:
@@ -205,7 +205,11 @@ class HeatMapGenerator:
205
205
  bucket_config: dict[str, t.Any],
206
206
  ) -> dict[str, t.Any]:
207
207
  """Build error count matrix for files and time buckets."""
208
- error_matrix: dict[str, dict[int, int]] = defaultdict(lambda: defaultdict(int))
208
+ from collections import defaultdict
209
+
210
+ error_matrix: dict[str, t.Any] = defaultdict(
211
+ lambda: defaultdict(int) # type: ignore[call-overload]
212
+ )
209
213
 
210
214
  for file_path, errors in self.error_data.items():
211
215
  for error in errors:
@@ -450,7 +454,7 @@ class HeatMapGenerator:
450
454
 
451
455
  def _calculate_metric_max_values(self, metric_types: list[str]) -> dict[str, float]:
452
456
  """Calculate max values for normalization."""
453
- max_values = {}
457
+ max_values: dict[str, float] = {}
454
458
  for metric_type in metric_types:
455
459
  values = [
456
460
  data["metrics"][metric_type]
@@ -558,8 +562,13 @@ class HeatMapGenerator:
558
562
  self, test_errors: list[dict[str, t.Any]]
559
563
  ) -> defaultdict[str, defaultdict[str, int]]:
560
564
  """Group test errors by file and error type."""
565
+ from collections import defaultdict as dd
566
+
567
+ def make_inner_defaultdict() -> defaultdict[str, int]:
568
+ return dd(int)
569
+
561
570
  test_matrix: defaultdict[str, defaultdict[str, int]] = defaultdict(
562
- lambda: defaultdict(int)
571
+ make_inner_defaultdict
563
572
  )
564
573
 
565
574
  for error in test_errors: