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,291 @@
1
+ """WebSocket endpoints for metrics streaming.
2
+
3
+ This module handles real-time metrics streaming, historical data,
4
+ alerts, and dashboard overview WebSocket connections.
5
+ """
6
+
7
+ import asyncio
8
+ import json
9
+ import typing as t
10
+ from datetime import datetime
11
+
12
+ from acb.depends import depends
13
+ from fastapi import FastAPI, WebSocket, WebSocketDisconnect
14
+
15
+ from crackerjack.events import WorkflowEventTelemetry
16
+ from crackerjack.services.quality.quality_baseline_enhanced import (
17
+ EnhancedQualityBaselineService,
18
+ TrendDirection,
19
+ UnifiedMetrics,
20
+ )
21
+
22
+ from ..metrics import get_monitoring_current_metrics
23
+ from ..websocket_manager import MonitoringWebSocketManager
24
+
25
+
26
+ def register_metrics_websockets(
27
+ app: FastAPI,
28
+ job_manager: t.Any,
29
+ ws_manager: MonitoringWebSocketManager,
30
+ quality_service: EnhancedQualityBaselineService,
31
+ ) -> None:
32
+ """Register metrics-related WebSocket endpoints."""
33
+
34
+ @app.websocket("/ws/metrics/live")
35
+ async def websocket_metrics_live(websocket: WebSocket) -> None:
36
+ """WebSocket endpoint for live metrics streaming."""
37
+ await _handle_live_metrics_websocket(
38
+ websocket, ws_manager, quality_service, job_manager
39
+ )
40
+
41
+ @app.websocket("/ws/metrics/historical/{days}")
42
+ async def websocket_metrics_historical(websocket: WebSocket, days: int) -> None:
43
+ """WebSocket endpoint for historical metrics data."""
44
+ await _handle_historical_metrics_websocket(
45
+ websocket, ws_manager, quality_service, days
46
+ )
47
+
48
+ @app.websocket("/ws/alerts/subscribe")
49
+ async def websocket_alerts_subscribe(websocket: WebSocket) -> None:
50
+ """WebSocket endpoint for alert subscriptions."""
51
+ await _handle_alerts_websocket(websocket, ws_manager)
52
+
53
+ @app.websocket("/ws/dashboard/overview")
54
+ async def websocket_dashboard_overview(websocket: WebSocket) -> None:
55
+ """WebSocket endpoint for comprehensive dashboard data."""
56
+ await _handle_dashboard_websocket(
57
+ websocket, ws_manager, quality_service, job_manager
58
+ )
59
+
60
+
61
+ async def _handle_live_metrics_websocket(
62
+ websocket: WebSocket,
63
+ ws_manager: MonitoringWebSocketManager,
64
+ quality_service: EnhancedQualityBaselineService,
65
+ job_manager: t.Any,
66
+ ) -> None:
67
+ """Handle live metrics WebSocket connection."""
68
+ client_id = f"metrics_{datetime.now().timestamp()}"
69
+ await ws_manager.connect_metrics(websocket, client_id)
70
+
71
+ try:
72
+ # Send initial metrics
73
+ current_metrics = await get_monitoring_current_metrics(
74
+ quality_service, job_manager
75
+ )
76
+ await websocket.send_text(
77
+ json.dumps(
78
+ {
79
+ "type": "initial_metrics",
80
+ "data": current_metrics.to_dict(),
81
+ "timestamp": datetime.now().isoformat(),
82
+ }
83
+ )
84
+ )
85
+
86
+ # Keep connection alive and handle client messages
87
+ while True:
88
+ try:
89
+ message = await asyncio.wait_for(websocket.receive_text(), timeout=30.0)
90
+ data = json.loads(message)
91
+
92
+ if data.get("type") == "request_update":
93
+ metrics = await get_monitoring_current_metrics(
94
+ quality_service, job_manager
95
+ )
96
+ await websocket.send_text(
97
+ json.dumps(
98
+ {
99
+ "type": "metrics_update",
100
+ "data": metrics.to_dict(),
101
+ "timestamp": datetime.now().isoformat(),
102
+ }
103
+ )
104
+ )
105
+
106
+ except TimeoutError:
107
+ metrics = await get_monitoring_current_metrics(
108
+ quality_service, job_manager
109
+ )
110
+ await ws_manager.broadcast_metrics(metrics)
111
+
112
+ except WebSocketDisconnect:
113
+ ws_manager.disconnect(websocket, client_id)
114
+
115
+
116
+ async def _handle_historical_metrics_websocket(
117
+ websocket: WebSocket,
118
+ ws_manager: MonitoringWebSocketManager,
119
+ quality_service: EnhancedQualityBaselineService,
120
+ days: int,
121
+ ) -> None:
122
+ """Handle historical metrics WebSocket connection."""
123
+ if days > 365:
124
+ await websocket.close(code=1008, reason="Days parameter too large")
125
+ return
126
+
127
+ client_id = f"historical_{datetime.now().timestamp()}"
128
+ await ws_manager.connect_metrics(websocket, client_id)
129
+
130
+ try:
131
+ baselines = await quality_service.aget_recent_baselines(limit=days)
132
+ historical_data = _convert_baselines_to_metrics(baselines)
133
+
134
+ await _send_historical_data_chunks(websocket, historical_data)
135
+
136
+ # Keep connection open for updates
137
+ while True:
138
+ await websocket.receive_text()
139
+
140
+ except WebSocketDisconnect:
141
+ ws_manager.disconnect(websocket, client_id)
142
+
143
+
144
+ def _convert_baselines_to_metrics(
145
+ baselines: list[t.Any],
146
+ ) -> list[UnifiedMetrics]:
147
+ """Convert quality baselines to UnifiedMetrics objects."""
148
+ return [
149
+ UnifiedMetrics(
150
+ timestamp=baseline.timestamp,
151
+ quality_score=baseline.quality_score,
152
+ test_coverage=baseline.coverage_percent,
153
+ hook_duration=0.0,
154
+ active_jobs=0,
155
+ error_count=baseline.hook_failures
156
+ + baseline.security_issues
157
+ + baseline.type_errors
158
+ + baseline.linting_issues,
159
+ trend_direction=TrendDirection.STABLE,
160
+ predictions={},
161
+ )
162
+ for baseline in baselines
163
+ ]
164
+
165
+
166
+ async def _send_historical_data_chunks(
167
+ websocket: WebSocket, historical_data: list[UnifiedMetrics]
168
+ ) -> None:
169
+ """Send historical data in chunks to avoid overwhelming the client."""
170
+ chunk_size = 100
171
+
172
+ for i in range(0, len(historical_data), chunk_size):
173
+ chunk = historical_data[i : i + chunk_size]
174
+ await websocket.send_text(
175
+ json.dumps(
176
+ {
177
+ "type": "historical_chunk",
178
+ "data": [m.to_dict() for m in chunk],
179
+ "chunk_index": i // chunk_size,
180
+ "total_chunks": (len(historical_data) + chunk_size - 1)
181
+ // chunk_size,
182
+ "timestamp": datetime.now().isoformat(),
183
+ }
184
+ )
185
+ )
186
+ await asyncio.sleep(0.1)
187
+
188
+ # Send completion signal
189
+ await websocket.send_text(
190
+ json.dumps(
191
+ {
192
+ "type": "historical_complete",
193
+ "total_records": len(historical_data),
194
+ "timestamp": datetime.now().isoformat(),
195
+ }
196
+ )
197
+ )
198
+
199
+
200
+ async def _handle_alerts_websocket(
201
+ websocket: WebSocket, ws_manager: MonitoringWebSocketManager
202
+ ) -> None:
203
+ """Handle alerts WebSocket connection."""
204
+ client_id = f"alerts_{datetime.now().timestamp()}"
205
+ await ws_manager.connect_alerts(websocket, client_id)
206
+
207
+ try:
208
+ # Send current active alerts - would need to track these separately
209
+ active_alerts = [] # For now, empty list
210
+ await websocket.send_text(
211
+ json.dumps(
212
+ {
213
+ "type": "active_alerts",
214
+ "data": [alert.to_dict() for alert in active_alerts],
215
+ "timestamp": datetime.now().isoformat(),
216
+ }
217
+ )
218
+ )
219
+
220
+ # Keep connection alive
221
+ while True:
222
+ await websocket.receive_text()
223
+
224
+ except WebSocketDisconnect:
225
+ ws_manager.disconnect(websocket, client_id)
226
+
227
+
228
+ async def _handle_dashboard_websocket(
229
+ websocket: WebSocket,
230
+ ws_manager: MonitoringWebSocketManager,
231
+ quality_service: EnhancedQualityBaselineService,
232
+ job_manager: t.Any,
233
+ ) -> None:
234
+ """Handle dashboard overview WebSocket connection."""
235
+ client_id = f"dashboard_{datetime.now().timestamp()}"
236
+ await ws_manager.connect_metrics(websocket, client_id)
237
+
238
+ try:
239
+ telemetry: WorkflowEventTelemetry | None
240
+ try:
241
+ telemetry = depends.get_sync(WorkflowEventTelemetry)
242
+ except Exception:
243
+ telemetry = None
244
+
245
+ while True:
246
+ current_metrics = await get_monitoring_current_metrics(
247
+ quality_service, job_manager
248
+ )
249
+
250
+ metrics_dict = _create_dashboard_metrics_dict(current_metrics)
251
+
252
+ dashboard_state = await asyncio.to_thread(
253
+ quality_service.create_dashboard_state,
254
+ metrics_dict,
255
+ len(job_manager.active_connections),
256
+ 7,
257
+ )
258
+
259
+ telemetry_snapshot: dict[str, t.Any] | None = None
260
+ if telemetry is not None:
261
+ telemetry_snapshot = await telemetry.snapshot()
262
+
263
+ await websocket.send_text(
264
+ json.dumps(
265
+ {
266
+ "type": "dashboard_update",
267
+ "data": dashboard_state.to_dict(),
268
+ "telemetry": telemetry_snapshot,
269
+ "timestamp": datetime.now().isoformat(),
270
+ }
271
+ )
272
+ )
273
+
274
+ await asyncio.sleep(10)
275
+
276
+ except WebSocketDisconnect:
277
+ ws_manager.disconnect(websocket, client_id)
278
+
279
+
280
+ def _create_dashboard_metrics_dict(current_metrics: UnifiedMetrics) -> dict[str, t.Any]:
281
+ """Create basic metrics dict for dashboard state."""
282
+ return {
283
+ "coverage_percent": current_metrics.test_coverage,
284
+ "test_count": 0,
285
+ "test_pass_rate": 100.0,
286
+ "hook_failures": 0,
287
+ "complexity_violations": 0,
288
+ "security_issues": 0,
289
+ "type_errors": 0,
290
+ "linting_issues": 0,
291
+ }
@@ -0,0 +1,21 @@
1
+ """Backward compatibility wrapper for refactored monitoring endpoints.
2
+
3
+ This module re-exports the main factory function from the new monitoring/ directory
4
+ to maintain backward compatibility with existing code that imports from
5
+ crackerjack.mcp.websocket.monitoring_endpoints.
6
+
7
+ The actual implementation has been split into organized modules:
8
+ - monitoring/models.py - Pydantic data models
9
+ - monitoring/websocket_manager.py - WebSocket connection management
10
+ - monitoring/utils.py - Utility functions
11
+ - monitoring/dashboard.py - Dashboard HTML rendering
12
+ - monitoring/websockets/ - WebSocket endpoint modules (metrics, intelligence, dependencies, heatmap)
13
+ - monitoring/api/ - REST API endpoint modules (telemetry, metrics, intelligence, dependencies, heatmap)
14
+ - monitoring/factory.py - Endpoint registration orchestration
15
+
16
+ All imports should work exactly as before via the main factory function.
17
+ """
18
+
19
+ from .monitoring import MonitoringWebSocketManager, create_monitoring_endpoints
20
+
21
+ __all__ = ["create_monitoring_endpoints", "MonitoringWebSocketManager"]
@@ -0,0 +1,174 @@
1
+ import asyncio
2
+ import contextlib
3
+ import signal
4
+ import subprocess
5
+ import tempfile
6
+ import time
7
+ import typing as t
8
+ from pathlib import Path
9
+
10
+ import uvicorn
11
+ from acb import console
12
+
13
+ from crackerjack.core.timeout_manager import get_timeout_manager
14
+
15
+ from .app import create_websocket_app
16
+ from .jobs import JobManager
17
+
18
+
19
+ class WebSocketServer:
20
+ def __init__(self, port: int = 8675) -> None:
21
+ self.port = port
22
+ self.progress_dir = Path(tempfile.gettempdir()) / "crackerjack-mcp-progress"
23
+ self.is_running = True
24
+ self.job_manager: JobManager | None = None
25
+ self.app: t.Any = None
26
+ self.timeout_manager = get_timeout_manager()
27
+ self.server_task: asyncio.Task[t.Any] | None = None
28
+
29
+ def setup(self) -> None:
30
+ self.progress_dir.mkdir(exist_ok=True)
31
+
32
+ self.job_manager = JobManager(self.progress_dir)
33
+
34
+ self.app = create_websocket_app(self.job_manager, self.progress_dir)
35
+
36
+ signal.signal(signal.SIGINT, self._signal_handler)
37
+ signal.signal(signal.SIGTERM, self._signal_handler)
38
+
39
+ def _signal_handler(self, _signum: int, _frame: t.Any) -> None:
40
+ console.print("\n[yellow]Shutting down WebSocket server...[/yellow]")
41
+ self.is_running = False
42
+
43
+ if self.server_task and not self.server_task.done():
44
+ self.server_task.cancel()
45
+
46
+ if self.job_manager:
47
+ with contextlib.suppress(Exception):
48
+ asyncio.create_task(self._graceful_shutdown())
49
+
50
+ async def _graceful_shutdown(self) -> None:
51
+ if self.job_manager:
52
+ try:
53
+ await asyncio.sleep(2.0)
54
+
55
+ console.print(
56
+ "[yellow]Forcing remaining WebSocket connections to close[/yellow]"
57
+ )
58
+ except Exception as e:
59
+ console.print(f"[red]Error during graceful shutdown: {e}[/red]")
60
+
61
+ def run(self) -> None:
62
+ try:
63
+ self.setup()
64
+ console.print(
65
+ f"[green]Starting WebSocket server on port {self.port}[/green]",
66
+ )
67
+ console.print(f"Progress directory: {self.progress_dir}")
68
+ console.print("Press Ctrl+C to stop")
69
+
70
+ config = uvicorn.Config(
71
+ app=self.app,
72
+ port=self.port,
73
+ host="127.0.0.1",
74
+ log_level="info",
75
+ timeout_keep_alive=30,
76
+ timeout_graceful_shutdown=30,
77
+ )
78
+
79
+ server = uvicorn.Server(config)
80
+
81
+ try:
82
+ asyncio.run(self._run_with_timeout(server))
83
+ except KeyboardInterrupt:
84
+ console.print("\n[yellow]Server interrupted by user[/yellow]")
85
+
86
+ except KeyboardInterrupt:
87
+ console.print("\n[yellow]Server stopped by user[/yellow]")
88
+ except Exception as e:
89
+ console.print(f"[red]Server error: {e}[/red]")
90
+ finally:
91
+ console.print("[green]WebSocket server shutdown complete[/green]")
92
+
93
+ async def _run_with_timeout(self, server: uvicorn.Server) -> None:
94
+ try:
95
+ self.server_task = asyncio.create_task(server.serve())
96
+
97
+ while self.is_running and not self.server_task.done():
98
+ try:
99
+ await asyncio.sleep(5.0)
100
+
101
+ except asyncio.CancelledError:
102
+ console.print("[yellow]Server monitoring cancelled[/yellow]")
103
+ break
104
+ except Exception as e:
105
+ console.print(f"[red]Server monitoring error: {e}[/red]")
106
+ break
107
+
108
+ if self.server_task and not self.server_task.done():
109
+ try:
110
+ await asyncio.wait_for(self.server_task, timeout=30.0)
111
+ except TimeoutError:
112
+ console.print(
113
+ "[yellow]Server shutdown timeout, forcing termination[/yellow]"
114
+ )
115
+ self.server_task.cancel()
116
+ try:
117
+ await self.server_task
118
+ except asyncio.CancelledError:
119
+ pass
120
+
121
+ except Exception as e:
122
+ console.print(f"[red]Server runtime error: {e}[/red]")
123
+
124
+
125
+ def handle_websocket_server_command(
126
+ start: bool = False,
127
+ stop: bool = False,
128
+ restart: bool = False,
129
+ port: int = 8675,
130
+ ) -> None:
131
+ if stop or restart:
132
+ console.print("[yellow]Stopping WebSocket servers...[/yellow]")
133
+
134
+ try:
135
+ result = subprocess.run(
136
+ ["pkill", "-f", f"uvicorn.*: {port}"],
137
+ check=False,
138
+ capture_output=True,
139
+ text=True,
140
+ timeout=10,
141
+ )
142
+ if result.returncode == 0:
143
+ console.print("[green]✅ WebSocket servers stopped[/green]")
144
+ else:
145
+ console.print("[dim]No WebSocket servers were running[/dim]")
146
+ except subprocess.TimeoutExpired:
147
+ console.print("[red]Timeout stopping WebSocket servers[/red]")
148
+ except Exception as e:
149
+ console.print(f"[red]Error stopping WebSocket servers: {e}[/red]")
150
+
151
+ if stop:
152
+ return
153
+
154
+ time.sleep(2)
155
+
156
+ if start or restart:
157
+ console.print(f"[green]Starting WebSocket server on port {port}...[/green]")
158
+ try:
159
+ server = WebSocketServer(port)
160
+ server.run()
161
+ except Exception as e:
162
+ console.print(f"[red]Failed to start WebSocket server: {e}[/red]")
163
+
164
+
165
+ def main(port: int = 8675) -> None:
166
+ server = WebSocketServer(port)
167
+ server.run()
168
+
169
+
170
+ if __name__ == "__main__":
171
+ import sys
172
+
173
+ port = int(sys.argv[1]) if len(sys.argv) > 1 else 8675
174
+ main(port)