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
@@ -0,0 +1,198 @@
1
+ """Generic configuration loading and validation service."""
2
+
3
+ import json
4
+ from pathlib import Path
5
+ from typing import Any
6
+
7
+ import yaml
8
+ from loguru import logger
9
+ from pydantic import BaseModel, ValidationError
10
+
11
+
12
+ class ConfigService:
13
+ """Generic configuration loading and validation service."""
14
+
15
+ @staticmethod
16
+ def load_config(path: str | Path) -> dict[str, Any]:
17
+ """
18
+ Load configuration file based on extension.
19
+
20
+ Args:
21
+ path: Path to the configuration file
22
+
23
+ Returns:
24
+ Dictionary with configuration data
25
+
26
+ Raises:
27
+ ValueError: If file extension is not supported
28
+ FileNotFoundError: If the file doesn't exist
29
+ Exception: For other file loading errors
30
+ """
31
+ path = Path(path)
32
+
33
+ if not path.exists():
34
+ raise FileNotFoundError(f"Configuration file does not exist: {path}")
35
+
36
+ if path.suffix.lower() == ".json":
37
+ return ConfigService._load_json(path)
38
+ elif path.suffix.lower() in (".yml", ".yaml"):
39
+ return ConfigService._load_yaml(path)
40
+ elif path.suffix.lower() == ".toml":
41
+ return ConfigService._load_toml(path)
42
+ else:
43
+ raise ValueError(f"Unsupported config format: {path.suffix}")
44
+
45
+ @staticmethod
46
+ async def load_config_async(path: str | Path) -> dict[str, Any]:
47
+ """
48
+ Asynchronously load configuration file based on extension.
49
+
50
+ Args:
51
+ path: Path to the configuration file
52
+
53
+ Returns:
54
+ Dictionary with configuration data
55
+
56
+ Raises:
57
+ ValueError: If file extension is not supported
58
+ FileNotFoundError: If the file doesn't exist
59
+ Exception: For other file loading errors
60
+ """
61
+ from crackerjack.services.file_io_service import FileIOService
62
+
63
+ path = Path(path)
64
+
65
+ if not path.exists():
66
+ raise FileNotFoundError(f"Configuration file does not exist: {path}")
67
+
68
+ if path.suffix.lower() == ".json":
69
+ content = await FileIOService.read_text_file(path)
70
+ return json.loads(content)
71
+ elif path.suffix.lower() in (".yml", ".yaml"):
72
+ content = await FileIOService.read_text_file(path)
73
+ return yaml.safe_load(content)
74
+ elif path.suffix.lower() == ".toml":
75
+ content = await FileIOService.read_text_file(path)
76
+ import toml
77
+
78
+ return toml.loads(content)
79
+ else:
80
+ raise ValueError(f"Unsupported config format: {path.suffix}")
81
+
82
+ @staticmethod
83
+ def _load_json(path: Path) -> dict[str, Any]:
84
+ """Load JSON configuration."""
85
+ with path.open(encoding="utf-8") as f:
86
+ return json.load(f)
87
+
88
+ @staticmethod
89
+ def _load_yaml(path: Path) -> dict[str, Any]:
90
+ """Load YAML configuration."""
91
+ with path.open(encoding="utf-8") as f:
92
+ return yaml.safe_load(f)
93
+
94
+ @staticmethod
95
+ def _load_toml(path: Path) -> dict[str, Any]:
96
+ """Load TOML configuration."""
97
+ import toml
98
+
99
+ with path.open("r", encoding="utf-8") as f:
100
+ return toml.load(f)
101
+
102
+ @staticmethod
103
+ def validate_config(
104
+ config: dict[str, Any], model_class: type[BaseModel]
105
+ ) -> BaseModel:
106
+ """
107
+ Validate configuration against a Pydantic model.
108
+
109
+ Args:
110
+ config: Configuration dictionary to validate
111
+ model_class: Pydantic model class to validate against
112
+
113
+ Returns:
114
+ Validated Pydantic model instance
115
+
116
+ Raises:
117
+ ValidationError: If the configuration doesn't match the model
118
+ """
119
+ try:
120
+ return model_class.model_validate(config)
121
+ except ValidationError as e:
122
+ logger.error(f"Config validation failed: {e}")
123
+ raise
124
+
125
+ @staticmethod
126
+ def save_config(
127
+ config: dict[str, Any], path: str | Path, format: str | None = None
128
+ ) -> None:
129
+ """
130
+ Save configuration to file.
131
+
132
+ Args:
133
+ config: Configuration dictionary to save
134
+ path: Path to save the configuration to
135
+ format: Format to save as ('json', 'yaml', 'toml'). If None, inferred from path extension.
136
+ """
137
+ path = Path(path)
138
+ format = format or path.suffix.lower().lstrip(".")
139
+
140
+ # Create parent directories if they don't exist
141
+ path.parent.mkdir(parents=True, exist_ok=True)
142
+
143
+ if format == "json":
144
+ ConfigService._save_json(config, path)
145
+ elif format in ("yml", "yaml"):
146
+ ConfigService._save_yaml(config, path)
147
+ elif format == "toml":
148
+ ConfigService._save_toml(config, path)
149
+ else:
150
+ raise ValueError(f"Unsupported config format: {format}")
151
+
152
+ @staticmethod
153
+ def _save_json(config: dict[str, Any], path: Path) -> None:
154
+ """Save configuration as JSON."""
155
+ with path.open("w", encoding="utf-8") as f:
156
+ json.dump(config, f, indent=2, ensure_ascii=False)
157
+
158
+ @staticmethod
159
+ def _save_yaml(config: dict[str, Any], path: Path) -> None:
160
+ """Save configuration as YAML."""
161
+ with path.open("w", encoding="utf-8") as f:
162
+ yaml.dump(config, f, default_flow_style=False, allow_unicode=True)
163
+
164
+ @staticmethod
165
+ def _save_toml(config: dict[str, Any], path: Path) -> None:
166
+ """Save configuration as TOML."""
167
+ import toml
168
+
169
+ with path.open("w", encoding="utf-8") as f:
170
+ toml.dump(config, f)
171
+
172
+ @staticmethod
173
+ def merge_configs(
174
+ base_config: dict[str, Any], override_config: dict[str, Any]
175
+ ) -> dict[str, Any]:
176
+ """
177
+ Recursively merge two configuration dictionaries.
178
+
179
+ Args:
180
+ base_config: Base configuration
181
+ override_config: Configuration to merge on top of base
182
+
183
+ Returns:
184
+ Merged configuration dictionary
185
+ """
186
+ result = base_config.copy()
187
+
188
+ for key, value in override_config.items():
189
+ if (
190
+ key in result
191
+ and isinstance(result[key], dict)
192
+ and isinstance(value, dict)
193
+ ):
194
+ result[key] = ConfigService.merge_configs(result[key], value)
195
+ else:
196
+ result[key] = value
197
+
198
+ return result
@@ -1,5 +1,4 @@
1
1
  import hashlib
