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,188 @@
1
+ """WebSocket bridge for routing WorkflowEventBus events to connected clients.
2
+
3
+ This module provides the EventBusWebSocketBridge class that connects the
4
+ WorkflowEventBus to WebSocket clients, enabling real-time workflow progress
5
+ updates without polling.
6
+
7
+ Phase 7.3: WebSocket Streaming for Real-Time Updates
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import typing as t
13
+ from collections import defaultdict
14
+
15
+ from acb.depends import Inject, depends
16
+
17
+ from crackerjack.events.workflow_bus import WorkflowEvent, WorkflowEventBus
18
+
19
+ if t.TYPE_CHECKING:
20
+ from acb.actions.events import Event
21
+ from fastapi import WebSocket
22
+
23
+
24
+ @depends.inject
25
+ class EventBusWebSocketBridge:
26
+ """Bridges workflow events to WebSocket clients for real-time updates.
27
+
28
+ This class subscribes to all WorkflowEvent types from the WorkflowEventBus
29
+ and routes them to appropriate WebSocket clients based on job_id.
30
+
31
+ Architecture:
32
+ WorkflowActions → WorkflowEventBus → EventBusWebSocketBridge → WebSocket Clients
33
+
34
+ Usage:
35
+ bridge = EventBusWebSocketBridge(event_bus)
36
+ await bridge.register_client(job_id, websocket)
37
+ # Events automatically routed to client
38
+ await bridge.unregister_client(job_id, websocket)
39
+ """
40
+
41
+ def __init__(
42
+ self,
43
+ event_bus: Inject[WorkflowEventBus] = None,
44
+ ) -> None:
45
+ """Initialize event bridge with WorkflowEventBus.
46
+
47
+ Args:
48
+ event_bus: WorkflowEventBus instance (injected via DI)
49
+ """
50
+ self._event_bus = event_bus
51
+ self._clients: dict[str, list[WebSocket]] = defaultdict(list)
52
+ self._subscription_ids: list[str] = []
53
+
54
+ # Subscribe to all workflow events
55
+ if self._event_bus:
56
+ self._subscribe_to_events()
57
+
58
+ def _subscribe_to_events(self) -> None:
59
+ """Subscribe to all WorkflowEvent types for event routing."""
60
+ for event_type in WorkflowEvent:
61
+ subscription_id = self._event_bus.subscribe(
62
+ event_type,
63
+ self._handle_workflow_event,
64
+ )
65
+ self._subscription_ids.append(subscription_id)
66
+
67
+ async def _handle_workflow_event(self, event: Event) -> None:
68
+ """Handle workflow event and route to appropriate clients.
69
+
70
+ Args:
71
+ event: ACB Event object with workflow event data
72
+ """
73
+ # Extract job_id from event payload
74
+ # Events include step_id in format "action_name_timestamp" or "workflow_id"
75
+ payload = event.payload
76
+ step_id = payload.get("step_id", "")
77
+
78
+ if not step_id:
79
+ # No step_id in payload, skip routing
80
+ return
81
+
82
+ # For now, broadcast to all connected clients
83
+ # In future, could parse step_id to extract workflow_id/job_id for filtering
84
+ all_clients: list[WebSocket] = []
85
+ for clients in self._clients.values():
86
+ all_clients.extend(clients)
87
+
88
+ if not all_clients:
89
+ # No clients connected
90
+ return
91
+
92
+ # Transform event to WebSocket message format
93
+ message = self._transform_event_to_message(event)
94
+
95
+ # Send to all clients
96
+ await self._broadcast_to_clients(all_clients, message)
97
+
98
+ def _transform_event_to_message(self, event: Event) -> dict[str, t.Any]:
99
+ """Transform ACB Event to WebSocket message format.
100
+
101
+ Args:
102
+ event: ACB Event object
103
+
104
+ Returns:
105
+ dict with event_type, data, and timestamp
106
+ """
107
+ return {
108
+ "event_type": event.event_type.value
109
+ if hasattr(event.event_type, "value")
110
+ else str(event.event_type),
111
+ "data": event.payload,
112
+ "timestamp": event.payload.get("timestamp"),
113
+ }
114
+
115
+ async def _broadcast_to_clients(
116
+ self,
117
+ clients: list[WebSocket],
118
+ message: dict[str, t.Any],
119
+ ) -> None:
120
+ """Broadcast message to all clients, removing disconnected ones.
121
+
122
+ Args:
123
+ clients: List of WebSocket clients to send to
124
+ message: Message data to send
125
+ """
126
+ disconnected: list[WebSocket] = []
127
+
128
+ for websocket in clients:
129
+ try:
130
+ await websocket.send_json(message)
131
+ except Exception:
132
+ # Client disconnected, mark for removal
133
+ disconnected.append(websocket)
134
+
135
+ # Remove disconnected clients
136
+ for websocket in disconnected:
137
+ clients.remove(websocket)
138
+
139
+ async def register_client(self, job_id: str, websocket: WebSocket) -> None:
140
+ """Register WebSocket client for job-specific event updates.
141
+
142
+ Args:
143
+ job_id: Job identifier to subscribe to
144
+ websocket: WebSocket connection to send events to
145
+ """
146
+ self._clients[job_id].append(websocket)
147
+
148
+ async def unregister_client(self, job_id: str, websocket: WebSocket) -> None:
149
+ """Unregister WebSocket client from event updates.
150
+
151
+ Args:
152
+ job_id: Job identifier to unsubscribe from
153
+ websocket: WebSocket connection to remove
154
+ """
155
+ if job_id in self._clients:
156
+ with suppress(ValueError):
157
+ self._clients[job_id].remove(websocket)
158
+
159
+ # Clean up empty job client lists
160
+ if not self._clients[job_id]:
161
+ del self._clients[job_id]
162
+
163
+ def get_active_connections(self) -> int:
164
+ """Get count of active WebSocket connections.
165
+
166
+ Returns:
167
+ Total number of active WebSocket connections across all jobs
168
+ """
169
+ return sum(len(clients) for clients in self._clients.values())
170
+
171
+ def get_jobs_with_clients(self) -> list[str]:
172
+ """Get list of job IDs with active clients.
173
+
174
+ Returns:
175
+ List of job_id strings that have connected clients
176
+ """
177
+ return [job_id for job_id, clients in self._clients.items() if clients]
178
+
179
+ def cleanup(self) -> None:
180
+ """Cleanup event subscriptions and client connections."""
181
+ # Unsubscribe from all events
182
+ if self._event_bus:
183
+ for subscription_id in self._subscription_ids:
184
+ self._event_bus.unsubscribe(subscription_id)
185
+
186
+ # Clear client lists
187
+ self._clients.clear()
188
+ self._subscription_ids.clear()
@@ -5,15 +5,23 @@ import typing as t
5
5
  import uuid
6
6
  from contextlib import suppress
7
7
  from pathlib import Path
8
- from typing import Any
8
+ from typing import Any, Final
9
+ from uuid import UUID, uuid4
9
10
 
10
- from rich.console import Console
11
+ from acb import console
12
+ from acb.depends import depends
11
13
 
12
14
  from crackerjack.core.timeout_manager import TimeoutStrategy, get_timeout_manager
13
15
  from crackerjack.services.input_validator import get_input_validator
14
16
  from crackerjack.services.secure_path_utils import SecurePathValidator
15
17
 
16
- console = Console()
18
+ # Phase 9.3: ACB Integration - Module registration for dependency injection
19
+ # Note: Currently using file-based JSON storage for job tracking
20
+ # Future enhancement: Consider ACB SQL adapter for scalability if needed
21
+ MODULE_ID: Final[UUID] = uuid4()
22
+ MODULE_STATUS: Final[str] = "stable"
23
+
24
+ # console imported from acb
17
25
 
18
26
 
19
27
  class JobManager:
@@ -380,4 +388,19 @@ class JobManager:
380
388
 
381
389
  def cleanup(self) -> None:
382
390
  self.is_running = False
383
- console.print("[blue]Job manager cleanup completed[/ blue]")
391
+ console.print("[blue]Job manager cleanup completed[/blue]")
392
+
393
+ @property
394
+ def module_id(self) -> UUID:
395
+ """Reference to module-level MODULE_ID for ACB integration."""
396
+ return MODULE_ID
397
+
398
+ @property
399
+ def module_status(self) -> str:
400
+ """Module status for ACB integration."""
401
+ return MODULE_STATUS
402
+
403
+
404
+ # Phase 9.3: ACB Integration - Register JobManager with dependency injection system
405
+ with suppress(Exception):
406
+ depends.set(JobManager)
@@ -0,0 +1,25 @@
1
+ """Monitoring endpoints module.
2
+
3
+ This module provides WebSocket and REST API endpoints for real-time
4
+ monitoring, metrics streaming, intelligence features, and error analysis.
5
+ """
6
+
7
+ from .factory import create_monitoring_endpoints
8
+ from .models import (
9
+ HealthResponseModel,
10
+ TelemetryEventModel,
11
+ TelemetryResponseModel,
12
+ TelemetrySnapshotModel,
13
+ UnifiedMetricsModel,
14
+ )
15
+ from .websocket_manager import MonitoringWebSocketManager
16
+
17
+ __all__ = [
18
+ "create_monitoring_endpoints",
19
+ "MonitoringWebSocketManager",
20
+ "TelemetryEventModel",
21
+ "TelemetrySnapshotModel",
22
+ "TelemetryResponseModel",
23
+ "UnifiedMetricsModel",
24
+ "HealthResponseModel",
25
+ ]
@@ -0,0 +1,19 @@
1
+ """REST API endpoint registration.
2
+
3
+ This module provides registration functions for all REST API endpoints
4
+ including telemetry, metrics, intelligence, dependencies, and heatmap analysis.
5
+ """
6
+
7
+ from .dependencies import register_dependency_api_endpoints
8
+ from .heatmap import register_heatmap_api_endpoints
9
+ from .intelligence import register_intelligence_api_endpoints
10
+ from .metrics import register_metrics_api_endpoints
11
+ from .telemetry import register_telemetry_api_endpoints
12
+
13
+ __all__ = [
14
+ "register_telemetry_api_endpoints",
15
+ "register_metrics_api_endpoints",
16
+ "register_intelligence_api_endpoints",
17
+ "register_dependency_api_endpoints",
18
+ "register_heatmap_api_endpoints",
19
+ ]
@@ -0,0 +1,141 @@
1
+ """REST API endpoints for dependency analysis.
2
+
3
+ This module provides HTTP endpoints for dependency graph visualization,
4
+ metrics, clustering, and analysis triggers.
5
+ """
6
+
7
+ from datetime import datetime
8
+
9
+ from fastapi import FastAPI, HTTPException
10
+ from fastapi.responses import JSONResponse
11
+
12
+ from crackerjack.services.dependency_analyzer import (
13
+ DependencyAnalyzer,
14
+ DependencyGraph,
15
+ )
16
+
17
+ from ..filters import _apply_graph_filters
18
+
19
+
20
+ def register_dependency_api_endpoints(
21
+ app: FastAPI, dependency_analyzer: DependencyAnalyzer
22
+ ) -> None:
23
+ """Register dependency-related REST API endpoints."""
24
+
25
+ @app.get("/api/dependencies/graph")
26
+ async def get_dependency_graph(
27
+ filter_type: str = None,
28
+ max_nodes: int = 1000,
29
+ include_external: bool = False,
30
+ ) -> None:
31
+ """Get dependency graph data."""
32
+ return await _handle_dependency_graph_request(
33
+ dependency_analyzer, filter_type, max_nodes, include_external
34
+ )
35
+
36
+ @app.get("/api/dependencies/metrics")
37
+ async def get_dependency_metrics() -> None:
38
+ """Get dependency graph metrics."""
39
+ return await _handle_dependency_metrics_request(dependency_analyzer)
40
+
41
+ @app.get("/api/dependencies/clusters")
42
+ async def get_dependency_clusters() -> None:
43
+ """Get dependency graph clusters."""
44
+ return await _handle_dependency_clusters_request(dependency_analyzer)
45
+
46
+ @app.post("/api/dependencies/analyze")
47
+ async def trigger_dependency_analysis(request: dict) -> None:
48
+ """Trigger fresh dependency analysis."""
49
+ return await _handle_dependency_analysis_request(dependency_analyzer, request)
50
+
51
+
52
+ async def _handle_dependency_graph_request(
53
+ dependency_analyzer: DependencyAnalyzer,
54
+ filter_type: str | None,
55
+ max_nodes: int,
56
+ include_external: bool,
57
+ ) -> JSONResponse:
58
+ """Handle dependency graph API request."""
59
+ try:
60
+ graph = dependency_analyzer.analyze_project()
61
+
62
+ # Apply filters if requested
63
+ if filter_type or max_nodes < len(graph.nodes):
64
+ filters = {
65
+ "type": filter_type,
66
+ "max_nodes": max_nodes,
67
+ "include_external": include_external,
68
+ }
69
+ graph = await _apply_graph_filters(graph, filters)
70
+
71
+ return JSONResponse(
72
+ {
73
+ "status": "success",
74
+ "data": graph.to_dict(),
75
+ "timestamp": datetime.now().isoformat(),
76
+ }
77
+ )
78
+ except Exception as e:
79
+ raise HTTPException(status_code=500, detail=str(e))
80
+
81
+
82
+ async def _handle_dependency_metrics_request(
83
+ dependency_analyzer: DependencyAnalyzer,
84
+ ) -> JSONResponse:
85
+ """Handle dependency metrics API request."""
86
+ try:
87
+ graph = dependency_analyzer.analyze_project()
88
+
89
+ return JSONResponse(
90
+ {
91
+ "status": "success",
92
+ "data": graph.metrics,
93
+ "timestamp": datetime.now().isoformat(),
94
+ }
95
+ )
96
+ except Exception as e:
97
+ raise HTTPException(status_code=500, detail=str(e))
98
+
99
+
100
+ async def _handle_dependency_clusters_request(
101
+ dependency_analyzer: DependencyAnalyzer,
102
+ ) -> JSONResponse:
103
+ """Handle dependency clusters API request."""
104
+ try:
105
+ graph = dependency_analyzer.analyze_project()
106
+
107
+ return JSONResponse(
108
+ {
109
+ "status": "success",
110
+ "data": graph.clusters,
111
+ "timestamp": datetime.now().isoformat(),
112
+ }
113
+ )
114
+ except Exception as e:
115
+ raise HTTPException(status_code=500, detail=str(e))
116
+
117
+
118
+ async def _handle_dependency_analysis_request(
119
+ dependency_analyzer: DependencyAnalyzer, request: dict
120
+ ) -> JSONResponse:
121
+ """Handle dependency analysis trigger API request."""
122
+ try:
123
+ # Reset analyzer for fresh analysis
124
+ dependency_analyzer.dependency_graph = DependencyGraph()
125
+ graph = dependency_analyzer.analyze_project()
126
+
127
+ return JSONResponse(
128
+ {
129
+ "status": "success",
130
+ "message": "Dependency analysis completed",
131
+ "data": {
132
+ "nodes": len(graph.nodes),
133
+ "edges": len(graph.edges),
134
+ "clusters": len(graph.clusters),
135
+ "metrics": graph.metrics,
136
+ },
137
+ "timestamp": datetime.now().isoformat(),
138
+ }
139
+ )
140
+ except Exception as e:
141
+ raise HTTPException(status_code=500, detail=str(e))
@@ -0,0 +1,154 @@
1
+ """REST API endpoints for error heatmap analysis.
2
+
3
+ This module provides HTTP endpoints for file-based, temporal, and
4
+ function-based error heatmap visualization and pattern analysis.
5
+ """
6
+
7
+ from datetime import datetime
8
+
9
+ from fastapi import FastAPI, HTTPException
10
+ from fastapi.responses import JSONResponse
11
+
12
+ from crackerjack.services.cache import CrackerjackCache
13
+ from crackerjack.services.monitoring.error_pattern_analyzer import (
14
+ ErrorPatternAnalyzer,
15
+ )
16
+
17
+
18
+ def register_heatmap_api_endpoints(
19
+ app: FastAPI, error_analyzer: ErrorPatternAnalyzer, cache: CrackerjackCache
20
+ ) -> None:
21
+ """Register heatmap-related REST API endpoints."""
22
+
23
+ @app.get("/api/heatmap/file_errors")
24
+ async def get_file_error_heatmap() -> None:
25
+ """Get error heat map by file."""
26
+ return await _handle_file_error_heatmap_request(error_analyzer)
27
+
28
+ @app.get("/api/heatmap/temporal_errors")
29
+ async def get_temporal_error_heatmap(time_buckets: int = 24) -> None:
30
+ """Get error heat map over time."""
31
+ return await _handle_temporal_error_heatmap_request(
32
+ error_analyzer, time_buckets
33
+ )
34
+
35
+ @app.get("/api/heatmap/function_errors")
36
+ async def get_function_error_heatmap() -> None:
37
+ """Get error heat map by function."""
38
+ return await _handle_function_error_heatmap_request(error_analyzer)
39
+
40
+ @app.get("/api/error_patterns")
41
+ async def get_error_patterns(
42
+ days: int = 30, min_occurrences: int = 2, severity: str | None = None
43
+ ) -> None:
44
+ """Get analyzed error patterns."""
45
+ return await _handle_error_patterns_request(
46
+ error_analyzer, days, min_occurrences, severity
47
+ )
48
+
49
+ @app.post("/api/trigger_error_analysis")
50
+ async def trigger_error_analysis(request: dict) -> None:
51
+ """Trigger fresh error pattern analysis."""
52
+ return await _handle_trigger_error_analysis_request(
53
+ error_analyzer, cache, request
54
+ )
55
+
56
+
57
+ async def _handle_file_error_heatmap_request(
58
+ error_analyzer: ErrorPatternAnalyzer,
59
+ ) -> JSONResponse:
60
+ """Handle file error heatmap API request."""
61
+ try:
62
+ error_analyzer.analyze_error_patterns(days=30)
63
+ heatmap = error_analyzer.generate_file_error_heatmap()
64
+ return JSONResponse(heatmap.to_dict())
65
+ except Exception as e:
66
+ raise HTTPException(status_code=500, detail=str(e))
67
+
68
+
69
+ async def _handle_temporal_error_heatmap_request(
70
+ error_analyzer: ErrorPatternAnalyzer, time_buckets: int
71
+ ) -> JSONResponse:
72
+ """Handle temporal error heatmap API request."""
73
+ try:
74
+ error_analyzer.analyze_error_patterns(days=30)
75
+ heatmap = error_analyzer.generate_temporal_heatmap(time_buckets=time_buckets)
76
+ return JSONResponse(heatmap.to_dict())
77
+ except Exception as e:
78
+ raise HTTPException(status_code=500, detail=str(e))
79
+
80
+
81
+ async def _handle_function_error_heatmap_request(
82
+ error_analyzer: ErrorPatternAnalyzer,
83
+ ) -> JSONResponse:
84
+ """Handle function error heatmap API request."""
85
+ try:
86
+ error_analyzer.analyze_error_patterns(days=30)
87
+ heatmap = error_analyzer.generate_function_error_heatmap()
88
+ return JSONResponse(heatmap.to_dict())
89
+ except Exception as e:
90
+ raise HTTPException(status_code=500, detail=str(e))
91
+
92
+
93
+ async def _handle_error_patterns_request(
94
+ error_analyzer: ErrorPatternAnalyzer,
95
+ days: int,
96
+ min_occurrences: int,
97
+ severity: str | None,
98
+ ) -> JSONResponse:
99
+ """Handle error patterns API request."""
100
+ try:
101
+ patterns = error_analyzer.analyze_error_patterns(
102
+ days=days, min_occurrences=min_occurrences
103
+ )
104
+
105
+ # Filter by severity if specified
106
+ if severity:
107
+ patterns = [p for p in patterns if p.severity == severity]
108
+
109
+ return JSONResponse(
110
+ {
111
+ "patterns": [pattern.to_dict() for pattern in patterns],
112
+ "total_count": len(patterns),
113
+ "analysis_period_days": days,
114
+ "generated_at": datetime.now().isoformat(),
115
+ }
116
+ )
117
+ except Exception as e:
118
+ raise HTTPException(status_code=500, detail=str(e))
119
+
120
+
121
+ async def _handle_trigger_error_analysis_request(
122
+ error_analyzer: ErrorPatternAnalyzer, cache: CrackerjackCache, request: dict
123
+ ) -> JSONResponse:
124
+ """Handle trigger error analysis API request."""
125
+ try:
126
+ days = request.get("days", 30)
127
+ min_occurrences = request.get("min_occurrences", 2)
128
+
129
+ # Perform fresh analysis
130
+ patterns = error_analyzer.analyze_error_patterns(
131
+ days=days, min_occurrences=min_occurrences
132
+ )
133
+
134
+ # Store results in cache
135
+ cache_key = f"error_patterns_{days}d"
136
+ cache.set(cache_key, [p.to_dict() for p in patterns], ttl_seconds=1800)
137
+
138
+ severity_breakdown = {
139
+ severity: len([p for p in patterns if p.severity == severity])
140
+ for severity in ("low", "medium", "high", "critical")
141
+ }
142
+
143
+ return JSONResponse(
144
+ {
145
+ "status": "success",
146
+ "message": "Error pattern analysis completed",
147
+ "patterns_found": len(patterns),
148
+ "analysis_period_days": days,
149
+ "severity_breakdown": severity_breakdown,
150
+ "generated_at": datetime.now().isoformat(),
151
+ }
152
+ )
153
+ except Exception as e:
154
+ raise HTTPException(status_code=500, detail=str(e))