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,335 @@
1
+ import importlib
2
+ import importlib.util
3
+ import json
4
+ import logging
5
+ import typing as t
6
+ from pathlib import Path
7
+
8
+ from crackerjack.config.hooks import HookStage
9
+
10
+ from .base import (
11
+ PluginBase,
12
+ PluginMetadata,
13
+ PluginRegistry,
14
+ PluginType,
15
+ get_plugin_registry,
16
+ )
17
+ from .hooks import CustomHookDefinition, CustomHookPlugin
18
+
19
+
20
+ class PluginLoadError(Exception):
21
+ pass
22
+
23
+
24
+ class PluginLoader:
25
+ def __init__(self, registry: PluginRegistry | None = None) -> None:
26
+ self.registry = registry or get_plugin_registry()
27
+ self.logger = logging.getLogger("crackerjack.plugin_loader")
28
+
29
+ def load_plugin_from_file(self, plugin_file: Path) -> PluginBase:
30
+ if not plugin_file.exists():
31
+ msg = f"Plugin file not found: {plugin_file}"
32
+ raise PluginLoadError(msg)
33
+
34
+ if plugin_file.suffix != ".py":
35
+ msg = f"Plugin file must be .py: {plugin_file}"
36
+ raise PluginLoadError(msg)
37
+
38
+ spec = importlib.util.spec_from_file_location(plugin_file.stem, plugin_file)
39
+ if not spec or not spec.loader:
40
+ msg = f"Could not create module spec for: {plugin_file}"
41
+ raise PluginLoadError(msg)
42
+
43
+ module = importlib.util.module_from_spec(spec)
44
+
45
+ try:
46
+ spec.loader.exec_module(module)
47
+ except Exception as e:
48
+ msg = f"Failed to execute plugin module {plugin_file}: {e}"
49
+ raise PluginLoadError(msg)
50
+
51
+ plugin = self._extract_plugin_from_module(module, plugin_file)
52
+
53
+ if not isinstance(plugin, PluginBase):
54
+ msg = f"Plugin {plugin_file} does not provide a PluginBase instance"
55
+ raise PluginLoadError(
56
+ msg,
57
+ )
58
+
59
+ return plugin
60
+
61
+ def load_plugin_from_config(self, config_file: Path) -> PluginBase:
62
+ if not config_file.exists():
63
+ msg = f"Plugin config file not found: {config_file}"
64
+ raise PluginLoadError(msg)
65
+
66
+ try:
67
+ if config_file.suffix == ".json":
68
+ with config_file.open() as f:
69
+ config = json.load(f)
70
+ elif config_file.suffix in (".yaml", ".yml"):
71
+ import yaml
72
+
73
+ with config_file.open() as f:
74
+ config = yaml.safe_load(f)
75
+ else:
76
+ msg = f"Unsupported config format: {config_file.suffix}"
77
+ raise PluginLoadError(
78
+ msg,
79
+ )
80
+ except Exception as e:
81
+ msg = f"Failed to parse config file {config_file}: {e}"
82
+ raise PluginLoadError(msg)
83
+
84
+ return self._create_plugin_from_config(config, config_file)
85
+
86
+ def _extract_plugin_from_module(
87
+ self,
88
+ module: t.Any,
89
+ plugin_file: Path,
90
+ ) -> PluginBase:
91
+ plugin = self._try_standard_entry_points(module)
92
+ if plugin:
93
+ return plugin
94
+
95
+ plugin = self._try_plugin_subclasses(module, plugin_file)
96
+ if plugin:
97
+ return plugin
98
+
99
+ msg = f"No valid plugin found in {plugin_file}"
100
+ raise PluginLoadError(msg)
101
+
102
+ def _try_standard_entry_points(self, module: t.Any) -> PluginBase | None:
103
+ entry_points = [
104
+ "plugin",
105
+ "create_plugin",
106
+ "PLUGIN",
107
+ ]
108
+
109
+ for entry_point in entry_points:
110
+ plugin = self._try_single_entry_point(module, entry_point)
111
+ if plugin:
112
+ return plugin
113
+
114
+ return None
115
+
116
+ def _try_single_entry_point(
117
+ self,
118
+ module: t.Any,
119
+ entry_point: str,
120
+ ) -> PluginBase | None:
121
+ if not hasattr(module, entry_point):
122
+ return None
123
+
124
+ obj = getattr(module, entry_point)
125
+
126
+ if isinstance(obj, PluginBase):
127
+ return obj
128
+ if callable(obj):
129
+ return self._try_factory_function(obj, entry_point)
130
+
131
+ return None
132
+
133
+ def _try_factory_function(
134
+ self,
135
+ factory: t.Callable[..., t.Any],
136
+ name: str,
137
+ ) -> PluginBase | None:
138
+ try:
139
+ result = factory()
140
+ if isinstance(result, PluginBase):
141
+ return result
142
+ except Exception as e:
143
+ self.logger.warning(f"Plugin factory {name} failed: {e}")
144
+ return None
145
+
146
+ def _try_plugin_subclasses(
147
+ self,
148
+ module: t.Any,
149
+ plugin_file: Path,
150
+ ) -> PluginBase | None:
151
+ for name, obj in vars(module).items():
152
+ if self._is_valid_plugin_class(obj):
153
+ plugin = self._try_instantiate_plugin_class(obj, name, plugin_file)
154
+ if plugin:
155
+ return plugin
156
+ return None
157
+
158
+ def _is_valid_plugin_class(self, obj: t.Any) -> bool:
159
+ return (
160
+ isinstance(obj, type)
161
+ and issubclass(obj, PluginBase)
162
+ and obj is not PluginBase
163
+ )
164
+
165
+ def _try_instantiate_plugin_class(
166
+ self,
167
+ plugin_class: type[PluginBase],
168
+ name: str,
169
+ plugin_file: Path,
170
+ ) -> PluginBase | None:
171
+ try:
172
+ metadata = PluginMetadata(
173
+ name=plugin_file.stem,
174
+ version="1.0.0",
175
+ plugin_type=PluginType.HOOK,
176
+ description="Custom plugin",
177
+ )
178
+ return plugin_class(metadata)
179
+ except Exception as e:
180
+ self.logger.warning(f"Failed to instantiate plugin class {name}: {e}")
181
+ return None
182
+
183
+ def _create_plugin_from_config(
184
+ self,
185
+ config: dict[str, t.Any],
186
+ config_file: Path,
187
+ ) -> PluginBase:
188
+ metadata = PluginMetadata(
189
+ name=config.get("name", config_file.stem),
190
+ version=config.get("version", "1.0.0"),
191
+ plugin_type=PluginType(config.get("type", "hook")),
192
+ description=config.get("description", "Custom plugin"),
193
+ author=config.get("author", ""),
194
+ license=config.get("license", ""),
195
+ dependencies=config.get("dependencies", []),
196
+ )
197
+
198
+ if metadata.plugin_type == PluginType.HOOK:
199
+ return self._create_hook_plugin_from_config(metadata, config)
200
+ msg = f"Unsupported plugin type: {metadata.plugin_type}"
201
+ raise PluginLoadError(msg)
202
+
203
+ def _create_hook_plugin_from_config(
204
+ self,
205
+ metadata: PluginMetadata,
206
+ config: dict[str, t.Any],
207
+ ) -> CustomHookPlugin:
208
+ hooks_config = config.get("hooks", [])
209
+ hook_definitions = []
210
+
211
+ for hook_config in hooks_config:
212
+ hook_def = CustomHookDefinition(
213
+ name=hook_config["name"],
214
+ description=hook_config.get("description", ""),
215
+ command=hook_config.get("command", []),
216
+ file_patterns=hook_config.get("file_patterns", []),
217
+ timeout=hook_config.get("timeout", 60),
218
+ stage=HookStage(hook_config.get("stage", "comprehensive")),
219
+ requires_files=hook_config.get("requires_files", True),
220
+ parallel_safe=hook_config.get("parallel_safe", True),
221
+ )
222
+ hook_definitions.append(hook_def)
223
+
224
+ return CustomHookPlugin(metadata, hook_definitions)
225
+
226
+ def load_and_register(self, plugin_source: Path) -> bool:
227
+ try:
228
+ if plugin_source.suffix == ".py":
229
+ plugin = self.load_plugin_from_file(plugin_source)
230
+ elif plugin_source.suffix in (".json", ".yaml", ".yml"):
231
+ plugin = self.load_plugin_from_config(plugin_source)
232
+ else:
233
+ self.logger.error(f"Unsupported plugin file type: {plugin_source}")
234
+ return False
235
+
236
+ success = self.registry.register(plugin)
237
+ if success:
238
+ self.logger.info(f"Successfully loaded plugin: {plugin.name}")
239
+ else:
240
+ self.logger.warning(f"Plugin already registered: {plugin.name}")
241
+
242
+ return success
243
+
244
+ except PluginLoadError as e:
245
+ self.logger.exception(f"Failed to load plugin from {plugin_source}: {e}")
246
+ return False
247
+ except Exception as e:
248
+ self.logger.exception(
249
+ f"Unexpected error loading plugin {plugin_source}: {e}"
250
+ )
251
+ return False
252
+
253
+
254
+ class PluginDiscovery:
255
+ def __init__(self, loader: PluginLoader | None = None) -> None:
256
+ self.loader = loader or PluginLoader()
257
+ self.logger = logging.getLogger("crackerjack.plugin_discovery")
258
+
259
+ def discover_in_directory(
260
+ self,
261
+ directory: Path,
262
+ recursive: bool = False,
263
+ ) -> list[Path]:
264
+ if not directory.exists() or not directory.is_dir():
265
+ return []
266
+
267
+ plugin_files: list[Path] = []
268
+
269
+ patterns = ["*.py", "*.json", "*.yaml", "*.yml"]
270
+
271
+ for pattern in patterns:
272
+ if recursive:
273
+ plugin_files.extend(directory.rglob(pattern))
274
+ else:
275
+ plugin_files.extend(directory.glob(pattern))
276
+
277
+ return [f for f in plugin_files if self._looks_like_plugin_file(f)]
278
+
279
+ def discover_in_project(self, project_path: Path) -> list[Path]:
280
+ plugin_files: list[Path] = []
281
+
282
+ plugin_dirs = [
283
+ project_path / "plugins",
284
+ project_path / ".cache" / "crackerjack" / "plugins",
285
+ project_path / "tools" / "crackerjack",
286
+ ]
287
+
288
+ for plugin_dir in plugin_dirs:
289
+ if plugin_dir.exists():
290
+ plugin_files.extend(
291
+ self.discover_in_directory(plugin_dir, recursive=True),
292
+ )
293
+
294
+ return plugin_files
295
+
296
+ def load_discovered_plugins(self, plugin_files: list[Path]) -> dict[str, bool]:
297
+ results = {}
298
+
299
+ for plugin_file in plugin_files:
300
+ self.logger.info(f"Loading plugin: {plugin_file}")
301
+ success = self.loader.load_and_register(plugin_file)
302
+ results[str(plugin_file)] = success
303
+
304
+ return results
305
+
306
+ def auto_discover_and_load(self, project_path: Path) -> dict[str, bool]:
307
+ plugin_files = self.discover_in_project(project_path)
308
+
309
+ if plugin_files:
310
+ self.logger.info(f"Found {len(plugin_files)} potential plugin files")
311
+ return self.load_discovered_plugins(plugin_files)
312
+ self.logger.info("No plugin files found")
313
+ return {}
314
+
315
+ def _looks_like_plugin_file(self, file_path: Path) -> bool:
316
+ name_lower = file_path.name.lower()
317
+
318
+ if name_lower.startswith(("test_", "__", ".")):
319
+ return False
320
+
321
+ if name_lower in ("__init__.py", "setup.py", "conftest.py"):
322
+ return False
323
+
324
+ plugin_indicators = [
325
+ "plugin",
326
+ "hook",
327
+ "extension",
328
+ "addon",
329
+ "crackerjack",
330
+ "check",
331
+ "lint",
332
+ "format",
333
+ ]
334
+
335
+ return any(indicator in name_lower for indicator in plugin_indicators)
@@ -0,0 +1,264 @@
1
+ import logging
2
+ import typing as t
3
+ from pathlib import Path
4
+
5
+ from acb.console import Console
6
+
7
+ from crackerjack.models.protocols import OptionsProtocol
8
+
9
+ from .base import PluginRegistry, PluginType, get_plugin_registry
10
+ from .hooks import HookPluginBase, HookPluginRegistry, get_hook_plugin_registry
11
+ from .loader import PluginDiscovery, PluginLoader
12
+
13
+
14
+ class PluginManager:
15
+ def __init__(
16
+ self,
17
+ console: Console,
18
+ project_path: Path,
19
+ registry: PluginRegistry | None = None,
20
+ hook_registry: HookPluginRegistry | None = None,
21
+ ) -> None:
22
+ self.console = console
23
+ self.project_path = project_path
24
+ self.registry = registry or get_plugin_registry()
25
+ self.hook_registry = hook_registry or get_hook_plugin_registry()
26
+
27
+ self.loader = PluginLoader(self.registry)
28
+ self.discovery = PluginDiscovery(self.loader)
29
+ self.logger = logging.getLogger("crackerjack.plugin_manager")
30
+
31
+ self._initialized = False
32
+
33
+ def initialize(self) -> bool:
34
+ if self._initialized:
35
+ return True
36
+
37
+ self.logger.info("Initializing plugin system")
38
+
39
+ try:
40
+ results = self.discovery.auto_discover_and_load(self.project_path)
41
+
42
+ loaded_count = sum(1 for success in results.values() if success)
43
+ total_count = len(results)
44
+
45
+ if total_count > 0:
46
+ self.console.print(
47
+ f"[green]✅[/ green] Loaded {loaded_count} / {total_count} plugins",
48
+ )
49
+
50
+ activation_results = self.registry.activate_all()
51
+ activated_count = sum(
52
+ 1 for success in activation_results.values() if success
53
+ )
54
+
55
+ if activated_count > 0:
56
+ self.console.print(
57
+ f"[green]✅[/ green] Activated {activated_count} plugins",
58
+ )
59
+
60
+ hook_plugins = self.registry.get_enabled(PluginType.HOOK)
61
+ for plugin in hook_plugins:
62
+ if isinstance(plugin, HookPluginBase):
63
+ if hasattr(plugin, "initialize"):
64
+ plugin.initialize(self.console, self.project_path)
65
+ self.hook_registry.register_hook_plugin(plugin)
66
+
67
+ self._initialized = True
68
+ return True
69
+
70
+ except Exception as e:
71
+ self.logger.exception(f"Failed to initialize plugin system: {e}")
72
+ self.console.print(
73
+ f"[red]❌[/ red] Plugin system initialization failed: {e}",
74
+ )
75
+ return False
76
+
77
+ def shutdown(self) -> None:
78
+ if not self._initialized:
79
+ return
80
+
81
+ self.logger.info("Shutting down plugin system")
82
+
83
+ try:
84
+ results = self.registry.deactivate_all()
85
+ deactivated_count = sum(1 for success in results.values() if success)
86
+
87
+ if deactivated_count > 0:
88
+ self.console.print(
89
+ f"[yellow]⏹️[/ yellow] Deactivated {deactivated_count} plugins",
90
+ )
91
+
92
+ self._initialized = False
93
+
94
+ except Exception as e:
95
+ self.logger.exception(f"Error during plugin system shutdown: {e}")
96
+
97
+ def list_plugins(self, plugin_type: PluginType | None = None) -> dict[str, t.Any]:
98
+ if plugin_type:
99
+ plugins = self.registry.get_by_type(plugin_type)
100
+ else:
101
+ plugins = list[t.Any](self.registry.list_all().values())
102
+
103
+ plugin_info = []
104
+ for plugin in plugins:
105
+ info = plugin.get_info()
106
+ info["active"] = plugin.enabled
107
+ plugin_info.append(info)
108
+
109
+ return {
110
+ "plugins": plugin_info,
111
+ "total": len(plugin_info),
112
+ "enabled": len([p for p in plugins if p.enabled]),
113
+ }
114
+
115
+ def get_plugin_stats(self) -> dict[str, t.Any]:
116
+ stats = self.registry.get_stats()
117
+
118
+ hook_plugins = self.registry.get_enabled(PluginType.HOOK)
119
+ custom_hooks = self.hook_registry.get_all_custom_hooks()
120
+
121
+ stats["hook_plugins"] = {
122
+ "active_plugins": len(hook_plugins),
123
+ "total_custom_hooks": len(custom_hooks),
124
+ "hook_names": list[t.Any](custom_hooks.keys()),
125
+ }
126
+
127
+ return stats
128
+
129
+ def enable_plugin(self, plugin_name: str) -> bool:
130
+ plugin = self.registry.get(plugin_name)
131
+ if not plugin:
132
+ self.console.print(f"[red]❌[/ red] Plugin not found: {plugin_name}")
133
+ return False
134
+
135
+ if plugin.enabled:
136
+ self.console.print(
137
+ f"[yellow]⚠️[/ yellow] Plugin already enabled: {plugin_name}",
138
+ )
139
+ return True
140
+
141
+ try:
142
+ plugin.enable()
143
+ success = plugin.activate()
144
+
145
+ if success:
146
+ self.console.print(f"[green]✅[/ green] Enabled plugin: {plugin_name}")
147
+
148
+ if plugin.plugin_type == PluginType.HOOK and isinstance(
149
+ plugin, HookPluginBase
150
+ ):
151
+ self.hook_registry.register_hook_plugin(plugin)
152
+
153
+ return True
154
+ plugin.disable()
155
+ self.console.print(
156
+ f"[red]❌[/ red] Failed to activate plugin: {plugin_name}",
157
+ )
158
+ return False
159
+
160
+ except Exception as e:
161
+ self.console.print(
162
+ f"[red]❌[/ red] Error enabling plugin {plugin_name}: {e}",
163
+ )
164
+ return False
165
+
166
+ def disable_plugin(self, plugin_name: str) -> bool:
167
+ plugin = self.registry.get(plugin_name)
168
+ if not plugin:
169
+ self.console.print(f"[red]❌[/ red] Plugin not found: {plugin_name}")
170
+ return False
171
+
172
+ if not plugin.enabled:
173
+ self.console.print(
174
+ f"[yellow]⚠️[/ yellow] Plugin already disabled: {plugin_name}",
175
+ )
176
+ return True
177
+
178
+ try:
179
+ success = plugin.deactivate()
180
+ plugin.disable()
181
+
182
+ if plugin.plugin_type == PluginType.HOOK:
183
+ self.hook_registry.unregister_hook_plugin(plugin_name)
184
+
185
+ if success:
186
+ self.console.print(
187
+ f"[yellow]⏹️[/ yellow] Disabled plugin: {plugin_name}"
188
+ )
189
+ else:
190
+ self.console.print(
191
+ f"[yellow]⚠️[/ yellow] Plugin disabled with warnings: {plugin_name}",
192
+ )
193
+
194
+ return True
195
+
196
+ except Exception as e:
197
+ self.console.print(
198
+ f"[red]❌[/ red] Error disabling plugin {plugin_name}: {e}",
199
+ )
200
+ return False
201
+
202
+ def reload_plugin(self, plugin_name: str) -> bool:
203
+ if not self.disable_plugin(plugin_name):
204
+ return False
205
+
206
+ return self.enable_plugin(plugin_name)
207
+
208
+ def configure_plugin(self, plugin_name: str, config: dict[str, t.Any]) -> bool:
209
+ plugin = self.registry.get(plugin_name)
210
+ if not plugin:
211
+ self.console.print(f"[red]❌[/ red] Plugin not found: {plugin_name}")
212
+ return False
213
+
214
+ try:
215
+ plugin.configure(config)
216
+ self.console.print(f"[green]✅[/ green] Configured plugin: {plugin_name}")
217
+ return True
218
+ except Exception as e:
219
+ self.console.print(
220
+ f"[red]❌[/ red] Error configuring plugin {plugin_name}: {e}",
221
+ )
222
+ return False
223
+
224
+ def install_plugin_from_file(self, plugin_file: Path) -> bool:
225
+ try:
226
+ success = self.loader.load_and_register(plugin_file)
227
+
228
+ if success:
229
+ self.console.print(
230
+ f"[green]✅[/ green] Installed plugin from: {plugin_file}",
231
+ )
232
+
233
+ if self._initialized:
234
+ plugins = self.registry.list_all()
235
+ if plugins:
236
+ latest_plugin_name = max(
237
+ plugins.keys(),
238
+ key=lambda k: id(plugins[k]),
239
+ )
240
+ self.enable_plugin(latest_plugin_name)
241
+ else:
242
+ self.console.print(
243
+ f"[red]❌[/ red] Failed to install plugin from: {plugin_file}",
244
+ )
245
+
246
+ return success
247
+
248
+ except Exception as e:
249
+ self.console.print(
250
+ f"[red]❌[/ red] Error installing plugin {plugin_file}: {e}",
251
+ )
252
+ return False
253
+
254
+ def get_available_custom_hooks(self) -> list[str]:
255
+ custom_hooks = self.hook_registry.get_all_custom_hooks()
256
+ return list[t.Any](custom_hooks.keys())
257
+
258
+ def execute_custom_hook(
259
+ self,
260
+ hook_name: str,
261
+ files: list[Path],
262
+ options: OptionsProtocol,
263
+ ) -> t.Any:
264
+ return self.hook_registry.execute_custom_hook(hook_name, files, options)