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,267 @@
1
+ import logging
2
+ import time
3
+ import typing as t
4
+ from pathlib import Path
5
+
6
+ from ..agents.base import AgentContext, Issue, IssueType, Priority
7
+ from ..agents.coordinator import AgentCoordinator
8
+ from ..models.protocols import OptionsProtocol
9
+
10
+
11
+ class ProactiveWorkflowPipeline:
12
+ def __init__(self, project_path: Path) -> None:
13
+ self.project_path = project_path
14
+ self.logger = logging.getLogger(__name__)
15
+ self._architect_agent_coordinator: AgentCoordinator | None = None
16
+
17
+ async def run_complete_workflow_with_planning(
18
+ self, options: OptionsProtocol
19
+ ) -> bool:
20
+ self.logger.info("Starting proactive workflow with architectural planning")
21
+
22
+ start_time = time.time()
23
+
24
+ try:
25
+ assessment = await self._assess_codebase_architecture()
26
+
27
+ if assessment.needs_planning:
28
+ self.logger.info("Codebase requires architectural planning")
29
+
30
+ architectural_plan = await self._create_comprehensive_plan(assessment)
31
+
32
+ result = await self._execute_planned_workflow(
33
+ options, architectural_plan
34
+ )
35
+ else:
36
+ self.logger.info(
37
+ "Codebase is architecturally sound, using standard workflow"
38
+ )
39
+
40
+ result = await self._execute_standard_workflow(options)
41
+
42
+ execution_time = time.time() - start_time
43
+ self.logger.info(f"Proactive workflow completed in {execution_time: .2f}s")
44
+
45
+ return result
46
+
47
+ except Exception as e:
48
+ self.logger.exception(f"Proactive workflow failed: {e}")
49
+
50
+ return await self._execute_standard_workflow(options)
51
+
52
+ async def _assess_codebase_architecture(self) -> "ArchitecturalAssessment":
53
+ self.logger.info("Assessing codebase architecture")
54
+
55
+ if not self._architect_agent_coordinator:
56
+ agent_context = AgentContext(project_path=self.project_path)
57
+ self._architect_agent_coordinator = AgentCoordinator(agent_context)
58
+ self._architect_agent_coordinator.initialize_agents()
59
+
60
+ test_issues = await self._identify_potential_issues()
61
+
62
+ needs_planning = self._evaluate_planning_need(test_issues)
63
+
64
+ return ArchitecturalAssessment(
65
+ needs_planning=needs_planning,
66
+ complexity_score=len(test_issues),
67
+ potential_issues=test_issues,
68
+ recommended_strategy="proactive" if needs_planning else "standard",
69
+ )
70
+
71
+ async def _identify_potential_issues(self) -> list[Issue]:
72
+ potential_issues: list[Issue] = []
73
+
74
+ potential_issues.extend(
75
+ (
76
+ Issue(
77
+ id="arch_assessment_complexity",
78
+ type=IssueType.COMPLEXITY,
79
+ severity=Priority.HIGH,
80
+ message="Potential complexity hotspots detected",
81
+ file_path=str(self.project_path),
82
+ details=["Multiple functions may exceed complexity threshold"],
83
+ ),
84
+ Issue(
85
+ id="arch_assessment_dry",
86
+ type=IssueType.DRY_VIOLATION,
87
+ severity=Priority.MEDIUM,
88
+ message="Potential code duplication patterns",
89
+ file_path=str(self.project_path),
90
+ details=["Similar patterns may exist across modules"],
91
+ ),
92
+ )
93
+ )
94
+
95
+ return potential_issues
96
+
97
+ def _evaluate_planning_need(self, issues: list[Issue]) -> bool:
98
+ complex_issues = [
99
+ issue
100
+ for issue in issues
101
+ if issue.type
102
+ in {IssueType.COMPLEXITY, IssueType.DRY_VIOLATION, IssueType.PERFORMANCE}
103
+ ]
104
+
105
+ return len(complex_issues) >= 2
106
+
107
+ async def _create_comprehensive_plan(
108
+ self, assessment: "ArchitecturalAssessment"
109
+ ) -> dict[str, t.Any]:
110
+ self.logger.info("Creating comprehensive architectural plan")
111
+
112
+ if self._architect_agent_coordinator is None:
113
+ raise RuntimeError("ArchitectAgentCoordinator is not initialized")
114
+
115
+ architect = self._architect_agent_coordinator._get_architect_agent()
116
+
117
+ if not architect:
118
+ self.logger.warning("No ArchitectAgent available, creating basic plan")
119
+ return {
120
+ "strategy": "basic_reactive",
121
+ "phases": ["standard_workflow"],
122
+ "patterns": ["default"],
123
+ }
124
+
125
+ complex_issues = [
126
+ issue
127
+ for issue in assessment.potential_issues
128
+ if issue.type in {IssueType.COMPLEXITY, IssueType.DRY_VIOLATION}
129
+ ]
130
+
131
+ if complex_issues:
132
+ primary_issue = complex_issues[0]
133
+ base_plan = await architect.plan_before_action(primary_issue)
134
+
135
+ comprehensive_plan = base_plan | {
136
+ "phases": [
137
+ "configuration_setup",
138
+ "fast_hooks_with_architecture",
139
+ "architectural_refactoring",
140
+ "comprehensive_validation",
141
+ "pattern_learning",
142
+ ],
143
+ "integration_points": [
144
+ "architect_guided_fixing",
145
+ "pattern_caching",
146
+ "validation_against_plan",
147
+ ],
148
+ }
149
+ else:
150
+ comprehensive_plan = {
151
+ "strategy": "lightweight_proactive",
152
+ "phases": ["standard_workflow_enhanced"],
153
+ "patterns": ["cached_patterns"],
154
+ }
155
+
156
+ self.logger.info(
157
+ f"Created plan with strategy: {comprehensive_plan.get('strategy')}"
158
+ )
159
+ return comprehensive_plan
160
+
161
+ async def _execute_planned_workflow(
162
+ self, options: OptionsProtocol, plan: dict[str, t.Any]
163
+ ) -> bool:
164
+ strategy = plan.get("strategy", "basic_reactive")
165
+ phases = plan.get("phases", ["standard_workflow"])
166
+
167
+ self.logger.info(f"Executing {strategy} workflow with {len(phases)} phases")
168
+
169
+ for phase in phases:
170
+ success = await self._execute_workflow_phase(phase, options, plan)
171
+ if not success and phase in (
172
+ "configuration_setup",
173
+ "architectural_refactoring",
174
+ ):
175
+ self.logger.error(f"Critical phase {phase} failed")
176
+ return False
177
+ elif not success:
178
+ self.logger.warning(f"Phase {phase} had issues but continuing")
179
+
180
+ return True
181
+
182
+ async def _execute_workflow_phase(
183
+ self, phase: str, options: OptionsProtocol, plan: dict[str, t.Any]
184
+ ) -> bool:
185
+ self.logger.info(f"Executing phase: {phase}")
186
+
187
+ if phase == "configuration_setup":
188
+ return await self._setup_with_architecture(options, plan)
189
+ elif phase == "fast_hooks_with_architecture":
190
+ return await self._run_fast_hooks_with_planning(options, plan)
191
+ elif phase == "architectural_refactoring":
192
+ return await self._perform_architectural_refactoring(options, plan)
193
+ elif phase == "comprehensive_validation":
194
+ return await self._comprehensive_validation(options, plan)
195
+ elif phase == "pattern_learning":
196
+ return await self._learn_and_cache_patterns(plan)
197
+
198
+ return await self._execute_standard_workflow(options)
199
+
200
+ async def _setup_with_architecture(
201
+ self, options: OptionsProtocol, plan: dict[str, t.Any]
202
+ ) -> bool:
203
+ self.logger.info("Setting up project with architectural planning")
204
+
205
+ return True
206
+
207
+ async def _run_fast_hooks_with_planning(
208
+ self, options: OptionsProtocol, plan: dict[str, t.Any]
209
+ ) -> bool:
210
+ self.logger.info("Running fast hooks with architectural planning")
211
+
212
+ return True
213
+
214
+ async def _perform_architectural_refactoring(
215
+ self, options: OptionsProtocol, plan: dict[str, t.Any]
216
+ ) -> bool:
217
+ self.logger.info("Performing architectural refactoring")
218
+
219
+ if self._architect_agent_coordinator:
220
+ architect = self._architect_agent_coordinator._get_architect_agent()
221
+ if architect:
222
+ patterns = plan.get("patterns", [])
223
+ self.logger.info(f"Applying architectural patterns: {patterns}")
224
+ return True
225
+
226
+ return True
227
+
228
+ async def _comprehensive_validation(
229
+ self, options: OptionsProtocol, plan: dict[str, t.Any]
230
+ ) -> bool:
231
+ self.logger.info("Performing comprehensive validation")
232
+ validation_steps = plan.get("validation", [])
233
+
234
+ for step in validation_steps:
235
+ self.logger.info(f"Validating: {step}")
236
+
237
+ return True
238
+
239
+ async def _learn_and_cache_patterns(self, plan: dict[str, t.Any]) -> bool:
240
+ self.logger.info("Learning and caching successful patterns")
241
+
242
+ if self._architect_agent_coordinator:
243
+ architect = self._architect_agent_coordinator._get_architect_agent()
244
+ if architect and hasattr(architect, "get_cached_patterns"):
245
+ cached_patterns = architect.get_cached_patterns()
246
+ self.logger.info(f"Cached {len(cached_patterns)} patterns")
247
+
248
+ return True
249
+
250
+ async def _execute_standard_workflow(self, options: OptionsProtocol) -> bool:
251
+ self.logger.info("Executing standard workflow (fallback)")
252
+
253
+ return True
254
+
255
+
256
+ class ArchitecturalAssessment:
257
+ def __init__(
258
+ self,
259
+ needs_planning: bool,
260
+ complexity_score: int,
261
+ potential_issues: list[Issue],
262
+ recommended_strategy: str,
263
+ ) -> None:
264
+ self.needs_planning = needs_planning
265
+ self.complexity_score = complexity_score
266
+ self.potential_issues = potential_issues
267
+ self.recommended_strategy = recommended_strategy
@@ -0,0 +1,425 @@
1
+ import asyncio
2
+ import contextlib
3
+ import logging
4
+ import tempfile
5
+ import threading
6
+ import time
7
+ import typing as t
8
+ import weakref
9
+ from abc import ABC, abstractmethod
10
+ from pathlib import Path
11
+ from types import TracebackType
12
+
13
+
14
+ class ResourceProtocol(t.Protocol):
15
+ async def cleanup(self) -> None: ...
16
+
17
+
18
+ class ResourceManager:
19
+ def __init__(self, logger: logging.Logger | None = None) -> None:
20
+ self.logger = logger or logging.getLogger(__name__)
21
+ self._resources: list[ResourceProtocol] = []
22
+ self._cleanup_callbacks: list[t.Callable[[], t.Awaitable[None]]] = []
23
+ self._lock = threading.RLock()
24
+ self._closed = False
25
+
26
+ def register_resource(self, resource: ResourceProtocol) -> None:
27
+ with self._lock:
28
+ if self._closed:
29
+ asyncio.create_task(resource.cleanup())
30
+ return
31
+ self._resources.append(resource)
32
+
33
+ def register_cleanup_callback(
34
+ self, callback: t.Callable[[], t.Awaitable[None]]
35
+ ) -> None:
36
+ with self._lock:
37
+ if self._closed:
38
+ coro = callback()
39
+ if asyncio.iscoroutine(coro):
40
+ asyncio.ensure_future(coro)
41
+ return
42
+ self._cleanup_callbacks.append(callback)
43
+
44
+ async def cleanup_all(self) -> None:
45
+ with self._lock:
46
+ if self._closed:
47
+ return
48
+ self._closed = True
49
+
50
+ resources = self._resources.copy()
51
+ callbacks = self._cleanup_callbacks.copy()
52
+
53
+ for resource in resources:
54
+ try:
55
+ await resource.cleanup()
56
+ except Exception as e:
57
+ self.logger.warning(f"Error cleaning up resource {resource}: {e}")
58
+
59
+ for callback in callbacks:
60
+ try:
61
+ await callback()
62
+ except Exception as e:
63
+ self.logger.warning(f"Error in cleanup callback: {e}")
64
+
65
+ with self._lock:
66
+ self._resources.clear()
67
+ self._cleanup_callbacks.clear()
68
+
69
+ async def __aenter__(self) -> "ResourceManager":
70
+ return self
71
+
72
+ async def __aexit__(
73
+ self,
74
+ exc_type: type[BaseException] | None,
75
+ exc_val: BaseException | None,
76
+ exc_tb: TracebackType | None,
77
+ ) -> None:
78
+ await self.cleanup_all()
79
+
80
+
81
+ class ManagedResource(ABC):
82
+ def __init__(self, manager: ResourceManager | None = None) -> None:
83
+ self.manager = manager
84
+ self._closed = False
85
+
86
+ if manager:
87
+ manager.register_resource(self)
88
+
89
+ @abstractmethod
90
+ async def cleanup(self) -> None:
91
+ pass
92
+
93
+ async def close(self) -> None:
94
+ if not self._closed:
95
+ self._closed = True
96
+ await self.cleanup()
97
+
98
+ def __del__(self) -> None:
99
+ if not self._closed:
100
+ with contextlib.suppress(RuntimeError):
101
+ loop = asyncio.get_event_loop()
102
+ if loop.is_running():
103
+ asyncio.create_task(self.cleanup())
104
+
105
+
106
+ class ManagedTemporaryFile(ManagedResource):
107
+ def __init__(
108
+ self,
109
+ suffix: str = "",
110
+ prefix: str = "crackerjack-",
111
+ manager: ResourceManager | None = None,
112
+ ) -> None:
113
+ super().__init__(manager)
114
+ self.temp_file = tempfile.NamedTemporaryFile(
115
+ suffix=suffix,
116
+ prefix=prefix,
117
+ delete=False,
118
+ )
119
+ self.path = Path(self.temp_file.name)
120
+
121
+ async def cleanup(self) -> None:
122
+ if not self._closed:
123
+ self._closed = True
124
+
125
+ if not self.temp_file.closed:
126
+ self.temp_file.close()
127
+
128
+ try:
129
+ if self.path.exists():
130
+ self.path.unlink()
131
+ except OSError as e:
132
+ logging.getLogger(__name__).warning(
133
+ f"Failed to remove temporary file {self.path}: {e}"
134
+ )
135
+
136
+ def write_text(self, content: str, encoding: str = "utf-8") -> None:
137
+ if self._closed:
138
+ raise RuntimeError("Cannot write to closed temporary file")
139
+ self.path.write_text(content, encoding=encoding)
140
+
141
+ def read_text(self, encoding: str = "utf-8") -> str:
142
+ return self.path.read_text(encoding=encoding)
143
+
144
+
145
+ class ManagedTemporaryDirectory(ManagedResource):
146
+ def __init__(
147
+ self,
148
+ suffix: str = "",
149
+ prefix: str = "crackerjack-",
150
+ manager: ResourceManager | None = None,
151
+ ) -> None:
152
+ super().__init__(manager)
153
+ self.temp_dir = tempfile.mkdtemp(suffix=suffix, prefix=prefix)
154
+ self.path = Path(self.temp_dir)
155
+
156
+ async def cleanup(self) -> None:
157
+ if not self._closed:
158
+ self._closed = True
159
+
160
+ try:
161
+ import shutil
162
+
163
+ if self.path.exists():
164
+ shutil.rmtree(self.path)
165
+ except OSError as e:
166
+ logging.getLogger(__name__).warning(
167
+ f"Failed to remove temporary directory {self.path}: {e}"
168
+ )
169
+
170
+
171
+ class ManagedProcess(ManagedResource):
172
+ def __init__(
173
+ self,
174
+ process: asyncio.subprocess.Process,
175
+ timeout: float = 30.0,
176
+ manager: ResourceManager | None = None,
177
+ ) -> None:
178
+ super().__init__(manager)
179
+ self.process = process
180
+ self.timeout = timeout
181
+
182
+ async def cleanup(self) -> None:
183
+ if not self._closed and self.process.returncode is None:
184
+ self._closed = True
185
+
186
+ try:
187
+ self.process.terminate()
188
+
189
+ try:
190
+ await asyncio.wait_for(self.process.wait(), timeout=5.0)
191
+ except TimeoutError:
192
+ self.process.kill()
193
+ try:
194
+ await asyncio.wait_for(self.process.wait(), timeout=2.0)
195
+ except TimeoutError:
196
+ logging.getLogger(__name__).warning(
197
+ f"Process {self.process.pid} did not terminate after force kill"
198
+ )
199
+
200
+ except ProcessLookupError:
201
+ pass
202
+ except Exception as e:
203
+ logging.getLogger(__name__).warning(
204
+ f"Error cleaning up process {self.process.pid}: {e}"
205
+ )
206
+
207
+
208
+ class ManagedTask(ManagedResource):
209
+ def __init__(
210
+ self,
211
+ task: asyncio.Task[t.Any],
212
+ timeout: float = 30.0,
213
+ manager: ResourceManager | None = None,
214
+ ) -> None:
215
+ super().__init__(manager)
216
+ self.task = task
217
+ self.timeout = timeout
218
+
219
+ async def cleanup(self) -> None:
220
+ if not self._closed and not self.task.done():
221
+ self._closed = True
222
+
223
+ self.task.cancel()
224
+
225
+ try:
226
+ await asyncio.wait_for(self.task, timeout=self.timeout)
227
+ except (TimeoutError, asyncio.CancelledError):
228
+ pass
229
+ except Exception as e:
230
+ logging.getLogger(__name__).warning(f"Error cleaning up task: {e}")
231
+
232
+
233
+ class ManagedFileHandle(ManagedResource):
234
+ def __init__(
235
+ self,
236
+ file_handle: t.IO[t.Any],
237
+ manager: ResourceManager | None = None,
238
+ ) -> None:
239
+ super().__init__(manager)
240
+ self.file_handle = file_handle
241
+
242
+ async def cleanup(self) -> None:
243
+ if not self._closed and not self.file_handle.closed:
244
+ self._closed = True
245
+
246
+ try:
247
+ self.file_handle.close()
248
+ except Exception as e:
249
+ logging.getLogger(__name__).warning(f"Error closing file handle: {e}")
250
+
251
+
252
+ class ResourceContext:
253
+ def __init__(self) -> None:
254
+ self.resource_manager = ResourceManager()
255
+
256
+ def managed_temp_file(
257
+ self,
258
+ suffix: str = "",
259
+ prefix: str = "crackerjack-",
260
+ ) -> ManagedTemporaryFile:
261
+ return ManagedTemporaryFile(suffix, prefix, self.resource_manager)
262
+
263
+ def managed_temp_dir(
264
+ self,
265
+ suffix: str = "",
266
+ prefix: str = "crackerjack-",
267
+ ) -> ManagedTemporaryDirectory:
268
+ return ManagedTemporaryDirectory(suffix, prefix, self.resource_manager)
269
+
270
+ def managed_process(
271
+ self,
272
+ process: asyncio.subprocess.Process,
273
+ timeout: float = 30.0,
274
+ ) -> ManagedProcess:
275
+ return ManagedProcess(process, timeout, self.resource_manager)
276
+
277
+ def managed_task(
278
+ self,
279
+ task: asyncio.Task[t.Any],
280
+ timeout: float = 30.0,
281
+ ) -> ManagedTask:
282
+ return ManagedTask(task, timeout, self.resource_manager)
283
+
284
+ def managed_file(
285
+ self,
286
+ file_handle: t.IO[t.Any],
287
+ ) -> ManagedFileHandle:
288
+ return ManagedFileHandle(file_handle, self.resource_manager)
289
+
290
+ async def __aenter__(self) -> "ResourceContext":
291
+ await self.resource_manager.__aenter__()
292
+ return self
293
+
294
+ async def __aexit__(
295
+ self,
296
+ exc_type: type[BaseException] | None,
297
+ exc_val: BaseException | None,
298
+ exc_tb: TracebackType | None,
299
+ ) -> None:
300
+ await self.resource_manager.__aexit__(exc_type, exc_val, exc_tb)
301
+
302
+
303
+ _global_managers: weakref.WeakSet[ResourceManager] = weakref.WeakSet()
304
+
305
+
306
+ def register_global_resource_manager(manager: ResourceManager) -> None:
307
+ _global_managers.add(manager)
308
+
309
+
310
+ async def cleanup_all_global_resources() -> None:
311
+ managers = list[t.Any](_global_managers)
312
+
313
+ cleanup_tasks = [asyncio.create_task(manager.cleanup_all()) for manager in managers]
314
+
315
+ if cleanup_tasks:
316
+ await asyncio.gather(*cleanup_tasks, return_exceptions=True)
317
+
318
+
319
+ @contextlib.asynccontextmanager
320
+ async def with_resource_cleanup() -> t.AsyncIterator[ResourceContext]:
321
+ async with ResourceContext() as ctx:
322
+ yield ctx
323
+
324
+
325
+ @contextlib.asynccontextmanager
326
+ async def with_temp_file(
327
+ suffix: str = "", prefix: str = "crackerjack-"
328
+ ) -> t.AsyncIterator[ManagedTemporaryFile]:
329
+ async with ResourceContext() as ctx:
330
+ temp_file = ctx.managed_temp_file(suffix, prefix)
331
+ try:
332
+ yield temp_file
333
+ finally:
334
+ await temp_file.cleanup()
335
+
336
+
337
+ @contextlib.asynccontextmanager
338
+ async def with_temp_dir(
339
+ suffix: str = "", prefix: str = "crackerjack-"
340
+ ) -> t.AsyncIterator[ManagedTemporaryDirectory]:
341
+ async with ResourceContext() as ctx:
342
+ temp_dir = ctx.managed_temp_dir(suffix, prefix)
343
+ try:
344
+ yield temp_dir
345
+ finally:
346
+ await temp_dir.cleanup()
347
+
348
+
349
+ @contextlib.asynccontextmanager
350
+ async def with_managed_process(
351
+ process: asyncio.subprocess.Process,
352
+ timeout: float = 30.0,
353
+ ) -> t.AsyncIterator[asyncio.subprocess.Process]:
354
+ async with ResourceContext() as ctx:
355
+ managed_proc = ctx.managed_process(process, timeout)
356
+ try:
357
+ yield managed_proc.process
358
+ finally:
359
+ await managed_proc.cleanup()
360
+
361
+
362
+ class ResourceLeakDetector:
363
+ def __init__(self) -> None:
364
+ self.open_files: set[str] = set()
365
+ self.active_processes: set[int] = set()
366
+ self.active_tasks: set[asyncio.Task[t.Any]] = set()
367
+ self._start_time = time.time()
368
+
369
+ def track_file(self, file_path: str) -> None:
370
+ self.open_files.add(file_path)
371
+
372
+ def untrack_file(self, file_path: str) -> None:
373
+ self.open_files.discard(file_path)
374
+
375
+ def track_process(self, pid: int) -> None:
376
+ self.active_processes.add(pid)
377
+
378
+ def untrack_process(self, pid: int) -> None:
379
+ self.active_processes.discard(pid)
380
+
381
+ def track_task(self, task: asyncio.Task[t.Any]) -> None:
382
+ self.active_tasks.add(task)
383
+
384
+ def untrack_task(self, task: asyncio.Task[t.Any]) -> None:
385
+ self.active_tasks.discard(task)
386
+
387
+ def get_leak_report(self) -> dict[str, t.Any]:
388
+ return {
389
+ "duration_seconds": time.time() - self._start_time,
390
+ "open_files": list[t.Any](self.open_files),
391
+ "active_processes": list[t.Any](self.active_processes),
392
+ "active_tasks": len([t for t in self.active_tasks if not t.done()]),
393
+ "total_tracked_files": len(self.open_files),
394
+ "total_tracked_processes": len(self.active_processes),
395
+ "total_tracked_tasks": len(self.active_tasks),
396
+ }
397
+
398
+ def has_potential_leaks(self) -> bool:
399
+ return bool(
400
+ self.open_files
401
+ or self.active_processes
402
+ or any(not t.done() for t in self.active_tasks)
403
+ )
404
+
405
+
406
+ _leak_detector: ResourceLeakDetector | None = None
407
+
408
+
409
+ def enable_leak_detection() -> ResourceLeakDetector:
410
+ global _leak_detector
411
+ _leak_detector = ResourceLeakDetector()
412
+ return _leak_detector
413
+
414
+
415
+ def get_leak_detector() -> ResourceLeakDetector | None:
416
+ return _leak_detector
417
+
418
+
419
+ def disable_leak_detection() -> dict[str, t.Any] | None:
420
+ global _leak_detector
421
+ if _leak_detector:
422
+ report = _leak_detector.get_leak_report()
423
+ _leak_detector = None
424
+ return report
425
+ return None