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,600 @@
1
+ import asyncio
2
+ import hashlib
3
+ import typing as t
4
+ from collections import defaultdict
5
+ from itertools import starmap
6
+
7
+ from crackerjack.agents.base import (
8
+ AgentContext,
9
+ FixResult,
10
+ Issue,
11
+ IssueType,
12
+ SubAgent,
13
+ agent_registry,
14
+ )
15
+ from crackerjack.agents.error_middleware import agent_error_boundary
16
+ from crackerjack.agents.tracker import get_agent_tracker
17
+ from crackerjack.services.cache import CrackerjackCache
18
+ from crackerjack.services.debug import get_ai_agent_debugger
19
+ from crackerjack.services.logging import get_logger
20
+
21
+ ISSUE_TYPE_TO_AGENTS: dict[IssueType, list[str]] = {
22
+ IssueType.FORMATTING: ["FormattingAgent"],
23
+ IssueType.TYPE_ERROR: ["TestCreationAgent", "RefactoringAgent"],
24
+ IssueType.SECURITY: ["SecurityAgent"],
25
+ IssueType.TEST_FAILURE: ["TestSpecialistAgent", "TestCreationAgent"],
26
+ IssueType.IMPORT_ERROR: ["ImportOptimizationAgent"],
27
+ IssueType.COMPLEXITY: ["RefactoringAgent"],
28
+ IssueType.DEAD_CODE: ["RefactoringAgent", "ImportOptimizationAgent"],
29
+ IssueType.DEPENDENCY: ["ImportOptimizationAgent"],
30
+ IssueType.DRY_VIOLATION: ["DRYAgent"],
31
+ IssueType.PERFORMANCE: ["PerformanceAgent"],
32
+ IssueType.DOCUMENTATION: ["DocumentationAgent"],
33
+ IssueType.TEST_ORGANIZATION: ["TestSpecialistAgent"],
34
+ IssueType.COVERAGE_IMPROVEMENT: ["TestCreationAgent"],
35
+ IssueType.REGEX_VALIDATION: ["SecurityAgent", "RefactoringAgent"],
36
+ IssueType.SEMANTIC_CONTEXT: ["SemanticAgent", "ArchitectAgent"],
37
+ }
38
+
39
+
40
+ class AgentCoordinator:
41
+ def __init__(
42
+ self, context: AgentContext, cache: CrackerjackCache | None = None
43
+ ) -> None:
44
+ self.context = context
45
+ self.agents: list[SubAgent] = []
46
+ self.logger = get_logger(__name__)
47
+ self._issue_cache: dict[str, FixResult] = {}
48
+ self._collaboration_threshold = 0.7
49
+ self.tracker = get_agent_tracker()
50
+ self.debugger = get_ai_agent_debugger()
51
+ self.proactive_mode = True
52
+ self.cache = cache or CrackerjackCache()
53
+
54
+ def initialize_agents(self) -> None:
55
+ self.agents = agent_registry.create_all(self.context)
56
+ agent_types = [a.name for a in self.agents]
57
+ self.logger.info(f"Initialized {len(self.agents)} agents: {agent_types}")
58
+
59
+ self.tracker.register_agents(agent_types)
60
+ self.tracker.set_coordinator_status("active")
61
+
62
+ self.debugger.log_agent_activity(
63
+ agent_name="coordinator",
64
+ activity="agents_initialized",
65
+ metadata={"agent_count": len(self.agents), "agent_types": agent_types},
66
+ )
67
+
68
+ async def handle_issues(self, issues: list[Issue]) -> FixResult:
69
+ if not self.agents:
70
+ self.initialize_agents()
71
+
72
+ if not issues:
73
+ return FixResult(success=True, confidence=1.0)
74
+
75
+ self.logger.info(f"Handling {len(issues)} issues")
76
+
77
+ issues_by_type = self._group_issues_by_type(issues)
78
+
79
+ # Optimization: Run ALL issue types in parallel instead of sequential
80
+ tasks = list[t.Any](
81
+ starmap(self._handle_issues_by_type, issues_by_type.items())
82
+ )
83
+
84
+ results = await asyncio.gather(*tasks, return_exceptions=True)
85
+
86
+ overall_result = FixResult(success=True, confidence=1.0)
87
+ for result in results:
88
+ if isinstance(result, FixResult):
89
+ overall_result = overall_result.merge_with(result)
90
+ else:
91
+ self.logger.error(f"Issue type handling failed: {result}")
92
+ overall_result.success = False
93
+ overall_result.remaining_issues.append(
94
+ f"Type handling failed: {result}"
95
+ )
96
+
97
+ return overall_result
98
+
99
+ async def _handle_issues_by_type(
100
+ self,
101
+ issue_type: IssueType,
102
+ issues: list[Issue],
103
+ ) -> FixResult:
104
+ self.logger.info(f"Handling {len(issues)} {issue_type.value} issues")
105
+
106
+ # Fast agent lookup using static mapping
107
+ preferred_agent_names = ISSUE_TYPE_TO_AGENTS.get(issue_type, [])
108
+ specialist_agents = []
109
+
110
+ # First, try to use agents from static mapping for O(1) lookup
111
+ specialist_agents = [
112
+ agent
113
+ for agent in self.agents
114
+ if agent.__class__.__name__ in preferred_agent_names
115
+ ]
116
+
117
+ # Fallback: use traditional dynamic lookup if no static match
118
+ if not specialist_agents:
119
+ specialist_agents = [
120
+ agent
121
+ for agent in self.agents
122
+ if issue_type in agent.get_supported_types()
123
+ ]
124
+
125
+ if not specialist_agents:
126
+ self.logger.warning(f"No specialist agents for {issue_type.value}")
127
+ return FixResult(
128
+ success=False,
129
+ confidence=0.0,
130
+ remaining_issues=[f"No agents for {issue_type.value} issues"],
131
+ )
132
+
133
+ tasks: list[t.Coroutine[t.Any, t.Any, FixResult]] = []
134
+ for issue in issues:
135
+ best_specialist = await self._find_best_specialist(specialist_agents, issue)
136
+ if best_specialist:
137
+ task = self._handle_with_single_agent(best_specialist, issue)
138
+ tasks.append(task)
139
+
140
+ if not tasks:
141
+ return FixResult(success=False, confidence=0.0)
142
+
143
+ results = await asyncio.gather(*tasks, return_exceptions=True)
144
+
145
+ combined_result = FixResult(success=True, confidence=1.0)
146
+ for result in results:
147
+ if isinstance(result, FixResult):
148
+ combined_result = combined_result.merge_with(result)
149
+ else:
150
+ self.logger.error(f"Agent task failed: {result}")
151
+ combined_result.success = False
152
+ combined_result.remaining_issues.append(f"Agent failed: {result}")
153
+
154
+ return combined_result
155
+
156
+ async def _find_best_specialist(
157
+ self,
158
+ specialists: list[SubAgent],
159
+ issue: Issue,
160
+ ) -> SubAgent | None:
161
+ candidates = await self._score_all_specialists(specialists, issue)
162
+ if not candidates:
163
+ return None
164
+
165
+ best_agent, best_score = self._find_highest_scoring_agent(candidates)
166
+ return self._apply_built_in_preference(candidates, best_agent, best_score)
167
+
168
+ async def _score_all_specialists(
169
+ self, specialists: list[SubAgent], issue: Issue
170
+ ) -> list[tuple[SubAgent, float]]:
171
+ """Score all specialist agents for handling an issue."""
172
+ candidates: list[tuple[SubAgent, float]] = []
173
+
174
+ for agent in specialists:
175
+ try:
176
+ score = await agent.can_handle(issue)
177
+ candidates.append((agent, score))
178
+ except Exception as e:
179
+ self.logger.exception(f"Error evaluating specialist {agent.name}: {e}")
180
+
181
+ return candidates
182
+
183
+ def _find_highest_scoring_agent(
184
+ self, candidates: list[tuple[SubAgent, float]]
185
+ ) -> tuple[SubAgent | None, float]:
186
+ """Find the agent with the highest score."""
187
+ best_agent = None
188
+ best_score = 0.0
189
+
190
+ for agent, score in candidates:
191
+ if score > best_score:
192
+ best_score = score
193
+ best_agent = agent
194
+
195
+ return best_agent, best_score
196
+
197
+ def _apply_built_in_preference(
198
+ self,
199
+ candidates: list[tuple[SubAgent, float]],
200
+ best_agent: SubAgent | None,
201
+ best_score: float,
202
+ ) -> SubAgent | None:
203
+ """Apply preference for built-in agents when scores are close."""
204
+ if not best_agent or best_score <= 0:
205
+ return best_agent
206
+
207
+ # Threshold for considering scores "close" (5% difference)
208
+ CLOSE_SCORE_THRESHOLD = 0.05
209
+
210
+ for agent, score in candidates:
211
+ if self._should_prefer_built_in_agent(
212
+ agent, best_agent, score, best_score, CLOSE_SCORE_THRESHOLD
213
+ ):
214
+ self._log_built_in_preference(
215
+ agent, score, best_agent, best_score, best_score - score
216
+ )
217
+ return agent
218
+
219
+ return best_agent
220
+
221
+ def _should_prefer_built_in_agent(
222
+ self,
223
+ agent: SubAgent,
224
+ best_agent: SubAgent,
225
+ score: float,
226
+ best_score: float,
227
+ threshold: float,
228
+ ) -> bool:
229
+ """Check if a built-in agent should be preferred over the current best."""
230
+ return (
231
+ agent != best_agent
232
+ and self._is_built_in_agent(agent)
233
+ and 0 < (best_score - score) <= threshold
234
+ )
235
+
236
+ def _log_built_in_preference(
237
+ self,
238
+ agent: SubAgent,
239
+ score: float,
240
+ best_agent: SubAgent,
241
+ best_score: float,
242
+ score_difference: float,
243
+ ) -> None:
244
+ """Log when preferring a built-in agent."""
245
+ self.logger.info(
246
+ f"Preferring built-in agent {agent.name} (score: {score:.2f}) "
247
+ f"over {best_agent.name} (score: {best_score:.2f}) "
248
+ f"due to {score_difference:.2f} threshold preference"
249
+ )
250
+
251
+ def _is_built_in_agent(self, agent: SubAgent) -> bool:
252
+ """Check if agent is a built-in Crackerjack agent."""
253
+ built_in_agent_names = {
254
+ "ArchitectAgent",
255
+ "DocumentationAgent",
256
+ "DRYAgent",
257
+ "FormattingAgent",
258
+ "ImportOptimizationAgent",
259
+ "PerformanceAgent",
260
+ "RefactoringAgent",
261
+ "SecurityAgent",
262
+ "TestCreationAgent",
263
+ "TestSpecialistAgent",
264
+ }
265
+ return agent.__class__.__name__ in built_in_agent_names
266
+
267
+ async def _handle_with_single_agent(
268
+ self,
269
+ agent: SubAgent,
270
+ issue: Issue,
271
+ ) -> FixResult:
272
+ self.logger.info(f"Handling issue with {agent.name}: {issue.message[:100]}")
273
+
274
+ # Create cache key from issue content
275
+ issue_hash = self._create_issue_hash(issue)
276
+
277
+ # Check cache for previous agent decision
278
+ cached_decision = self.cache.get_agent_decision(agent.name, issue_hash)
279
+ if cached_decision:
280
+ self.logger.debug(f"Using cached decision for {agent.name}")
281
+ self.tracker.track_agent_complete(agent.name, cached_decision)
282
+ return cached_decision # type: ignore[no-any-return]
283
+
284
+ confidence = await agent.can_handle(issue)
285
+ self.tracker.track_agent_processing(agent.name, issue, confidence)
286
+
287
+ self.debugger.log_agent_activity(
288
+ agent_name=agent.name,
289
+ activity="processing_started",
290
+ issue_id=issue.id,
291
+ confidence=confidence,
292
+ metadata={"issue_type": issue.type.value, "severity": issue.severity.value},
293
+ )
294
+
295
+ result = await self._execute_agent(agent, issue)
296
+ if result.success:
297
+ self.logger.info(f"{agent.name} successfully fixed issue")
298
+ else:
299
+ self.logger.warning(f"{agent.name} failed to fix issue")
300
+
301
+ self.tracker.track_agent_complete(agent.name, result)
302
+
303
+ self.debugger.log_agent_activity(
304
+ agent_name=agent.name,
305
+ activity="processing_completed",
306
+ issue_id=issue.id,
307
+ confidence=result.confidence,
308
+ result={
309
+ "success": result.success,
310
+ "remaining_issues": len(result.remaining_issues),
311
+ },
312
+ metadata={"fix_applied": result.success},
313
+ )
314
+
315
+ return result
316
+
317
+ def _group_issues_by_type(
318
+ self,
319
+ issues: list[Issue],
320
+ ) -> dict[IssueType, list[Issue]]:
321
+ grouped: defaultdict[IssueType, list[Issue]] = defaultdict(list)
322
+ for issue in issues:
323
+ grouped[issue.type].append(issue)
324
+ return dict(grouped)
325
+
326
+ def _create_issue_hash(self, issue: Issue) -> str:
327
+ """Create a hash from issue content for caching decisions."""
328
+ content = (
329
+ f"{issue.type.value}:{issue.message}:{issue.file_path}:{issue.line_number}"
330
+ )
331
+ return hashlib.md5(content.encode(), usedforsecurity=False).hexdigest()
332
+
333
+ def _get_cache_key(self, agent_name: str, issue: Issue) -> str:
334
+ """Get cache key for agent-issue combination."""
335
+ issue_hash = self._create_issue_hash(issue)
336
+ return f"{agent_name}:{issue_hash}"
337
+
338
+ @agent_error_boundary
339
+ async def _execute_agent(self, agent: SubAgent, issue: Issue) -> FixResult:
340
+ """Execute agent analysis with centralized error handling."""
341
+ return await self._cached_analyze_and_fix(agent, issue)
342
+
343
+ async def _cached_analyze_and_fix(self, agent: SubAgent, issue: Issue) -> FixResult:
344
+ """Analyze and fix issue with intelligent caching."""
345
+ cache_key = self._get_cache_key(agent.name, issue)
346
+
347
+ # Check in-memory cache first (fastest)
348
+ if cache_key in self._issue_cache:
349
+ self.logger.debug(f"Using in-memory cache for {agent.name}")
350
+ return self._issue_cache[cache_key]
351
+
352
+ # Check persistent cache
353
+ cached_result = self.cache.get_agent_decision(
354
+ agent.name, self._create_issue_hash(issue)
355
+ )
356
+ if cached_result:
357
+ self.logger.debug(f"Using persistent cache for {agent.name}")
358
+ # Store in memory cache for even faster future access
359
+ self._issue_cache[cache_key] = cached_result
360
+ return cached_result # type: ignore[no-any-return]
361
+
362
+ # No cache hit - perform actual analysis
363
+ result = await agent.analyze_and_fix(issue)
364
+
365
+ # Cache successful results with high confidence
366
+ if result.success and result.confidence > 0.7:
367
+ self._issue_cache[cache_key] = result
368
+ self.cache.set_agent_decision(
369
+ agent.name, self._create_issue_hash(issue), result
370
+ )
371
+
372
+ return result
373
+
374
+ def get_agent_capabilities(self) -> dict[str, dict[str, t.Any]]:
375
+ if not self.agents:
376
+ self.initialize_agents()
377
+
378
+ capabilities = {}
379
+ for agent in self.agents:
380
+ capabilities[agent.name] = {
381
+ "supported_types": [t.value for t in agent.get_supported_types()],
382
+ "class": agent.__class__.__name__,
383
+ }
384
+ return capabilities
385
+
386
+ async def handle_issues_proactively(self, issues: list[Issue]) -> FixResult:
387
+ if not self.proactive_mode:
388
+ return await self.handle_issues(issues)
389
+
390
+ if not self.agents:
391
+ self.initialize_agents()
392
+
393
+ if not issues:
394
+ return FixResult(success=True, confidence=1.0)
395
+
396
+ self.logger.info(f"Handling {len(issues)} issues with proactive planning")
397
+
398
+ architectural_plan = await self._create_architectural_plan(issues)
399
+
400
+ overall_result = await self._apply_fixes_with_plan(issues, architectural_plan)
401
+
402
+ validation_result = await self._validate_against_plan(
403
+ overall_result, architectural_plan
404
+ )
405
+
406
+ return validation_result
407
+
408
+ async def _create_architectural_plan(self, issues: list[Issue]) -> dict[str, t.Any]:
409
+ architect = self._get_architect_agent()
410
+
411
+ if not architect:
412
+ return self._create_fallback_plan(
413
+ "No ArchitectAgent available for planning"
414
+ )
415
+
416
+ complex_issues = self._filter_complex_issues(issues)
417
+ if not complex_issues:
418
+ return {"strategy": "simple_fixes", "patterns": ["standard_patterns"]}
419
+
420
+ return await self._generate_architectural_plan(
421
+ architect, complex_issues, issues
422
+ )
423
+
424
+ def _create_fallback_plan(self, reason: str) -> dict[str, t.Any]:
425
+ """Create a fallback plan when architectural planning fails."""
426
+ self.logger.warning(reason)
427
+ return {"strategy": "reactive_fallback", "patterns": []}
428
+
429
+ def _filter_complex_issues(self, issues: list[Issue]) -> list[Issue]:
430
+ """Filter issues that require architectural planning."""
431
+ complex_types = {
432
+ IssueType.COMPLEXITY,
433
+ IssueType.DRY_VIOLATION,
434
+ IssueType.PERFORMANCE,
435
+ }
436
+ return [issue for issue in issues if issue.type in complex_types]
437
+
438
+ async def _generate_architectural_plan(
439
+ self, architect: t.Any, complex_issues: list[Issue], all_issues: list[Issue]
440
+ ) -> dict[str, t.Any]:
441
+ """Generate architectural plan using the architect agent."""
442
+ primary_issue = complex_issues[0]
443
+
444
+ try:
445
+ plan = await architect.plan_before_action(primary_issue)
446
+ # Ensure plan is properly typed as dict[str, Any]
447
+ if not isinstance(plan, dict):
448
+ plan = {"strategy": "default", "confidence": 0.5}
449
+ enriched_plan = self._enrich_architectural_plan(plan, all_issues)
450
+
451
+ self.logger.info(
452
+ f"Created architectural plan: {enriched_plan.get('strategy', 'unknown')}"
453
+ )
454
+ return enriched_plan
455
+
456
+ except Exception as e:
457
+ self.logger.exception(f"Failed to create architectural plan: {e}")
458
+ return {"strategy": "reactive_fallback", "patterns": [], "error": str(e)}
459
+
460
+ def _enrich_architectural_plan(
461
+ self, plan: dict[str, t.Any], issues: list[Issue]
462
+ ) -> dict[str, t.Any]:
463
+ """Enrich the architectural plan with issue metadata."""
464
+ plan["all_issues"] = [issue.id for issue in issues]
465
+ plan["issue_types"] = list[t.Any]({issue.type.value for issue in issues})
466
+ return plan
467
+
468
+ async def _apply_fixes_with_plan(
469
+ self, issues: list[Issue], plan: dict[str, t.Any]
470
+ ) -> FixResult:
471
+ strategy = plan.get("strategy", "reactive_fallback")
472
+
473
+ if strategy == "reactive_fallback":
474
+ return await self.handle_issues(issues)
475
+
476
+ self.logger.info(f"Applying fixes with {strategy} strategy")
477
+ prioritized_issues = self._prioritize_issues_by_plan(issues, plan)
478
+
479
+ return await self._process_prioritized_groups(prioritized_issues, plan)
480
+
481
+ async def _process_prioritized_groups(
482
+ self, prioritized_issues: list[list[Issue]], plan: dict[str, t.Any]
483
+ ) -> FixResult:
484
+ """Process prioritized issue groups according to the plan."""
485
+ overall_result = FixResult(success=True, confidence=1.0)
486
+
487
+ for issue_group in prioritized_issues:
488
+ group_result = await self._handle_issue_group_with_plan(issue_group, plan)
489
+ overall_result = overall_result.merge_with(group_result)
490
+
491
+ if self._should_fail_on_group_failure(group_result, issue_group, plan):
492
+ overall_result = self._mark_critical_group_failure(
493
+ overall_result, issue_group
494
+ )
495
+
496
+ return overall_result
497
+
498
+ def _should_fail_on_group_failure(
499
+ self, group_result: FixResult, issue_group: list[Issue], plan: dict[str, t.Any]
500
+ ) -> bool:
501
+ """Determine if overall process should fail when a group fails."""
502
+ return not group_result.success and self._is_critical_group(issue_group, plan)
503
+
504
+ def _mark_critical_group_failure(
505
+ self, overall_result: FixResult, issue_group: list[Issue]
506
+ ) -> FixResult:
507
+ """Mark overall result as failed due to critical group failure."""
508
+ overall_result.success = False
509
+ overall_result.remaining_issues.append(
510
+ f"Critical issue group failed: {[i.id for i in issue_group]}"
511
+ )
512
+ return overall_result
513
+
514
+ async def _validate_against_plan(
515
+ self, result: FixResult, plan: dict[str, t.Any]
516
+ ) -> FixResult:
517
+ validation_steps = plan.get("validation", [])
518
+
519
+ if not validation_steps:
520
+ return result
521
+
522
+ self.logger.info(f"Validating against plan: {validation_steps}")
523
+
524
+ result.recommendations.extend(
525
+ [
526
+ f"Validate with: {', '.join(validation_steps)}",
527
+ f"Applied strategy: {plan.get('strategy', 'unknown')}",
528
+ f"Used patterns: {', '.join(plan.get('patterns', []))}",
529
+ ]
530
+ )
531
+
532
+ return result
533
+
534
+ def _get_architect_agent(self) -> SubAgent | None:
535
+ for agent in self.agents:
536
+ if agent.__class__.__name__ == "ArchitectAgent":
537
+ return agent
538
+ return None
539
+
540
+ def _prioritize_issues_by_plan(
541
+ self, issues: list[Issue], plan: dict[str, t.Any]
542
+ ) -> list[list[Issue]]:
543
+ strategy = plan.get("strategy", "reactive_fallback")
544
+
545
+ if strategy == "external_specialist_guided":
546
+ complex_issues = [
547
+ issue
548
+ for issue in issues
549
+ if issue.type in {IssueType.COMPLEXITY, IssueType.DRY_VIOLATION}
550
+ ]
551
+ other_issues = [issue for issue in issues if issue not in complex_issues]
552
+ return [complex_issues, other_issues] if complex_issues else [other_issues]
553
+
554
+ groups = self._group_issues_by_type(issues)
555
+ return list[t.Any](groups.values())
556
+
557
+ async def _handle_issue_group_with_plan(
558
+ self, issues: list[Issue], plan: dict[str, t.Any]
559
+ ) -> FixResult:
560
+ if not issues:
561
+ return FixResult(success=True, confidence=1.0)
562
+
563
+ representative_issue = issues[0]
564
+
565
+ if self._should_use_architect_for_group(issues, plan):
566
+ architect = self._get_architect_agent()
567
+ if architect:
568
+ group_result = FixResult(success=True, confidence=1.0)
569
+
570
+ for issue in issues:
571
+ issue_result = await architect.analyze_and_fix(issue)
572
+ group_result = group_result.merge_with(issue_result)
573
+
574
+ return group_result
575
+
576
+ return await self._handle_issues_by_type(representative_issue.type, issues)
577
+
578
+ def _should_use_architect_for_group(
579
+ self, issues: list[Issue], plan: dict[str, t.Any]
580
+ ) -> bool:
581
+ strategy = plan.get("strategy", "")
582
+
583
+ if strategy == "external_specialist_guided":
584
+ return True
585
+
586
+ architectural_types = {
587
+ IssueType.COMPLEXITY,
588
+ IssueType.DRY_VIOLATION,
589
+ IssueType.PERFORMANCE,
590
+ }
591
+
592
+ return any(issue.type in architectural_types for issue in issues)
593
+
594
+ def _is_critical_group(self, issues: list[Issue], plan: dict[str, t.Any]) -> bool:
595
+ critical_types = {IssueType.COMPLEXITY, IssueType.DRY_VIOLATION}
596
+ return any(issue.type in critical_types for issue in issues)
597
+
598
+ def set_proactive_mode(self, enabled: bool) -> None:
599
+ self.proactive_mode = enabled
600
+ self.logger.info(f"Proactive mode {'enabled' if enabled else 'disabled'}")