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,411 @@
1
+ import os
2
+ import signal
3
+ import sys
4
+ import time
5
+ import typing as t
6
+ from pathlib import Path
7
+
8
+ from acb.console import Console
9
+ from acb.depends import Inject, depends
10
+ from mcp_common.ui import ServerPanels
11
+
12
+ from .secure_subprocess import execute_secure_subprocess
13
+ from .security_logger import get_security_logger
14
+
15
+
16
+ def find_mcp_server_processes() -> list[dict[str, t.Any]]:
17
+ security_logger = get_security_logger()
18
+
19
+ try:
20
+ result = execute_secure_subprocess(
21
+ command=["ps", "aux"],
22
+ capture_output=True,
23
+ text=True,
24
+ check=True,
25
+ timeout=10.0,
26
+ )
27
+
28
+ return _parse_mcp_processes(result.stdout)
29
+
30
+ except Exception as e:
31
+ security_logger.log_subprocess_failure(
32
+ command=["ps", "aux"],
33
+ exit_code=-1,
34
+ error_output=str(e),
35
+ )
36
+ return []
37
+
38
+
39
+ def _parse_mcp_processes(stdout: str) -> list[dict[str, t.Any]]:
40
+ processes: list[dict[str, t.Any]] = []
41
+ str(Path.cwd())
42
+
43
+ for line in stdout.splitlines():
44
+ if _is_mcp_server_process(line):
45
+ process_info = _extract_process_info(line)
46
+ if process_info:
47
+ processes.append(process_info)
48
+
49
+ return processes
50
+
51
+
52
+ def _is_mcp_server_process(line: str) -> bool:
53
+ return (
54
+ "crackerjack" in line
55
+ and "--start-mcp-server" in line
56
+ and "python" in line.lower()
57
+ )
58
+
59
+
60
+ def _is_zuban_lsp_process(line: str) -> bool:
61
+ return (
62
+ "zuban" in line
63
+ and "server" in line
64
+ and ("uv" in line.lower() or "python" in line.lower())
65
+ )
66
+
67
+
68
+ def _extract_process_info(line: str) -> dict[str, t.Any] | None:
69
+ parts = line.split()
70
+ if len(parts) < 11:
71
+ return None
72
+
73
+ try:
74
+ pid = int(parts[1])
75
+
76
+ command_start_index = _find_command_start_index(parts)
77
+
78
+ return {
79
+ "pid": pid,
80
+ "command": " ".join(parts[command_start_index:]),
81
+ "user": parts[0],
82
+ "cpu": parts[2],
83
+ "mem": parts[3],
84
+ }
85
+ except (ValueError, IndexError):
86
+ return None
87
+
88
+
89
+ def _find_command_start_index(parts: list[str]) -> int:
90
+ command_start_index = 10
91
+ for i, part in enumerate(parts):
92
+ if part.endswith("python") or "Python" in part:
93
+ command_start_index = i
94
+ break
95
+ return command_start_index
96
+
97
+
98
+ def find_websocket_server_processes() -> list[dict[str, t.Any]]:
99
+ security_logger = get_security_logger()
100
+
101
+ try:
102
+ result = execute_secure_subprocess(
103
+ command=["ps", "aux"],
104
+ capture_output=True,
105
+ text=True,
106
+ check=True,
107
+ timeout=10.0,
108
+ )
109
+
110
+ processes: list[dict[str, t.Any]] = []
111
+
112
+ for line in result.stdout.splitlines():
113
+ if "crackerjack" in line and "- - start - websocket-server" in line:
114
+ parts = line.split()
115
+ if len(parts) >= 11:
116
+ try:
117
+ pid = int(parts[1])
118
+ processes.append(
119
+ {
120
+ "pid": pid,
121
+ "command": " ".join(parts[10:]),
122
+ "user": parts[0],
123
+ "cpu": parts[2],
124
+ "mem": parts[3],
125
+ },
126
+ )
127
+ except (ValueError, IndexError):
128
+ continue
129
+
130
+ return processes
131
+
132
+ except Exception as e:
133
+ security_logger.log_subprocess_failure(
134
+ command=["ps", "aux"],
135
+ exit_code=-1,
136
+ error_output=str(e),
137
+ )
138
+ return []
139
+
140
+
141
+ def find_zuban_lsp_processes() -> list[dict[str, t.Any]]:
142
+ """Find running zuban LSP server processes."""
143
+ security_logger = get_security_logger()
144
+
145
+ try:
146
+ result = execute_secure_subprocess(
147
+ command=["ps", "aux"],
148
+ capture_output=True,
149
+ text=True,
150
+ check=True,
151
+ timeout=10.0,
152
+ )
153
+
154
+ return _parse_zuban_lsp_processes(result.stdout)
155
+
156
+ except Exception as e:
157
+ security_logger.log_subprocess_failure(
158
+ command=["ps", "aux"],
159
+ exit_code=-1,
160
+ error_output=str(e),
161
+ )
162
+ return []
163
+
164
+
165
+ def _parse_zuban_lsp_processes(stdout: str) -> list[dict[str, t.Any]]:
166
+ """Parse zuban LSP processes from ps output."""
167
+ processes: list[dict[str, t.Any]] = []
168
+
169
+ for line in stdout.splitlines():
170
+ if _is_zuban_lsp_process(line):
171
+ process_info = _extract_process_info(line)
172
+ if process_info:
173
+ processes.append(process_info)
174
+
175
+ return processes
176
+
177
+
178
+ def stop_process(pid: int, force: bool = False) -> bool:
179
+ try:
180
+ if force:
181
+ os.kill(pid, signal.SIGKILL)
182
+ else:
183
+ os.kill(pid, signal.SIGTERM)
184
+
185
+ for _ in range(10):
186
+ try:
187
+ os.kill(pid, 0)
188
+ time.sleep(0.5)
189
+ except OSError:
190
+ return True
191
+
192
+ if not force:
193
+ os.kill(pid, signal.SIGKILL)
194
+ time.sleep(1)
195
+
196
+ return True
197
+
198
+ except (OSError, ProcessLookupError):
199
+ return True
200
+
201
+
202
+ @depends.inject
203
+ def stop_mcp_server(console: Inject[Console]) -> bool:
204
+ processes = find_mcp_server_processes()
205
+
206
+ if not processes:
207
+ console.print("[yellow]⚠️ No MCP server processes found[/ yellow]")
208
+ return True
209
+
210
+ ServerPanels.info(
211
+ title="MCP Server", message=f"Stopping {len(processes)} process(es)"
212
+ )
213
+
214
+ success = True
215
+ for proc in processes:
216
+ console.print(f"Stopping process {proc['pid']}...")
217
+ if stop_process(proc["pid"]):
218
+ console.print(f"✅ Process {proc['pid']} terminated gracefully")
219
+ else:
220
+ console.print(f"❌ Failed to stop process {proc['pid']}")
221
+ success = False
222
+
223
+ if success:
224
+ ServerPanels.info(
225
+ title="MCP Server",
226
+ message=f"Successfully stopped {len(processes)} process(es)",
227
+ )
228
+
229
+ return success
230
+
231
+
232
+ @depends.inject
233
+ def stop_websocket_server(console: Inject[Console]) -> bool:
234
+ processes = find_websocket_server_processes()
235
+
236
+ if not processes:
237
+ console.print("[yellow]⚠️ No WebSocket server processes found[/ yellow]")
238
+ return True
239
+
240
+ success = True
241
+ for proc in processes:
242
+ console.print(f"🛑 Stopping WebSocket server process {proc['pid']}")
243
+ if stop_process(proc["pid"]):
244
+ console.print(f"✅ Stopped process {proc['pid']}")
245
+ else:
246
+ console.print(f"❌ Failed to stop process {proc['pid']}")
247
+ success = False
248
+
249
+ return success
250
+
251
+
252
+ @depends.inject
253
+ def stop_zuban_lsp(console: Inject[Console]) -> bool:
254
+ """Stop running zuban LSP server processes."""
255
+ processes = find_zuban_lsp_processes()
256
+
257
+ if not processes:
258
+ console.print("[yellow]⚠️ No Zuban LSP server processes found[/ yellow]")
259
+ return True
260
+
261
+ success = True
262
+ for proc in processes:
263
+ console.print(f"🛑 Stopping Zuban LSP server process {proc['pid']}")
264
+ if stop_process(proc["pid"]):
265
+ console.print(f"✅ Stopped process {proc['pid']}")
266
+ else:
267
+ console.print(f"❌ Failed to stop process {proc['pid']}")
268
+ success = False
269
+
270
+ return success
271
+
272
+
273
+ @depends.inject
274
+ def stop_all_servers(console: Inject[Console]) -> bool:
275
+ mcp_success = stop_mcp_server()
276
+ websocket_success = stop_websocket_server()
277
+ zuban_lsp_success = stop_zuban_lsp()
278
+
279
+ return mcp_success and websocket_success and zuban_lsp_success
280
+
281
+
282
+ @depends.inject
283
+ def restart_mcp_server(
284
+ websocket_port: int | None = None,
285
+ console: Inject[Console] = None,
286
+ ) -> bool:
287
+ ServerPanels.info(
288
+ title="MCP Server", message="Restarting Crackerjack MCP Server..."
289
+ )
290
+
291
+ stop_mcp_server()
292
+
293
+ ServerPanels.simple_message("⏳ Waiting for cleanup...", style="dim")
294
+ time.sleep(2)
295
+
296
+ ServerPanels.simple_message("🚀 Starting new server instance...", style="green")
297
+ try:
298
+ cmd = [sys.executable, "-m", "crackerjack", "--start-mcp-server"]
299
+ if websocket_port:
300
+ cmd.extend(["--websocket-port", str(websocket_port)])
301
+
302
+ import subprocess
303
+
304
+ process = subprocess.Popen(
305
+ cmd,
306
+ stdout=subprocess.DEVNULL,
307
+ stderr=subprocess.DEVNULL,
308
+ start_new_session=True,
309
+ )
310
+
311
+ security_logger = get_security_logger()
312
+ security_logger.log_subprocess_execution(
313
+ command=cmd,
314
+ purpose="mcp_server_restart",
315
+ )
316
+
317
+ # Give the server a moment to start
318
+ time.sleep(1)
319
+
320
+ # Display success panel with server details
321
+ http_endpoint = "http://127.0.0.1:8676/mcp"
322
+
323
+ ServerPanels.startup_success(
324
+ server_name="Crackerjack MCP",
325
+ endpoint=http_endpoint,
326
+ process_id=process.pid,
327
+ )
328
+ return True
329
+
330
+ except Exception as e:
331
+ ServerPanels.error(title="MCP Restart Error", message=str(e))
332
+ return False
333
+
334
+
335
+ @depends.inject
336
+ def restart_zuban_lsp(console: Inject[Console]) -> bool:
337
+ """Restart zuban LSP server."""
338
+ console.print("[bold cyan]🔄 Restarting Zuban LSP server...[/ bold cyan]")
339
+
340
+ stop_zuban_lsp()
341
+
342
+ console.print("⏳ Waiting for cleanup")
343
+ time.sleep(2)
344
+
345
+ console.print("🚀 Starting new Zuban LSP server")
346
+ try:
347
+ cmd = [sys.executable, "-m", "crackerjack", "--start-zuban-lsp"]
348
+
349
+ import subprocess
350
+
351
+ subprocess.Popen(
352
+ cmd,
353
+ stdout=subprocess.DEVNULL,
354
+ stderr=subprocess.DEVNULL,
355
+ start_new_session=True,
356
+ )
357
+
358
+ security_logger = get_security_logger()
359
+ security_logger.log_subprocess_execution(
360
+ command=cmd,
361
+ purpose="zuban_lsp_restart",
362
+ )
363
+
364
+ console.print("✅ Zuban LSP server restart initiated")
365
+ return True
366
+
367
+ except Exception as e:
368
+ console.print(f"❌ Failed to restart Zuban LSP server: {e}")
369
+ return False
370
+
371
+
372
+ @depends.inject
373
+ def list_server_status(console: Inject[Console]) -> None:
374
+ console.print("[bold cyan]📊 Crackerjack Server Status[/ bold cyan]")
375
+
376
+ mcp_processes = find_mcp_server_processes()
377
+ websocket_processes = find_websocket_server_processes()
378
+ zuban_lsp_processes = find_zuban_lsp_processes()
379
+
380
+ if mcp_processes:
381
+ console.print("\n[bold green]MCP Servers: [/ bold green]")
382
+ for proc in mcp_processes:
383
+ console.print(
384
+ f" • PID {proc['pid']} - CPU: {proc['cpu']}%-Memory: {proc['mem']}%",
385
+ )
386
+ console.print(f" Command: {proc['command']}")
387
+ else:
388
+ console.print("\n[yellow]MCP Servers: None running[/ yellow]")
389
+
390
+ if websocket_processes:
391
+ console.print("\n[bold green]WebSocket Servers: [/ bold green]")
392
+ for proc in websocket_processes:
393
+ console.print(
394
+ f" • PID {proc['pid']} - CPU: {proc['cpu']}%-Memory: {proc['mem']}%",
395
+ )
396
+ console.print(f" Command: {proc['command']}")
397
+ else:
398
+ console.print("\n[yellow]WebSocket Servers: None running[/ yellow]")
399
+
400
+ if zuban_lsp_processes:
401
+ console.print("\n[bold green]Zuban LSP Servers: [/ bold green]")
402
+ for proc in zuban_lsp_processes:
403
+ console.print(
404
+ f" • PID {proc['pid']} - CPU: {proc['cpu']}%-Memory: {proc['mem']}%",
405
+ )
406
+ console.print(f" Command: {proc['command']}")
407
+ else:
408
+ console.print("\n[yellow]Zuban LSP Servers: None running[/ yellow]")
409
+
410
+ if not mcp_processes and not websocket_processes and not zuban_lsp_processes:
411
+ console.print("\n[dim]No crackerjack servers currently running[/ dim]")
@@ -0,0 +1,167 @@
1
+ import os
2
+ import subprocess
3
+ import typing as t
4
+ from contextlib import suppress
5
+ from datetime import datetime, timedelta
6
+ from pathlib import Path
7
+
8
+ from acb.console import Console
9
+ from acb.depends import Inject, depends
10
+
11
+ from crackerjack.models.protocols import ServiceProtocol, SmartSchedulingServiceProtocol
12
+
13
+
14
+ class SmartSchedulingService(SmartSchedulingServiceProtocol, ServiceProtocol):
15
+ @depends.inject
16
+ def __init__(self, console: Inject[Console], project_path: Path) -> None:
17
+ self.console = console
18
+ self.project_path = project_path
19
+ self.cache_dir = Path.home() / ".cache" / "crackerjack"
20
+ self.cache_dir.mkdir(parents=True, exist_ok=True)
21
+
22
+ def initialize(self) -> None:
23
+ pass
24
+
25
+ def cleanup(self) -> None:
26
+ pass
27
+
28
+ def health_check(self) -> bool:
29
+ return True
30
+
31
+ def shutdown(self) -> None:
32
+ pass
33
+
34
+ def metrics(self) -> dict[str, t.Any]:
35
+ return {}
36
+
37
+ def is_healthy(self) -> bool:
38
+ return True
39
+
40
+ def register_resource(self, resource: t.Any) -> None:
41
+ pass
42
+
43
+ def cleanup_resource(self, resource: t.Any) -> None:
44
+ pass
45
+
46
+ def record_error(self, error: Exception) -> None:
47
+ pass
48
+
49
+ def increment_requests(self) -> None:
50
+ pass
51
+
52
+ def get_custom_metric(self, name: str) -> t.Any:
53
+ return None
54
+
55
+ def set_custom_metric(self, name: str, value: t.Any) -> None:
56
+ pass
57
+
58
+ def should_scheduled_init(self) -> bool:
59
+ init_schedule = os.environ.get("CRACKERJACK_INIT_SCHEDULE", "weekly")
60
+
61
+ if init_schedule == "disabled":
62
+ return False
63
+
64
+ if init_schedule == "weekly":
65
+ return self._check_weekly_schedule()
66
+ if init_schedule == "commit-based":
67
+ return self._check_commit_based_schedule()
68
+ if init_schedule == "activity-based":
69
+ return self._check_activity_based_schedule()
70
+
71
+ return self._check_weekly_schedule()
72
+
73
+ def record_init_timestamp(self) -> None:
74
+ timestamp_file = self.cache_dir / f"{self.project_path.name}.init_timestamp"
75
+ try:
76
+ timestamp_file.write_text(datetime.now().isoformat())
77
+ except OSError as e:
78
+ self.console.print(
79
+ f"[yellow]⚠️ Could not record init timestamp: {e}[/ yellow]",
80
+ )
81
+
82
+ def _check_weekly_schedule(self) -> bool:
83
+ init_day = os.environ.get("CRACKERJACK_INIT_DAY", "monday")
84
+ today = datetime.now().strftime("% A").lower()
85
+
86
+ if today == init_day.lower():
87
+ last_init = self._get_last_init_timestamp()
88
+ if datetime.now() - last_init > timedelta(days=6):
89
+ self.console.print(
90
+ f"[blue]📅 Weekly initialization scheduled for {init_day}[/ blue]",
91
+ )
92
+ return True
93
+
94
+ return False
95
+
96
+ def _check_commit_based_schedule(self) -> bool:
97
+ commits_since_init = self._count_commits_since_init()
98
+ threshold = int(os.environ.get("CRACKERJACK_INIT_COMMITS", "50"))
99
+
100
+ if commits_since_init >= threshold:
101
+ self.console.print(
102
+ f"[blue]📊 {commits_since_init} commits since last init "
103
+ f"(threshold: {threshold})[/ blue]",
104
+ )
105
+ return True
106
+
107
+ return False
108
+
109
+ def _check_activity_based_schedule(self) -> bool:
110
+ if self._has_recent_activity() and self._days_since_init() >= 7:
111
+ self.console.print(
112
+ "[blue]⚡ Recent activity detected, initialization recommended[/ blue]",
113
+ )
114
+ return True
115
+
116
+ return False
117
+
118
+ def _get_last_init_timestamp(self) -> datetime:
119
+ timestamp_file = self.cache_dir / f"{self.project_path.name}.init_timestamp"
120
+
121
+ if timestamp_file.exists():
122
+ with suppress(OSError, ValueError):
123
+ timestamp_str = timestamp_file.read_text().strip()
124
+ return datetime.fromisoformat(timestamp_str)
125
+
126
+ return datetime.now() - timedelta(days=30)
127
+
128
+ def _count_commits_since_init(self) -> int:
129
+ since_date = self._get_last_init_timestamp().strftime("% Y - % m - % d")
130
+
131
+ try:
132
+ result = subprocess.run(
133
+ ["git", "log", f"--since ={since_date}", "--oneline"],
134
+ cwd=self.project_path,
135
+ capture_output=True,
136
+ text=True,
137
+ timeout=10,
138
+ check=False,
139
+ )
140
+
141
+ if result.returncode == 0:
142
+ return len([line for line in result.stdout.strip().split("\n") if line])
143
+
144
+ except (FileNotFoundError, subprocess.TimeoutExpired):
145
+ pass
146
+
147
+ return 0
148
+
149
+ def _has_recent_activity(self) -> bool:
150
+ try:
151
+ result = subprocess.run(
152
+ ["git", "log", "-1", "--since=24.hours", "--oneline"],
153
+ cwd=self.project_path,
154
+ capture_output=True,
155
+ text=True,
156
+ timeout=10,
157
+ check=False,
158
+ )
159
+
160
+ return result.returncode == 0 and bool(result.stdout.strip())
161
+
162
+ except (FileNotFoundError, subprocess.TimeoutExpired):
163
+ return False
164
+
165
+ def _days_since_init(self) -> int:
166
+ last_init = self._get_last_init_timestamp()
167
+ return (datetime.now() - last_init).days