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,349 @@
1
+ import time
2
+ import typing as t
3
+ from contextlib import suppress
4
+ from pathlib import Path
5
+
6
+ from acb.console import Console
7
+ from acb.depends import Inject, depends
8
+
9
+ from crackerjack.config.hooks import HookDefinition, HookStrategy
10
+ from crackerjack.executors.hook_executor import HookExecutionResult, HookExecutor
11
+ from crackerjack.models.task import HookResult
12
+ from crackerjack.services.lsp_client import LSPClient
13
+
14
+ # Conditional import for ToolProxy
15
+ try:
16
+ from crackerjack.executors.tool_proxy import ToolProxy
17
+ except ImportError:
18
+ ToolProxy = None # type: ignore
19
+
20
+
21
+ class LSPAwareHookExecutor(HookExecutor):
22
+ """Hook executor that can leverage LSP server for enhanced performance."""
23
+
24
+ @depends.inject
25
+ def __init__(
26
+ self,
27
+ console: Inject[Console],
28
+ pkg_path: Path,
29
+ verbose: bool = False,
30
+ quiet: bool = False,
31
+ debug: bool = False,
32
+ use_tool_proxy: bool = True,
33
+ use_incremental: bool = False,
34
+ git_service: t.Any | None = None,
35
+ ) -> None:
36
+ super().__init__(
37
+ console, pkg_path, verbose, quiet, debug, use_incremental, git_service
38
+ )
39
+ self.lsp_client = LSPClient()
40
+ self.use_tool_proxy = use_tool_proxy and ToolProxy is not None
41
+ self.tool_proxy = ToolProxy() if self.use_tool_proxy else None
42
+ self.debug = debug
43
+
44
+ def execute_strategy(self, strategy: HookStrategy) -> HookExecutionResult:
45
+ """Execute hook strategy with LSP optimization where possible."""
46
+ start_time = time.time()
47
+ results = []
48
+
49
+ # Check if LSP server is available
50
+ lsp_available = self._check_lsp_availability()
51
+
52
+ # Execute hooks with LSP optimization and tool proxy resilience
53
+ for hook in strategy.hooks:
54
+ self._handle_progress_start(len(strategy.hooks))
55
+ result = self._execute_single_hook_with_strategies(hook, lsp_available)
56
+ results.append(result)
57
+ self._handle_progress_completion(len(strategy.hooks))
58
+
59
+ duration = time.time() - start_time
60
+ success = all(result.status in ("passed", "skipped") for result in results)
61
+
62
+ return HookExecutionResult(
63
+ strategy_name=strategy.name,
64
+ results=results,
65
+ total_duration=duration,
66
+ success=success,
67
+ concurrent_execution=False,
68
+ )
69
+
70
+ def _check_lsp_availability(self) -> bool:
71
+ """Check if LSP server is available and print info message."""
72
+ lsp_available = self.lsp_client.is_server_running()
73
+
74
+ if lsp_available and not self.quiet:
75
+ server_info = self.lsp_client.get_server_info()
76
+ if server_info:
77
+ self.console.print(
78
+ f"🔍 LSP server available (PID: {server_info['pid']}), using optimized execution"
79
+ )
80
+
81
+ return lsp_available
82
+
83
+ def _execute_single_hook_with_strategies(
84
+ self, hook: HookDefinition, lsp_available: bool
85
+ ) -> HookResult:
86
+ """Execute a single hook using appropriate strategy."""
87
+ if self._should_use_lsp_for_hook(hook, lsp_available):
88
+ return self._execute_lsp_hook(hook)
89
+ elif self._should_use_tool_proxy(hook):
90
+ return self._execute_hook_with_proxy(hook)
91
+
92
+ return self.execute_single_hook(hook)
93
+
94
+ def _handle_progress_start(self, total_hooks: int | None = None) -> None:
95
+ """Handle progress start callback."""
96
+ with suppress(Exception):
97
+ callback = getattr(self, "_progress_start_callback", None)
98
+ if callback:
99
+ # _total_hooks/_started_hooks are initialized by set_progress_callbacks on base class
100
+ self._started_hooks += 1 # type: ignore[attr-defined]
101
+ total = self._total_hooks or total_hooks # type: ignore[attr-defined]
102
+ if total:
103
+ callback(self._started_hooks, total) # type: ignore[attr-defined]
104
+
105
+ def _handle_progress_completion(self, total_hooks: int | None = None) -> None:
106
+ """Handle progress completion callback."""
107
+ with suppress(Exception):
108
+ callback = getattr(self, "_progress_callback", None)
109
+ if callback:
110
+ self._completed_hooks += 1 # type: ignore[attr-defined]
111
+ total = self._total_hooks or total_hooks # type: ignore[attr-defined]
112
+ if total:
113
+ callback(self._completed_hooks, total) # type: ignore[attr-defined]
114
+
115
+ def _should_use_lsp_for_hook(
116
+ self, hook: HookDefinition, lsp_available: bool
117
+ ) -> bool:
118
+ """Determine if a hook should use LSP-based execution."""
119
+ # Only use LSP for type-checking hooks when server is available
120
+ return (
121
+ lsp_available
122
+ and hook.name == "zuban"
123
+ and hook.stage.value == "comprehensive"
124
+ )
125
+
126
+ def _execute_lsp_hook(self, hook: HookDefinition) -> HookResult:
127
+ """Execute a hook using LSP server with real-time feedback."""
128
+ start_time = time.time()
129
+
130
+ try:
131
+ return self._perform_lsp_execution(hook, start_time)
132
+ except Exception as e:
133
+ return self._handle_lsp_execution_error(hook, start_time, e)
134
+
135
+ def _perform_lsp_execution(
136
+ self, hook: HookDefinition, start_time: float
137
+ ) -> HookResult:
138
+ """Perform the actual LSP execution."""
139
+ if not self.quiet:
140
+ self.console.print(
141
+ f"🚀 Using LSP-optimized execution for {hook.name}", style="cyan"
142
+ )
143
+
144
+ # Use the new real-time feedback method
145
+ diagnostics, summary = self.lsp_client.check_project_with_feedback(
146
+ self.pkg_path, show_progress=not self.quiet
147
+ )
148
+
149
+ duration = time.time() - start_time
150
+ has_errors = any(diags for diags in diagnostics.values())
151
+ output = self._format_lsp_output(diagnostics, duration)
152
+
153
+ self._display_lsp_results(hook, has_errors, output, summary)
154
+
155
+ # Create hook result
156
+ return self._create_lsp_hook_result(
157
+ hook, duration, has_errors, output, diagnostics
158
+ )
159
+
160
+ def _create_lsp_hook_result(
161
+ self,
162
+ hook: HookDefinition,
163
+ duration: float,
164
+ has_errors: bool,
165
+ output: str,
166
+ diagnostics: dict,
167
+ ) -> HookResult:
168
+ """Create the HookResult for LSP execution."""
169
+ # Ensure failed hooks always have at least 1 issue count
170
+ issues_found = [output] if has_errors else []
171
+ issues_count = max(len(issues_found), 1 if has_errors else 0)
172
+
173
+ return HookResult(
174
+ id=f"{hook.name}-lsp-{int(time.time())}",
175
+ name=f"{hook.name}-lsp",
176
+ status="failed" if has_errors else "passed",
177
+ duration=duration,
178
+ files_processed=len(diagnostics),
179
+ issues_found=issues_found,
180
+ issues_count=issues_count,
181
+ )
182
+
183
+ def _format_lsp_output(self, diagnostics: dict[str, t.Any], duration: float) -> str:
184
+ """Format LSP diagnostic output with performance info."""
185
+ output = self.lsp_client.format_diagnostics(diagnostics)
186
+ file_count = len(self.lsp_client.get_project_files(self.pkg_path))
187
+ perf_info = f"\n⚡ LSP-optimized check completed in {duration:.2f}s ({file_count} files)"
188
+ return output + perf_info
189
+
190
+ def _display_lsp_results(
191
+ self, hook: HookDefinition, has_errors: bool, output: str, summary: str
192
+ ) -> None:
193
+ """Display LSP execution results."""
194
+ if self.verbose or has_errors:
195
+ if not self.quiet:
196
+ self.console.print(f"🔍 {hook.name} (LSP):", style="bold blue")
197
+ if has_errors:
198
+ self.console.print(output)
199
+ else:
200
+ self.console.print(summary, style="green")
201
+
202
+ def _handle_lsp_execution_error(
203
+ self, hook: HookDefinition, start_time: float, error: Exception
204
+ ) -> HookResult:
205
+ """Handle LSP execution errors with fallback."""
206
+ time.time() - start_time
207
+ error_msg = f"LSP execution failed: {error}"
208
+
209
+ if not self.quiet:
210
+ self.console.print(f"❌ {hook.name} (LSP): {error_msg}", style="red")
211
+ self.console.print(f"🔄 Falling back to regular {hook.name} execution")
212
+
213
+ return self.execute_single_hook(hook)
214
+
215
+ def _should_use_tool_proxy(self, hook: HookDefinition) -> bool:
216
+ """Determine if a hook should use tool proxy for resilient execution."""
217
+ if not self.use_tool_proxy or not self.tool_proxy:
218
+ return False
219
+
220
+ # Use tool proxy for known fragile tools
221
+ fragile_tools = {"zuban", "skylos", "bandit"}
222
+ return hook.name in fragile_tools
223
+
224
+ def _execute_hook_with_proxy(self, hook: HookDefinition) -> HookResult:
225
+ """Execute a hook using tool proxy for resilient execution."""
226
+ start_time = time.time()
227
+
228
+ try:
229
+ return self._perform_proxy_execution(hook, start_time)
230
+ except Exception as e:
231
+ return self._handle_proxy_execution_error(hook, start_time, e)
232
+
233
+ def _perform_proxy_execution(
234
+ self, hook: HookDefinition, start_time: float
235
+ ) -> HookResult:
236
+ """Perform the actual proxy execution."""
237
+ if not self.quiet:
238
+ self.console.print(
239
+ f"🛡️ Using resilient execution for {hook.name}", style="blue"
240
+ )
241
+
242
+ # Parse hook entry to extract tool name and args
243
+ tool_name, args = self._parse_hook_entry(hook)
244
+
245
+ # Execute through tool proxy
246
+ if self.tool_proxy is not None:
247
+ exit_code = self.tool_proxy.execute_tool(tool_name, args)
248
+ else:
249
+ exit_code = -1 # Error code when tool proxy is not available
250
+
251
+ duration = time.time() - start_time
252
+ status = "passed" if exit_code == 0 else "failed"
253
+
254
+ # Get tool status for output
255
+ tool_status = (
256
+ self.tool_proxy.get_tool_status().get(tool_name, {})
257
+ if self.tool_proxy is not None
258
+ else {}
259
+ )
260
+ output = self._format_proxy_output(tool_name, tool_status, duration)
261
+
262
+ # Ensure failed hooks always have at least 1 issue count
263
+ issues_found = [output] if status == "failed" else []
264
+ issues_count = max(len(issues_found), 1 if status == "failed" else 0)
265
+
266
+ return HookResult(
267
+ id=f"{hook.name}-proxy-{int(time.time())}",
268
+ name=f"{hook.name}-proxy",
269
+ status=status,
270
+ duration=duration,
271
+ files_processed=1, # Placeholder value
272
+ issues_found=issues_found,
273
+ issues_count=issues_count,
274
+ )
275
+
276
+ def _handle_proxy_execution_error(
277
+ self, hook: HookDefinition, start_time: float, error: Exception
278
+ ) -> HookResult:
279
+ """Handle proxy execution errors with fallback."""
280
+ time.time() - start_time
281
+ error_msg = f"Tool proxy execution failed: {error}"
282
+
283
+ if not self.quiet:
284
+ self.console.print(f"❌ {hook.name} (proxy): {error_msg}", style="red")
285
+ self.console.print(f"🔄 Falling back to regular {hook.name} execution")
286
+
287
+ # Fallback to regular execution
288
+ return self.execute_single_hook(hook)
289
+
290
+ def _parse_hook_entry(self, hook: HookDefinition) -> tuple[str, list[str]]:
291
+ """Parse hook entry to extract tool name and arguments."""
292
+ entry_str = " ".join(hook.command)
293
+ entry_parts = entry_str.split()
294
+
295
+ if len(entry_parts) < 3: # e.g., "uv run zuban"
296
+ raise ValueError(f"Invalid hook entry format: {entry_str}")
297
+
298
+ # Extract tool name (assuming "uv run <tool>" format)
299
+ if entry_parts[0] == "uv" and entry_parts[1] == "run":
300
+ tool_name = entry_parts[2]
301
+ args = entry_parts[3:] if len(entry_parts) > 3 else []
302
+ else:
303
+ # Direct tool execution
304
+ tool_name = entry_parts[0]
305
+ args = entry_parts[1:]
306
+
307
+ return tool_name, args
308
+
309
+ def _format_proxy_output(
310
+ self, tool_name: str, tool_status: dict[str, t.Any], duration: float
311
+ ) -> str:
312
+ """Format tool proxy execution output."""
313
+ status_info = []
314
+
315
+ if tool_status.get("circuit_breaker_open"):
316
+ status_info.append("Circuit breaker: OPEN")
317
+
318
+ if tool_status.get("is_healthy") is False:
319
+ status_info.append("Health check: FAILED")
320
+
321
+ fallback_tools = tool_status.get("fallback_tools", [])
322
+ if fallback_tools:
323
+ status_info.append(f"Fallbacks: {', '.join(fallback_tools)}")
324
+
325
+ status_str = f" ({', '.join(status_info)})" if status_info else ""
326
+
327
+ return f"🛡️ Resilient execution completed in {duration:.2f}s{status_str}"
328
+
329
+ def get_execution_mode_summary(self) -> dict[str, t.Any]:
330
+ """Get summary of execution mode capabilities."""
331
+ lsp_available = self.lsp_client.is_server_running()
332
+ server_info = self.lsp_client.get_server_info() if lsp_available else None
333
+
334
+ summary = {
335
+ "lsp_server_available": lsp_available,
336
+ "lsp_server_info": server_info,
337
+ "optimization_enabled": lsp_available,
338
+ "supported_hooks": ["zuban"] if lsp_available else [],
339
+ "tool_proxy_enabled": self.use_tool_proxy,
340
+ "resilient_tools": ["zuban", "skylos", "bandit"]
341
+ if self.use_tool_proxy
342
+ else [],
343
+ }
344
+
345
+ # Add tool proxy status if available
346
+ if self.tool_proxy:
347
+ summary["tool_status"] = self.tool_proxy.get_tool_status()
348
+
349
+ return summary
@@ -0,0 +1,282 @@
1
+ """Enhanced hook executor with rich progress indicators.
2
+
3
+ Extends base HookExecutor with real-time progress feedback using rich library.
4
+ Part of Phase 10.2.2: Development Velocity Improvements.
5
+ """
6
+
7
+ import time
8
+ import typing as t
9
+ from concurrent.futures import ThreadPoolExecutor, as_completed
10
+ from pathlib import Path
11
+
12
+ from acb.console import Console
13
+ from rich.progress import (
14
+ BarColumn,
15
+ MofNCompleteColumn,
16
+ Progress,
17
+ SpinnerColumn,
18
+ TaskProgressColumn,
19
+ TextColumn,
20
+ TimeElapsedColumn,
21
+ TimeRemainingColumn,
22
+ )
23
+
24
+ from crackerjack.config.hooks import HookStrategy, RetryPolicy
25
+ from crackerjack.executors.hook_executor import HookExecutionResult, HookExecutor
26
+ from crackerjack.models.task import HookResult
27
+
28
+
29
+ class ProgressHookExecutor(HookExecutor):
30
+ """Hook executor with enhanced progress indicators.
31
+
32
+ Provides real-time feedback during hook execution using rich progress bars,
33
+ improving developer experience during long-running quality checks.
34
+ """
35
+
36
+ def __init__(
37
+ self,
38
+ console: Console,
39
+ pkg_path: Path,
40
+ verbose: bool = False,
41
+ quiet: bool = False,
42
+ show_progress: bool = True,
43
+ debug: bool = False,
44
+ use_incremental: bool = False,
45
+ git_service: t.Any | None = None,
46
+ ) -> None:
47
+ """Initialize progress-enhanced hook executor.
48
+
49
+ Args:
50
+ console: Rich console for output
51
+ pkg_path: Project root path
52
+ verbose: Show detailed output
53
+ quiet: Suppress output
54
+ show_progress: Enable progress bars (disable for CI/testing)
55
+ debug: Enable debug output
56
+ use_incremental: Run hooks only on changed files
57
+ git_service: GitService instance for incremental execution
58
+ """
59
+ super().__init__(
60
+ console, pkg_path, verbose, quiet, debug, use_incremental, git_service
61
+ )
62
+ self.show_progress = show_progress and not quiet
63
+ self.debug = debug
64
+
65
+ def execute_strategy(self, strategy: HookStrategy) -> HookExecutionResult:
66
+ """Execute hook strategy with progress indicators.
67
+
68
+ Args:
69
+ strategy: Hook strategy to execute
70
+
71
+ Returns:
72
+ Execution result with timing and status information
73
+ """
74
+ start_time = time.time()
75
+
76
+ self._print_strategy_header(strategy)
77
+
78
+ if not self.show_progress:
79
+ # Fall back to base implementation without progress bars
80
+ return super().execute_strategy(strategy)
81
+
82
+ # Create progress bar context
83
+ with self._create_progress_bar() as progress:
84
+ # Add main task for overall progress
85
+ main_task = progress.add_task(
86
+ f"[cyan]Running {len(strategy.hooks)} hooks...",
87
+ total=len(strategy.hooks),
88
+ )
89
+
90
+ if strategy.parallel and len(strategy.hooks) > 1:
91
+ results = self._execute_parallel_with_progress(
92
+ strategy, progress, main_task
93
+ )
94
+ else:
95
+ results = self._execute_sequential_with_progress(
96
+ strategy, progress, main_task
97
+ )
98
+
99
+ # Handle retries (without progress bar to avoid confusion)
100
+ if strategy.retry_policy != RetryPolicy.NONE:
101
+ if not self.quiet:
102
+ self.console.print("\n[yellow]Retrying failed hooks...[/yellow]")
103
+ results = self._handle_retries(strategy, results)
104
+
105
+ total_duration = time.time() - start_time
106
+ success = all(r.status == "passed" for r in results)
107
+
108
+ # Calculate performance gain for the summary
109
+ performance_gain = 0.0 # Default value for progress executor
110
+ if not self.quiet:
111
+ self._print_summary(strategy, results, success, performance_gain)
112
+
113
+ return HookExecutionResult(
114
+ strategy_name=strategy.name,
115
+ results=results,
116
+ total_duration=total_duration,
117
+ success=success,
118
+ )
119
+
120
+ def _create_progress_bar(self) -> Progress:
121
+ """Create configured progress bar with appropriate columns.
122
+
123
+ Progress bar width is constrained to respect console width by limiting
124
+ description text and using compact time format.
125
+
126
+ Logger output is suppressed at the source (logging level) to prevent
127
+ interference with progress bar updates.
128
+
129
+ Returns:
130
+ Configured Progress instance
131
+ """
132
+ return Progress(
133
+ SpinnerColumn(spinner_name="dots"),
134
+ TextColumn("[progress.description]{task.description}", justify="left"),
135
+ BarColumn(bar_width=20), # Fixed narrow bar to prevent overflow
136
+ TaskProgressColumn(),
137
+ MofNCompleteColumn(),
138
+ TimeElapsedColumn(),
139
+ TimeRemainingColumn(),
140
+ console=self.console,
141
+ transient=True, # Clear progress bar after completion (consistent with test progress)
142
+ refresh_per_second=10, # Smooth single-line updates
143
+ )
144
+
145
+ def _execute_sequential_with_progress(
146
+ self,
147
+ strategy: HookStrategy,
148
+ progress: Progress,
149
+ main_task: t.Any,
150
+ ) -> list[HookResult]:
151
+ """Execute hooks sequentially with progress updates.
152
+
153
+ Args:
154
+ strategy: Hook strategy to execute
155
+ progress: Progress bar context
156
+ main_task: Main progress task ID
157
+
158
+ Returns:
159
+ List of hook execution results
160
+ """
161
+ results: list[HookResult] = []
162
+
163
+ for hook in strategy.hooks:
164
+ # Update description to show current hook
165
+ progress.update(
166
+ main_task,
167
+ description=f"[cyan]Running {hook.name}...",
168
+ )
169
+
170
+ result = self.execute_single_hook(hook)
171
+ results.append(result)
172
+
173
+ # Update progress with completion
174
+ status_icon = "✅" if result.status == "passed" else "❌"
175
+ progress.update(
176
+ main_task,
177
+ advance=1,
178
+ description=f"[cyan]Completed {hook.name} {status_icon}",
179
+ )
180
+
181
+ return results
182
+
183
+ def _execute_parallel_with_progress(
184
+ self,
185
+ strategy: HookStrategy,
186
+ progress: Progress,
187
+ main_task: t.Any,
188
+ ) -> list[HookResult]:
189
+ """Execute hooks in parallel with progress updates.
190
+
191
+ Formatting hooks run sequentially first, then analysis hooks run in parallel.
192
+
193
+ Args:
194
+ strategy: Hook strategy to execute
195
+ progress: Progress bar context
196
+ main_task: Main progress task ID
197
+
198
+ Returns:
199
+ List of hook execution results
200
+ """
201
+ results: list[HookResult] = []
202
+
203
+ # Separate formatting hooks (must run sequentially)
204
+ formatting_hooks = [h for h in strategy.hooks if h.is_formatting]
205
+ other_hooks = [h for h in strategy.hooks if not h.is_formatting]
206
+
207
+ # Execute formatting hooks sequentially
208
+ for hook in formatting_hooks:
209
+ progress.update(
210
+ main_task,
211
+ description=f"[cyan]Running {hook.name}...",
212
+ )
213
+
214
+ result = self.execute_single_hook(hook)
215
+ results.append(result)
216
+
217
+ status_icon = "✅" if result.status == "passed" else "❌"
218
+ progress.update(
219
+ main_task,
220
+ advance=1,
221
+ description=f"[cyan]Completed {hook.name} {status_icon}",
222
+ )
223
+
224
+ # Execute analysis hooks in parallel
225
+ if other_hooks:
226
+ progress.update(
227
+ main_task,
228
+ description=f"[cyan]Running {len(other_hooks)} hooks in parallel...",
229
+ )
230
+
231
+ with ThreadPoolExecutor(max_workers=strategy.max_workers) as executor:
232
+ future_to_hook = {
233
+ executor.submit(self.execute_single_hook, hook): hook
234
+ for hook in other_hooks
235
+ }
236
+
237
+ for future in as_completed(future_to_hook):
238
+ try:
239
+ result = future.result()
240
+ results.append(result)
241
+
242
+ status_icon = "✅" if result.status == "passed" else "❌"
243
+ progress.update(
244
+ main_task,
245
+ advance=1,
246
+ description=f"[cyan]Completed {result.name} {status_icon}",
247
+ )
248
+
249
+ except Exception as e:
250
+ hook = future_to_hook[future]
251
+ error_result = HookResult(
252
+ id=hook.name,
253
+ name=hook.name,
254
+ status="error",
255
+ duration=0.0,
256
+ issues_found=[str(e)],
257
+ issues_count=1, # Error counts as 1 issue
258
+ stage=hook.stage.value,
259
+ )
260
+ results.append(error_result)
261
+
262
+ progress.update(
263
+ main_task,
264
+ advance=1,
265
+ description=f"[cyan]Failed {hook.name} ❌",
266
+ )
267
+
268
+ return results
269
+
270
+ def _display_hook_result(self, result: HookResult) -> None:
271
+ """Display hook result with emoji status.
272
+
273
+ When progress bars are disabled, always show inline hook status.
274
+ When progress bars are enabled, suppress inline output (progress bar shows it).
275
+
276
+ Args:
277
+ result: Hook execution result
278
+ """
279
+ # Always show inline status when progress bars are disabled
280
+ # Skip inline output when progress bars are enabled (they show the status)
281
+ if not self.show_progress:
282
+ super()._display_hook_result(result)