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,719 @@
1
+ import time
2
+ import typing as t
3
+ from dataclasses import dataclass
4
+ from enum import Enum, auto
5
+ from functools import partial
6
+ from typing import Protocol
7
+
8
+ from acb.console import Console
9
+ from acb.depends import depends
10
+ from rich.panel import Panel
11
+ from rich.prompt import Confirm
12
+ from rich.table import Table
13
+ from rich.text import Text
14
+ from rich.tree import Tree
15
+
16
+ from .errors import CrackerjackError, ErrorCode
17
+
18
+
19
+ class TaskStatus(Enum):
20
+ PENDING = auto()
21
+ RUNNING = auto()
22
+ SUCCESS = auto()
23
+ FAILED = auto()
24
+ SKIPPED = auto()
25
+
26
+
27
+ @dataclass
28
+ class InteractiveWorkflowOptions:
29
+ clean: bool = False
30
+ test: bool = False
31
+ publish: str | None = None
32
+ bump: str | None = None
33
+ commit: bool = False
34
+ create_pr: bool = False
35
+ interactive: bool = True
36
+ dry_run: bool = False
37
+
38
+ def __init__(
39
+ self,
40
+ clean: bool = False,
41
+ test: bool = False,
42
+ publish: str | None = None,
43
+ bump: str | None = None,
44
+ commit: bool = False,
45
+ create_pr: bool = False,
46
+ interactive: bool = True,
47
+ dry_run: bool = False,
48
+ ) -> None:
49
+ self.clean = clean
50
+ self.test = test
51
+ self.publish = publish
52
+ self.bump = bump
53
+ self.commit = commit
54
+ self.create_pr = create_pr
55
+ self.interactive = interactive
56
+ self.dry_run = dry_run
57
+
58
+ @classmethod
59
+ def from_args(cls, args: t.Any) -> "InteractiveWorkflowOptions":
60
+ return cls(
61
+ clean=getattr(args, "clean", False),
62
+ test=getattr(args, "test", False),
63
+ publish=getattr(args, "publish", None),
64
+ bump=getattr(args, "bump", None),
65
+ commit=getattr(args, "commit", False),
66
+ create_pr=getattr(args, "create_pr", False),
67
+ interactive=getattr(args, "interactive", True),
68
+ dry_run=getattr(args, "dry_run", False),
69
+ )
70
+
71
+
72
+ class TaskExecutor(Protocol):
73
+ def __call__(self) -> bool: ...
74
+
75
+
76
+ @dataclass
77
+ class TaskDefinition:
78
+ id: str
79
+ name: str
80
+ description: str
81
+ dependencies: list[str]
82
+ optional: bool = False
83
+ estimated_duration: float = 0.0
84
+
85
+ def __post_init__(self) -> None:
86
+ if not self.dependencies:
87
+ self.dependencies = []
88
+
89
+
90
+ class Task:
91
+ def __init__(
92
+ self,
93
+ definition: TaskDefinition,
94
+ executor: TaskExecutor | None = None,
95
+ workflow_tasks: dict[str, "Task"] | None = None,
96
+ ) -> None:
97
+ self.definition = definition
98
+ self.executor = executor
99
+ self.status = TaskStatus.PENDING
100
+ self.start_time: float | None = None
101
+ self.end_time: float | None = None
102
+ self.error: CrackerjackError | None = None
103
+ self._workflow_tasks = workflow_tasks
104
+ import logging
105
+
106
+ self.logger = logging.getLogger(f"crackerjack.task.{definition.id}")
107
+
108
+ @property
109
+ def name(self) -> str:
110
+ return self.definition.name
111
+
112
+ @property
113
+ def description(self) -> str:
114
+ return self.definition.description
115
+
116
+ @property
117
+ def dependencies(self) -> list["Task"] | list[str]:
118
+ if self._workflow_tasks:
119
+ return [
120
+ self._workflow_tasks[dep_name]
121
+ for dep_name in self.definition.dependencies
122
+ if dep_name in self._workflow_tasks
123
+ ]
124
+ return self.definition.dependencies
125
+
126
+ def get_resolved_dependencies(
127
+ self,
128
+ workflow_tasks: dict[str, "Task"],
129
+ ) -> list["Task"]:
130
+ return [
131
+ workflow_tasks[dep_name]
132
+ for dep_name in self.definition.dependencies
133
+ if dep_name in workflow_tasks
134
+ ]
135
+
136
+ @property
137
+ def duration(self) -> float | None:
138
+ if self.start_time is None:
139
+ return None
140
+ end = self.end_time or time.time()
141
+ return end - self.start_time
142
+
143
+ def start(self) -> None:
144
+ self.status = TaskStatus.RUNNING
145
+ self.start_time = time.time()
146
+ self.logger.info("Task started", extra={"task_id": self.definition.id})
147
+
148
+ def complete(self, success: bool = True) -> None:
149
+ self.end_time = time.time()
150
+ self.status = TaskStatus.SUCCESS if success else TaskStatus.FAILED
151
+
152
+ self.logger.info(
153
+ "Task completed",
154
+ extra={
155
+ "task_id": self.definition.id,
156
+ "success": success,
157
+ "duration": self.duration,
158
+ },
159
+ )
160
+
161
+ def skip(self) -> None:
162
+ self.status = TaskStatus.SKIPPED
163
+ self.end_time = time.time()
164
+ self.logger.info("Task skipped", extra={"task_id": self.definition.id})
165
+
166
+ def fail(self, error: CrackerjackError) -> None:
167
+ self.status = TaskStatus.FAILED
168
+ self.end_time = time.time()
169
+ self.error = error
170
+
171
+ self.logger.error(
172
+ "Task failed",
173
+ extra={
174
+ "task_id": self.definition.id,
175
+ "error": str(error),
176
+ "duration": self.duration,
177
+ },
178
+ )
179
+
180
+ def can_run(self, completed_tasks: set[str]) -> bool:
181
+ if self._workflow_tasks:
182
+ resolved_deps = self.get_resolved_dependencies(self._workflow_tasks)
183
+ return all(
184
+ dep.status in (TaskStatus.SUCCESS, TaskStatus.SKIPPED)
185
+ for dep in resolved_deps
186
+ )
187
+
188
+ return all(dep in completed_tasks for dep in self.definition.dependencies)
189
+
190
+
191
+ class WorkflowBuilder:
192
+ def __init__(self, console: Console) -> None:
193
+ self.console = console
194
+ self.tasks: dict[str, TaskDefinition] = {}
195
+ import logging
196
+
197
+ self.logger = logging.getLogger("crackerjack.workflow.builder")
198
+
199
+ def add_task(
200
+ self,
201
+ task_id: str,
202
+ name: str,
203
+ description: str,
204
+ dependencies: list[str] | None = None,
205
+ optional: bool = False,
206
+ estimated_duration: float = 0.0,
207
+ ) -> "WorkflowBuilder":
208
+ task_def = TaskDefinition(
209
+ id=task_id,
210
+ name=name,
211
+ description=description,
212
+ dependencies=dependencies or [],
213
+ optional=optional,
214
+ estimated_duration=estimated_duration,
215
+ )
216
+
217
+ self.tasks[task_id] = task_def
218
+ self.logger.debug("Task added to workflow", extra={"task_id": task_id})
219
+ return self
220
+
221
+ def add_conditional_task(
222
+ self,
223
+ condition: bool,
224
+ task_id: str,
225
+ name: str,
226
+ description: str,
227
+ dependencies: list[str] | None = None,
228
+ estimated_duration: float = 0.0,
229
+ ) -> str:
230
+ if condition:
231
+ self.add_task(
232
+ task_id=task_id,
233
+ name=name,
234
+ description=description,
235
+ dependencies=dependencies,
236
+ estimated_duration=estimated_duration,
237
+ )
238
+ return task_id
239
+
240
+ return dependencies[-1] if dependencies else ""
241
+
242
+ def build(self) -> dict[str, TaskDefinition]:
243
+ self._validate_workflow()
244
+ return self.tasks.copy()
245
+
246
+ def _validate_workflow(self) -> None:
247
+ self._validate_dependencies()
248
+ self._check_circular_dependencies()
249
+
250
+ def _validate_dependencies(self) -> None:
251
+ for task_id, task_def in self.tasks.items():
252
+ for dep in task_def.dependencies:
253
+ if dep not in self.tasks:
254
+ msg = f"Task {task_id} depends on unknown task {dep}"
255
+ raise ValueError(msg)
256
+
257
+ def _check_circular_dependencies(self) -> None:
258
+ visited: set[str] = set()
259
+ rec_stack: set[str] = set()
260
+
261
+ def has_cycle(task_id: str) -> bool:
262
+ visited.add(task_id)
263
+ rec_stack.add(task_id)
264
+
265
+ for dep in self.tasks[task_id].dependencies:
266
+ if dep not in visited:
267
+ if has_cycle(dep):
268
+ return True
269
+ elif dep in rec_stack:
270
+ return True
271
+
272
+ rec_stack.remove(task_id)
273
+ return False
274
+
275
+ for task_id in self.tasks:
276
+ if task_id not in visited and has_cycle(task_id):
277
+ msg = f"Circular dependency detected involving task {task_id}"
278
+ raise ValueError(
279
+ msg,
280
+ )
281
+
282
+
283
+ class WorkflowManager:
284
+ def __init__(self, console: Console) -> None:
285
+ self.console = console
286
+ self.tasks: dict[str, Task] = {}
287
+ self.task_definitions: dict[str, TaskDefinition] = {}
288
+ import logging
289
+
290
+ self.logger = logging.getLogger("crackerjack.workflow.manager")
291
+
292
+ def load_workflow(self, task_definitions: dict[str, TaskDefinition]) -> None:
293
+ self.task_definitions = task_definitions
294
+ self.tasks = {
295
+ task_id: Task(definition)
296
+ for task_id, definition in task_definitions.items()
297
+ }
298
+
299
+ for task in self.tasks.values():
300
+ task._workflow_tasks = self.tasks
301
+
302
+ self.logger.info("Workflow loaded", extra={"task_count": len(self.tasks)})
303
+
304
+ def set_task_executor(self, task_id: str, executor: TaskExecutor) -> None:
305
+ if task_id in self.tasks:
306
+ self.tasks[task_id].executor = executor
307
+
308
+ def get_next_task(self) -> Task | None:
309
+ completed_tasks = {
310
+ task_id
311
+ for task_id, task in self.tasks.items()
312
+ if task.status == TaskStatus.SUCCESS
313
+ }
314
+
315
+ for task in self.tasks.values():
316
+ if task.status == TaskStatus.PENDING and task.can_run(completed_tasks):
317
+ return task
318
+
319
+ return None
320
+
321
+ def all_tasks_completed(self) -> bool:
322
+ return all(
323
+ task.status in (TaskStatus.SUCCESS, TaskStatus.FAILED, TaskStatus.SKIPPED)
324
+ for task in self.tasks.values()
325
+ )
326
+
327
+ def run_task(self, task: Task) -> bool:
328
+ if not task.executor:
329
+ return self._handle_task_without_executor(task)
330
+
331
+ return self._execute_task_with_executor(task)
332
+
333
+ def _handle_task_without_executor(self, task: Task) -> bool:
334
+ task.skip()
335
+ self.console.print(f"[yellow]⏭️ Skipped {task.name} (no executor)[/ yellow]")
336
+ return True
337
+
338
+ def _execute_task_with_executor(self, task: Task) -> bool:
339
+ task.start()
340
+ self.console.print(f"[blue]🔄 Running {task.name}...[/ blue]")
341
+
342
+ try:
343
+ return self._try_execute_task(task)
344
+ except Exception as e:
345
+ return self._handle_task_exception(task, e)
346
+
347
+ def _try_execute_task(self, task: Task) -> bool:
348
+ self.logger.info(f"Executing task: {task.definition.id}")
349
+ success = task.executor() if task.executor else False
350
+ task.complete(success)
351
+
352
+ self._display_task_result(task, success)
353
+ return success
354
+
355
+ def _display_task_result(self, task: Task, success: bool) -> None:
356
+ if success:
357
+ duration_str = f" ({task.duration: .1f}s)" if task.duration else ""
358
+ self.console.print(f"[green]✅ {task.name}{duration_str}[/ green]")
359
+ else:
360
+ self.console.print(f"[red]❌ {task.name} failed[/ red]")
361
+
362
+ def _handle_task_exception(self, task: Task, e: Exception) -> bool:
363
+ error = CrackerjackError(
364
+ message=f"Task {task.name} failed: {e}",
365
+ error_code=ErrorCode.COMMAND_EXECUTION_ERROR,
366
+ )
367
+ task.fail(error)
368
+ self.console.print(f"[red]💥 {task.name} crashed: {e}[/ red]")
369
+ return False
370
+
371
+ def display_task_tree(self) -> None:
372
+ tree = Tree("🚀 Workflow Tasks")
373
+ status_groups = self._get_status_groups()
374
+
375
+ for status, (label, color) in status_groups.items():
376
+ self._add_status_branch(tree, status, label, color)
377
+
378
+ self.console.print(tree)
379
+
380
+ def _get_status_groups(self) -> dict[TaskStatus, tuple[str, str]]:
381
+ return {
382
+ TaskStatus.SUCCESS: ("✅ Completed", "green"),
383
+ TaskStatus.RUNNING: ("🔄 Running", "blue"),
384
+ TaskStatus.FAILED: ("❌ Failed", "red"),
385
+ TaskStatus.SKIPPED: ("⏭️ Skipped", "yellow"),
386
+ TaskStatus.PENDING: ("⏳ Pending", "white"),
387
+ }
388
+
389
+ def _add_status_branch(
390
+ self,
391
+ tree: Tree,
392
+ status: TaskStatus,
393
+ label: str,
394
+ color: str,
395
+ ) -> None:
396
+ status_tasks = [task for task in self.tasks.values() if task.status == status]
397
+
398
+ if not status_tasks:
399
+ return
400
+
401
+ status_branch = tree.add(f"[{color}]{label}[/{color}]")
402
+ for task in status_tasks:
403
+ duration_str = f" ({task.duration: .1f}s)" if task.duration else ""
404
+ status_branch.add(f"{task.name}{duration_str}")
405
+
406
+ def get_workflow_summary(self) -> dict[str, int]:
407
+ summary = {status.name.lower(): 0 for status in TaskStatus}
408
+
409
+ for task in self.tasks.values():
410
+ summary[task.status.name.lower()] += 1
411
+
412
+ return summary
413
+
414
+
415
+ class InteractiveCLI:
416
+ def __init__(self, console: Console | None = None) -> None:
417
+ self.console = console or depends.get_sync(Console)
418
+ self.workflow = WorkflowManager(self.console)
419
+ import logging
420
+
421
+ self.logger = logging.getLogger("crackerjack.interactive.cli")
422
+
423
+ def create_dynamic_workflow(self, options: InteractiveWorkflowOptions) -> None:
424
+ builder = WorkflowBuilder(self.console)
425
+
426
+ workflow_steps: list[t.Callable[[WorkflowBuilder, str], str]] = [
427
+ self._add_setup_phase,
428
+ self._add_config_phase,
429
+ partial(self._add_cleaning_phase, enabled=options.clean),
430
+ self._add_fast_hooks_phase,
431
+ partial(self._add_testing_phase, enabled=options.test),
432
+ self._add_comprehensive_hooks_phase,
433
+ partial(
434
+ self._add_version_phase,
435
+ enabled=bool(options.publish or options.bump),
436
+ ),
437
+ partial(self._add_publish_phase, enabled=bool(options.publish)),
438
+ partial(self._add_commit_phase, enabled=options.commit),
439
+ partial(self._add_pr_phase, enabled=options.create_pr),
440
+ ]
441
+
442
+ last_task = ""
443
+ for step in workflow_steps:
444
+ last_task = step(builder, last_task)
445
+
446
+ workflow_def = builder.build()
447
+ self.workflow.load_workflow(workflow_def)
448
+
449
+ self.logger.info(
450
+ "Dynamic workflow created",
451
+ extra={"task_count": len(workflow_def)},
452
+ )
453
+
454
+ def _add_setup_phase(self, builder: WorkflowBuilder, last_task: str) -> str:
455
+ builder.add_task(
456
+ "setup",
457
+ "Initialize",
458
+ "Initialize project structure",
459
+ estimated_duration=2.0,
460
+ )
461
+ return "setup"
462
+
463
+ def _add_config_phase(self, builder: WorkflowBuilder, last_task: str) -> str:
464
+ builder.add_task(
465
+ "config",
466
+ "Configure",
467
+ "Update configuration files",
468
+ dependencies=[last_task],
469
+ estimated_duration=3.0,
470
+ )
471
+ return "config"
472
+
473
+ def _add_cleaning_phase(
474
+ self,
475
+ builder: WorkflowBuilder,
476
+ last_task: str,
477
+ enabled: bool,
478
+ ) -> str:
479
+ return (
480
+ builder.add_conditional_task(
481
+ condition=enabled,
482
+ task_id="clean",
483
+ name="Clean Code",
484
+ description="Clean code (remove docstrings, comments)",
485
+ dependencies=[last_task],
486
+ estimated_duration=10.0,
487
+ )
488
+ or last_task
489
+ )
490
+
491
+ def _add_fast_hooks_phase(self, builder: WorkflowBuilder, last_task: str) -> str:
492
+ builder.add_task(
493
+ "fast_hooks",
494
+ "Format",
495
+ "Run formatting hooks",
496
+ dependencies=[last_task],
497
+ estimated_duration=15.0,
498
+ )
499
+ return "fast_hooks"
500
+
501
+ def _add_testing_phase(
502
+ self,
503
+ builder: WorkflowBuilder,
504
+ last_task: str,
505
+ enabled: bool,
506
+ ) -> str:
507
+ return (
508
+ builder.add_conditional_task(
509
+ condition=enabled,
510
+ task_id="test",
511
+ name="Test",
512
+ description="Run tests with coverage",
513
+ dependencies=[last_task],
514
+ estimated_duration=30.0,
515
+ )
516
+ or last_task
517
+ )
518
+
519
+ def _add_comprehensive_hooks_phase(
520
+ self,
521
+ builder: WorkflowBuilder,
522
+ last_task: str,
523
+ ) -> str:
524
+ builder.add_task(
525
+ "comprehensive_hooks",
526
+ "Quality Check",
527
+ "Run comprehensive hooks",
528
+ dependencies=[last_task],
529
+ estimated_duration=45.0,
530
+ )
531
+ return "comprehensive_hooks"
532
+
533
+ def _add_version_phase(
534
+ self,
535
+ builder: WorkflowBuilder,
536
+ last_task: str,
537
+ enabled: bool,
538
+ ) -> str:
539
+ return (
540
+ builder.add_conditional_task(
541
+ condition=enabled,
542
+ task_id="version",
543
+ name="Version",
544
+ description="Bump version",
545
+ dependencies=[last_task],
546
+ estimated_duration=5.0,
547
+ )
548
+ or last_task
549
+ )
550
+
551
+ def _add_publish_phase(
552
+ self,
553
+ builder: WorkflowBuilder,
554
+ last_task: str,
555
+ enabled: bool,
556
+ ) -> str:
557
+ return (
558
+ builder.add_conditional_task(
559
+ condition=enabled,
560
+ task_id="publish",
561
+ name="Publish",
562
+ description="Publish package",
563
+ dependencies=[last_task],
564
+ estimated_duration=20.0,
565
+ )
566
+ or last_task
567
+ )
568
+
569
+ def _add_commit_phase(
570
+ self,
571
+ builder: WorkflowBuilder,
572
+ last_task: str,
573
+ enabled: bool,
574
+ ) -> str:
575
+ return (
576
+ builder.add_conditional_task(
577
+ condition=enabled,
578
+ task_id="commit",
579
+ name="Commit",
580
+ description="Commit changes",
581
+ dependencies=[last_task],
582
+ estimated_duration=3.0,
583
+ )
584
+ or last_task
585
+ )
586
+
587
+ def _add_pr_phase(
588
+ self,
589
+ builder: WorkflowBuilder,
590
+ last_task: str,
591
+ enabled: bool,
592
+ ) -> str:
593
+ return (
594
+ builder.add_conditional_task(
595
+ condition=enabled,
596
+ task_id="pr",
597
+ name="Pull Request",
598
+ description="Create pull request",
599
+ dependencies=[last_task],
600
+ estimated_duration=5.0,
601
+ )
602
+ or last_task
603
+ )
604
+
605
+ def run_interactive_workflow(self, options: InteractiveWorkflowOptions) -> bool:
606
+ self.logger.info(
607
+ f"Starting interactive workflow with options: {options.__dict__}",
608
+ )
609
+ self.create_dynamic_workflow(options)
610
+
611
+ self.console.print("[bold blue]🚀 Starting Interactive Workflow[/ bold blue]")
612
+ self.workflow.display_task_tree()
613
+
614
+ if not Confirm.ask("Continue with workflow?"):
615
+ self.console.print("[yellow]Workflow cancelled by user[/ yellow]")
616
+ return False
617
+
618
+ return self._execute_workflow_loop()
619
+
620
+ def _execute_workflow_loop(self) -> bool:
621
+ overall_success = True
622
+
623
+ while not self.workflow.all_tasks_completed():
624
+ next_task = self.workflow.get_next_task()
625
+
626
+ if next_task is None:
627
+ overall_success = self._handle_stuck_workflow()
628
+ break
629
+
630
+ if not self._should_run_task(next_task):
631
+ continue
632
+
633
+ success = self._execute_single_task(next_task)
634
+ if not success:
635
+ overall_success = False
636
+ if not self._should_continue_after_failure():
637
+ break
638
+
639
+ self._display_workflow_summary()
640
+ return overall_success
641
+
642
+ def _handle_stuck_workflow(self) -> bool:
643
+ pending_tasks = [
644
+ task
645
+ for task in self.workflow.tasks.values()
646
+ if task.status == TaskStatus.PENDING
647
+ ]
648
+
649
+ if pending_tasks:
650
+ self.console.print("[red]❌ Workflow stuck-unresolved dependencies[/ red]")
651
+ return False
652
+ return True
653
+
654
+ def _should_run_task(self, task: Task) -> bool:
655
+ if not Confirm.ask(f"Run {task.name}?", default=True):
656
+ task.skip()
657
+ return False
658
+ return True
659
+
660
+ def _execute_single_task(self, task: Task) -> bool:
661
+ return self.workflow.run_task(task)
662
+
663
+ def _should_continue_after_failure(self) -> bool:
664
+ return Confirm.ask("Continue despite failure?", default=True)
665
+
666
+ def _display_workflow_summary(self) -> None:
667
+ summary = self.workflow.get_workflow_summary()
668
+
669
+ self.console.print("\n[bold]📊 Workflow Summary[/ bold]")
670
+
671
+ from rich.panel import Panel
672
+
673
+ table = Table(show_header=True, header_style="bold magenta")
674
+ table.add_column("Status", style="cyan")
675
+ table.add_column("Count", justify="right")
676
+
677
+ status_styles = {
678
+ "success": "green",
679
+ "failed": "red",
680
+ "skipped": "yellow",
681
+ "pending": "white",
682
+ }
683
+
684
+ for status, count in summary.items():
685
+ if count > 0:
686
+ style = status_styles.get(status, "white")
687
+ table.add_row(f"[{style}]{status.title()}[/{style}]", str(count))
688
+
689
+ self.console.print(
690
+ Panel(table, title="Workflow Summary", border_style="magenta")
691
+ )
692
+
693
+
694
+ def launch_interactive_cli(version: str, options: t.Any = None) -> None:
695
+ console = depends.get_sync(Console)
696
+ cli = InteractiveCLI(console)
697
+
698
+ title = Text("Crackerjack", style="bold cyan")
699
+ version_text = Text(f"v{version}", style="dim cyan")
700
+ subtitle = Text("Your Python project management toolkit", style="italic")
701
+ panel = Panel(
702
+ f"{title} {version_text}\n{subtitle}",
703
+ border_style="cyan",
704
+ expand=False,
705
+ )
706
+ console.print(panel)
707
+ console.print()
708
+
709
+ workflow_options = (
710
+ InteractiveWorkflowOptions.from_args(options)
711
+ if options
712
+ else InteractiveWorkflowOptions()
713
+ )
714
+ cli.create_dynamic_workflow(workflow_options)
715
+ cli.run_interactive_workflow(workflow_options)
716
+
717
+
718
+ if __name__ == "__main__":
719
+ launch_interactive_cli("0.19.8")