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,407 @@
1
+ import asyncio
2
+ import json
3
+ import time
4
+ import typing as t
5
+ import uuid
6
+ from dataclasses import asdict, dataclass
7
+ from enum import Enum
8
+ from pathlib import Path
9
+
10
+
11
+ class StageStatus(str, Enum):
12
+ PENDING = "pending"
13
+ RUNNING = "running"
14
+ COMPLETED = "completed"
15
+ FAILED = "failed"
16
+ ERROR = "error"
17
+
18
+
19
+ class Priority(str, Enum):
20
+ CRITICAL = "critical"
21
+ HIGH = "high"
22
+ MEDIUM = "medium"
23
+ LOW = "low"
24
+
25
+
26
+ @dataclass
27
+ class Issue:
28
+ id: str
29
+ type: str
30
+ message: str
31
+ file_path: str
32
+ line_number: int | None = None
33
+ priority: Priority = Priority.MEDIUM
34
+ stage: str = ""
35
+ suggested_fix: str | None = None
36
+ auto_fixable: bool = False
37
+
38
+ def to_dict(self) -> dict[str, t.Any]:
39
+ return asdict(self)
40
+
41
+
42
+ @dataclass
43
+ class StageResult:
44
+ stage: str
45
+ status: StageStatus
46
+ start_time: float
47
+ end_time: float | None = None
48
+ duration: float | None = None
49
+ issues_found: list[Issue] | None = None
50
+ fixes_applied: list[str] | None = None
51
+ error_message: str | None = None
52
+
53
+ def __post_init__(self) -> None:
54
+ if self.issues_found is None:
55
+ self.issues_found = []
56
+ if self.fixes_applied is None:
57
+ self.fixes_applied = []
58
+ if self.end_time and self.start_time:
59
+ self.duration = self.end_time - self.start_time
60
+
61
+ def to_dict(self) -> dict[str, t.Any]:
62
+ data = asdict(self)
63
+ data["issues_found"] = [issue.to_dict() for issue in self.issues_found or []]
64
+ return data
65
+
66
+
67
+ @dataclass
68
+ class SessionState:
69
+ session_id: str
70
+ start_time: float
71
+ current_stage: str | None = None
72
+ stages: dict[str, StageResult] | None = None
73
+ global_issues: list[Issue] | None = None
74
+ fixes_applied: list[str] | None = None
75
+ metadata: dict[str, t.Any] | None = None
76
+
77
+ def __post_init__(self) -> None:
78
+ if self.stages is None:
79
+ self.stages = {}
80
+ if self.global_issues is None:
81
+ self.global_issues = []
82
+ if self.fixes_applied is None:
83
+ self.fixes_applied = []
84
+ if self.metadata is None:
85
+ self.metadata = {}
86
+
87
+ def to_dict(self) -> dict[str, t.Any]:
88
+ data = asdict(self)
89
+ data["stages"] = {k: v.to_dict() for k, v in (self.stages or {}).items()}
90
+ data["global_issues"] = [issue.to_dict() for issue in self.global_issues or []]
91
+ return data
92
+
93
+
94
+ class StateManager:
95
+ def __init__(
96
+ self, state_dir: Path | None = None, batched_saver: t.Any | None = None
97
+ ) -> None:
98
+ self._lock = asyncio.Lock()
99
+ self.state_dir = state_dir or Path.home() / ".cache" / "crackerjack-mcp"
100
+ self.state_dir.mkdir(exist_ok=True)
101
+ self.session_state = SessionState(
102
+ session_id=self._generate_session_id(),
103
+ start_time=time.time(),
104
+ )
105
+ self.checkpoints_dir = self.state_dir / "checkpoints"
106
+ self.checkpoints_dir.mkdir(exist_ok=True)
107
+ self._batched_saver = batched_saver
108
+
109
+ def _generate_session_id(self) -> str:
110
+ return str(uuid.uuid4())[:8]
111
+
112
+ async def start_stage(self, stage: str) -> None:
113
+ async with self._lock:
114
+ if not self.session_state.stages:
115
+ self.session_state.stages = {}
116
+ self.session_state.current_stage = stage
117
+ self.session_state.stages[stage] = StageResult(
118
+ stage=stage,
119
+ status=StageStatus.RUNNING,
120
+ start_time=time.time(),
121
+ )
122
+ self._save_state()
123
+
124
+ async def complete_stage(
125
+ self,
126
+ stage: str,
127
+ issues: list[Issue] | None = None,
128
+ fixes: list[str] | None = None,
129
+ ) -> None:
130
+ async with self._lock:
131
+ stage_result = self._get_stage_result(stage)
132
+ if not stage_result:
133
+ return
134
+
135
+ self._update_stage_completion(stage_result)
136
+ self._process_stage_issues(stage_result, issues)
137
+ self._process_stage_fixes(stage_result, fixes)
138
+ self._clear_current_stage(stage)
139
+ self._save_state()
140
+
141
+ def _get_stage_result(self, stage: str) -> StageResult | None:
142
+ if not self.session_state.stages or stage not in self.session_state.stages:
143
+ return None
144
+ return self.session_state.stages[stage]
145
+
146
+ def _update_stage_completion(self, stage_result: StageResult) -> None:
147
+ stage_result.status = StageStatus.COMPLETED
148
+ stage_result.end_time = time.time()
149
+ stage_result.duration = stage_result.end_time - stage_result.start_time
150
+
151
+ def _process_stage_issues(
152
+ self,
153
+ stage_result: StageResult,
154
+ issues: list[Issue] | None,
155
+ ) -> None:
156
+ if not issues:
157
+ return
158
+ stage_result.issues_found = issues
159
+ if not self.session_state.global_issues:
160
+ self.session_state.global_issues = []
161
+ self.session_state.global_issues.extend(issues)
162
+
163
+ def _process_stage_fixes(
164
+ self,
165
+ stage_result: StageResult,
166
+ fixes: list[str] | None,
167
+ ) -> None:
168
+ if not fixes:
169
+ return
170
+ stage_result.fixes_applied = fixes
171
+ if not self.session_state.fixes_applied:
172
+ self.session_state.fixes_applied = []
173
+ self.session_state.fixes_applied.extend(fixes)
174
+
175
+ def _clear_current_stage(self, stage: str) -> None:
176
+ if self.session_state.current_stage == stage:
177
+ self.session_state.current_stage = None
178
+
179
+ async def fail_stage(self, stage: str, error_message: str) -> None:
180
+ async with self._lock:
181
+ if not self.session_state.stages or stage not in self.session_state.stages:
182
+ return
183
+ stage_result = self.session_state.stages[stage]
184
+ stage_result.status = StageStatus.FAILED
185
+ stage_result.end_time = time.time()
186
+ stage_result.duration = stage_result.end_time - stage_result.start_time
187
+ stage_result.error_message = error_message
188
+ if self.session_state.current_stage == stage:
189
+ self.session_state.current_stage = None
190
+ self._save_state()
191
+
192
+ async def update_stage_status(self, stage: str, status: str) -> None:
193
+ async with self._lock:
194
+ if not self.session_state.stages:
195
+ self.session_state.stages = {}
196
+ if stage not in self.session_state.stages:
197
+ self.session_state.stages[stage] = StageResult(
198
+ stage=stage,
199
+ status=StageStatus(status),
200
+ start_time=time.time(),
201
+ )
202
+ else:
203
+ self.session_state.stages[stage].status = StageStatus(status)
204
+ if status in ("completed", "failed", "error"):
205
+ self.session_state.stages[stage].end_time = time.time()
206
+ self._save_state()
207
+
208
+ async def add_issue(self, issue: Issue) -> None:
209
+ async with self._lock:
210
+ if not self.session_state.global_issues:
211
+ self.session_state.global_issues = []
212
+ self.session_state.global_issues.append(issue)
213
+ self._save_state()
214
+
215
+ def remove_issue(self, issue_id: str) -> bool:
216
+ if not self.session_state.global_issues:
217
+ return False
218
+ initial_count = len(self.session_state.global_issues)
219
+ self.session_state.global_issues = [
220
+ issue for issue in self.session_state.global_issues if issue.id != issue_id
221
+ ]
222
+ removed = len(self.session_state.global_issues) < initial_count
223
+ if removed:
224
+ self._save_state()
225
+
226
+ return removed
227
+
228
+ def get_issues_by_priority(self, priority: Priority) -> list[Issue]:
229
+ if not self.session_state.global_issues:
230
+ return []
231
+
232
+ return [
233
+ issue
234
+ for issue in self.session_state.global_issues
235
+ if issue.priority == priority
236
+ ]
237
+
238
+ def get_issues_by_type(self, issue_type: str) -> list[Issue]:
239
+ if not self.session_state.global_issues:
240
+ return []
241
+
242
+ return [
243
+ issue
244
+ for issue in self.session_state.global_issues
245
+ if issue.type == issue_type
246
+ ]
247
+
248
+ def get_auto_fixable_issues(self) -> list[Issue]:
249
+ if not self.session_state.global_issues:
250
+ return []
251
+
252
+ return [
253
+ issue for issue in self.session_state.global_issues if issue.auto_fixable
254
+ ]
255
+
256
+ def get_session_summary(self) -> dict[str, t.Any]:
257
+ stages = self.session_state.stages or {}
258
+ issues = self.session_state.global_issues or []
259
+ fixes = self.session_state.fixes_applied or []
260
+ priority_counts = {}
261
+ for priority in Priority:
262
+ priority_counts[priority.value] = len(self.get_issues_by_priority(priority))
263
+ type_counts: dict[str, int] = {}
264
+ for issue in issues:
265
+ type_counts[issue.type] = type_counts.get(issue.type, 0) + 1
266
+ stage_status = {}
267
+ for stage_name, stage_result in stages.items():
268
+ stage_status[stage_name] = stage_result.status.value
269
+
270
+ return {
271
+ "session_id": self.session_state.session_id,
272
+ "duration": time.time() - self.session_state.start_time,
273
+ "current_stage": self.session_state.current_stage,
274
+ "stages": stage_status,
275
+ "total_issues": len(issues),
276
+ "issues_by_priority": priority_counts,
277
+ "issues_by_type": type_counts,
278
+ "total_fixes": len(fixes),
279
+ "auto_fixable_issues": len(self.get_auto_fixable_issues()),
280
+ }
281
+
282
+ async def save_checkpoint(self, name: str) -> None:
283
+ async with self._lock:
284
+ checkpoint_file = self.checkpoints_dir / f"{name}.json"
285
+ checkpoint_data = {
286
+ "name": name,
287
+ "timestamp": time.time(),
288
+ "session_state": self.session_state.to_dict(),
289
+ }
290
+ with checkpoint_file.open("w") as f:
291
+ json.dump(checkpoint_data, f, indent=2)
292
+
293
+ def load_checkpoint(self, name: str) -> bool:
294
+ checkpoint_file = self.checkpoints_dir / f"{name}.json"
295
+ if not checkpoint_file.exists():
296
+ return False
297
+ try:
298
+ with checkpoint_file.open() as f:
299
+ checkpoint_data = json.load(f)
300
+ session_data = checkpoint_data["session_state"]
301
+ self.session_state = SessionState(
302
+ session_id=session_data["session_id"],
303
+ start_time=session_data["start_time"],
304
+ current_stage=session_data.get("current_stage"),
305
+ metadata=session_data.get("metadata", {}),
306
+ )
307
+ stages = {}
308
+ for stage_name, stage_data in session_data.get("stages", {}).items():
309
+ issues = [
310
+ Issue(**issue_data)
311
+ for issue_data in stage_data.get("issues_found", [])
312
+ ]
313
+ stages[stage_name] = StageResult(
314
+ stage=stage_data["stage"],
315
+ status=StageStatus(stage_data["status"]),
316
+ start_time=stage_data["start_time"],
317
+ end_time=stage_data.get("end_time"),
318
+ duration=stage_data.get("duration"),
319
+ issues_found=issues,
320
+ fixes_applied=stage_data.get("fixes_applied", []),
321
+ error_message=stage_data.get("error_message"),
322
+ )
323
+ self.session_state.stages = stages
324
+ global_issues = [
325
+ Issue(**issue_data)
326
+ for issue_data in session_data.get("global_issues", [])
327
+ ]
328
+ self.session_state.global_issues = global_issues
329
+ self.session_state.fixes_applied = session_data.get("fixes_applied", [])
330
+ self._save_state()
331
+ return True
332
+ except Exception:
333
+ return False
334
+
335
+ def list_checkpoints(self) -> list[dict[str, t.Any]]:
336
+ checkpoints: list[dict[str, t.Any]] = []
337
+ for checkpoint_file in self.checkpoints_dir.glob(" * .json"):
338
+ try:
339
+ with checkpoint_file.open() as f:
340
+ data = json.load(f)
341
+ checkpoints.append(
342
+ {
343
+ "name": data.get("name", checkpoint_file.stem),
344
+ "timestamp": data.get("timestamp", 0),
345
+ "file": str(checkpoint_file),
346
+ },
347
+ )
348
+ except Exception:
349
+ continue
350
+ import operator
351
+
352
+ checkpoints.sort(key=operator.itemgetter("timestamp"), reverse=True)
353
+ return checkpoints
354
+
355
+ def start_session(self) -> None:
356
+ self._save_state()
357
+
358
+ def complete_session(self) -> None:
359
+ if not self.session_state.metadata:
360
+ self.session_state.metadata = {}
361
+ self.session_state.metadata["status"] = "completed"
362
+ self.session_state.metadata["completed_time"] = time.time()
363
+ self._save_state()
364
+
365
+ async def reset_session(self) -> None:
366
+ async with self._lock:
367
+ self.session_state = SessionState(
368
+ session_id=self._generate_session_id(),
369
+ start_time=time.time(),
370
+ )
371
+ self._save_state()
372
+
373
+ def _save_state(self) -> None:
374
+ if self._batched_saver:
375
+ save_func = self._save_state_sync
376
+
377
+ save_func()
378
+ else:
379
+ self._save_state_sync()
380
+
381
+ def _save_state_sync(self) -> None:
382
+ state_file = self.state_dir / "current_session.json"
383
+ try:
384
+ with state_file.open("w") as f:
385
+ json.dump(self.session_state.to_dict(), f, indent=2)
386
+ except (OSError, json.JSONEncodeError):
387
+ pass
388
+ except Exception:
389
+ pass
390
+
391
+ def _load_state(self) -> bool:
392
+ state_file = self.state_dir / "current_session.json"
393
+ if not state_file.exists():
394
+ return False
395
+ try:
396
+ with state_file.open() as f:
397
+ session_data = json.load(f)
398
+ checkpoint_data = {"session_state": session_data}
399
+ temp_checkpoint = self.checkpoints_dir / "_temp.json"
400
+ with temp_checkpoint.open("w") as f:
401
+ json.dump(checkpoint_data, f)
402
+ result = self.load_checkpoint("_temp")
403
+ temp_checkpoint.unlink(missing_ok=True)
404
+
405
+ return result
406
+ except Exception:
407
+ return False
@@ -0,0 +1,259 @@
1
+ import asyncio
2
+ import logging
3
+ import time
4
+ import typing as t
5
+ from contextlib import asynccontextmanager, suppress
6
+ from dataclasses import dataclass
7
+
8
+ from acb import console
9
+
10
+ # console imported from acb
11
+ logger = logging.getLogger(__name__)
12
+
13
+
14
+ @dataclass
15
+ class TaskInfo:
16
+ task_id: str
17
+ task: asyncio.Task[t.Any]
18
+ created_at: float
19
+ description: str = ""
20
+ timeout_seconds: float | None = None
21
+
22
+
23
+ class AsyncTaskManager:
24
+ def __init__(self, max_concurrent_tasks: int = 10) -> None:
25
+ self.max_concurrent_tasks = max_concurrent_tasks
26
+ self._tasks: dict[str, TaskInfo] = {}
27
+ self._task_semaphore = asyncio.Semaphore(max_concurrent_tasks)
28
+ self._cleanup_task: asyncio.Task[t.Any] | None = None
29
+ self._running = False
30
+ self._lock = asyncio.Lock()
31
+
32
+ async def start(self) -> None:
33
+ self._running = True
34
+ self._cleanup_task = asyncio.create_task(self._cleanup_loop())
35
+ try:
36
+ console.print(
37
+ f"[green]🎯 Task Manager started (max {self.max_concurrent_tasks} concurrent)[ / green]",
38
+ )
39
+ except (ValueError, OSError):
40
+ import logging
41
+
42
+ logging.info(
43
+ f"Task Manager started (max {self.max_concurrent_tasks} concurrent) ",
44
+ )
45
+
46
+ async def stop(self) -> None:
47
+ self._running = False
48
+
49
+ if self._cleanup_task:
50
+ self._cleanup_task.cancel()
51
+ with suppress(asyncio.CancelledError):
52
+ await self._cleanup_task
53
+
54
+ await self._cancel_all_tasks()
55
+ try:
56
+ console.print("[yellow]🎯 Task Manager stopped[ / yellow]")
57
+ except (ValueError, OSError):
58
+ import logging
59
+
60
+ logging.info("Task Manager stopped")
61
+
62
+ async def create_task(
63
+ self,
64
+ coro: t.Coroutine[t.Any, t.Any, t.Any],
65
+ task_id: str,
66
+ description: str = "",
67
+ timeout_seconds: float | None = None,
68
+ ) -> asyncio.Task[t.Any]:
69
+ async with self._lock:
70
+ if task_id in self._tasks:
71
+ msg = f"Task {task_id} already exists"
72
+ raise ValueError(msg)
73
+
74
+ if len(self._tasks) >= self.max_concurrent_tasks:
75
+ msg = f"Maximum concurrent tasks ({self.max_concurrent_tasks}) reached"
76
+ raise RuntimeError(
77
+ msg,
78
+ )
79
+
80
+ if timeout_seconds:
81
+ coro = asyncio.wait_for(coro, timeout=timeout_seconds)
82
+
83
+ task = asyncio.create_task(self._wrap_task(coro, task_id))
84
+
85
+ task_info = TaskInfo(
86
+ task_id=task_id,
87
+ task=task,
88
+ created_at=time.time(),
89
+ description=description,
90
+ timeout_seconds=timeout_seconds,
91
+ )
92
+
93
+ async with self._lock:
94
+ self._tasks[task_id] = task_info
95
+
96
+ logger.info(f"Created task {task_id}: {description}")
97
+ from contextlib import suppress
98
+
99
+ with suppress(ValueError, OSError):
100
+ console.print(f"[blue]🚀 Task {task_id} created: {description}[ / blue]")
101
+ return task
102
+
103
+ async def _wrap_task(
104
+ self, coro: t.Coroutine[t.Any, t.Any, t.Any], task_id: str
105
+ ) -> t.Any:
106
+ try:
107
+ async with self._task_semaphore:
108
+ result = await coro
109
+ logger.info(f"Task {task_id} completed successfully")
110
+ return result
111
+ except asyncio.CancelledError:
112
+ logger.info(f"Task {task_id} was cancelled")
113
+ raise
114
+ except Exception as e:
115
+ logger.exception(f"Task {task_id} failed: {e}")
116
+ from contextlib import suppress
117
+
118
+ with suppress(ValueError, OSError):
119
+ console.print(f"[red]❌ Task {task_id} failed: {e}[ / red]")
120
+ raise
121
+ finally:
122
+ async with self._lock:
123
+ if task_id in self._tasks:
124
+ del self._tasks[task_id]
125
+
126
+ async def cancel_task(self, task_id: str) -> bool:
127
+ async with self._lock:
128
+ task_info = self._tasks.get(task_id)
129
+ if not task_info:
130
+ return False
131
+
132
+ task_info.task.cancel()
133
+ logger.info(f"Cancelled task {task_id}")
134
+ from contextlib import suppress
135
+
136
+ with suppress(ValueError, OSError):
137
+ console.print(f"[yellow]🚫 Task {task_id} cancelled[ / yellow]")
138
+ return True
139
+
140
+ async def get_task_status(self, task_id: str) -> dict[str, t.Any] | None:
141
+ async with self._lock:
142
+ task_info = self._tasks.get(task_id)
143
+ if not task_info:
144
+ return None
145
+
146
+ return {
147
+ "task_id": task_id,
148
+ "description": task_info.description,
149
+ "created_at": task_info.created_at,
150
+ "running_time": time.time() - task_info.created_at,
151
+ "done": task_info.task.done(),
152
+ "cancelled": task_info.task.cancelled(),
153
+ "timeout_seconds": task_info.timeout_seconds,
154
+ }
155
+
156
+ async def list_active_tasks(self) -> list[dict[str, t.Any]]:
157
+ async with self._lock:
158
+ tasks = []
159
+ for task_id, task_info in self._tasks.items():
160
+ task_status = {
161
+ "task_id": task_id,
162
+ "description": task_info.description,
163
+ "created_at": task_info.created_at,
164
+ "running_time": time.time() - task_info.created_at,
165
+ "done": task_info.task.done(),
166
+ "cancelled": task_info.task.cancelled(),
167
+ "timeout_seconds": task_info.timeout_seconds,
168
+ }
169
+ tasks.append(task_status)
170
+ return tasks
171
+
172
+ async def wait_for_task(self, task_id: str, timeout: float | None = None) -> t.Any:
173
+ async with self._lock:
174
+ task_info = self._tasks.get(task_id)
175
+ if not task_info:
176
+ msg = f"Task {task_id} not found"
177
+ raise ValueError(msg)
178
+
179
+ try:
180
+ if timeout:
181
+ return await asyncio.wait_for(task_info.task, timeout=timeout)
182
+ return await task_info.task
183
+ except TimeoutError:
184
+ logger.warning(f"Timeout waiting for task {task_id}")
185
+ raise
186
+
187
+ @asynccontextmanager
188
+ async def managed_task(
189
+ self,
190
+ coro: t.Coroutine[t.Any, t.Any, t.Any],
191
+ task_id: str,
192
+ description: str = "",
193
+ timeout_seconds: float | None = None,
194
+ ) -> t.AsyncGenerator[asyncio.Task[t.Any]]:
195
+ task = await self.create_task(coro, task_id, description, timeout_seconds)
196
+ try:
197
+ yield task
198
+ finally:
199
+ if not task.done():
200
+ task.cancel()
201
+ with suppress(asyncio.CancelledError):
202
+ await task
203
+
204
+ async def _cancel_all_tasks(self) -> None:
205
+ async with self._lock:
206
+ tasks_to_cancel = list[t.Any](self._tasks.values())
207
+
208
+ if not tasks_to_cancel:
209
+ return
210
+
211
+ try:
212
+ console.print(
213
+ f"[yellow]🧹 Cancelling {len(tasks_to_cancel)} running tasks[ / yellow]",
214
+ )
215
+ except (ValueError, OSError):
216
+ import logging
217
+
218
+ logging.info(f"Cancelling {len(tasks_to_cancel)} running tasks")
219
+
220
+ for task_info in tasks_to_cancel:
221
+ task_info.task.cancel()
222
+
223
+ await asyncio.gather(
224
+ *[task_info.task for task_info in tasks_to_cancel],
225
+ return_exceptions=True,
226
+ )
227
+
228
+ async with self._lock:
229
+ self._tasks.clear()
230
+
231
+ async def _cleanup_loop(self) -> None:
232
+ while self._running:
233
+ try:
234
+ await self._cleanup_completed_tasks()
235
+ await asyncio.sleep(30)
236
+ except asyncio.CancelledError:
237
+ break
238
+ except Exception as e:
239
+ logger.exception(f"Error in task cleanup loop: {e}")
240
+ await asyncio.sleep(5)
241
+
242
+ async def _cleanup_completed_tasks(self) -> None:
243
+ async with self._lock:
244
+ completed_tasks = []
245
+ for task_id, task_info in list[t.Any](self._tasks.items()):
246
+ if task_info.task.done():
247
+ completed_tasks.append(task_id)
248
+ del self._tasks[task_id]
249
+
250
+ if completed_tasks:
251
+ logger.info(f"Cleaned up {len(completed_tasks)} completed tasks")
252
+
253
+ def get_stats(self) -> dict[str, t.Any]:
254
+ return {
255
+ "running": self._running,
256
+ "active_tasks": len(self._tasks),
257
+ "max_concurrent_tasks": self.max_concurrent_tasks,
258
+ "available_slots": self._task_semaphore._value,
259
+ }
@@ -0,0 +1,27 @@
1
+ # MCP Tools
2
+
3
+ MCP tool definitions and adapters for the Crackerjack MCP server.
4
+
5
+ ## Tool Categories
6
+
7
+ - **`execution_tools.py`** - Execute crackerjack workflows, get job progress
8
+ - **`monitoring_tools.py`** - System health, status reporting, workflow monitoring
9
+ - **`progress_tools.py`** - Real-time progress tracking for test execution
10
+ - **`semantic_tools.py`** - Semantic search, file indexing, embeddings
11
+ - **`intelligence_tools.py`** - AI agent selection, recommendations, performance analysis
12
+ - **`error_analyzer.py`** - Smart error analysis and pattern detection
13
+ - **`proactive_tools.py`** - Proactive monitoring and preventive quality checks
14
+ - **`utility_tools.py`** - Helper utilities and common operations
15
+ - **`workflow_executor.py`** - Workflow orchestration and execution management
16
+
17
+ ## Core Tools
18
+
19
+ The MCP server provides these primary capabilities:
20
+
21
+ 1. **Workflow Execution** - Run crackerjack quality checks via MCP
22
+ 1. **Job Tracking** - Monitor async job progress and status
23
+ 1. **Error Analysis** - Intelligent error detection and root cause analysis
24
+ 1. **Semantic Search** - Code search with vector embeddings
25
+ 1. **Agent Intelligence** - Smart agent selection based on task context
26
+
27
+ See parent `mcp/README.md` for server architecture details.