2
- import subprocess
3
2
  import typing as t
4
3
  from contextlib import suppress
5
4
  from dataclasses import dataclass, field
@@ -8,7 +7,7 @@ from pathlib import Path
8
7
 
9
8
  import tomli
10
9
  import yaml
11
- from rich.console import Console
10
+ from acb.console import Console
12
11
 
13
12
 
14
13
  @dataclass
@@ -95,12 +94,13 @@ class ConfigTemplateService:
95
94
  "stages": ["pre-push", "manual"],
96
95
  },
97
96
  {
98
- "id": "pyright",
99
- "name": "pyright-type-checking",
100
- "entry": "uv run pyright",
97
+ "id": "zuban",
98
+ "name": "zuban-type-checking",
99
+ "entry": "uv run zuban check",
101
100
  "language": "system",
102
- "files": r"^crackerjack/.*\.py$",
103
- "exclude": r"^crackerjack/(mcp|plugins)/.*\.py$|crackerjack/code_cleaner\.py$",
101
+ "args": ["--config-file", "mypy.ini", "./crackerjack"],
102
+ "pass_filenames": False,
103
+ "exclude": r"^tests/|^src/",
104
104
  "stages": ["pre-push", "manual"],
105
105
  },
106
106
  ]
@@ -377,7 +377,7 @@ class ConfigTemplateService:
377
377
  )
