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,628 @@
1
+ import asyncio
2
+ import concurrent.futures
3
+ import subprocess
4
+ import typing as t
5
+ from pathlib import Path
6
+ from typing import Protocol
7
+
8
+ from acb.console import Console
9
+ from acb.depends import Inject, depends
10
+ from rich.progress import (
11
+ BarColumn,
12
+ Progress,
13
+ SpinnerColumn,
14
+ TextColumn,
15
+ TimeElapsedColumn,
16
+ )
17
+
18
+ from .server_manager import find_zuban_lsp_processes
19
+ from .zuban_lsp_service import ZubanLSPService
20
+
21
+
22
+ class ProgressCallback(Protocol):
23
+ """Protocol for progress reporting during type checking."""
24
+
25
+ def on_file_start(self, file_path: str) -> None:
26
+ """Called when starting to check a file."""
27
+ ...
28
+
29
+ def on_file_complete(self, file_path: str, error_count: int) -> None:
30
+ """Called when finished checking a file."""
31
+ ...
32
+
33
+ def on_progress(self, current: int, total: int) -> None:
34
+ """Called to report overall progress."""
35
+ ...
36
+
37
+
38
+ class RealTimeTypingFeedback:
39
+ """Provides real-time feedback during type checking operations."""
40
+
41
+ @depends.inject
42
+ def __init__(self, console: Inject[Console]) -> None:
43
+ self.console = console
44
+ self._total_errors = 0
45
+ self._files_checked = 0
46
+
47
+ def create_progress_display(self) -> Progress:
48
+ """Create a progress display for type checking."""
49
+ return Progress(
50
+ SpinnerColumn(),
51
+ TextColumn("[progress.description]{task.description}"),
52
+ BarColumn(),
53
+ TextColumn("[progress.percentage]{task.percentage:>3.0f}%"),
54
+ TextColumn("({task.completed}/{task.total})"),
55
+ TimeElapsedColumn(),
56
+ console=self.console,
57
+ )
58
+
59
+ def on_file_start(self, file_path: str) -> None:
60
+ """Report that we're starting to check a file."""
61
+ rel_path = Path(file_path).name
62
+ self.console.print(f"🔍 Checking {rel_path}...", style="dim")
63
+
64
+ def on_file_complete(self, file_path: str, error_count: int) -> None:
65
+ """Report completion of file checking."""
66
+ rel_path = Path(file_path).name
67
+ self._files_checked += 1
68
+ self._total_errors += error_count
69
+
70
+ if error_count == 0:
71
+ self.console.print(f"✅ {rel_path} - No issues", style="green dim")
72
+ else:
73
+ self.console.print(
74
+ f"❌ {rel_path} - {error_count} error(s)", style="red dim"
75
+ )
76
+
77
+ def on_progress(self, current: int, total: int) -> None:
78
+ """Report overall progress."""
79
+ pass # Progress bar handles this
80
+
81
+ def get_summary(self) -> str:
82
+ """Get a summary of the checking results."""
83
+ if self._total_errors == 0:
84
+ return f"✅ All {self._files_checked} files passed type checking"
85
+ return (
86
+ f"❌ Found {self._total_errors} type errors in {self._files_checked} files"
87
+ )
88
+
89
+
90
+ class JSONRPCClient:
91
+ """JSON-RPC client for LSP communication."""
92
+
93
+ def __init__(self, lsp_service: ZubanLSPService) -> None:
94
+ self.lsp_service = lsp_service
95
+ self._request_id = 0
96
+
97
+ def _next_request_id(self) -> int:
98
+ """Generate next request ID."""
99
+ self._request_id += 1
100
+ return self._request_id
101
+
102
+ async def initialize(self, root_path: str) -> dict[str, t.Any] | None:
103
+ """Initialize the LSP server for a workspace."""
104
+ params = {
105
+ "processId": None,
106
+ "rootPath": root_path,
107
+ "rootUri": f"file://{root_path}",
108
+ "capabilities": {
109
+ "textDocument": {
110
+ "publishDiagnostics": {
111
+ "versionSupport": True,
112
+ "tagSupport": {"valueSet": [1, 2]},
113
+ "relatedInformation": True,
114
+ "codeDescriptionSupport": True,
115
+ "dataSupport": True,
116
+ }
117
+ }
118
+ },
119
+ }
120
+ return await self.lsp_service.send_lsp_request("initialize", params)
121
+
122
+ async def did_open(self, file_path: str) -> dict[str, t.Any] | None:
123
+ """Notify server that a document was opened."""
124
+ content = Path(file_path).read_text(encoding="utf-8")
125
+
126
+ params = {
127
+ "textDocument": {
128
+ "uri": f"file://{file_path}",
129
+ "languageId": "python",
130
+ "version": 1,
131
+ "text": content,
132
+ }
133
+ }
134
+ return await self.lsp_service.send_lsp_request("textDocument/didOpen", params)
135
+
136
+ async def did_close(self, file_path: str) -> dict[str, t.Any] | None:
137
+ """Notify server that a document was closed."""
138
+ params = {
139
+ "textDocument": {
140
+ "uri": f"file://{file_path}",
141
+ }
142
+ }
143
+ return await self.lsp_service.send_lsp_request("textDocument/didClose", params)
144
+
145
+
146
+ class LSPClient:
147
+ """Client for communicating with Zuban LSP server."""
148
+
149
+ @depends.inject
150
+ def __init__(self, console: Inject[Console]) -> None:
151
+ self.console = console
152
+ self._server_port: int | None = None
153
+ self._server_host: str = "127.0.0.1"
154
+ self._lsp_service: ZubanLSPService | None = None
155
+ self._jsonrpc_client: JSONRPCClient | None = None
156
+
157
+ def is_server_running(self) -> bool:
158
+ """Check if Zuban LSP server is currently running."""
159
+ if self._lsp_service and self._lsp_service.is_running:
160
+ return True
161
+ processes = find_zuban_lsp_processes()
162
+ return len(processes) > 0
163
+
164
+ async def _ensure_lsp_service(self) -> bool:
165
+ """Ensure LSP service is available and initialized."""
166
+ if self._lsp_service and self._lsp_service.is_running:
167
+ return True
168
+
169
+ # Create new LSP service
170
+ self._lsp_service = ZubanLSPService(
171
+ port=self._server_port or 8677,
172
+ mode="stdio", # Currently zuban only supports stdio
173
+ console=self.console,
174
+ )
175
+
176
+ # Start the service
177
+ if await self._lsp_service.start():
178
+ self._jsonrpc_client = JSONRPCClient(self._lsp_service)
179
+ return True
180
+
181
+ return False
182
+
183
+ def get_server_info(self) -> dict[str, t.Any] | None:
184
+ """Get information about the running LSP server."""
185
+ processes = find_zuban_lsp_processes()
186
+ if not processes:
187
+ return None
188
+
189
+ return {
190
+ "pid": processes[0]["pid"],
191
+ "cpu": processes[0]["cpu"],
192
+ "mem": processes[0]["mem"],
193
+ "command": processes[0]["command"],
194
+ }
195
+
196
+ def check_files(
197
+ self,
198
+ file_paths: list[str],
199
+ progress_callback: ProgressCallback | None = None,
200
+ show_progress: bool = True,
201
+ ) -> dict[str, list[dict[str, t.Any]]]:
202
+ """
203
+ Check files for type errors using LSP server with real-time feedback.
204
+
205
+ Args:
206
+ file_paths: List of file paths to check
207
+ progress_callback: Optional callback for progress reporting
208
+ show_progress: Whether to show progress display
209
+
210
+ Returns:
211
+ Dictionary mapping file paths to lists of diagnostic messages.
212
+ Each diagnostic contains: line, column, severity, message, code.
213
+ """
214
+ if not self.is_server_running():
215
+ if progress_callback:
216
+ self.console.print(
217
+ "⚠️ Zuban LSP server not running, falling back to direct zuban calls",
218
+ style="yellow",
219
+ )
220
+ return self._check_files_with_feedback(
221
+ file_paths, progress_callback, show_progress
222
+ )
223
+
224
+ # When LSP server is running, use it for better performance
225
+ return self._check_files_via_lsp(file_paths, progress_callback, show_progress)
226
+
227
+ def _check_files_with_feedback(
228
+ self,
229
+ file_paths: list[str],
230
+ progress_callback: ProgressCallback | None = None,
231
+ show_progress: bool = True,
232
+ ) -> dict[str, list[dict[str, t.Any]]]:
233
+ """Check files with real-time feedback using direct zuban calls."""
234
+ total_files = len(file_paths)
235
+
236
+ if show_progress and total_files > 1:
237
+ return self._check_files_with_progress_display(
238
+ file_paths, progress_callback, total_files
239
+ )
240
+ return self._check_files_simple_feedback(file_paths, progress_callback)
241
+
242
+ def _check_files_with_progress_display(
243
+ self,
244
+ file_paths: list[str],
245
+ progress_callback: ProgressCallback | None,
246
+ total_files: int,
247
+ ) -> dict[str, list[dict[str, t.Any]]]:
248
+ """Check files with progress display."""
249
+ diagnostics = {}
250
+ feedback = RealTimeTypingFeedback()
251
+
252
+ with feedback.create_progress_display() as progress:
253
+ task = progress.add_task("Type checking files...", total=total_files)
254
+
255
+ for file_path in file_paths:
256
+ diagnostics.update(
257
+ self._process_single_file_with_zuban(file_path, progress_callback)
258
+ )
259
+ progress.update(task, advance=1)
260
+
261
+ return diagnostics
262
+
263
+ def _check_files_simple_feedback(
264
+ self,
265
+ file_paths: list[str],
266
+ progress_callback: ProgressCallback | None,
267
+ ) -> dict[str, list[dict[str, t.Any]]]:
268
+ """Check files without progress display."""
269
+ diagnostics = {}
270
+
271
+ for file_path in file_paths:
272
+ diagnostics.update(
273
+ self._process_single_file_with_zuban(file_path, progress_callback)
274
+ )
275
+
276
+ return diagnostics
277
+
278
+ def _process_single_file_with_zuban(
279
+ self,
280
+ file_path: str,
281
+ progress_callback: ProgressCallback | None,
282
+ ) -> dict[str, list[dict[str, t.Any]]]:
283
+ """Process a single file with zuban and handle callbacks."""
284
+ if progress_callback:
285
+ progress_callback.on_file_start(file_path)
286
+
287
+ file_diagnostics = self._check_file_with_zuban(file_path)
288
+
289
+ if progress_callback:
290
+ progress_callback.on_file_complete(file_path, len(file_diagnostics))
291
+
292
+ return {file_path: file_diagnostics}
293
+
294
+ def _check_files_via_lsp(
295
+ self,
296
+ file_paths: list[str],
297
+ progress_callback: ProgressCallback | None = None,
298
+ show_progress: bool = True,
299
+ ) -> dict[str, list[dict[str, t.Any]]]:
300
+ """Check files using LSP server communication."""
301
+ # Use asyncio to run the async LSP implementation
302
+ try:
303
+ # Try to get or create an event loop
304
+ try:
305
+ asyncio.get_running_loop()
306
+ # We're already in an async context, use a thread pool
307
+ with concurrent.futures.ThreadPoolExecutor() as executor:
308
+ future = executor.submit(
309
+ self._run_async_lsp_check,
310
+ file_paths,
311
+ progress_callback,
312
+ show_progress,
313
+ )
314
+ return future.result(timeout=120) # 2 minute timeout
315
+ except RuntimeError:
316
+ # No running loop, create new one
317
+ return asyncio.run(
318
+ self._async_check_files_via_lsp(
319
+ file_paths, progress_callback, show_progress
320
+ )
321
+ )
322
+ except Exception as e:
323
+ self.console.print(
324
+ f"[yellow]⚠️ LSP communication failed: {e}, falling back to direct calls[/yellow]"
325
+ )
326
+ return self._check_files_with_feedback(
327
+ file_paths, progress_callback, show_progress
328
+ )
329
+
330
+ def _run_async_lsp_check(
331
+ self,
332
+ file_paths: list[str],
333
+ progress_callback: ProgressCallback | None = None,
334
+ show_progress: bool = True,
335
+ ) -> dict[str, list[dict[str, t.Any]]]:
336
+ """Run async LSP check in a new event loop."""
337
+ return asyncio.run(
338
+ self._async_check_files_via_lsp(
339
+ file_paths, progress_callback, show_progress
340
+ )
341
+ )
342
+
343
+ async def _async_check_files_via_lsp(
344
+ self,
345
+ file_paths: list[str],
346
+ progress_callback: ProgressCallback | None = None,
347
+ show_progress: bool = True,
348
+ ) -> dict[str, list[dict[str, t.Any]]]:
349
+ """Async implementation of LSP-based file checking."""
350
+ # Validate prerequisites
351
+ if not await self._validate_lsp_prerequisites():
352
+ return self._check_files_with_feedback(
353
+ file_paths, progress_callback, show_progress
354
+ )
355
+
356
+ try:
357
+ # Initialize LSP workspace
358
+ await self._initialize_lsp_workspace(file_paths)
359
+
360
+ # Process files with appropriate progress handling
361
+ return await self._process_files_via_lsp(
362
+ file_paths, progress_callback, show_progress
363
+ )
364
+
365
+ except Exception as e:
366
+ self.console.print(
367
+ f"[yellow]⚠️ LSP protocol error: {e}, falling back to direct calls[/yellow]"
368
+ )
369
+ return self._check_files_with_feedback(
370
+ file_paths, progress_callback, show_progress
371
+ )
372
+
373
+ async def _validate_lsp_prerequisites(self) -> bool:
374
+ """Validate that LSP service and client are ready."""
375
+ if not await self._ensure_lsp_service():
376
+ return False
377
+
378
+ if not self._jsonrpc_client:
379
+ return False
380
+
381
+ return True
382
+
383
+ async def _initialize_lsp_workspace(self, file_paths: list[str]) -> None:
384
+ """Initialize LSP workspace with project root."""
385
+ assert self._jsonrpc_client is not None, "LSP client must be initialized"
386
+ project_root = (
387
+ str(Path(file_paths[0]).parent) if file_paths else str(Path.cwd())
388
+ )
389
+ await self._jsonrpc_client.initialize(project_root)
390
+
391
+ async def _process_files_via_lsp(
392
+ self,
393
+ file_paths: list[str],
394
+ progress_callback: ProgressCallback | None = None,
395
+ show_progress: bool = True,
396
+ ) -> dict[str, list[dict[str, t.Any]]]:
397
+ """Process files via LSP with progress tracking."""
398
+ total_files = len(file_paths)
399
+
400
+ if show_progress and total_files > 1:
401
+ return await self._process_files_with_progress(
402
+ file_paths, progress_callback, total_files
403
+ )
404
+ return await self._process_files_simple(file_paths, progress_callback)
405
+
406
+ async def _process_files_with_progress(
407
+ self,
408
+ file_paths: list[str],
409
+ progress_callback: ProgressCallback | None,
410
+ total_files: int,
411
+ ) -> dict[str, list[dict[str, t.Any]]]:
412
+ """Process files with progress display."""
413
+ diagnostics = {}
414
+ feedback = RealTimeTypingFeedback()
415
+
416
+ with feedback.create_progress_display() as progress:
417
+ task = progress.add_task("LSP type checking files...", total=total_files)
418
+
419
+ for file_path in file_paths:
420
+ diagnostics.update(
421
+ await self._process_single_file_with_callback(
422
+ file_path, progress_callback
423
+ )
424
+ )
425
+ progress.update(task, advance=1)
426
+
427
+ return diagnostics
428
+
429
+ async def _process_files_simple(
430
+ self,
431
+ file_paths: list[str],
432
+ progress_callback: ProgressCallback | None,
433
+ ) -> dict[str, list[dict[str, t.Any]]]:
434
+ """Process files without progress display."""
435
+ diagnostics = {}
436
+
437
+ for file_path in file_paths:
438
+ diagnostics.update(
439
+ await self._process_single_file_with_callback(
440
+ file_path, progress_callback
441
+ )
442
+ )
443
+
444
+ return diagnostics
445
+
446
+ async def _process_single_file_with_callback(
447
+ self,
448
+ file_path: str,
449
+ progress_callback: ProgressCallback | None,
450
+ ) -> dict[str, list[dict[str, t.Any]]]:
451
+ """Process a single file with progress callback handling."""
452
+ if progress_callback:
453
+ progress_callback.on_file_start(file_path)
454
+
455
+ file_diagnostics = await self._check_file_via_lsp(file_path)
456
+
457
+ if progress_callback:
458
+ progress_callback.on_file_complete(file_path, len(file_diagnostics))
459
+
460
+ return {file_path: file_diagnostics}
461
+
462
+ async def _check_file_via_lsp(self, file_path: str) -> list[dict[str, t.Any]]:
463
+ """Check a single file via LSP protocol."""
464
+ if not self._jsonrpc_client:
465
+ # Fallback to direct zuban call
466
+ return self._check_file_with_zuban(file_path)
467
+
468
+ try:
469
+ # Notify server about file
470
+ await self._jsonrpc_client.did_open(file_path)
471
+
472
+ # Wait briefly for diagnostics to be published
473
+ await asyncio.sleep(0.1)
474
+
475
+ # For now, since we don't have diagnostic collection implemented,
476
+ # we'll fall back to the direct zuban call but log that we used LSP
477
+ # In a full implementation, we'd collect diagnostics from LSP notifications
478
+ diagnostics = self._check_file_with_zuban(file_path)
479
+
480
+ # Clean up
481
+ await self._jsonrpc_client.did_close(file_path)
482
+
483
+ return diagnostics
484
+
485
+ except Exception:
486
+ # Fallback to direct zuban call on any LSP error
487
+ return self._check_file_with_zuban(file_path)
488
+
489
+ def _check_file_with_zuban(self, file_path: str) -> list[dict[str, t.Any]]:
490
+ """
491
+ Check a single file using zuban directly.
492
+
493
+ This is a temporary implementation that calls zuban directly.
494
+ A full LSP integration would use JSON-RPC protocol.
495
+ """
496
+ try:
497
+ result = self._execute_zuban_check(file_path)
498
+
499
+ if result.returncode == 0:
500
+ return [] # No errors
501
+
502
+ return self._parse_zuban_output(result.stderr)
503
+
504
+ except (
505
+ subprocess.TimeoutExpired,
506
+ subprocess.CalledProcessError,
507
+ FileNotFoundError,
508
+ ):
509
+ return []
510
+
511
+ def _execute_zuban_check(self, file_path: str) -> subprocess.CompletedProcess[str]:
512
+ """Execute zuban check command for a file."""
513
+ return subprocess.run(
514
+ ["zuban", "check", file_path],
515
+ capture_output=True,
516
+ text=True,
517
+ timeout=30,
518
+ )
519
+
520
+ def _parse_zuban_output(self, stderr_output: str) -> list[dict[str, t.Any]]:
521
+ """Parse zuban stderr output into diagnostic format."""
522
+ diagnostics = []
523
+
524
+ for line in stderr_output.splitlines():
525
+ if self._is_error_line(line):
526
+ diagnostic = self._parse_error_line(line)
527
+ if diagnostic:
528
+ diagnostics.append(diagnostic)
529
+
530
+ return diagnostics
531
+
532
+ def _is_error_line(self, line: str) -> bool:
533
+ """Check if a line contains an error message."""
534
+ return ":" in line and "error:" in line.lower()
535
+
536
+ def _parse_error_line(self, line: str) -> dict[str, t.Any] | None:
537
+ """Parse a single error line into diagnostic format."""
538
+ # Format: file:line:column: error: message
539
+ parts = line.split(":", 4)
540
+ if len(parts) < 4:
541
+ return None
542
+
543
+ try:
544
+ line_num = int(parts[1])
545
+ col_num = int(parts[2]) if parts[2].strip() else 1
546
+ message = parts[4].strip() if len(parts) > 4 else parts[3].strip()
547
+
548
+ return {
549
+ "line": line_num,
550
+ "column": col_num,
551
+ "severity": "error",
552
+ "message": message,
553
+ "code": "type-error",
554
+ }
555
+ except (ValueError, IndexError):
556
+ return None
557
+
558
+ def format_diagnostics(self, diagnostics: dict[str, list[dict[str, t.Any]]]) -> str:
559
+ """Format diagnostics for display."""
560
+ if not diagnostics or all(not diags for diags in diagnostics.values()):
561
+ return "✅ No type errors found"
562
+
563
+ lines = []
564
+ total_errors = sum(len(diags) for diags in diagnostics.values())
565
+ lines.append(f"❌ Found {total_errors} type error(s):")
566
+
567
+ for file_path, file_diagnostics in diagnostics.items():
568
+ if file_diagnostics:
569
+ lines.append(f"\n📄 {file_path}:")
570
+ for diag in file_diagnostics:
571
+ severity_icon = "🔴" if diag["severity"] == "error" else "🟡"
572
+ lines.append(
573
+ f" {severity_icon} Line {diag['line']}:{diag['column']} - {diag['message']}"
574
+ )
575
+
576
+ return "\n".join(lines)
577
+
578
+ def get_project_files(self, project_path: Path) -> list[str]:
579
+ """Get Python files in the project that should be type-checked."""
580
+ python_files = []
581
+
582
+ # Focus on crackerjack source files (matching pre-commit config)
583
+ crackerjack_dir = project_path / "crackerjack"
584
+ if crackerjack_dir.exists():
585
+ for py_file in crackerjack_dir.rglob("*.py"):
586
+ # Exclude patterns from pre-commit config
587
+ rel_path = py_file.relative_to(project_path)
588
+ rel_str = str(rel_path)
589
+
590
+ # Skip excluded directories
591
+ if "/mcp/" in rel_str or "/plugins/" in rel_str:
592
+ continue
593
+ if "code_cleaner.py" in rel_str:
594
+ continue
595
+
596
+ python_files.append(str(py_file))
597
+
598
+ return python_files
599
+
600
+ def check_project_with_feedback(
601
+ self, project_path: Path, show_progress: bool = True
602
+ ) -> tuple[dict[str, list[dict[str, t.Any]]], str]:
603
+ """
604
+ Check an entire project with real-time feedback.
605
+
606
+ Returns:
607
+ Tuple of (diagnostics dict[str, t.Any], summary message)
608
+ """
609
+ python_files = self.get_project_files(project_path)
610
+ if not python_files:
611
+ return {}, "📁 No Python files found to check"
612
+
613
+ feedback = RealTimeTypingFeedback()
614
+
615
+ self.console.print(
616
+ f"🔍 Starting type check of {len(python_files)} files...", style="bold blue"
617
+ )
618
+
619
+ diagnostics = self.check_files(
620
+ python_files,
621
+ progress_callback=feedback if show_progress else None,
622
+ show_progress=show_progress,
623
+ )
624
+
625
+ summary = feedback.get_summary()
626
+ self.console.print(f"\n{summary}", style="bold")
627
+
628
+ return diagnostics, summary