crackerjack 0.18.2__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 (533) hide show
  1. crackerjack/README.md +19 -0
  2. crackerjack/__init__.py +96 -2
  3. crackerjack/__main__.py +637 -138
  4. crackerjack/adapters/README.md +18 -0
  5. crackerjack/adapters/__init__.py +39 -0
  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/lsp/_base.py +194 -0
  27. crackerjack/adapters/lsp/_client.py +358 -0
  28. crackerjack/adapters/lsp/_manager.py +193 -0
  29. crackerjack/adapters/lsp/skylos.py +283 -0
  30. crackerjack/adapters/lsp/zuban.py +557 -0
  31. crackerjack/adapters/refactor/README.md +59 -0
  32. crackerjack/adapters/refactor/__init__.py +12 -0
  33. crackerjack/adapters/refactor/creosote.py +318 -0
  34. crackerjack/adapters/refactor/refurb.py +406 -0
  35. crackerjack/adapters/refactor/skylos.py +494 -0
  36. crackerjack/adapters/sast/README.md +132 -0
  37. crackerjack/adapters/sast/__init__.py +32 -0
  38. crackerjack/adapters/sast/_base.py +201 -0
  39. crackerjack/adapters/sast/bandit.py +423 -0
  40. crackerjack/adapters/sast/pyscn.py +405 -0
  41. crackerjack/adapters/sast/semgrep.py +241 -0
  42. crackerjack/adapters/security/README.md +111 -0
  43. crackerjack/adapters/security/__init__.py +17 -0
  44. crackerjack/adapters/security/gitleaks.py +339 -0
  45. crackerjack/adapters/type/README.md +52 -0
  46. crackerjack/adapters/type/__init__.py +12 -0
  47. crackerjack/adapters/type/pyrefly.py +402 -0
  48. crackerjack/adapters/type/ty.py +402 -0
  49. crackerjack/adapters/type/zuban.py +522 -0
  50. crackerjack/adapters/utility/README.md +51 -0
  51. crackerjack/adapters/utility/__init__.py +10 -0
  52. crackerjack/adapters/utility/checks.py +884 -0
  53. crackerjack/agents/README.md +264 -0
  54. crackerjack/agents/__init__.py +66 -0
  55. crackerjack/agents/architect_agent.py +238 -0
  56. crackerjack/agents/base.py +167 -0
  57. crackerjack/agents/claude_code_bridge.py +641 -0
  58. crackerjack/agents/coordinator.py +600 -0
  59. crackerjack/agents/documentation_agent.py +520 -0
  60. crackerjack/agents/dry_agent.py +585 -0
  61. crackerjack/agents/enhanced_coordinator.py +279 -0
  62. crackerjack/agents/enhanced_proactive_agent.py +185 -0
  63. crackerjack/agents/error_middleware.py +53 -0
  64. crackerjack/agents/formatting_agent.py +230 -0
  65. crackerjack/agents/helpers/__init__.py +9 -0
  66. crackerjack/agents/helpers/performance/__init__.py +22 -0
  67. crackerjack/agents/helpers/performance/performance_ast_analyzer.py +357 -0
  68. crackerjack/agents/helpers/performance/performance_pattern_detector.py +909 -0
  69. crackerjack/agents/helpers/performance/performance_recommender.py +572 -0
  70. crackerjack/agents/helpers/refactoring/__init__.py +22 -0
  71. crackerjack/agents/helpers/refactoring/code_transformer.py +536 -0
  72. crackerjack/agents/helpers/refactoring/complexity_analyzer.py +344 -0
  73. crackerjack/agents/helpers/refactoring/dead_code_detector.py +437 -0
  74. crackerjack/agents/helpers/test_creation/__init__.py +19 -0
  75. crackerjack/agents/helpers/test_creation/test_ast_analyzer.py +216 -0
  76. crackerjack/agents/helpers/test_creation/test_coverage_analyzer.py +643 -0
  77. crackerjack/agents/helpers/test_creation/test_template_generator.py +1031 -0
  78. crackerjack/agents/import_optimization_agent.py +1181 -0
  79. crackerjack/agents/performance_agent.py +325 -0
  80. crackerjack/agents/performance_helpers.py +205 -0
  81. crackerjack/agents/proactive_agent.py +55 -0
  82. crackerjack/agents/refactoring_agent.py +511 -0
  83. crackerjack/agents/refactoring_helpers.py +247 -0
  84. crackerjack/agents/security_agent.py +793 -0
  85. crackerjack/agents/semantic_agent.py +479 -0
  86. crackerjack/agents/semantic_helpers.py +356 -0
  87. crackerjack/agents/test_creation_agent.py +570 -0
  88. crackerjack/agents/test_specialist_agent.py +526 -0
  89. crackerjack/agents/tracker.py +110 -0
  90. crackerjack/api.py +647 -0
  91. crackerjack/cli/README.md +394 -0
  92. crackerjack/cli/__init__.py +24 -0
  93. crackerjack/cli/cache_handlers.py +209 -0
  94. crackerjack/cli/cache_handlers_enhanced.py +680 -0
  95. crackerjack/cli/facade.py +162 -0
  96. crackerjack/cli/formatting.py +13 -0
  97. crackerjack/cli/handlers/__init__.py +85 -0
  98. crackerjack/cli/handlers/advanced.py +103 -0
  99. crackerjack/cli/handlers/ai_features.py +62 -0
  100. crackerjack/cli/handlers/analytics.py +479 -0
  101. crackerjack/cli/handlers/changelog.py +271 -0
  102. crackerjack/cli/handlers/config_handlers.py +16 -0
  103. crackerjack/cli/handlers/coverage.py +84 -0
  104. crackerjack/cli/handlers/documentation.py +280 -0
  105. crackerjack/cli/handlers/main_handlers.py +497 -0
  106. crackerjack/cli/handlers/monitoring.py +371 -0
  107. crackerjack/cli/handlers.py +700 -0
  108. crackerjack/cli/interactive.py +488 -0
  109. crackerjack/cli/options.py +1216 -0
  110. crackerjack/cli/semantic_handlers.py +292 -0
  111. crackerjack/cli/utils.py +19 -0
  112. crackerjack/cli/version.py +19 -0
  113. crackerjack/code_cleaner.py +1307 -0
  114. crackerjack/config/README.md +472 -0
  115. crackerjack/config/__init__.py +275 -0
  116. crackerjack/config/global_lock_config.py +207 -0
  117. crackerjack/config/hooks.py +390 -0
  118. crackerjack/config/loader.py +239 -0
  119. crackerjack/config/settings.py +141 -0
  120. crackerjack/config/tool_commands.py +331 -0
  121. crackerjack/core/README.md +393 -0
  122. crackerjack/core/__init__.py +0 -0
  123. crackerjack/core/async_workflow_orchestrator.py +738 -0
  124. crackerjack/core/autofix_coordinator.py +282 -0
  125. crackerjack/core/container.py +105 -0
  126. crackerjack/core/enhanced_container.py +583 -0
  127. crackerjack/core/file_lifecycle.py +472 -0
  128. crackerjack/core/performance.py +244 -0
  129. crackerjack/core/performance_monitor.py +357 -0
  130. crackerjack/core/phase_coordinator.py +1227 -0
  131. crackerjack/core/proactive_workflow.py +267 -0
  132. crackerjack/core/resource_manager.py +425 -0
  133. crackerjack/core/retry.py +275 -0
  134. crackerjack/core/service_watchdog.py +601 -0
  135. crackerjack/core/session_coordinator.py +239 -0
  136. crackerjack/core/timeout_manager.py +563 -0
  137. crackerjack/core/websocket_lifecycle.py +410 -0
  138. crackerjack/core/workflow/__init__.py +21 -0
  139. crackerjack/core/workflow/workflow_ai_coordinator.py +863 -0
  140. crackerjack/core/workflow/workflow_event_orchestrator.py +1107 -0
  141. crackerjack/core/workflow/workflow_issue_parser.py +714 -0
  142. crackerjack/core/workflow/workflow_phase_executor.py +1158 -0
  143. crackerjack/core/workflow/workflow_security_gates.py +400 -0
  144. crackerjack/core/workflow_orchestrator.py +2243 -0
  145. crackerjack/data/README.md +11 -0
  146. crackerjack/data/__init__.py +8 -0
  147. crackerjack/data/models.py +79 -0
  148. crackerjack/data/repository.py +210 -0
  149. crackerjack/decorators/README.md +180 -0
  150. crackerjack/decorators/__init__.py +35 -0
  151. crackerjack/decorators/error_handling.py +649 -0
  152. crackerjack/decorators/error_handling_decorators.py +334 -0
  153. crackerjack/decorators/helpers.py +58 -0
  154. crackerjack/decorators/patterns.py +281 -0
  155. crackerjack/decorators/utils.py +58 -0
  156. crackerjack/docs/INDEX.md +11 -0
  157. crackerjack/docs/README.md +11 -0
  158. crackerjack/docs/generated/api/API_REFERENCE.md +10895 -0
  159. crackerjack/docs/generated/api/CLI_REFERENCE.md +109 -0
  160. crackerjack/docs/generated/api/CROSS_REFERENCES.md +1755 -0
  161. crackerjack/docs/generated/api/PROTOCOLS.md +3 -0
  162. crackerjack/docs/generated/api/SERVICES.md +1252 -0
  163. crackerjack/documentation/README.md +11 -0
  164. crackerjack/documentation/__init__.py +31 -0
  165. crackerjack/documentation/ai_templates.py +756 -0
  166. crackerjack/documentation/dual_output_generator.py +767 -0
  167. crackerjack/documentation/mkdocs_integration.py +518 -0
  168. crackerjack/documentation/reference_generator.py +1065 -0
  169. crackerjack/dynamic_config.py +678 -0
  170. crackerjack/errors.py +378 -0
  171. crackerjack/events/README.md +11 -0
  172. crackerjack/events/__init__.py +16 -0
  173. crackerjack/events/telemetry.py +175 -0
  174. crackerjack/events/workflow_bus.py +346 -0
  175. crackerjack/exceptions/README.md +301 -0
  176. crackerjack/exceptions/__init__.py +5 -0
  177. crackerjack/exceptions/config.py +4 -0
  178. crackerjack/exceptions/tool_execution_error.py +245 -0
  179. crackerjack/executors/README.md +591 -0
  180. crackerjack/executors/__init__.py +13 -0
  181. crackerjack/executors/async_hook_executor.py +938 -0
  182. crackerjack/executors/cached_hook_executor.py +316 -0
  183. crackerjack/executors/hook_executor.py +1295 -0
  184. crackerjack/executors/hook_lock_manager.py +708 -0
  185. crackerjack/executors/individual_hook_executor.py +739 -0
  186. crackerjack/executors/lsp_aware_hook_executor.py +349 -0
  187. crackerjack/executors/progress_hook_executor.py +282 -0
  188. crackerjack/executors/tool_proxy.py +433 -0
  189. crackerjack/hooks/README.md +485 -0
  190. crackerjack/hooks/lsp_hook.py +93 -0
  191. crackerjack/intelligence/README.md +557 -0
  192. crackerjack/intelligence/__init__.py +37 -0
  193. crackerjack/intelligence/adaptive_learning.py +693 -0
  194. crackerjack/intelligence/agent_orchestrator.py +485 -0
  195. crackerjack/intelligence/agent_registry.py +377 -0
  196. crackerjack/intelligence/agent_selector.py +439 -0
  197. crackerjack/intelligence/integration.py +250 -0
  198. crackerjack/interactive.py +719 -0
  199. crackerjack/managers/README.md +369 -0
  200. crackerjack/managers/__init__.py +11 -0
  201. crackerjack/managers/async_hook_manager.py +135 -0
  202. crackerjack/managers/hook_manager.py +585 -0
  203. crackerjack/managers/publish_manager.py +631 -0
  204. crackerjack/managers/test_command_builder.py +391 -0
  205. crackerjack/managers/test_executor.py +474 -0
  206. crackerjack/managers/test_manager.py +1357 -0
  207. crackerjack/managers/test_progress.py +187 -0
  208. crackerjack/mcp/README.md +374 -0
  209. crackerjack/mcp/__init__.py +0 -0
  210. crackerjack/mcp/cache.py +352 -0
  211. crackerjack/mcp/client_runner.py +121 -0
  212. crackerjack/mcp/context.py +802 -0
  213. crackerjack/mcp/dashboard.py +657 -0
  214. crackerjack/mcp/enhanced_progress_monitor.py +493 -0
  215. crackerjack/mcp/file_monitor.py +394 -0
  216. crackerjack/mcp/progress_components.py +607 -0
  217. crackerjack/mcp/progress_monitor.py +1016 -0
  218. crackerjack/mcp/rate_limiter.py +336 -0
  219. crackerjack/mcp/server.py +24 -0
  220. crackerjack/mcp/server_core.py +526 -0
  221. crackerjack/mcp/service_watchdog.py +505 -0
  222. crackerjack/mcp/state.py +407 -0
  223. crackerjack/mcp/task_manager.py +259 -0
  224. crackerjack/mcp/tools/README.md +27 -0
  225. crackerjack/mcp/tools/__init__.py +19 -0
  226. crackerjack/mcp/tools/core_tools.py +469 -0
  227. crackerjack/mcp/tools/error_analyzer.py +283 -0
  228. crackerjack/mcp/tools/execution_tools.py +384 -0
  229. crackerjack/mcp/tools/intelligence_tool_registry.py +46 -0
  230. crackerjack/mcp/tools/intelligence_tools.py +264 -0
  231. crackerjack/mcp/tools/monitoring_tools.py +628 -0
  232. crackerjack/mcp/tools/proactive_tools.py +367 -0
  233. crackerjack/mcp/tools/progress_tools.py +222 -0
  234. crackerjack/mcp/tools/semantic_tools.py +584 -0
  235. crackerjack/mcp/tools/utility_tools.py +358 -0
  236. crackerjack/mcp/tools/workflow_executor.py +699 -0
  237. crackerjack/mcp/websocket/README.md +31 -0
  238. crackerjack/mcp/websocket/__init__.py +14 -0
  239. crackerjack/mcp/websocket/app.py +54 -0
  240. crackerjack/mcp/websocket/endpoints.py +492 -0
  241. crackerjack/mcp/websocket/event_bridge.py +188 -0
  242. crackerjack/mcp/websocket/jobs.py +406 -0
  243. crackerjack/mcp/websocket/monitoring/__init__.py +25 -0
  244. crackerjack/mcp/websocket/monitoring/api/__init__.py +19 -0
  245. crackerjack/mcp/websocket/monitoring/api/dependencies.py +141 -0
  246. crackerjack/mcp/websocket/monitoring/api/heatmap.py +154 -0
  247. crackerjack/mcp/websocket/monitoring/api/intelligence.py +199 -0
  248. crackerjack/mcp/websocket/monitoring/api/metrics.py +203 -0
  249. crackerjack/mcp/websocket/monitoring/api/telemetry.py +101 -0
  250. crackerjack/mcp/websocket/monitoring/dashboard.py +18 -0
  251. crackerjack/mcp/websocket/monitoring/factory.py +109 -0
  252. crackerjack/mcp/websocket/monitoring/filters.py +10 -0
  253. crackerjack/mcp/websocket/monitoring/metrics.py +64 -0
  254. crackerjack/mcp/websocket/monitoring/models.py +90 -0
  255. crackerjack/mcp/websocket/monitoring/utils.py +171 -0
  256. crackerjack/mcp/websocket/monitoring/websocket_manager.py +78 -0
  257. crackerjack/mcp/websocket/monitoring/websockets/__init__.py +17 -0
  258. crackerjack/mcp/websocket/monitoring/websockets/dependencies.py +126 -0
  259. crackerjack/mcp/websocket/monitoring/websockets/heatmap.py +176 -0
  260. crackerjack/mcp/websocket/monitoring/websockets/intelligence.py +291 -0
  261. crackerjack/mcp/websocket/monitoring/websockets/metrics.py +291 -0
  262. crackerjack/mcp/websocket/monitoring_endpoints.py +21 -0
  263. crackerjack/mcp/websocket/server.py +174 -0
  264. crackerjack/mcp/websocket/websocket_handler.py +276 -0
  265. crackerjack/mcp/websocket_server.py +10 -0
  266. crackerjack/models/README.md +308 -0
  267. crackerjack/models/__init__.py +40 -0
  268. crackerjack/models/config.py +730 -0
  269. crackerjack/models/config_adapter.py +265 -0
  270. crackerjack/models/protocols.py +1535 -0
  271. crackerjack/models/pydantic_models.py +320 -0
  272. crackerjack/models/qa_config.py +145 -0
  273. crackerjack/models/qa_results.py +134 -0
  274. crackerjack/models/resource_protocols.py +299 -0
  275. crackerjack/models/results.py +35 -0
  276. crackerjack/models/semantic_models.py +258 -0
  277. crackerjack/models/task.py +173 -0
  278. crackerjack/models/test_models.py +60 -0
  279. crackerjack/monitoring/README.md +11 -0
  280. crackerjack/monitoring/__init__.py +0 -0
  281. crackerjack/monitoring/ai_agent_watchdog.py +405 -0
  282. crackerjack/monitoring/metrics_collector.py +427 -0
  283. crackerjack/monitoring/regression_prevention.py +580 -0
  284. crackerjack/monitoring/websocket_server.py +406 -0
  285. crackerjack/orchestration/README.md +340 -0
  286. crackerjack/orchestration/__init__.py +43 -0
  287. crackerjack/orchestration/advanced_orchestrator.py +894 -0
  288. crackerjack/orchestration/cache/README.md +312 -0
  289. crackerjack/orchestration/cache/__init__.py +37 -0
  290. crackerjack/orchestration/cache/memory_cache.py +338 -0
  291. crackerjack/orchestration/cache/tool_proxy_cache.py +340 -0
  292. crackerjack/orchestration/config.py +297 -0
  293. crackerjack/orchestration/coverage_improvement.py +180 -0
  294. crackerjack/orchestration/execution_strategies.py +361 -0
  295. crackerjack/orchestration/hook_orchestrator.py +1398 -0
  296. crackerjack/orchestration/strategies/README.md +401 -0
  297. crackerjack/orchestration/strategies/__init__.py +39 -0
  298. crackerjack/orchestration/strategies/adaptive_strategy.py +630 -0
  299. crackerjack/orchestration/strategies/parallel_strategy.py +237 -0
  300. crackerjack/orchestration/strategies/sequential_strategy.py +299 -0
  301. crackerjack/orchestration/test_progress_streamer.py +647 -0
  302. crackerjack/plugins/README.md +11 -0
  303. crackerjack/plugins/__init__.py +15 -0
  304. crackerjack/plugins/base.py +200 -0
  305. crackerjack/plugins/hooks.py +254 -0
  306. crackerjack/plugins/loader.py +335 -0
  307. crackerjack/plugins/managers.py +264 -0
  308. crackerjack/py313.py +191 -0
  309. crackerjack/security/README.md +11 -0
  310. crackerjack/security/__init__.py +0 -0
  311. crackerjack/security/audit.py +197 -0
  312. crackerjack/services/README.md +374 -0
  313. crackerjack/services/__init__.py +9 -0
  314. crackerjack/services/ai/README.md +295 -0
  315. crackerjack/services/ai/__init__.py +7 -0
  316. crackerjack/services/ai/advanced_optimizer.py +878 -0
  317. crackerjack/services/ai/contextual_ai_assistant.py +542 -0
  318. crackerjack/services/ai/embeddings.py +444 -0
  319. crackerjack/services/ai/intelligent_commit.py +328 -0
  320. crackerjack/services/ai/predictive_analytics.py +510 -0
  321. crackerjack/services/anomaly_detector.py +392 -0
  322. crackerjack/services/api_extractor.py +617 -0
  323. crackerjack/services/backup_service.py +467 -0
  324. crackerjack/services/bounded_status_operations.py +530 -0
  325. crackerjack/services/cache.py +369 -0
  326. crackerjack/services/changelog_automation.py +399 -0
  327. crackerjack/services/command_execution_service.py +305 -0
  328. crackerjack/services/config_integrity.py +132 -0
  329. crackerjack/services/config_merge.py +546 -0
  330. crackerjack/services/config_service.py +198 -0
  331. crackerjack/services/config_template.py +493 -0
  332. crackerjack/services/coverage_badge_service.py +173 -0
  333. crackerjack/services/coverage_ratchet.py +381 -0
  334. crackerjack/services/debug.py +733 -0
  335. crackerjack/services/dependency_analyzer.py +460 -0
  336. crackerjack/services/dependency_monitor.py +622 -0
  337. crackerjack/services/documentation_generator.py +493 -0
  338. crackerjack/services/documentation_service.py +704 -0
  339. crackerjack/services/enhanced_filesystem.py +497 -0
  340. crackerjack/services/enterprise_optimizer.py +865 -0
  341. crackerjack/services/error_pattern_analyzer.py +676 -0
  342. crackerjack/services/file_filter.py +221 -0
  343. crackerjack/services/file_hasher.py +149 -0
  344. crackerjack/services/file_io_service.py +361 -0
  345. crackerjack/services/file_modifier.py +615 -0
  346. crackerjack/services/filesystem.py +381 -0
  347. crackerjack/services/git.py +422 -0
  348. crackerjack/services/health_metrics.py +615 -0
  349. crackerjack/services/heatmap_generator.py +744 -0
  350. crackerjack/services/incremental_executor.py +380 -0
  351. crackerjack/services/initialization.py +823 -0
  352. crackerjack/services/input_validator.py +668 -0
  353. crackerjack/services/intelligent_commit.py +327 -0
  354. crackerjack/services/log_manager.py +289 -0
  355. crackerjack/services/logging.py +228 -0
  356. crackerjack/services/lsp_client.py +628 -0
  357. crackerjack/services/memory_optimizer.py +414 -0
  358. crackerjack/services/metrics.py +587 -0
  359. crackerjack/services/monitoring/README.md +30 -0
  360. crackerjack/services/monitoring/__init__.py +9 -0
  361. crackerjack/services/monitoring/dependency_monitor.py +678 -0
  362. crackerjack/services/monitoring/error_pattern_analyzer.py +676 -0
  363. crackerjack/services/monitoring/health_metrics.py +716 -0
  364. crackerjack/services/monitoring/metrics.py +587 -0
  365. crackerjack/services/monitoring/performance_benchmarks.py +410 -0
  366. crackerjack/services/monitoring/performance_cache.py +388 -0
  367. crackerjack/services/monitoring/performance_monitor.py +569 -0
  368. crackerjack/services/parallel_executor.py +527 -0
  369. crackerjack/services/pattern_cache.py +333 -0
  370. crackerjack/services/pattern_detector.py +478 -0
  371. crackerjack/services/patterns/__init__.py +142 -0
  372. crackerjack/services/patterns/agents.py +107 -0
  373. crackerjack/services/patterns/code/__init__.py +15 -0
  374. crackerjack/services/patterns/code/detection.py +118 -0
  375. crackerjack/services/patterns/code/imports.py +107 -0
  376. crackerjack/services/patterns/code/paths.py +159 -0
  377. crackerjack/services/patterns/code/performance.py +119 -0
  378. crackerjack/services/patterns/code/replacement.py +36 -0
  379. crackerjack/services/patterns/core.py +212 -0
  380. crackerjack/services/patterns/documentation/__init__.py +14 -0
  381. crackerjack/services/patterns/documentation/badges_markdown.py +96 -0
  382. crackerjack/services/patterns/documentation/comments_blocks.py +83 -0
  383. crackerjack/services/patterns/documentation/docstrings.py +89 -0
  384. crackerjack/services/patterns/formatting.py +226 -0
  385. crackerjack/services/patterns/operations.py +339 -0
  386. crackerjack/services/patterns/security/__init__.py +23 -0
  387. crackerjack/services/patterns/security/code_injection.py +122 -0
  388. crackerjack/services/patterns/security/credentials.py +190 -0
  389. crackerjack/services/patterns/security/path_traversal.py +221 -0
  390. crackerjack/services/patterns/security/unsafe_operations.py +216 -0
  391. crackerjack/services/patterns/templates.py +62 -0
  392. crackerjack/services/patterns/testing/__init__.py +18 -0
  393. crackerjack/services/patterns/testing/error_patterns.py +107 -0
  394. crackerjack/services/patterns/testing/pytest_output.py +126 -0
  395. crackerjack/services/patterns/tool_output/__init__.py +16 -0
  396. crackerjack/services/patterns/tool_output/bandit.py +72 -0
  397. crackerjack/services/patterns/tool_output/other.py +97 -0
  398. crackerjack/services/patterns/tool_output/pyright.py +67 -0
  399. crackerjack/services/patterns/tool_output/ruff.py +44 -0
  400. crackerjack/services/patterns/url_sanitization.py +114 -0
  401. crackerjack/services/patterns/utilities.py +42 -0
  402. crackerjack/services/patterns/utils.py +339 -0
  403. crackerjack/services/patterns/validation.py +46 -0
  404. crackerjack/services/patterns/versioning.py +62 -0
  405. crackerjack/services/predictive_analytics.py +523 -0
  406. crackerjack/services/profiler.py +280 -0
  407. crackerjack/services/quality/README.md +415 -0
  408. crackerjack/services/quality/__init__.py +11 -0
  409. crackerjack/services/quality/anomaly_detector.py +392 -0
  410. crackerjack/services/quality/pattern_cache.py +333 -0
  411. crackerjack/services/quality/pattern_detector.py +479 -0
  412. crackerjack/services/quality/qa_orchestrator.py +491 -0
  413. crackerjack/services/quality/quality_baseline.py +395 -0
  414. crackerjack/services/quality/quality_baseline_enhanced.py +649 -0
  415. crackerjack/services/quality/quality_intelligence.py +949 -0
  416. crackerjack/services/regex_patterns.py +58 -0
  417. crackerjack/services/regex_utils.py +483 -0
  418. crackerjack/services/secure_path_utils.py +524 -0
  419. crackerjack/services/secure_status_formatter.py +450 -0
  420. crackerjack/services/secure_subprocess.py +635 -0
  421. crackerjack/services/security.py +239 -0
  422. crackerjack/services/security_logger.py +495 -0
  423. crackerjack/services/server_manager.py +411 -0
  424. crackerjack/services/smart_scheduling.py +167 -0
  425. crackerjack/services/status_authentication.py +460 -0
  426. crackerjack/services/status_security_manager.py +315 -0
  427. crackerjack/services/terminal_utils.py +0 -0
  428. crackerjack/services/thread_safe_status_collector.py +441 -0
  429. crackerjack/services/tool_filter.py +368 -0
  430. crackerjack/services/tool_version_service.py +43 -0
  431. crackerjack/services/unified_config.py +115 -0
  432. crackerjack/services/validation_rate_limiter.py +220 -0
  433. crackerjack/services/vector_store.py +689 -0
  434. crackerjack/services/version_analyzer.py +461 -0
  435. crackerjack/services/version_checker.py +223 -0
  436. crackerjack/services/websocket_resource_limiter.py +438 -0
  437. crackerjack/services/zuban_lsp_service.py +391 -0
  438. crackerjack/slash_commands/README.md +11 -0
  439. crackerjack/slash_commands/__init__.py +59 -0
  440. crackerjack/slash_commands/init.md +112 -0
  441. crackerjack/slash_commands/run.md +197 -0
  442. crackerjack/slash_commands/status.md +127 -0
  443. crackerjack/tools/README.md +11 -0
  444. crackerjack/tools/__init__.py +30 -0
  445. crackerjack/tools/_git_utils.py +105 -0
  446. crackerjack/tools/check_added_large_files.py +139 -0
  447. crackerjack/tools/check_ast.py +105 -0
  448. crackerjack/tools/check_json.py +103 -0
  449. crackerjack/tools/check_jsonschema.py +297 -0
  450. crackerjack/tools/check_toml.py +103 -0
  451. crackerjack/tools/check_yaml.py +110 -0
  452. crackerjack/tools/codespell_wrapper.py +72 -0
  453. crackerjack/tools/end_of_file_fixer.py +202 -0
  454. crackerjack/tools/format_json.py +128 -0
  455. crackerjack/tools/mdformat_wrapper.py +114 -0
  456. crackerjack/tools/trailing_whitespace.py +198 -0
  457. crackerjack/tools/validate_input_validator_patterns.py +236 -0
  458. crackerjack/tools/validate_regex_patterns.py +188 -0
  459. crackerjack/ui/README.md +11 -0
  460. crackerjack/ui/__init__.py +1 -0
  461. crackerjack/ui/dashboard_renderer.py +28 -0
  462. crackerjack/ui/templates/README.md +11 -0
  463. crackerjack/utils/console_utils.py +13 -0
  464. crackerjack/utils/dependency_guard.py +230 -0
  465. crackerjack/utils/retry_utils.py +275 -0
  466. crackerjack/workflows/README.md +590 -0
  467. crackerjack/workflows/__init__.py +46 -0
  468. crackerjack/workflows/actions.py +811 -0
  469. crackerjack/workflows/auto_fix.py +444 -0
  470. crackerjack/workflows/container_builder.py +499 -0
  471. crackerjack/workflows/definitions.py +443 -0
  472. crackerjack/workflows/engine.py +177 -0
  473. crackerjack/workflows/event_bridge.py +242 -0
  474. crackerjack-0.45.2.dist-info/METADATA +1678 -0
  475. crackerjack-0.45.2.dist-info/RECORD +478 -0
  476. {crackerjack-0.18.2.dist-info → crackerjack-0.45.2.dist-info}/WHEEL +1 -1
  477. crackerjack-0.45.2.dist-info/entry_points.txt +2 -0
  478. crackerjack/.gitignore +0 -14
  479. crackerjack/.libcst.codemod.yaml +0 -18
  480. crackerjack/.pdm.toml +0 -1
  481. crackerjack/.pre-commit-config.yaml +0 -91
  482. crackerjack/.pytest_cache/.gitignore +0 -2
  483. crackerjack/.pytest_cache/CACHEDIR.TAG +0 -4
  484. crackerjack/.pytest_cache/README.md +0 -8
  485. crackerjack/.pytest_cache/v/cache/nodeids +0 -1
  486. crackerjack/.pytest_cache/v/cache/stepwise +0 -1
  487. crackerjack/.ruff_cache/.gitignore +0 -1
  488. crackerjack/.ruff_cache/0.1.11/3256171999636029978 +0 -0
  489. crackerjack/.ruff_cache/0.1.14/602324811142551221 +0 -0
  490. crackerjack/.ruff_cache/0.1.4/10355199064880463147 +0 -0
  491. crackerjack/.ruff_cache/0.1.6/15140459877605758699 +0 -0
  492. crackerjack/.ruff_cache/0.1.7/1790508110482614856 +0 -0
  493. crackerjack/.ruff_cache/0.1.9/17041001205004563469 +0 -0
  494. crackerjack/.ruff_cache/0.11.2/4070660268492669020 +0 -0
  495. crackerjack/.ruff_cache/0.11.3/9818742842212983150 +0 -0
  496. crackerjack/.ruff_cache/0.11.4/9818742842212983150 +0 -0
  497. crackerjack/.ruff_cache/0.11.6/3557596832929915217 +0 -0
  498. crackerjack/.ruff_cache/0.11.7/10386934055395314831 +0 -0
  499. crackerjack/.ruff_cache/0.11.7/3557596832929915217 +0 -0
  500. crackerjack/.ruff_cache/0.11.8/530407680854991027 +0 -0
  501. crackerjack/.ruff_cache/0.2.0/10047773857155985907 +0 -0
  502. crackerjack/.ruff_cache/0.2.1/8522267973936635051 +0 -0
  503. crackerjack/.ruff_cache/0.2.2/18053836298936336950 +0 -0
  504. crackerjack/.ruff_cache/0.3.0/12548816621480535786 +0 -0
  505. crackerjack/.ruff_cache/0.3.3/11081883392474770722 +0 -0
  506. crackerjack/.ruff_cache/0.3.4/676973378459347183 +0 -0
  507. crackerjack/.ruff_cache/0.3.5/16311176246009842383 +0 -0
  508. crackerjack/.ruff_cache/0.5.7/1493622539551733492 +0 -0
  509. crackerjack/.ruff_cache/0.5.7/6231957614044513175 +0 -0
  510. crackerjack/.ruff_cache/0.5.7/9932762556785938009 +0 -0
  511. crackerjack/.ruff_cache/0.6.0/11982804814124138945 +0 -0
  512. crackerjack/.ruff_cache/0.6.0/12055761203849489982 +0 -0
  513. crackerjack/.ruff_cache/0.6.2/1206147804896221174 +0 -0
  514. crackerjack/.ruff_cache/0.6.4/1206147804896221174 +0 -0
  515. crackerjack/.ruff_cache/0.6.5/1206147804896221174 +0 -0
  516. crackerjack/.ruff_cache/0.6.7/3657366982708166874 +0 -0
  517. crackerjack/.ruff_cache/0.6.9/285614542852677309 +0 -0
  518. crackerjack/.ruff_cache/0.7.1/1024065805990144819 +0 -0
  519. crackerjack/.ruff_cache/0.7.1/285614542852677309 +0 -0
  520. crackerjack/.ruff_cache/0.7.3/16061516852537040135 +0 -0
  521. crackerjack/.ruff_cache/0.8.4/16354268377385700367 +0 -0
  522. crackerjack/.ruff_cache/0.9.10/12813592349865671909 +0 -0
  523. crackerjack/.ruff_cache/0.9.10/923908772239632759 +0 -0
  524. crackerjack/.ruff_cache/0.9.3/13948373885254993391 +0 -0
  525. crackerjack/.ruff_cache/0.9.9/12813592349865671909 +0 -0
  526. crackerjack/.ruff_cache/0.9.9/8843823720003377982 +0 -0
  527. crackerjack/.ruff_cache/CACHEDIR.TAG +0 -1
  528. crackerjack/crackerjack.py +0 -855
  529. crackerjack/pyproject.toml +0 -214
  530. crackerjack-0.18.2.dist-info/METADATA +0 -420
  531. crackerjack-0.18.2.dist-info/RECORD +0 -59
  532. crackerjack-0.18.2.dist-info/entry_points.txt +0 -4
  533. {crackerjack-0.18.2.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()
@@ -0,0 +1,406 @@
1
+ import asyncio
2
+ import json
3
+ import time
4
+ import typing as t
5
+ import uuid
6
+ from contextlib import suppress
7
+ from pathlib import Path
8
+ from typing import Any, Final
9
+ from uuid import UUID, uuid4
10
+
11
+ from acb import console
12
+ from acb.depends import depends
13
+
14
+ from crackerjack.core.timeout_manager import TimeoutStrategy, get_timeout_manager
15
+ from crackerjack.services.input_validator import get_input_validator
16
+ from crackerjack.services.secure_path_utils import SecurePathValidator
17
+
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
25
+
26
+
27
+ class JobManager:
28
+ def __init__(self, progress_dir: Path) -> None:
29
+ self.progress_dir = SecurePathValidator.validate_safe_path(progress_dir)
30
+ self.active_connections: dict[str, set[Any]] = {}
31
+ self.known_jobs: set[str] = set()
32
+ self.is_running = True
33
+
34
+ self.progress_dir.mkdir(exist_ok=True)
35
+
36
+ def validate_job_id(self, job_id: str) -> bool:
37
+ if not job_id:
38
+ return False
39
+
40
+ with suppress(ValueError):
41
+ uuid.UUID(job_id)
42
+ return True
43
+
44
+ result = get_input_validator().validate_job_id(job_id)
45
+ return result.valid
46
+
47
+ def add_connection(self, job_id: str, websocket: Any) -> None:
48
+ if job_id not in self.active_connections:
49
+ self.active_connections[job_id] = set()
50
+ self.active_connections[job_id].add(websocket)
51
+
52
+ def remove_connection(self, job_id: str, websocket: Any) -> None:
53
+ if job_id in self.active_connections:
54
+ self.active_connections[job_id].discard(websocket)
55
+ if not self.active_connections[job_id]:
56
+ del self.active_connections[job_id]
57
+
58
+ async def broadcast_to_job(self, job_id: str, data: dict[str, t.Any]) -> None:
59
+ if job_id not in self.active_connections:
60
+ return
61
+
62
+ timeout_manager = get_timeout_manager()
63
+ connections = self.active_connections[job_id].copy()
64
+
65
+ send_tasks = self._create_broadcast_tasks(connections, timeout_manager, data)
66
+
67
+ if send_tasks:
68
+ await self._execute_broadcast_tasks(job_id, send_tasks)
69
+
70
+ def _create_broadcast_tasks(
71
+ self, connections: set[t.Any], timeout_manager: t.Any, data: dict[str, t.Any]
72
+ ) -> list[tuple[t.Any, asyncio.Task[t.Any]]]:
73
+ send_tasks = []
74
+ for websocket in connections:
75
+ task = asyncio.create_task(
76
+ timeout_manager.with_timeout(
77
+ "websocket_broadcast",
78
+ websocket.send_json(data),
79
+ timeout=2.0,
80
+ )
81
+ )
82
+ send_tasks.append((websocket, task))
83
+ return send_tasks
84
+
85
+ async def _execute_broadcast_tasks(
86
+ self, job_id: str, send_tasks: list[t.Any]
87
+ ) -> None:
88
+ try:
89
+ done, pending = await asyncio.wait(
90
+ [task for _, task in send_tasks],
91
+ timeout=5.0,
92
+ return_when=asyncio.ALL_COMPLETED,
93
+ )
94
+
95
+ await self._handle_broadcast_results(job_id, send_tasks, done, pending)
96
+
97
+ except Exception as e:
98
+ console.print(f"[red]Broadcast error: {e}[/red]")
99
+ await self._cleanup_failed_broadcast(job_id, send_tasks)
100
+
101
+ async def _handle_broadcast_results(
102
+ self,
103
+ job_id: str,
104
+ send_tasks: list[t.Any],
105
+ done: set[t.Any],
106
+ pending: set[t.Any],
107
+ ) -> None:
108
+ for websocket, task in send_tasks:
109
+ if task in pending:
110
+ task.cancel()
111
+ self.remove_connection(job_id, websocket)
112
+ elif task in done:
113
+ try:
114
+ await task
115
+ except Exception:
116
+ self.remove_connection(job_id, websocket)
117
+
118
+ if pending:
119
+ await asyncio.gather(*pending, return_exceptions=True)
120
+
121
+ async def _cleanup_failed_broadcast(
122
+ self, job_id: str, send_tasks: list[t.Any]
123
+ ) -> None:
124
+ for websocket, task in send_tasks:
125
+ if not task.done():
126
+ task.cancel()
127
+ self.remove_connection(job_id, websocket)
128
+
129
+ def get_latest_job_id(self) -> str | None:
130
+ if not self.progress_dir.exists():
131
+ return None
132
+
133
+ progress_files = list[t.Any](self.progress_dir.glob("job-*.json"))
134
+ if not progress_files:
135
+ return None
136
+
137
+ latest_file = max(progress_files, key=lambda f: f.stat().st_mtime)
138
+ return self.extract_job_id_from_file(latest_file)
139
+
140
+ def extract_job_id_from_file(self, progress_file: Path) -> str | None:
141
+ return (
142
+ progress_file.stem[4:] if progress_file.stem.startswith("job -") else None
143
+ )
144
+
145
+ def get_job_progress(self, job_id: str) -> dict[str, t.Any] | None:
146
+ if not self.validate_job_id(job_id):
147
+ return None
148
+
149
+ try:
150
+ progress_file = SecurePathValidator.secure_path_join(
151
+ self.progress_dir, f"job-{job_id}.json"
152
+ )
153
+ if not progress_file.exists():
154
+ return None
155
+
156
+ SecurePathValidator.validate_file_size(progress_file)
157
+
158
+ return json.loads(progress_file.read_text()) # type: ignore[no-any-return]
159
+ except (json.JSONDecodeError, OSError):
160
+ return None
161
+
162
+ async def _process_progress_file(self, progress_file: Path) -> None:
163
+ try:
164
+ validated_file = SecurePathValidator.validate_safe_path(
165
+ progress_file, self.progress_dir
166
+ )
167
+ except Exception:
168
+ return
169
+
170
+ job_id = self.extract_job_id_from_file(validated_file)
171
+ if not (job_id and self.validate_job_id(job_id)):
172
+ return
173
+
174
+ progress_data = self.get_job_progress(job_id)
175
+ if progress_data and job_id not in self.known_jobs:
176
+ self.known_jobs.add(job_id)
177
+ console.print(f"[green]New job detected: {job_id}[/ green]")
178
+ await self.broadcast_to_job(job_id, progress_data)
179
+
180
+ async def _monitor_directory_changes(self) -> None:
181
+ timeout_manager = get_timeout_manager()
182
+ consecutive_errors = 0
183
+ max_consecutive_errors = 5
184
+
185
+ while self.is_running:
186
+ try:
187
+ async with timeout_manager.timeout_context(
188
+ "file_operations",
189
+ timeout=10.0,
190
+ strategy=TimeoutStrategy.GRACEFUL_DEGRADATION,
191
+ ):
192
+ if self.progress_dir.exists():
193
+ for progress_file in self.progress_dir.glob("job-*.json"):
194
+ try:
195
+ await timeout_manager.with_timeout(
196
+ "file_operations",
197
+ self._process_progress_file(progress_file),
198
+ timeout=5.0,
199
+ )
200
+ except Exception as e:
201
+ console.print(
202
+ f"[yellow]File processing error: {e}[/yellow]"
203
+ )
204
+ continue
205
+
206
+ consecutive_errors = 0
207
+ await asyncio.sleep(1)
208
+
209
+ except Exception as e:
210
+ consecutive_errors += 1
211
+ console.print(f"[red]Progress monitoring error: {e}[/red]")
212
+
213
+ if consecutive_errors >= max_consecutive_errors:
214
+ console.print(
215
+ f"[red]Too many consecutive errors ({consecutive_errors}), stopping monitor[/red]"
216
+ )
217
+ break
218
+
219
+ delay = min(5 * (2 ** (consecutive_errors - 1)), 60)
220
+ await asyncio.sleep(delay)
221
+
222
+ async def monitor_progress_files(self) -> None:
223
+ from crackerjack.mcp.file_monitor import create_progress_monitor
224
+
225
+ console.print("[blue]Starting progress file monitoring...[/blue]")
226
+ timeout_manager = get_timeout_manager()
227
+
228
+ try:
229
+ async with timeout_manager.timeout_context(
230
+ "file_operations",
231
+ timeout=30.0,
232
+ strategy=TimeoutStrategy.GRACEFUL_DEGRADATION,
233
+ ):
234
+ monitor = create_progress_monitor(self.progress_dir)
235
+ await monitor.start()
236
+
237
+ def on_progress_update(
238
+ job_id: str, progress_data: dict[str, t.Any]
239
+ ) -> None:
240
+ if job_id and self.validate_job_id(job_id):
241
+
242
+ async def safe_broadcast() -> None:
243
+ try:
244
+ await timeout_manager.with_timeout(
245
+ "websocket_broadcast",
246
+ self.broadcast_to_job(job_id, progress_data),
247
+ timeout=5.0,
248
+ )
249
+ except Exception as e:
250
+ console.print(
251
+ f"[yellow]Broadcast failed for job {job_id}: {e}[/yellow]"
252
+ )
253
+
254
+ asyncio.create_task(safe_broadcast()) # type: ignore[no-untyped-call]
255
+
256
+ if job_id not in self.known_jobs:
257
+ self.known_jobs.add(job_id)
258
+ console.print(f"[green]New job detected: {job_id}[/green]")
259
+
260
+ await self._monitor_directory_changes()
261
+
262
+ except Exception as e:
263
+ console.print(f"[red]Progress monitoring setup error: {e}[/red]")
264
+
265
+ async def cleanup_old_jobs(self) -> None:
266
+ timeout_manager = get_timeout_manager()
267
+
268
+ while self.is_running:
269
+ try:
270
+ await timeout_manager.with_timeout(
271
+ "file_operations",
272
+ self._perform_cleanup_cycle(),
273
+ timeout=30.0,
274
+ strategy=TimeoutStrategy.GRACEFUL_DEGRADATION,
275
+ )
276
+ await asyncio.sleep(3600)
277
+ except Exception as e:
278
+ console.print(f"[red]Cleanup error: {e}[/red]")
279
+
280
+ await asyncio.sleep(1800)
281
+
282
+ async def _perform_cleanup_cycle(self) -> None:
283
+ if not self.progress_dir.exists():
284
+ return
285
+
286
+ cutoff_time = self._calculate_cleanup_cutoff_time()
287
+ old_job_files = self._find_old_job_files(cutoff_time)
288
+
289
+ for progress_file in old_job_files:
290
+ self._cleanup_old_job_file(progress_file)
291
+
292
+ def _calculate_cleanup_cutoff_time(self) -> float:
293
+ return time.time() - (24 * 60 * 60)
294
+
295
+ def _find_old_job_files(self, cutoff_time: float) -> list[Path]:
296
+ return [
297
+ progress_file
298
+ for progress_file in self.progress_dir.glob("job - *.json")
299
+ if progress_file.stat().st_mtime < cutoff_time
300
+ ]
301
+
302
+ def _cleanup_old_job_file(self, progress_file: Path) -> None:
303
+ job_id = self.extract_job_id_from_file(progress_file)
304
+
305
+ if job_id not in self.active_connections:
306
+ progress_file.unlink(missing_ok=True)
307
+ console.print(f"[yellow]Cleaned up old job: {job_id}[/ yellow]")
308
+
309
+ async def timeout_stuck_jobs(self) -> None:
310
+ timeout_manager = get_timeout_manager()
311
+
312
+ while self.is_running:
313
+ try:
314
+ await timeout_manager.with_timeout(
315
+ "file_operations",
316
+ self._check_and_timeout_stuck_jobs(),
317
+ timeout=60.0,
318
+ strategy=TimeoutStrategy.GRACEFUL_DEGRADATION,
319
+ )
320
+ await asyncio.sleep(300)
321
+ except Exception as e:
322
+ console.print(f"[red]Timeout check error: {e}[/red]")
323
+
324
+ await asyncio.sleep(300)
325
+
326
+ async def _check_and_timeout_stuck_jobs(self) -> None:
327
+ if not self.progress_dir.exists():
328
+ return
329
+
330
+ current_time = time.time()
331
+ timeout_seconds = 30 * 60
332
+
333
+ for progress_file in self.progress_dir.glob("job-* .json"):
334
+ await self._process_job_timeout_check(
335
+ progress_file,
336
+ current_time,
337
+ timeout_seconds,
338
+ )
339
+
340
+ async def _process_job_timeout_check(
341
+ self,
342
+ progress_file: Path,
343
+ current_time: float,
344
+ timeout_seconds: int,
345
+ ) -> None:
346
+ try:
347
+ validated_file = SecurePathValidator.validate_safe_path(
348
+ progress_file, self.progress_dir
349
+ )
350
+
351
+ SecurePathValidator.validate_file_size(validated_file)
352
+
353
+ progress_data = json.loads(validated_file.read_text())
354
+
355
+ if self._should_timeout_job(
356
+ progress_data,
357
+ validated_file,
358
+ current_time,
359
+ timeout_seconds,
360
+ ):
361
+ self._timeout_job(progress_data, validated_file)
362
+
363
+ except (json.JSONDecodeError, OSError, Exception):
364
+ pass
365
+
366
+ def _should_timeout_job(
367
+ self,
368
+ progress_data: dict[str, t.Any],
369
+ progress_file: Path,
370
+ current_time: float,
371
+ timeout_seconds: int,
372
+ ) -> bool:
373
+ return (
374
+ progress_data.get("status") == "running"
375
+ and current_time - progress_file.stat().st_mtime > timeout_seconds
376
+ )
377
+
378
+ def _timeout_job(
379
+ self, progress_data: dict[str, t.Any], progress_file: Path
380
+ ) -> None:
381
+ progress_data["status"] = "failed"
382
+ progress_data["message"] = "Job timed out (no updates for 30 minutes)"
383
+
384
+ progress_file.write_text(json.dumps(progress_data, indent=2))
385
+
386
+ job_id = progress_data.get("job_id", "unknown")
387
+ console.print(f"[red]Job {job_id} timed out and marked as failed[/ red]")
388
+
389
+ def cleanup(self) -> None:
390
+ self.is_running = False
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
+ ]