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,358 @@
1
+ """LSP client wrapper for Zuban communication."""
2
+
3
+ import asyncio
4
+ import json
5
+ import logging
6
+ import socket
7
+ import typing as t
8
+ from pathlib import Path
9
+
10
+ logger = logging.getLogger("crackerjack.lsp_client")
11
+
12
+
13
+ class ZubanLSPClient:
14
+ """Minimal LSP client for zuban communication."""
15
+
16
+ def __init__(self, host: str = "127.0.0.1", port: int = 8677) -> None:
17
+ """Initialize LSP client.
18
+
19
+ Args:
20
+ host: LSP server host
21
+ port: LSP server port
22
+ """
23
+ self.host = host
24
+ self.port = port
25
+ self._socket: socket.socket | None = None
26
+ self._reader: asyncio.StreamReader | None = None
27
+ self._writer: asyncio.StreamWriter | None = None
28
+ self._request_id = 0
29
+ self._initialized = False
30
+
31
+ def _next_request_id(self) -> int:
32
+ """Generate next request ID."""
33
+ self._request_id += 1
34
+ return self._request_id
35
+
36
+ async def connect(self, timeout: float = 5.0) -> bool:
37
+ """Connect to zuban LSP server.
38
+
39
+ Args:
40
+ timeout: Connection timeout in seconds
41
+
42
+ Returns:
43
+ True if connected successfully
44
+ """
45
+ try:
46
+ # Attempt TCP connection
47
+ self._reader, self._writer = await asyncio.wait_for(
48
+ asyncio.open_connection(self.host, self.port), timeout=timeout
49
+ )
50
+
51
+ logger.info(f"Connected to Zuban LSP server at {self.host}:{self.port}")
52
+ return True
53
+
54
+ except (TimeoutError, OSError) as e:
55
+ logger.warning(f"Failed to connect to LSP server: {e}")
56
+ return False
57
+
58
+ async def disconnect(self) -> None:
59
+ """Disconnect from LSP server."""
60
+ if self._writer:
61
+ try:
62
+ # Send shutdown request
63
+ if self._initialized:
64
+ await self._send_request("shutdown")
65
+ await self._send_notification("exit")
66
+
67
+ self._writer.close()
68
+ await self._writer.wait_closed()
69
+
70
+ except Exception as e:
71
+ logger.warning(f"Error during disconnect: {e}")
72
+ finally:
73
+ self._writer = None
74
+ self._reader = None
75
+ self._initialized = False
76
+
77
+ async def initialize(self, root_path: Path) -> dict[str, t.Any] | None:
78
+ """Send initialize request.
79
+
80
+ Args:
81
+ root_path: Workspace root path
82
+
83
+ Returns:
84
+ Initialize response from server
85
+ """
86
+ if self._initialized:
87
+ return {"status": "already_initialized"}
88
+
89
+ params = {
90
+ "processId": None,
91
+ "rootPath": str(root_path),
92
+ "rootUri": f"file://{root_path}",
93
+ "capabilities": {
94
+ "textDocument": {
95
+ "publishDiagnostics": {
96
+ "versionSupport": True,
97
+ "tagSupport": {"valueSet": [1, 2]},
98
+ "relatedInformation": True,
99
+ }
100
+ },
101
+ "workspace": {
102
+ "workspaceFolders": True,
103
+ "configuration": True,
104
+ },
105
+ },
106
+ "workspaceFolders": [
107
+ {"uri": f"file://{root_path}", "name": root_path.name}
108
+ ],
109
+ }
110
+
111
+ response = await self._send_request("initialize", params)
112
+ if response and not response.get("error"):
113
+ # Send initialized notification
114
+ await self._send_notification("initialized")
115
+ self._initialized = True
116
+ logger.info("LSP client initialized successfully")
117
+
118
+ return response
119
+
120
+ async def text_document_did_open(self, file_path: Path) -> None:
121
+ """Notify server of opened document.
122
+
123
+ Args:
124
+ file_path: Path to opened file
125
+ """
126
+ if not file_path.exists():
127
+ logger.warning(f"File does not exist: {file_path}")
128
+ return
129
+
130
+ try:
131
+ content = file_path.read_text(encoding="utf-8")
132
+ except UnicodeDecodeError:
133
+ logger.warning(f"Could not read file as UTF-8: {file_path}")
134
+ return
135
+
136
+ params = {
137
+ "textDocument": {
138
+ "uri": f"file://{file_path}",
139
+ "languageId": "python",
140
+ "version": 1,
141
+ "text": content,
142
+ }
143
+ }
144
+
145
+ await self._send_notification("textDocument/didOpen", params)
146
+
147
+ async def text_document_did_change(
148
+ self, file_path: Path, content: str, version: int = 2
149
+ ) -> None:
150
+ """Notify server of document changes.
151
+
152
+ Args:
153
+ file_path: Path to changed file
154
+ content: New file content
155
+ version: Document version number
156
+ """
157
+ params = {
158
+ "textDocument": {
159
+ "uri": f"file://{file_path}",
160
+ "version": version,
161
+ },
162
+ "contentChanges": [{"text": content}],
163
+ }
164
+
165
+ await self._send_notification("textDocument/didChange", params)
166
+
167
+ async def text_document_did_close(self, file_path: Path) -> None:
168
+ """Notify server of closed document.
169
+
170
+ Args:
171
+ file_path: Path to closed file
172
+ """
173
+ params = {
174
+ "textDocument": {
175
+ "uri": f"file://{file_path}",
176
+ }
177
+ }
178
+
179
+ await self._send_notification("textDocument/didClose", params)
180
+
181
+ async def get_diagnostics(self, timeout: float = 2.0) -> list[dict[str, t.Any]]:
182
+ """Retrieve current diagnostics from server.
183
+
184
+ Args:
185
+ timeout: Timeout for waiting for diagnostics
186
+
187
+ Returns:
188
+ List of diagnostic messages
189
+ """
190
+ # For now, return empty list[t.Any] as diagnostics are typically pushed via notifications
191
+ # In a full implementation, we'd maintain a diagnostics store updated by notifications
192
+ return []
193
+
194
+ async def _send_request(
195
+ self, method: str, params: dict[str, t.Any] | None = None, timeout: float = 10.0
196
+ ) -> dict[str, t.Any] | None:
197
+ """Send LSP request and wait for response.
198
+
199
+ Args:
200
+ method: LSP method name
201
+ params: Request parameters
202
+ timeout: Response timeout
203
+
204
+ Returns:
205
+ Response from server
206
+ """
207
+ if not self._writer or not self._reader:
208
+ return None
209
+
210
+ request_id = self._next_request_id()
211
+ request = {
212
+ "jsonrpc": "2.0",
213
+ "id": request_id,
214
+ "method": method,
215
+ }
216
+
217
+ if params is not None:
218
+ request["params"] = params
219
+
220
+ try:
221
+ # Send request
222
+ await self._send_message(request)
223
+
224
+ # Wait for response
225
+ response = await asyncio.wait_for(
226
+ self._read_response(request_id), timeout=timeout
227
+ )
228
+
229
+ return response
230
+
231
+ except TimeoutError:
232
+ logger.warning(f"LSP request {method} timed out")
233
+ return {"error": "timeout", "id": request_id}
234
+ except Exception as e:
235
+ logger.error(f"LSP request {method} failed: {e}")
236
+ return {"error": str(e), "id": request_id}
237
+
238
+ async def _send_notification(
239
+ self, method: str, params: dict[str, t.Any] | None = None
240
+ ) -> None:
241
+ """Send LSP notification (no response expected).
242
+
243
+ Args:
244
+ method: LSP method name
245
+ params: Notification parameters
246
+ """
247
+ if not self._writer:
248
+ return
249
+
250
+ notification: dict[str, t.Any] = {
251
+ "jsonrpc": "2.0",
252
+ "method": method,
253
+ }
254
+
255
+ if params is not None:
256
+ notification["params"] = params
257
+
258
+ try:
259
+ await self._send_message(notification)
260
+ except Exception as e:
261
+ logger.error(f"LSP notification {method} failed: {e}")
262
+
263
+ async def _send_message(self, message: dict[str, t.Any]) -> None:
264
+ """Send LSP message with proper formatting.
265
+
266
+ Args:
267
+ message: Message to send
268
+ """
269
+ if not self._writer:
270
+ return
271
+
272
+ content_bytes = json.dumps(message).encode("utf-8")
273
+ content_length = len(content_bytes)
274
+
275
+ # LSP protocol: Content-Length header + \r\n\r\n + JSON
276
+ header = f"Content-Length: {content_length}\r\n\r\n"
277
+ full_message = header.encode("ascii") + content_bytes
278
+
279
+ self._writer.write(full_message)
280
+ await self._writer.drain()
281
+
282
+ async def _read_response(self, expected_id: int) -> dict[str, t.Any] | None:
283
+ """Read LSP response for specific request ID.
284
+
285
+ Args:
286
+ expected_id: Expected request ID
287
+
288
+ Returns:
289
+ Response message
290
+ """
291
+ while True:
292
+ message = await self._read_message()
293
+ if not message:
294
+ return None
295
+
296
+ # Check if this is the response we're waiting for
297
+ if message.get("id") == expected_id:
298
+ return message
299
+
300
+ # If it's a different response or notification, log and continue
301
+ if "id" in message:
302
+ logger.debug(
303
+ f"Received response for ID {message['id']}, expected {expected_id}"
304
+ )
305
+ else:
306
+ logger.debug(
307
+ f"Received notification: {message.get('method', 'unknown')}"
308
+ )
309
+
310
+ async def _read_message(self) -> dict[str, t.Any] | None:
311
+ """Read complete LSP message.
312
+
313
+ Returns:
314
+ Parsed message dictionary
315
+ """
316
+ if not self._reader:
317
+ return None
318
+
319
+ try:
320
+ # Read Content-Length header
321
+ header_line = await self._reader.readline()
322
+ header_str = header_line.decode("ascii").strip()
323
+
324
+ if not header_str.startswith("Content-Length:"):
325
+ logger.warning(f"Invalid LSP header: {header_str}")
326
+ return None
327
+
328
+ content_length = int(header_str.split(":", 1)[1].strip())
329
+
330
+ # Read separator line
331
+ separator = await self._reader.readline()
332
+ if separator.strip():
333
+ logger.warning("Expected empty separator line")
334
+
335
+ # Read JSON content
336
+ content_bytes = await self._reader.readexactly(content_length)
337
+ content = content_bytes.decode()
338
+
339
+ json_result = json.loads(content)
340
+ return t.cast(dict[str, t.Any] | None, json_result)
341
+
342
+ except Exception as e:
343
+ logger.error(f"Failed to read LSP message: {e}")
344
+ return None
345
+
346
+ async def __aenter__(self) -> "ZubanLSPClient":
347
+ """Async context manager entry."""
348
+ await self.connect()
349
+ return self
350
+
351
+ async def __aexit__(
352
+ self,
353
+ exc_type: type[BaseException] | None,
354
+ exc_val: BaseException | None,
355
+ exc_tb: t.Any,
356
+ ) -> None:
357
+ """Async context manager exit."""
358
+ await self.disconnect()
@@ -0,0 +1,193 @@
1
+ """Rust tool manager for unified execution and coordination."""
2
+
3
+ import asyncio
4
+ import time
5
+ import typing as t
6
+ from pathlib import Path
7
+
8
+ from ._base import BaseRustToolAdapter, ToolResult
9
+ from .skylos import SkylosAdapter
10
+ from .zuban import ZubanAdapter
11
+
12
+ if t.TYPE_CHECKING:
13
+ from crackerjack.orchestration.execution_strategies import ExecutionContext
14
+
15
+
16
+ class RustToolHookManager:
17
+ """Manager for coordinating Rust-based analysis tools."""
18
+
19
+ def __init__(self, context: "ExecutionContext") -> None:
20
+ """Initialize manager with execution context."""
21
+ self.context = context
22
+ self.adapters: dict[str, BaseRustToolAdapter] = {}
23
+ self._initialize_adapters()
24
+
25
+ def _initialize_adapters(self) -> None:
26
+ """Initialize available Rust tool adapters."""
27
+ # Dead code detection with Skylos
28
+ self.adapters["skylos"] = SkylosAdapter(context=self.context)
29
+
30
+ # Type checking with Zuban
31
+ self.adapters["zuban"] = ZubanAdapter(context=self.context)
32
+
33
+ async def run_all_tools(
34
+ self, target_files: list[Path] | None = None
35
+ ) -> dict[str, ToolResult]:
36
+ """Run all available Rust tools in parallel."""
37
+ target_files = target_files or []
38
+
39
+ # Filter to available tools only
40
+ available_adapters = {
41
+ name: adapter
42
+ for name, adapter in self.adapters.items()
43
+ if adapter.validate_tool_available()
44
+ }
45
+
46
+ if not available_adapters:
47
+ return {
48
+ "error": ToolResult(
49
+ success=False,
50
+ error=(
51
+ "No Rust tools are available. "
52
+ "Install skylos and zuban with: uv add skylos zuban"
53
+ ),
54
+ )
55
+ }
56
+
57
+ # Run tools in parallel
58
+ tasks = [
59
+ self._run_single_tool(name, adapter, target_files)
60
+ for name, adapter in available_adapters.items()
61
+ ]
62
+
63
+ results = await asyncio.gather(*tasks, return_exceptions=True)
64
+
65
+ # Process results
66
+ tool_results = {}
67
+ for i, (name, _) in enumerate(available_adapters.items()):
68
+ result = results[i]
69
+ if isinstance(result, Exception):
70
+ tool_results[name] = ToolResult(
71
+ success=False,
72
+ error=f"Tool execution failed: {result}",
73
+ )
74
+ elif isinstance(result, ToolResult): # Explicit check for mypy
75
+ tool_results[name] = result
76
+
77
+ return tool_results
78
+
79
+ async def run_single_tool(
80
+ self, tool_name: str, target_files: list[Path] | None = None
81
+ ) -> ToolResult:
82
+ """Run a single Rust tool by name."""
83
+ if tool_name not in self.adapters:
84
+ return ToolResult(
85
+ success=False,
86
+ error=(
87
+ f"Unknown tool: {tool_name}. "
88
+ f"Available: {list[t.Any](self.adapters.keys())}"
89
+ ),
90
+ )
91
+
92
+ adapter = self.adapters[tool_name]
93
+ if not adapter.validate_tool_available():
94
+ return ToolResult(
95
+ success=False,
96
+ error=(
97
+ f"Tool {tool_name} is not available. "
98
+ f"Install with: uv add {tool_name}"
99
+ ),
100
+ )
101
+
102
+ return await self._run_single_tool(tool_name, adapter, target_files or [])
103
+
104
+ async def _run_single_tool(
105
+ self, name: str, adapter: BaseRustToolAdapter, target_files: list[Path]
106
+ ) -> ToolResult:
107
+ """Execute a single tool adapter."""
108
+ start_time = time.time()
109
+
110
+ try:
111
+ # Get command arguments
112
+ cmd_args = adapter.get_command_args(target_files)
113
+
114
+ # Execute command
115
+ process = await asyncio.create_subprocess_exec(
116
+ *cmd_args,
117
+ stdout=asyncio.subprocess.PIPE,
118
+ stderr=asyncio.subprocess.STDOUT,
119
+ cwd=self.context.working_directory,
120
+ )
121
+
122
+ stdout, _ = await process.communicate()
123
+ output = stdout.decode() if stdout else ""
124
+
125
+ # Parse output
126
+ result = adapter.parse_output(output)
127
+ result.execution_time = time.time() - start_time
128
+
129
+ return result
130
+
131
+ except Exception as e:
132
+ return ToolResult(
133
+ success=False,
134
+ error=f"Failed to execute {name}: {e}",
135
+ execution_time=time.time() - start_time,
136
+ tool_version=adapter.get_tool_version(),
137
+ )
138
+
139
+ def get_available_tools(self) -> list[str]:
140
+ """Get list[t.Any] of available Rust tools."""
141
+ return [
142
+ name
143
+ for name, adapter in self.adapters.items()
144
+ if adapter.validate_tool_available()
145
+ ]
146
+
147
+ def get_tool_info(self) -> dict[str, dict[str, t.Any]]:
148
+ """Get information about all configured tools."""
149
+ info: dict[str, dict[str, t.Any]] = {}
150
+ for name, adapter in self.adapters.items():
151
+ info[name] = {
152
+ "available": adapter.validate_tool_available(),
153
+ "supports_json": adapter.supports_json_output(),
154
+ "version": adapter.get_tool_version(),
155
+ "tool_name": adapter.get_tool_name(),
156
+ }
157
+ return info
158
+
159
+ def create_consolidated_report(
160
+ self, results: dict[str, ToolResult]
161
+ ) -> dict[str, t.Any]:
162
+ """Create a consolidated report from multiple tool results."""
163
+ total_issues = 0
164
+ total_errors = 0
165
+ total_warnings = 0
166
+ all_success = True
167
+ execution_times = {}
168
+
169
+ for tool_name, result in results.items():
170
+ if tool_name == "error":
171
+ all_success = False
172
+ continue
173
+
174
+ total_issues += len(result.issues)
175
+ total_errors += result.error_count
176
+ total_warnings += result.warning_count
177
+ execution_times[tool_name] = result.execution_time
178
+
179
+ if not result.success:
180
+ all_success = False
181
+
182
+ return {
183
+ "overall_success": all_success,
184
+ "total_issues": total_issues,
185
+ "total_errors": total_errors,
186
+ "total_warnings": total_warnings,
187
+ "tools_run": list[t.Any](results.keys()),
188
+ "execution_times": execution_times,
189
+ "total_time": sum(execution_times.values()),
190
+ "results_by_tool": {
191
+ name: result.to_dict() for name, result in results.items()
192
+ },
193
+ }