crackerjack 0.37.9__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 (425) hide show
  1. crackerjack/README.md +19 -0
  2. crackerjack/__init__.py +30 -1
  3. crackerjack/__main__.py +342 -1263
  4. crackerjack/adapters/README.md +18 -0
  5. crackerjack/adapters/__init__.py +27 -5
  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/{rust_tool_manager.py → lsp/_manager.py} +3 -3
  27. crackerjack/adapters/{skylos_adapter.py → lsp/skylos.py} +59 -7
  28. crackerjack/adapters/{zuban_adapter.py → lsp/zuban.py} +3 -6
  29. crackerjack/adapters/refactor/README.md +59 -0
  30. crackerjack/adapters/refactor/__init__.py +12 -0
  31. crackerjack/adapters/refactor/creosote.py +318 -0
  32. crackerjack/adapters/refactor/refurb.py +406 -0
  33. crackerjack/adapters/refactor/skylos.py +494 -0
  34. crackerjack/adapters/sast/README.md +132 -0
  35. crackerjack/adapters/sast/__init__.py +32 -0
  36. crackerjack/adapters/sast/_base.py +201 -0
  37. crackerjack/adapters/sast/bandit.py +423 -0
  38. crackerjack/adapters/sast/pyscn.py +405 -0
  39. crackerjack/adapters/sast/semgrep.py +241 -0
  40. crackerjack/adapters/security/README.md +111 -0
  41. crackerjack/adapters/security/__init__.py +17 -0
  42. crackerjack/adapters/security/gitleaks.py +339 -0
  43. crackerjack/adapters/type/README.md +52 -0
  44. crackerjack/adapters/type/__init__.py +12 -0
  45. crackerjack/adapters/type/pyrefly.py +402 -0
  46. crackerjack/adapters/type/ty.py +402 -0
  47. crackerjack/adapters/type/zuban.py +522 -0
  48. crackerjack/adapters/utility/README.md +51 -0
  49. crackerjack/adapters/utility/__init__.py +10 -0
  50. crackerjack/adapters/utility/checks.py +884 -0
  51. crackerjack/agents/README.md +264 -0
  52. crackerjack/agents/__init__.py +40 -12
  53. crackerjack/agents/base.py +1 -0
  54. crackerjack/agents/claude_code_bridge.py +641 -0
  55. crackerjack/agents/coordinator.py +49 -53
  56. crackerjack/agents/dry_agent.py +187 -3
  57. crackerjack/agents/enhanced_coordinator.py +279 -0
  58. crackerjack/agents/enhanced_proactive_agent.py +185 -0
  59. crackerjack/agents/error_middleware.py +53 -0
  60. crackerjack/agents/formatting_agent.py +6 -8
  61. crackerjack/agents/helpers/__init__.py +9 -0
  62. crackerjack/agents/helpers/performance/__init__.py +22 -0
  63. crackerjack/agents/helpers/performance/performance_ast_analyzer.py +357 -0
  64. crackerjack/agents/helpers/performance/performance_pattern_detector.py +909 -0
  65. crackerjack/agents/helpers/performance/performance_recommender.py +572 -0
  66. crackerjack/agents/helpers/refactoring/__init__.py +22 -0
  67. crackerjack/agents/helpers/refactoring/code_transformer.py +536 -0
  68. crackerjack/agents/helpers/refactoring/complexity_analyzer.py +344 -0
  69. crackerjack/agents/helpers/refactoring/dead_code_detector.py +437 -0
  70. crackerjack/agents/helpers/test_creation/__init__.py +19 -0
  71. crackerjack/agents/helpers/test_creation/test_ast_analyzer.py +216 -0
  72. crackerjack/agents/helpers/test_creation/test_coverage_analyzer.py +643 -0
  73. crackerjack/agents/helpers/test_creation/test_template_generator.py +1031 -0
  74. crackerjack/agents/performance_agent.py +121 -1152
  75. crackerjack/agents/refactoring_agent.py +156 -655
  76. crackerjack/agents/semantic_agent.py +479 -0
  77. crackerjack/agents/semantic_helpers.py +356 -0
  78. crackerjack/agents/test_creation_agent.py +19 -1605
  79. crackerjack/api.py +5 -7
  80. crackerjack/cli/README.md +394 -0
  81. crackerjack/cli/__init__.py +1 -1
  82. crackerjack/cli/cache_handlers.py +23 -18
  83. crackerjack/cli/cache_handlers_enhanced.py +1 -4
  84. crackerjack/cli/facade.py +70 -8
  85. crackerjack/cli/formatting.py +13 -0
  86. crackerjack/cli/handlers/__init__.py +85 -0
  87. crackerjack/cli/handlers/advanced.py +103 -0
  88. crackerjack/cli/handlers/ai_features.py +62 -0
  89. crackerjack/cli/handlers/analytics.py +479 -0
  90. crackerjack/cli/handlers/changelog.py +271 -0
  91. crackerjack/cli/handlers/config_handlers.py +16 -0
  92. crackerjack/cli/handlers/coverage.py +84 -0
  93. crackerjack/cli/handlers/documentation.py +280 -0
  94. crackerjack/cli/handlers/main_handlers.py +497 -0
  95. crackerjack/cli/handlers/monitoring.py +371 -0
  96. crackerjack/cli/handlers.py +249 -49
  97. crackerjack/cli/interactive.py +8 -5
  98. crackerjack/cli/options.py +203 -110
  99. crackerjack/cli/semantic_handlers.py +292 -0
  100. crackerjack/cli/version.py +19 -0
  101. crackerjack/code_cleaner.py +60 -24
  102. crackerjack/config/README.md +472 -0
  103. crackerjack/config/__init__.py +256 -0
  104. crackerjack/config/global_lock_config.py +191 -54
  105. crackerjack/config/hooks.py +188 -16
  106. crackerjack/config/loader.py +239 -0
  107. crackerjack/config/settings.py +141 -0
  108. crackerjack/config/tool_commands.py +331 -0
  109. crackerjack/core/README.md +393 -0
  110. crackerjack/core/async_workflow_orchestrator.py +79 -53
  111. crackerjack/core/autofix_coordinator.py +22 -9
  112. crackerjack/core/container.py +10 -9
  113. crackerjack/core/enhanced_container.py +9 -9
  114. crackerjack/core/performance.py +1 -1
  115. crackerjack/core/performance_monitor.py +5 -3
  116. crackerjack/core/phase_coordinator.py +1018 -634
  117. crackerjack/core/proactive_workflow.py +3 -3
  118. crackerjack/core/retry.py +275 -0
  119. crackerjack/core/service_watchdog.py +167 -23
  120. crackerjack/core/session_coordinator.py +187 -382
  121. crackerjack/core/timeout_manager.py +161 -44
  122. crackerjack/core/workflow/__init__.py +21 -0
  123. crackerjack/core/workflow/workflow_ai_coordinator.py +863 -0
  124. crackerjack/core/workflow/workflow_event_orchestrator.py +1107 -0
  125. crackerjack/core/workflow/workflow_issue_parser.py +714 -0
  126. crackerjack/core/workflow/workflow_phase_executor.py +1158 -0
  127. crackerjack/core/workflow/workflow_security_gates.py +400 -0
  128. crackerjack/core/workflow_orchestrator.py +1247 -953
  129. crackerjack/data/README.md +11 -0
  130. crackerjack/data/__init__.py +8 -0
  131. crackerjack/data/models.py +79 -0
  132. crackerjack/data/repository.py +210 -0
  133. crackerjack/decorators/README.md +180 -0
  134. crackerjack/decorators/__init__.py +35 -0
  135. crackerjack/decorators/error_handling.py +649 -0
  136. crackerjack/decorators/error_handling_decorators.py +334 -0
  137. crackerjack/decorators/helpers.py +58 -0
  138. crackerjack/decorators/patterns.py +281 -0
  139. crackerjack/decorators/utils.py +58 -0
  140. crackerjack/docs/README.md +11 -0
  141. crackerjack/docs/generated/api/CLI_REFERENCE.md +1 -1
  142. crackerjack/documentation/README.md +11 -0
  143. crackerjack/documentation/ai_templates.py +1 -1
  144. crackerjack/documentation/dual_output_generator.py +11 -9
  145. crackerjack/documentation/reference_generator.py +104 -59
  146. crackerjack/dynamic_config.py +52 -61
  147. crackerjack/errors.py +1 -1
  148. crackerjack/events/README.md +11 -0
  149. crackerjack/events/__init__.py +16 -0
  150. crackerjack/events/telemetry.py +175 -0
  151. crackerjack/events/workflow_bus.py +346 -0
  152. crackerjack/exceptions/README.md +301 -0
  153. crackerjack/exceptions/__init__.py +5 -0
  154. crackerjack/exceptions/config.py +4 -0
  155. crackerjack/exceptions/tool_execution_error.py +245 -0
  156. crackerjack/executors/README.md +591 -0
  157. crackerjack/executors/__init__.py +2 -0
  158. crackerjack/executors/async_hook_executor.py +539 -77
  159. crackerjack/executors/cached_hook_executor.py +3 -3
  160. crackerjack/executors/hook_executor.py +967 -102
  161. crackerjack/executors/hook_lock_manager.py +31 -22
  162. crackerjack/executors/individual_hook_executor.py +66 -32
  163. crackerjack/executors/lsp_aware_hook_executor.py +136 -57
  164. crackerjack/executors/progress_hook_executor.py +282 -0
  165. crackerjack/executors/tool_proxy.py +23 -7
  166. crackerjack/hooks/README.md +485 -0
  167. crackerjack/hooks/lsp_hook.py +8 -9
  168. crackerjack/intelligence/README.md +557 -0
  169. crackerjack/interactive.py +37 -10
  170. crackerjack/managers/README.md +369 -0
  171. crackerjack/managers/async_hook_manager.py +41 -57
  172. crackerjack/managers/hook_manager.py +449 -79
  173. crackerjack/managers/publish_manager.py +81 -36
  174. crackerjack/managers/test_command_builder.py +290 -12
  175. crackerjack/managers/test_executor.py +93 -8
  176. crackerjack/managers/test_manager.py +1082 -75
  177. crackerjack/managers/test_progress.py +118 -26
  178. crackerjack/mcp/README.md +374 -0
  179. crackerjack/mcp/cache.py +25 -2
  180. crackerjack/mcp/client_runner.py +35 -18
  181. crackerjack/mcp/context.py +9 -9
  182. crackerjack/mcp/dashboard.py +24 -8
  183. crackerjack/mcp/enhanced_progress_monitor.py +34 -23
  184. crackerjack/mcp/file_monitor.py +27 -6
  185. crackerjack/mcp/progress_components.py +45 -34
  186. crackerjack/mcp/progress_monitor.py +6 -9
  187. crackerjack/mcp/rate_limiter.py +11 -7
  188. crackerjack/mcp/server.py +2 -0
  189. crackerjack/mcp/server_core.py +187 -55
  190. crackerjack/mcp/service_watchdog.py +12 -9
  191. crackerjack/mcp/task_manager.py +2 -2
  192. crackerjack/mcp/tools/README.md +27 -0
  193. crackerjack/mcp/tools/__init__.py +2 -0
  194. crackerjack/mcp/tools/core_tools.py +75 -52
  195. crackerjack/mcp/tools/execution_tools.py +87 -31
  196. crackerjack/mcp/tools/intelligence_tools.py +2 -2
  197. crackerjack/mcp/tools/proactive_tools.py +1 -1
  198. crackerjack/mcp/tools/semantic_tools.py +584 -0
  199. crackerjack/mcp/tools/utility_tools.py +180 -132
  200. crackerjack/mcp/tools/workflow_executor.py +87 -46
  201. crackerjack/mcp/websocket/README.md +31 -0
  202. crackerjack/mcp/websocket/app.py +11 -1
  203. crackerjack/mcp/websocket/event_bridge.py +188 -0
  204. crackerjack/mcp/websocket/jobs.py +27 -4
  205. crackerjack/mcp/websocket/monitoring/__init__.py +25 -0
  206. crackerjack/mcp/websocket/monitoring/api/__init__.py +19 -0
  207. crackerjack/mcp/websocket/monitoring/api/dependencies.py +141 -0
  208. crackerjack/mcp/websocket/monitoring/api/heatmap.py +154 -0
  209. crackerjack/mcp/websocket/monitoring/api/intelligence.py +199 -0
  210. crackerjack/mcp/websocket/monitoring/api/metrics.py +203 -0
  211. crackerjack/mcp/websocket/monitoring/api/telemetry.py +101 -0
  212. crackerjack/mcp/websocket/monitoring/dashboard.py +18 -0
  213. crackerjack/mcp/websocket/monitoring/factory.py +109 -0
  214. crackerjack/mcp/websocket/monitoring/filters.py +10 -0
  215. crackerjack/mcp/websocket/monitoring/metrics.py +64 -0
  216. crackerjack/mcp/websocket/monitoring/models.py +90 -0
  217. crackerjack/mcp/websocket/monitoring/utils.py +171 -0
  218. crackerjack/mcp/websocket/monitoring/websocket_manager.py +78 -0
  219. crackerjack/mcp/websocket/monitoring/websockets/__init__.py +17 -0
  220. crackerjack/mcp/websocket/monitoring/websockets/dependencies.py +126 -0
  221. crackerjack/mcp/websocket/monitoring/websockets/heatmap.py +176 -0
  222. crackerjack/mcp/websocket/monitoring/websockets/intelligence.py +291 -0
  223. crackerjack/mcp/websocket/monitoring/websockets/metrics.py +291 -0
  224. crackerjack/mcp/websocket/monitoring_endpoints.py +16 -2930
  225. crackerjack/mcp/websocket/server.py +1 -3
  226. crackerjack/mcp/websocket/websocket_handler.py +107 -6
  227. crackerjack/models/README.md +308 -0
  228. crackerjack/models/__init__.py +10 -1
  229. crackerjack/models/config.py +639 -22
  230. crackerjack/models/config_adapter.py +6 -6
  231. crackerjack/models/protocols.py +1167 -23
  232. crackerjack/models/pydantic_models.py +320 -0
  233. crackerjack/models/qa_config.py +145 -0
  234. crackerjack/models/qa_results.py +134 -0
  235. crackerjack/models/results.py +35 -0
  236. crackerjack/models/semantic_models.py +258 -0
  237. crackerjack/models/task.py +19 -3
  238. crackerjack/models/test_models.py +60 -0
  239. crackerjack/monitoring/README.md +11 -0
  240. crackerjack/monitoring/ai_agent_watchdog.py +5 -4
  241. crackerjack/monitoring/metrics_collector.py +4 -3
  242. crackerjack/monitoring/regression_prevention.py +4 -3
  243. crackerjack/monitoring/websocket_server.py +4 -241
  244. crackerjack/orchestration/README.md +340 -0
  245. crackerjack/orchestration/__init__.py +43 -0
  246. crackerjack/orchestration/advanced_orchestrator.py +20 -67
  247. crackerjack/orchestration/cache/README.md +312 -0
  248. crackerjack/orchestration/cache/__init__.py +37 -0
  249. crackerjack/orchestration/cache/memory_cache.py +338 -0
  250. crackerjack/orchestration/cache/tool_proxy_cache.py +340 -0
  251. crackerjack/orchestration/config.py +297 -0
  252. crackerjack/orchestration/coverage_improvement.py +13 -6
  253. crackerjack/orchestration/execution_strategies.py +6 -6
  254. crackerjack/orchestration/hook_orchestrator.py +1398 -0
  255. crackerjack/orchestration/strategies/README.md +401 -0
  256. crackerjack/orchestration/strategies/__init__.py +39 -0
  257. crackerjack/orchestration/strategies/adaptive_strategy.py +630 -0
  258. crackerjack/orchestration/strategies/parallel_strategy.py +237 -0
  259. crackerjack/orchestration/strategies/sequential_strategy.py +299 -0
  260. crackerjack/orchestration/test_progress_streamer.py +1 -1
  261. crackerjack/plugins/README.md +11 -0
  262. crackerjack/plugins/hooks.py +3 -2
  263. crackerjack/plugins/loader.py +3 -3
  264. crackerjack/plugins/managers.py +1 -1
  265. crackerjack/py313.py +191 -0
  266. crackerjack/security/README.md +11 -0
  267. crackerjack/services/README.md +374 -0
  268. crackerjack/services/__init__.py +8 -21
  269. crackerjack/services/ai/README.md +295 -0
  270. crackerjack/services/ai/__init__.py +7 -0
  271. crackerjack/services/ai/advanced_optimizer.py +878 -0
  272. crackerjack/services/{contextual_ai_assistant.py → ai/contextual_ai_assistant.py} +5 -3
  273. crackerjack/services/ai/embeddings.py +444 -0
  274. crackerjack/services/ai/intelligent_commit.py +328 -0
  275. crackerjack/services/ai/predictive_analytics.py +510 -0
  276. crackerjack/services/api_extractor.py +5 -3
  277. crackerjack/services/bounded_status_operations.py +45 -5
  278. crackerjack/services/cache.py +249 -318
  279. crackerjack/services/changelog_automation.py +7 -3
  280. crackerjack/services/command_execution_service.py +305 -0
  281. crackerjack/services/config_integrity.py +83 -39
  282. crackerjack/services/config_merge.py +9 -6
  283. crackerjack/services/config_service.py +198 -0
  284. crackerjack/services/config_template.py +13 -26
  285. crackerjack/services/coverage_badge_service.py +6 -4
  286. crackerjack/services/coverage_ratchet.py +53 -27
  287. crackerjack/services/debug.py +18 -7
  288. crackerjack/services/dependency_analyzer.py +4 -4
  289. crackerjack/services/dependency_monitor.py +13 -13
  290. crackerjack/services/documentation_generator.py +4 -2
  291. crackerjack/services/documentation_service.py +62 -33
  292. crackerjack/services/enhanced_filesystem.py +81 -27
  293. crackerjack/services/enterprise_optimizer.py +1 -1
  294. crackerjack/services/error_pattern_analyzer.py +10 -10
  295. crackerjack/services/file_filter.py +221 -0
  296. crackerjack/services/file_hasher.py +5 -7
  297. crackerjack/services/file_io_service.py +361 -0
  298. crackerjack/services/file_modifier.py +615 -0
  299. crackerjack/services/filesystem.py +80 -109
  300. crackerjack/services/git.py +99 -5
  301. crackerjack/services/health_metrics.py +4 -6
  302. crackerjack/services/heatmap_generator.py +12 -3
  303. crackerjack/services/incremental_executor.py +380 -0
  304. crackerjack/services/initialization.py +101 -49
  305. crackerjack/services/log_manager.py +2 -2
  306. crackerjack/services/logging.py +120 -68
  307. crackerjack/services/lsp_client.py +12 -12
  308. crackerjack/services/memory_optimizer.py +27 -22
  309. crackerjack/services/monitoring/README.md +30 -0
  310. crackerjack/services/monitoring/__init__.py +9 -0
  311. crackerjack/services/monitoring/dependency_monitor.py +678 -0
  312. crackerjack/services/monitoring/error_pattern_analyzer.py +676 -0
  313. crackerjack/services/monitoring/health_metrics.py +716 -0
  314. crackerjack/services/monitoring/metrics.py +587 -0
  315. crackerjack/services/{performance_benchmarks.py → monitoring/performance_benchmarks.py} +100 -14
  316. crackerjack/services/{performance_cache.py → monitoring/performance_cache.py} +21 -15
  317. crackerjack/services/{performance_monitor.py → monitoring/performance_monitor.py} +10 -6
  318. crackerjack/services/parallel_executor.py +166 -55
  319. crackerjack/services/patterns/__init__.py +142 -0
  320. crackerjack/services/patterns/agents.py +107 -0
  321. crackerjack/services/patterns/code/__init__.py +15 -0
  322. crackerjack/services/patterns/code/detection.py +118 -0
  323. crackerjack/services/patterns/code/imports.py +107 -0
  324. crackerjack/services/patterns/code/paths.py +159 -0
  325. crackerjack/services/patterns/code/performance.py +119 -0
  326. crackerjack/services/patterns/code/replacement.py +36 -0
  327. crackerjack/services/patterns/core.py +212 -0
  328. crackerjack/services/patterns/documentation/__init__.py +14 -0
  329. crackerjack/services/patterns/documentation/badges_markdown.py +96 -0
  330. crackerjack/services/patterns/documentation/comments_blocks.py +83 -0
  331. crackerjack/services/patterns/documentation/docstrings.py +89 -0
  332. crackerjack/services/patterns/formatting.py +226 -0
  333. crackerjack/services/patterns/operations.py +339 -0
  334. crackerjack/services/patterns/security/__init__.py +23 -0
  335. crackerjack/services/patterns/security/code_injection.py +122 -0
  336. crackerjack/services/patterns/security/credentials.py +190 -0
  337. crackerjack/services/patterns/security/path_traversal.py +221 -0
  338. crackerjack/services/patterns/security/unsafe_operations.py +216 -0
  339. crackerjack/services/patterns/templates.py +62 -0
  340. crackerjack/services/patterns/testing/__init__.py +18 -0
  341. crackerjack/services/patterns/testing/error_patterns.py +107 -0
  342. crackerjack/services/patterns/testing/pytest_output.py +126 -0
  343. crackerjack/services/patterns/tool_output/__init__.py +16 -0
  344. crackerjack/services/patterns/tool_output/bandit.py +72 -0
  345. crackerjack/services/patterns/tool_output/other.py +97 -0
  346. crackerjack/services/patterns/tool_output/pyright.py +67 -0
  347. crackerjack/services/patterns/tool_output/ruff.py +44 -0
  348. crackerjack/services/patterns/url_sanitization.py +114 -0
  349. crackerjack/services/patterns/utilities.py +42 -0
  350. crackerjack/services/patterns/utils.py +339 -0
  351. crackerjack/services/patterns/validation.py +46 -0
  352. crackerjack/services/patterns/versioning.py +62 -0
  353. crackerjack/services/predictive_analytics.py +21 -8
  354. crackerjack/services/profiler.py +280 -0
  355. crackerjack/services/quality/README.md +415 -0
  356. crackerjack/services/quality/__init__.py +11 -0
  357. crackerjack/services/quality/anomaly_detector.py +392 -0
  358. crackerjack/services/quality/pattern_cache.py +333 -0
  359. crackerjack/services/quality/pattern_detector.py +479 -0
  360. crackerjack/services/quality/qa_orchestrator.py +491 -0
  361. crackerjack/services/{quality_baseline.py → quality/quality_baseline.py} +163 -2
  362. crackerjack/services/{quality_baseline_enhanced.py → quality/quality_baseline_enhanced.py} +4 -1
  363. crackerjack/services/{quality_intelligence.py → quality/quality_intelligence.py} +180 -16
  364. crackerjack/services/regex_patterns.py +58 -2987
  365. crackerjack/services/regex_utils.py +55 -29
  366. crackerjack/services/secure_status_formatter.py +42 -15
  367. crackerjack/services/secure_subprocess.py +35 -2
  368. crackerjack/services/security.py +16 -8
  369. crackerjack/services/server_manager.py +40 -51
  370. crackerjack/services/smart_scheduling.py +46 -6
  371. crackerjack/services/status_authentication.py +3 -3
  372. crackerjack/services/thread_safe_status_collector.py +1 -0
  373. crackerjack/services/tool_filter.py +368 -0
  374. crackerjack/services/tool_version_service.py +9 -5
  375. crackerjack/services/unified_config.py +43 -351
  376. crackerjack/services/vector_store.py +689 -0
  377. crackerjack/services/version_analyzer.py +6 -4
  378. crackerjack/services/version_checker.py +14 -8
  379. crackerjack/services/zuban_lsp_service.py +5 -4
  380. crackerjack/slash_commands/README.md +11 -0
  381. crackerjack/slash_commands/init.md +2 -12
  382. crackerjack/slash_commands/run.md +84 -50
  383. crackerjack/tools/README.md +11 -0
  384. crackerjack/tools/__init__.py +30 -0
  385. crackerjack/tools/_git_utils.py +105 -0
  386. crackerjack/tools/check_added_large_files.py +139 -0
  387. crackerjack/tools/check_ast.py +105 -0
  388. crackerjack/tools/check_json.py +103 -0
  389. crackerjack/tools/check_jsonschema.py +297 -0
  390. crackerjack/tools/check_toml.py +103 -0
  391. crackerjack/tools/check_yaml.py +110 -0
  392. crackerjack/tools/codespell_wrapper.py +72 -0
  393. crackerjack/tools/end_of_file_fixer.py +202 -0
  394. crackerjack/tools/format_json.py +128 -0
  395. crackerjack/tools/mdformat_wrapper.py +114 -0
  396. crackerjack/tools/trailing_whitespace.py +198 -0
  397. crackerjack/tools/validate_regex_patterns.py +7 -3
  398. crackerjack/ui/README.md +11 -0
  399. crackerjack/ui/dashboard_renderer.py +28 -0
  400. crackerjack/ui/templates/README.md +11 -0
  401. crackerjack/utils/console_utils.py +13 -0
  402. crackerjack/utils/dependency_guard.py +230 -0
  403. crackerjack/utils/retry_utils.py +275 -0
  404. crackerjack/workflows/README.md +590 -0
  405. crackerjack/workflows/__init__.py +46 -0
  406. crackerjack/workflows/actions.py +811 -0
  407. crackerjack/workflows/auto_fix.py +444 -0
  408. crackerjack/workflows/container_builder.py +499 -0
  409. crackerjack/workflows/definitions.py +443 -0
  410. crackerjack/workflows/engine.py +177 -0
  411. crackerjack/workflows/event_bridge.py +242 -0
  412. {crackerjack-0.37.9.dist-info → crackerjack-0.45.2.dist-info}/METADATA +678 -98
  413. crackerjack-0.45.2.dist-info/RECORD +478 -0
  414. {crackerjack-0.37.9.dist-info → crackerjack-0.45.2.dist-info}/WHEEL +1 -1
  415. crackerjack/managers/test_manager_backup.py +0 -1075
  416. crackerjack/mcp/tools/execution_tools_backup.py +0 -1011
  417. crackerjack/mixins/__init__.py +0 -3
  418. crackerjack/mixins/error_handling.py +0 -145
  419. crackerjack/services/config.py +0 -358
  420. crackerjack/ui/server_panels.py +0 -125
  421. crackerjack-0.37.9.dist-info/RECORD +0 -231
  422. /crackerjack/adapters/{rust_tool_adapter.py → lsp/_base.py} +0 -0
  423. /crackerjack/adapters/{lsp_client.py → lsp/_client.py} +0 -0
  424. {crackerjack-0.37.9.dist-info → crackerjack-0.45.2.dist-info}/entry_points.txt +0 -0
  425. {crackerjack-0.37.9.dist-info → crackerjack-0.45.2.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,676 @@
1
+ """Error pattern analysis service for heat map visualizations."""
2
+
3
+ import json
4
+ import logging
5
+ import typing as t
6
+ from collections import defaultdict
7
+ from dataclasses import dataclass, field
8
+ from datetime import datetime, timedelta
9
+ from pathlib import Path
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+
14
+ @dataclass
15
+ class ErrorPattern:
16
+ """Represents an error pattern for visualization."""
17
+
18
+ error_type: str
19
+ message: str
20
+ file_path: str
21
+ function_name: str | None
22
+ line_number: int | None
23
+ count: int
24
+ severity: str # low, medium, high, critical
25
+ first_seen: datetime
26
+ last_seen: datetime
27
+ trend: str # increasing, decreasing, stable
28
+ confidence: float # 0.0 to 1.0
29
+ metadata: dict[str, t.Any] = field(default_factory=dict[str, t.Any])
30
+
31
+ def to_dict(self) -> dict[str, t.Any]:
32
+ """Convert to dictionary for JSON serialization."""
33
+ return {
34
+ "error_type": self.error_type,
35
+ "message": self.message,
36
+ "file_path": self.file_path,
37
+ "function_name": self.function_name,
38
+ "line_number": self.line_number,
39
+ "count": self.count,
40
+ "severity": self.severity,
41
+ "first_seen": self.first_seen.isoformat(),
42
+ "last_seen": self.last_seen.isoformat(),
43
+ "trend": self.trend,
44
+ "confidence": self.confidence,
45
+ "metadata": self.metadata,
46
+ }
47
+
48
+
49
+ @dataclass
50
+ class HeatMapCell:
51
+ """Represents a cell in the heat map."""
52
+
53
+ x: str # file_path or time period
54
+ y: str # error_type or function_name
55
+ value: float # intensity/count
56
+ color_intensity: float # 0.0 to 1.0
57
+ tooltip_data: dict[str, t.Any]
58
+ severity: str
59
+
60
+ def to_dict(self) -> dict[str, t.Any]:
61
+ """Convert to dictionary for JSON serialization."""
62
+ return {
63
+ "x": self.x,
64
+ "y": self.y,
65
+ "value": self.value,
66
+ "color_intensity": self.color_intensity,
67
+ "tooltip_data": self.tooltip_data,
68
+ "severity": self.severity,
69
+ }
70
+
71
+
72
+ @dataclass
73
+ class HeatMapData:
74
+ """Complete heat map visualization data."""
75
+
76
+ cells: list[HeatMapCell]
77
+ x_labels: list[str]
78
+ y_labels: list[str]
79
+ title: str
80
+ subtitle: str
81
+ max_value: float
82
+ min_value: float
83
+ generated_at: datetime = field(default_factory=datetime.now)
84
+
85
+ def to_dict(self) -> dict[str, t.Any]:
86
+ """Convert to dictionary for JSON serialization."""
87
+ return {
88
+ "cells": [cell.to_dict() for cell in self.cells],
89
+ "x_labels": self.x_labels,
90
+ "y_labels": self.y_labels,
91
+ "title": self.title,
92
+ "subtitle": self.subtitle,
93
+ "max_value": self.max_value,
94
+ "min_value": self.min_value,
95
+ "generated_at": self.generated_at.isoformat(),
96
+ }
97
+
98
+
99
+ class ErrorPatternAnalyzer:
100
+ """Analyzes error patterns and generates heat map visualizations."""
101
+
102
+ def __init__(self, project_root: Path):
103
+ """Initialize with project root directory."""
104
+ self.project_root = Path(project_root)
105
+ self.error_patterns: list[ErrorPattern] = []
106
+
107
+ def analyze_error_patterns(
108
+ self,
109
+ days: int = 30,
110
+ min_occurrences: int = 2,
111
+ ) -> list[ErrorPattern]:
112
+ """Analyze error patterns from various sources."""
113
+ logger.info(f"Analyzing error patterns for last {days} days")
114
+
115
+ # Collect and process errors
116
+ errors = self._collect_all_errors()
117
+ self.error_patterns = self._process_error_data(errors, min_occurrences)
118
+ self._finalize_pattern_analysis()
119
+
120
+ logger.info(f"Found {len(self.error_patterns)} error patterns")
121
+ return self.error_patterns
122
+
123
+ def _collect_all_errors(self) -> list[dict[str, t.Any]]:
124
+ """Collect errors from all available sources."""
125
+ errors: list[dict[str, t.Any]] = []
126
+ errors.extend(self._analyze_test_failures())
127
+ errors.extend(self._analyze_lint_errors())
128
+ errors.extend(self._analyze_git_history())
129
+ errors.extend(self._analyze_log_files())
130
+ return errors
131
+
132
+ def _process_error_data(
133
+ self, errors: list[dict[str, t.Any]], min_occurrences: int
134
+ ) -> list[ErrorPattern]:
135
+ """Process collected errors into patterns."""
136
+ pattern_groups = self._group_similar_errors(errors)
137
+ return self._create_error_patterns(pattern_groups, min_occurrences)
138
+
139
+ def _finalize_pattern_analysis(self) -> None:
140
+ """Apply final analysis steps to error patterns."""
141
+ self._calculate_error_trends()
142
+ self._assign_severity_levels()
143
+
144
+ def generate_file_error_heatmap(self) -> HeatMapData:
145
+ """Generate heat map showing errors by file."""
146
+
147
+ def _make_float_defaultdict() -> defaultdict[str, float]:
148
+ return defaultdict(float)
149
+
150
+ file_error_counts: defaultdict[str, defaultdict[str, float]] = defaultdict(
151
+ _make_float_defaultdict
152
+ )
153
+ max_value = 0.0
154
+
155
+ for pattern in self.error_patterns:
156
+ file_path = self._get_relative_path(pattern.file_path)
157
+ error_type = pattern.error_type
158
+ count = pattern.count
159
+
160
+ file_error_counts[file_path][error_type] += float(count)
161
+ max_value = max(max_value, file_error_counts[file_path][error_type])
162
+
163
+ # Create heat map cells
164
+ cells = []
165
+ files = sorted(file_error_counts.keys())
166
+ error_types = sorted(
167
+ {
168
+ error_type
169
+ for file_errors in file_error_counts.values()
170
+ for error_type in file_errors.keys()
171
+ }
172
+ )
173
+
174
+ for file_path in files:
175
+ for error_type in error_types:
176
+ count = file_error_counts[file_path].get(error_type, 0)
177
+ if count > 0:
178
+ intensity: float = count / max_value if max_value > 0 else 0.0
179
+ severity = self._get_severity_for_type(error_type)
180
+
181
+ cells.append(
182
+ HeatMapCell(
183
+ x=file_path,
184
+ y=error_type,
185
+ value=count,
186
+ color_intensity=intensity,
187
+ tooltip_data={
188
+ "file": file_path,
189
+ "error_type": error_type,
190
+ "count": count,
191
+ "severity": severity,
192
+ },
193
+ severity=severity,
194
+ )
195
+ )
196
+
197
+ return HeatMapData(
198
+ cells=cells,
199
+ x_labels=files,
200
+ y_labels=error_types,
201
+ title="Error Distribution by File",
202
+ subtitle=f"Showing {len(self.error_patterns)} error patterns across {len(files)} files",
203
+ max_value=max_value,
204
+ min_value=0.0,
205
+ )
206
+
207
+ def generate_temporal_heatmap(self, time_buckets: int = 24) -> HeatMapData:
208
+ """Generate heat map showing errors over time."""
209
+ time_labels, time_buckets_data, bucket_size = self._create_time_buckets(
210
+ time_buckets
211
+ )
212
+ temporal_counts, max_value = self._count_errors_by_time(
213
+ time_labels, time_buckets_data, bucket_size
214
+ )
215
+ cells, error_types = self._create_temporal_heatmap_cells(
216
+ time_labels, temporal_counts, max_value
217
+ )
218
+
219
+ return HeatMapData(
220
+ cells=cells,
221
+ x_labels=time_labels,
222
+ y_labels=error_types,
223
+ title="Error Patterns Over Time",
224
+ subtitle=f"24-hour view of {len(self.error_patterns)} error patterns",
225
+ max_value=max_value,
226
+ min_value=0.0,
227
+ )
228
+
229
+ def _create_time_buckets(
230
+ self, time_buckets: int
231
+ ) -> tuple[list[str], list[datetime], timedelta]:
232
+ """Create time buckets for temporal analysis."""
233
+ now = datetime.now()
234
+ bucket_size = timedelta(hours=24 // time_buckets)
235
+
236
+ time_labels = []
237
+ time_buckets_data = []
238
+ for i in range(time_buckets):
239
+ bucket_start = now - timedelta(days=30) + (i * bucket_size)
240
+ time_labels.append(bucket_start.strftime("%m-%d %H:%M"))
241
+ time_buckets_data.append(bucket_start)
242
+
243
+ return time_labels, time_buckets_data, bucket_size
244
+
245
+ def _count_errors_by_time(
246
+ self,
247
+ time_labels: list[str],
248
+ time_buckets_data: list[datetime],
249
+ bucket_size: timedelta,
250
+ ) -> tuple[defaultdict[str, defaultdict[str, float]], float]:
251
+ """Count errors by time bucket and type."""
252
+
253
+ def _make_float_defaultdict_temporal() -> defaultdict[str, float]:
254
+ return defaultdict(float)
255
+
256
+ temporal_counts: defaultdict[str, defaultdict[str, float]] = defaultdict(
257
+ _make_float_defaultdict_temporal
258
+ )
259
+ max_value = 0.0
260
+
261
+ for pattern in self.error_patterns:
262
+ bucket_idx = self._find_time_bucket(
263
+ pattern.last_seen, time_buckets_data, bucket_size
264
+ )
265
+ if bucket_idx is not None:
266
+ bucket_label = time_labels[bucket_idx]
267
+ error_type = pattern.error_type
268
+ temporal_counts[bucket_label][error_type] += pattern.count
269
+ max_value = max(max_value, temporal_counts[bucket_label][error_type])
270
+
271
+ return temporal_counts, max_value
272
+
273
+ def _find_time_bucket(
274
+ self,
275
+ error_time: datetime,
276
+ time_buckets_data: list[datetime],
277
+ bucket_size: timedelta,
278
+ ) -> int | None:
279
+ """Find which time bucket an error belongs to."""
280
+ for i, bucket_time in enumerate(time_buckets_data):
281
+ if bucket_time <= error_time <= bucket_time + bucket_size:
282
+ return i
283
+ return None
284
+
285
+ def _create_temporal_heatmap_cells(
286
+ self,
287
+ time_labels: list[str],
288
+ temporal_counts: defaultdict[str, defaultdict[str, float]],
289
+ max_value: float,
290
+ ) -> tuple[list[HeatMapCell], list[str]]:
291
+ """Create heatmap cells for temporal data."""
292
+ error_types = sorted(
293
+ {
294
+ error_type
295
+ for time_errors in temporal_counts.values()
296
+ for error_type in time_errors.keys()
297
+ }
298
+ )
299
+
300
+ cells = []
301
+ for time_label in time_labels:
302
+ for error_type in error_types:
303
+ count = temporal_counts[time_label].get(error_type, 0)
304
+ if count > 0:
305
+ cell = self._create_temporal_cell(
306
+ time_label, error_type, count, max_value
307
+ )
308
+ cells.append(cell)
309
+
310
+ return cells, error_types
311
+
312
+ def _create_temporal_cell(
313
+ self, time_label: str, error_type: str, count: float, max_value: float
314
+ ) -> HeatMapCell:
315
+ """Create a single temporal heatmap cell."""
316
+ intensity: float = count / max_value if max_value > 0 else 0.0
317
+ severity = self._get_severity_for_type(error_type)
318
+
319
+ return HeatMapCell(
320
+ x=time_label,
321
+ y=error_type,
322
+ value=count,
323
+ color_intensity=intensity,
324
+ tooltip_data={
325
+ "time": time_label,
326
+ "error_type": error_type,
327
+ "count": count,
328
+ "severity": severity,
329
+ },
330
+ severity=severity,
331
+ )
332
+
333
+ def generate_function_error_heatmap(self) -> HeatMapData:
334
+ """Generate heat map showing errors by function."""
335
+ function_error_counts, max_value = self._count_errors_by_function()
336
+ cells, functions, error_types = self._create_function_heatmap_cells(
337
+ function_error_counts, max_value
338
+ )
339
+
340
+ return HeatMapData(
341
+ cells=cells,
342
+ x_labels=functions,
343
+ y_labels=error_types,
344
+ title="Error Distribution by Function",
345
+ subtitle=f"Showing errors across {len(functions)} functions",
346
+ max_value=max_value,
347
+ min_value=0.0,
348
+ )
349
+
350
+ def _count_errors_by_function(
351
+ self,
352
+ ) -> tuple[defaultdict[str, defaultdict[str, float]], float]:
353
+ """Count errors by function and type."""
354
+
355
+ def _make_float_defaultdict_function() -> defaultdict[str, float]:
356
+ return defaultdict(float)
357
+
358
+ function_error_counts: defaultdict[str, defaultdict[str, float]] = defaultdict(
359
+ _make_float_defaultdict_function
360
+ )
361
+ max_value = 0.0
362
+
363
+ for pattern in self.error_patterns:
364
+ if pattern.function_name:
365
+ file_path = self._get_relative_path(pattern.file_path)
366
+ function_id = f"{file_path}::{pattern.function_name}"
367
+ error_type = pattern.error_type
368
+ count = pattern.count
369
+
370
+ function_error_counts[function_id][error_type] += count
371
+ max_value = max(
372
+ max_value, function_error_counts[function_id][error_type]
373
+ )
374
+
375
+ return function_error_counts, max_value
376
+
377
+ def _create_function_heatmap_cells(
378
+ self,
379
+ function_error_counts: defaultdict[str, defaultdict[str, float]],
380
+ max_value: float,
381
+ ) -> tuple[list[HeatMapCell], list[str], list[str]]:
382
+ """Create heatmap cells for function error data."""
383
+ functions = sorted(function_error_counts.keys())
384
+ error_types = sorted(
385
+ {
386
+ error_type
387
+ for func_errors in function_error_counts.values()
388
+ for error_type in func_errors.keys()
389
+ }
390
+ )
391
+
392
+ cells = []
393
+ for function_id in functions:
394
+ for error_type in error_types:
395
+ count = function_error_counts[function_id].get(error_type, 0)
396
+ if count > 0:
397
+ cell = self._create_function_cell(
398
+ function_id, error_type, count, max_value
399
+ )
400
+ cells.append(cell)
401
+
402
+ return cells, functions, error_types
403
+
404
+ def _create_function_cell(
405
+ self, function_id: str, error_type: str, count: float, max_value: float
406
+ ) -> HeatMapCell:
407
+ """Create a single function heatmap cell."""
408
+ intensity: float = count / max_value if max_value > 0 else 0.0
409
+ severity = self._get_severity_for_type(error_type)
410
+
411
+ return HeatMapCell(
412
+ x=function_id,
413
+ y=error_type,
414
+ value=count,
415
+ color_intensity=intensity,
416
+ tooltip_data={
417
+ "function": function_id,
418
+ "error_type": error_type,
419
+ "count": count,
420
+ "severity": severity,
421
+ },
422
+ severity=severity,
423
+ )
424
+
425
+ def _analyze_test_failures(self) -> list[dict[str, t.Any]]:
426
+ """Analyze test failure patterns."""
427
+ errors: list[dict[str, t.Any]] = []
428
+
429
+ # Look for pytest cache and reports
430
+ pytest_cache = self.project_root / ".pytest_cache"
431
+ if pytest_cache.exists():
432
+ # Simulate some test failure patterns
433
+ errors.extend(
434
+ [
435
+ {
436
+ "type": "test_failure",
437
+ "message": "AssertionError: Expected 5 but got 3",
438
+ "file": "tests/test_calculator.py",
439
+ "function": "test_addition",
440
+ "line": 42,
441
+ "timestamp": datetime.now() - timedelta(days=2),
442
+ },
443
+ {
444
+ "type": "import_error",
445
+ "message": "ModuleNotFoundError: No module named 'missing_dep'",
446
+ "file": "tests/test_integration.py",
447
+ "function": "test_integration_flow",
448
+ "line": 15,
449
+ "timestamp": datetime.now() - timedelta(days=5),
450
+ },
451
+ ]
452
+ )
453
+
454
+ return errors
455
+
456
+ def _analyze_lint_errors(self) -> list[dict[str, t.Any]]:
457
+ """Analyze linting error patterns."""
458
+ errors: list[dict[str, t.Any]] = []
459
+
460
+ # Look for ruff/flake8 outputs
461
+ # Simulate common linting errors
462
+ errors.extend(
463
+ [
464
+ {
465
+ "type": "unused_import",
466
+ "message": "F401 'os' imported but unused",
467
+ "file": "crackerjack/services/file_service.py",
468
+ "function": None,
469
+ "line": 3,
470
+ "timestamp": datetime.now() - timedelta(days=1),
471
+ },
472
+ {
473
+ "type": "line_too_long",
474
+ "message": "E501 line too long (89 > 88 characters)",
475
+ "file": "crackerjack/cli/options.py",
476
+ "function": "parse_arguments",
477
+ "line": 156,
478
+ "timestamp": datetime.now() - timedelta(hours=6),
479
+ },
480
+ {
481
+ "type": "complexity_error",
482
+ "message": "C901 'process_workflow' is too complex (16)",
483
+ "file": "crackerjack/orchestrators/workflow.py",
484
+ "function": "process_workflow",
485
+ "line": 89,
486
+ "timestamp": datetime.now() - timedelta(days=3),
487
+ },
488
+ ]
489
+ )
490
+
491
+ return errors
492
+
493
+ def _analyze_git_history(self) -> list[dict[str, t.Any]]:
494
+ """Analyze git commit history for error patterns."""
495
+ errors: list[dict[str, t.Any]] = []
496
+
497
+ # Look for fix commits and reverts
498
+ # This would normally parse git log
499
+ errors.extend(
500
+ [
501
+ {
502
+ "type": "hotfix",
503
+ "message": "Fix critical security vulnerability in auth",
504
+ "file": "crackerjack/services/security.py",
505
+ "function": "validate_token",
506
+ "line": None,
507
+ "timestamp": datetime.now() - timedelta(days=7),
508
+ },
509
+ {
510
+ "type": "revert",
511
+ "message": "Revert broken deployment pipeline",
512
+ "file": "crackerjack/cli/deploy.py",
513
+ "function": "deploy_application",
514
+ "line": None,
515
+ "timestamp": datetime.now() - timedelta(days=4),
516
+ },
517
+ ]
518
+ )
519
+
520
+ return errors
521
+
522
+ def _analyze_log_files(self) -> list[dict[str, t.Any]]:
523
+ """Analyze application log files for error patterns."""
524
+ errors: list[dict[str, t.Any]] = []
525
+
526
+ # Look for log files with error patterns
527
+ log_dirs = [self.project_root / "logs", Path.home() / "logs"]
528
+
529
+ for log_dir in log_dirs:
530
+ if log_dir.exists():
531
+ # Simulate log analysis
532
+ errors.extend(
533
+ [
534
+ {
535
+ "type": "runtime_error",
536
+ "message": "ConnectionError: Failed to connect to database",
537
+ "file": "crackerjack/services/database.py",
538
+ "function": "connect",
539
+ "line": 78,
540
+ "timestamp": datetime.now() - timedelta(hours=12),
541
+ },
542
+ {
543
+ "type": "timeout_error",
544
+ "message": "TimeoutError: Request took longer than 30s",
545
+ "file": "crackerjack/services/http_client.py",
546
+ "function": "make_request",
547
+ "line": 124,
548
+ "timestamp": datetime.now() - timedelta(hours=18),
549
+ },
550
+ ]
551
+ )
552
+
553
+ return errors
554
+
555
+ def _group_similar_errors(
556
+ self, errors: list[dict[str, t.Any]]
557
+ ) -> dict[str, list[dict[str, t.Any]]]:
558
+ """Group similar errors together."""
559
+ groups = defaultdict(list)
560
+
561
+ for error in errors:
562
+ # Create a key based on error type and file
563
+ key = f"{error['type']}:{error['file']}"
564
+ if error.get("function"):
565
+ key += f":{error['function']}"
566
+
567
+ groups[key].append(error)
568
+
569
+ return dict[str, t.Any](groups)
570
+
571
+ def _create_error_patterns(
572
+ self, groups: dict[str, list[dict[str, t.Any]]], min_occurrences: int
573
+ ) -> list[ErrorPattern]:
574
+ """Create ErrorPattern objects from grouped errors."""
575
+ patterns = []
576
+
577
+ for group_key, error_list in groups.items():
578
+ if len(error_list) < min_occurrences:
579
+ continue
580
+
581
+ first_error = error_list[0]
582
+ timestamps = [e["timestamp"] for e in error_list]
583
+
584
+ pattern = ErrorPattern(
585
+ error_type=first_error["type"],
586
+ message=first_error["message"],
587
+ file_path=first_error["file"],
588
+ function_name=first_error.get("function"),
589
+ line_number=first_error.get("line"),
590
+ count=len(error_list),
591
+ severity="medium", # Will be calculated later
592
+ first_seen=min(timestamps),
593
+ last_seen=max(timestamps),
594
+ trend="stable", # Will be calculated later
595
+ confidence=min(1.0, len(error_list) / 10.0),
596
+ metadata={
597
+ "group_key": group_key,
598
+ "unique_messages": len({e["message"] for e in error_list}),
599
+ },
600
+ )
601
+
602
+ patterns.append(pattern)
603
+
604
+ return patterns
605
+
606
+ def _calculate_error_trends(self) -> None:
607
+ """Calculate trend information for error patterns."""
608
+ for pattern in self.error_patterns:
609
+ # Simple trend calculation based on recency
610
+ time_diff = (datetime.now() - pattern.last_seen).days
611
+
612
+ if time_diff <= 1:
613
+ pattern.trend = "increasing"
614
+ elif time_diff <= 7:
615
+ pattern.trend = "stable"
616
+ else:
617
+ pattern.trend = "decreasing"
618
+
619
+ def _assign_severity_levels(self) -> None:
620
+ """Assign severity levels based on error type and frequency."""
621
+ severity_map = {
622
+ "security_vulnerability": "critical",
623
+ "runtime_error": "high",
624
+ "test_failure": "high",
625
+ "import_error": "high",
626
+ "complexity_error": "medium",
627
+ "hotfix": "high",
628
+ "revert": "medium",
629
+ "timeout_error": "medium",
630
+ "line_too_long": "low",
631
+ "unused_import": "low",
632
+ }
633
+
634
+ for pattern in self.error_patterns:
635
+ # Base severity from type
636
+ base_severity = severity_map.get(pattern.error_type, "medium")
637
+
638
+ # Increase severity for high-frequency errors
639
+ if pattern.count > 10:
640
+ severity_levels = ["low", "medium", "high", "critical"]
641
+ current_index = severity_levels.index(base_severity)
642
+ if current_index < len(severity_levels) - 1:
643
+ base_severity = severity_levels[current_index + 1]
644
+
645
+ pattern.severity = base_severity
646
+
647
+ def _get_relative_path(self, file_path: str) -> str:
648
+ """Get relative path from project root."""
649
+ try:
650
+ path = Path(file_path)
651
+ if path.is_absolute():
652
+ return str(path.relative_to(self.project_root))
653
+ return file_path
654
+ except ValueError:
655
+ return file_path
656
+
657
+ def _get_severity_for_type(self, error_type: str) -> str:
658
+ """Get severity level for error type."""
659
+ for pattern in self.error_patterns:
660
+ if pattern.error_type == error_type:
661
+ return pattern.severity
662
+ return "medium"
663
+
664
+
665
+ def analyze_error_patterns(
666
+ project_root: str | Path, days: int = 30
667
+ ) -> list[ErrorPattern]:
668
+ """Analyze error patterns and return pattern data."""
669
+ analyzer = ErrorPatternAnalyzer(Path(project_root))
670
+ return analyzer.analyze_error_patterns(days=days)
671
+
672
+
673
+ def export_heatmap_data(heatmap: HeatMapData, output_path: str | Path) -> None:
674
+ """Export heat map data to JSON file."""
675
+ with open(output_path, "w", encoding="utf-8") as f:
676
+ json.dump(heatmap.to_dict(), f, indent=2)