378
378
 
379
379
  self._update_version_tracking(project_path, "pre-commit", template.version)
380
- self._invalidate_precommit_cache(project_path)
380
+ self._invalidate_cache(project_path)
381
381
 
382
382
  self.console.print(
383
383
  f"[green]✅[/green] Updated {config_file.name} to version {template.version}"
@@ -452,7 +452,7 @@ class ConfigTemplateService:
452
452
  """Update version tracking file."""
453
453
  version_file = project_path / ".crackerjack-config.yaml"
454
454
 
455
- data = {"version": "1.0.0", "configs": {}}
455
+ data: dict[str, t.Any] = {"version": "1.0.0", "configs": {}}
456
456
  if version_file.exists():
457
457
  with suppress(Exception):
458
458
  with version_file.open() as f:
@@ -472,23 +472,10 @@ class ConfigTemplateService:
472
472
  with version_file.open("w") as f:
473
473
  yaml.dump(data, f, default_flow_style=False, sort_keys=False)
474
474
 
475
- def _invalidate_precommit_cache(self, project_path: Path) -> None:
476
- """Invalidate pre-commit cache to ensure fresh environment."""
477
- with suppress(Exception):
478
- subprocess.run(
479
- ["pre-commit", "clean"],
480
- cwd=project_path,
481
- capture_output=True,
482
- text=True,
483
- timeout=30,
484
- )
485
- subprocess.run(
486
- ["pre-commit", "install"],
487
- cwd=project_path,
488
- capture_output=True,
489
- text=True,
490
- timeout=30,
491
- )
475
+ def _invalidate_cache(self, project_path: Path) -> None:
476
+ """Invalidate cache to ensure fresh environment."""
477
+ # No-op in the new system - cache invalidation handled differently
478
+ pass
492
479
 
493
480
  def get_config_hash(self, config_path: Path) -> str:
494
481
  """Generate hash of configuration file for cache invalidation."""
@@ -1,7 +1,8 @@
1
1
  from contextlib import suppress
2
2
  from pathlib import Path
3
3
 
4
- from rich.console import Console
4
+ from acb.console import Console
5
+ from acb.depends import Inject, depends
5
6
 
6
7
  from .regex_patterns import SAFE_PATTERNS
7
8
 
@@ -9,7 +10,8 @@ from .regex_patterns import SAFE_PATTERNS
9
10
  class CoverageBadgeService:
10
11
  """Service for managing coverage badges in README.md files."""
11
12
 
12
- def __init__(self, console: Console, project_root: Path) -> None:
13
+ @depends.inject
14
+ def __init__(self, console: Inject[Console], project_root: Path) -> None:
13
15
  self.console = console
14
16
  self.project_root = project_root
15
17
  self.readme_path = project_root / "README.md"
@@ -154,8 +156,8 @@ class CoverageBadgeService:
154
156
  if current_coverage is None:
155
157
  return True # No badge exists, should add one
156
158
 
157
- # Only update if coverage changed by at least 0.1%
158
- return abs(coverage_percent - current_coverage) >= 0.1
159
+ # Only update if coverage changed by at least 0.01% (more accurate reporting)
160
+ return abs(coverage_percent - current_coverage) >= 0.01
159
161
 
160
162
  except Exception:
161
163
  return True # On error, attempt update
@@ -3,20 +3,66 @@ import typing as t
3
3
  from datetime import datetime
4
4
  from pathlib import Path
5
5
 
6
- from rich.console import Console
6
+ from acb.console import Console
7
+ from acb.depends import Inject, depends
7
8
  from rich.progress import BarColumn, Progress, SpinnerColumn, TextColumn
8
9
 
10
+ from crackerjack.models.protocols import CoverageRatchetProtocol
11
+ from crackerjack.services.filesystem import FileSystemService
12
+ from crackerjack.services.regex_patterns import update_coverage_requirement
9
13
 
10
- class CoverageRatchetService:
14
+
15
+ class CoverageRatchetService(CoverageRatchetProtocol):
11
16
  MILESTONES = [15, 20, 25, 30, 40, 50, 60, 70, 80, 90, 95, 100]
12
17
 
13
18
  TOLERANCE_MARGIN = 2.0
14
19
 
15
- def __init__(self, pkg_path: Path, console: Console) -> None:
16
- self.pkg_path = pkg_path
20
+ @depends.inject
21
+ def __init__(self, pkg_path: Path, console: Inject[Console]) -> None:
22
+ # Normalize to pathlib.Path to avoid async path behaviors
23
+ try:
24
+ self.pkg_path = Path(str(pkg_path))
25
+ except Exception:
26
+ self.pkg_path = Path(pkg_path)
17
27
  self.console = console
18
- self.ratchet_file = pkg_path / ".coverage-ratchet.json"
19
- self.pyproject_file = pkg_path / "pyproject.toml"
28
+ self.ratchet_file = self.pkg_path / ".coverage-ratchet.json"
29
+ self.pyproject_file = self.pkg_path / "pyproject.toml"
30
+
31
+ def initialize(self) -> None:
32
+ pass
33
+
34
+ def cleanup(self) -> None:
35
+ pass
36
+
37
+ def health_check(self) -> bool:
38
+ return True
39
+
40
+ def shutdown(self) -> None:
41
+ pass
42
+
43
+ def metrics(self) -> dict[str, t.Any]:
44
+ return {}
45
+
46
+ def is_healthy(self) -> bool:
47
+ return True
48
+
49
+ def register_resource(self, resource: t.Any) -> None:
50
+ pass
51
+
52
+ def cleanup_resource(self, resource: t.Any) -> None:
53
+ pass
54
+
55
+ def record_error(self, error: Exception) -> None:
56
+ pass
57
+
58
+ def increment_requests(self) -> None:
59
+ pass
60
+
61
+ def get_custom_metric(self, name: str) -> t.Any:
62
+ return None
63
+
64
+ def set_custom_metric(self, name: str, value: t.Any) -> None:
65
+ pass
20
66
 
21
67
  def initialize_baseline(self, initial_coverage: float) -> None:
22
68
  if self.ratchet_file.exists():
@@ -136,7 +182,7 @@ class CoverageRatchetService:
136
182
  def _check_milestones(
137
183
  self, old_coverage: float, new_coverage: float, data: dict[str, t.Any]
138
184
  ) -> list[float]:
139
- achieved_milestones = set[t.Any](data.get("milestones_achieved", []))
185
+ achieved_milestones = set(data.get("milestones_achieved", []))
140
186
  return [
141
187
  milestone
142
188
  for milestone in self.MILESTONES
@@ -184,13 +230,9 @@ class CoverageRatchetService:
184
230
  try:
185
231
  content = self.pyproject_file.read_text()
186
232
 
187
- from crackerjack.services.regex_patterns import update_coverage_requirement
188
-
189
233
  updated_content = update_coverage_requirement(content, new_coverage)
190
234
 
191
235
  if updated_content != content:
192
- from crackerjack.services.filesystem import FileSystemService
193
-
194
236
  updated_content = (
195
237
  FileSystemService.clean_trailing_whitespace_and_newlines(
196
238
  updated_content
@@ -236,22 +278,6 @@ class CoverageRatchetService:
236
278
  needed = milestone - current
237
279
  return max(0.0, needed)
238
280
  return 0.0
239
- data = self.get_ratchet_data()
240
- if not data:
241
- return {"status": "not_initialized"}
242
-
243
- return {
244
- "status": "active",
245
- "current_coverage": data["baseline"],
246
- "target_coverage": data["target"],
247
- "next_milestone": data.get("next_milestone"),
248
- "milestones_achieved": data.get("milestones_achieved", []),
249
- "total_milestones": len(self.MILESTONES),
250
- "progress_percent": (data["baseline"] / data["target"]) * 100,
251
- "last_updated": data["last_updated"],
252
- "history_count": len(data.get("history", [])),
253
- "improvement_trend": self._calculate_trend(data),
254
- }
255
281
 
256
282
  def _calculate_trend(self, data: dict[str, t.Any]) -> str:
257
283
  history = data.get("history", [])
@@ -8,7 +8,8 @@ from datetime import datetime
8
8
  from pathlib import Path
9
9
  from typing import Any
10
10
 
11
- from rich.console import Console
11
+ from acb.console import Console
12
+ from acb.depends import depends
12
13
  from rich.panel import Panel
13
14
  from rich.table import Table
14
15
 
@@ -20,7 +21,7 @@ class AIAgentDebugger:
20
21
  def __init__(self, enabled: bool = False, verbose: bool = False) -> None:
21
22
  self.enabled = enabled
22
23
  self.verbose = verbose
23
- self.console = Console(force_terminal=True, stderr=True)
24
+ self.console = depends.get_sync(Console)
24
25
  self.logger = get_logger("crackerjack.ai_agent.debug")
25
26
  self.session_id = f"debug_{int(time.time())}"
26
27
 
@@ -351,7 +352,9 @@ class AIAgentDebugger:
351
352
  f"Total test fixes: {self.total_test_fixes}, hook fixes: {self.total_hook_fixes}",
352
353
  )
353
354
 
354
- self.console.print(table)
355
+ self.console.print(
356
+ Panel(table, title="AI Agent Debug Summary", border_style=border_style)
357
+ )
355
358
 
356
359
  if self.iteration_stats:
357
360
  self._print_iteration_breakdown(border_style)
@@ -397,7 +400,9 @@ class AIAgentDebugger:
397
400
  else "N / A",
398
401
  )
399
402
 
400
- self.console.print(table)
403
+ self.console.print(
404
+ Panel(table, title="Iteration Breakdown", border_style=border_style)
405
+ )
401
406
 
402
407
  def _print_agent_activity_breakdown(self, border_style: str = "red") -> None:
403
408
  agent_stats: dict[str, dict[str, t.Any]] = {}
@@ -436,7 +441,9 @@ class AIAgentDebugger:
436
441
  )
437
442
  table.add_row(agent, str(stats["activities"]), confidence_text)
438
443
 
439
- self.console.print(table)
444
+ self.console.print(
445
+ Panel(table, title="Agent Activity Breakdown", border_style=border_style)
446
+ )
440
447
 
441
448
  def _print_total_statistics(self, border_style: str = "red") -> None:
442
449
  success_icon = "✅" if self.workflow_success else "❌"
@@ -475,7 +482,9 @@ class AIAgentDebugger:
475
482
  f"{total_fixes}/{total_issues} issues resolved",
476
483
  )
477
484
 
478
- self.console.print(table)
485
+ self.console.print(
486
+ Panel(table, title="Total Workflow Statistics", border_style=border_style)
487
+ )
479
488
 
480
489
  def _print_mcp_operation_breakdown(self, border_style: str = "red") -> None:
481
490
  tool_stats = {}
@@ -510,7 +519,9 @@ class AIAgentDebugger:
510
519
  f"{avg_duration: .2f}s" if avg_duration > 0 else "N / A",
511
520
  )
512
521
 
513
- self.console.print(table)
522
+ self.console.print(
523
+ Panel(table, title="MCP Tool Usage", border_style=border_style)
524
+ )
514
525
 
515
526
  def log_iteration_start(self, iteration_number: int) -> None:
516
527
  if not self.enabled:
@@ -67,10 +67,10 @@ class DependencyEdge:
67
67
  class DependencyGraph:
68
68
  """Complete dependency graph data structure."""
69
69
 
70
- nodes: dict[str, DependencyNode] = field(default_factory=dict[str, t.Any])
70
+ nodes: dict[str, DependencyNode] = field(default_factory=dict)
71
71
  edges: list[DependencyEdge] = field(default_factory=list)
72
- clusters: dict[str, list[str]] = field(default_factory=dict[str, t.Any])
73
- metrics: dict[str, t.Any] = field(default_factory=dict[str, t.Any])
72
+ clusters: dict[str, list[str]] = field(default_factory=dict)
73
+ metrics: dict[str, t.Any] = field(default_factory=dict)
74
74
  generated_at: datetime = field(default_factory=datetime.now)
75
75
 
76
76
  def to_dict(self) -> dict[str, t.Any]:
@@ -193,7 +193,7 @@ class DependencyAnalyzer:
193
193
  edges = self.dependency_graph.edges
194
194
 
195
195
  # Basic metrics
196
- metrics = {
196
+ metrics: dict[str, t.Any] = {
197
197
  "total_nodes": len(nodes),
198
198
  "total_edges": len(edges),
199
199
  "total_clusters": len(self.dependency_graph.clusters),
@@ -68,8 +68,12 @@ class DependencyMonitorService:
68
68
 
69
69
  def _parse_dependencies(self) -> dict[str, str]:
70
70
  try:
71
- with self.pyproject_path.open("rb") as f:
72
- data = tomllib.load(f)
71
+ content = self.filesystem.read_file(self.pyproject_path)
72
+ if isinstance(content, bytes):
73
+ content_str = content.decode("utf-8")
74
+ else:
75
+ content_str = content
76
+ data = tomllib.loads(content_str)
73
77
 
74
78
  dependencies: dict[str, str] = {}
75
79
  project_data = data.get("project", {})
@@ -357,8 +361,7 @@ class DependencyMonitorService:
357
361
 
358
362
  cached_data = cache[cache_key]
359
363
  cache_age = current_time - cached_data["timestamp"]
360
- is_fresh: bool = cache_age < 86400
361
- return is_fresh
364
+ return cache_age < 86400
362
365
 
363
366
  def _create_major_update_from_cache(
364
367
  self,
@@ -452,13 +455,13 @@ class DependencyMonitorService:
452
455
 
453
456
  import requests
454
457
 
455
- url = f"https://pypi.org/pypi/{package}/json"
458
+ url = f"https: //pypi.org/pypi/{package}/json"
456
459
  self._validate_pypi_url(url)
457
460
 
458
461
  parsed = urlparse(url)
459
462
 
460
463
  if parsed.scheme != "https" or parsed.netloc != "pypi.org":
461
- msg = f"Invalid URL: only https://pypi.org URLs are allowed, got {url}"
464
+ msg = f"Invalid URL: only https: //pypi.org URLs are allowed, got {url}"
462
465
  raise ValueError(msg)
463
466
 
464
467
  response = requests.get(url, timeout=10, verify=True)
@@ -502,8 +505,7 @@ class DependencyMonitorService:
502
505
  def _get_release_date(self, releases: dict[str, t.Any], version: str) -> str:
503
506
  release_info = releases.get(version, [])
504
507
  if release_info:
505
- upload_time: str = release_info[0].get("upload_time", "")
506
- return upload_time
508
+ return release_info[0].get("upload_time", "")
507
509
  return ""
508
510
 
509
511
  def _has_breaking_changes(self, version: str) -> bool:
@@ -536,15 +538,13 @@ class DependencyMonitorService:
536
538
  def _load_update_cache(self) -> dict[str, t.Any]:
537
539
  with suppress(Exception):
538
540
  if self.cache_file.exists():
539
- with self.cache_file.open() as f:
540
- return t.cast(dict[str, t.Any], json.load(f))
541
+ content = self.filesystem.read_file(self.cache_file)
542
+ return t.cast(dict[str, t.Any], json.loads(content))
541
543
  return {}
542
544
 
543
545
  def _save_update_cache(self, cache: dict[str, t.Any]) -> None:
544
546
  with suppress(Exception):
545
- self.cache_file.parent.mkdir(exist_ok=True)
546
- with self.cache_file.open("w") as f:
547
- json.dump(cache, f, indent=2)
547
+ self.filesystem.write_file(self.cache_file, json.dumps(cache))
548
548
 
549
549
  def _report_vulnerabilities(
550
550
  self,
@@ -4,7 +4,8 @@ import typing as t
4
4
  from pathlib import Path
5
5
  from string import Template
6
6
 
7
- from rich.console import Console
7
+ from acb.console import Console
8
+ from acb.depends import Inject, depends
8
9
 
9
10
  from ..models.protocols import DocumentationGeneratorProtocol
10
11
 
@@ -125,7 +126,8 @@ $functions
125
126
  class DocumentationGeneratorImpl(DocumentationGeneratorProtocol):
126
127
  """Implementation of documentation generation from extracted API data."""
127
128
 
128
- def __init__(self, console: Console) -> None:
129
+ @depends.inject
130
+ def __init__(self, console: Inject[Console]) -> None:
129
131
  self.console = console
130
132
  self.renderer = MarkdownTemplateRenderer()
131
133