crackerjack 0.37.9__py3-none-any.whl → 0.45.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (425) hide show
  1. crackerjack/README.md +19 -0
  2. crackerjack/__init__.py +30 -1
  3. crackerjack/__main__.py +342 -1263
  4. crackerjack/adapters/README.md +18 -0
  5. crackerjack/adapters/__init__.py +27 -5
  6. crackerjack/adapters/_output_paths.py +167 -0
  7. crackerjack/adapters/_qa_adapter_base.py +309 -0
  8. crackerjack/adapters/_tool_adapter_base.py +706 -0
  9. crackerjack/adapters/ai/README.md +65 -0
  10. crackerjack/adapters/ai/__init__.py +5 -0
  11. crackerjack/adapters/ai/claude.py +853 -0
  12. crackerjack/adapters/complexity/README.md +53 -0
  13. crackerjack/adapters/complexity/__init__.py +10 -0
  14. crackerjack/adapters/complexity/complexipy.py +641 -0
  15. crackerjack/adapters/dependency/__init__.py +22 -0
  16. crackerjack/adapters/dependency/pip_audit.py +418 -0
  17. crackerjack/adapters/format/README.md +72 -0
  18. crackerjack/adapters/format/__init__.py +11 -0
  19. crackerjack/adapters/format/mdformat.py +313 -0
  20. crackerjack/adapters/format/ruff.py +516 -0
  21. crackerjack/adapters/lint/README.md +47 -0
  22. crackerjack/adapters/lint/__init__.py +11 -0
  23. crackerjack/adapters/lint/codespell.py +273 -0
  24. crackerjack/adapters/lsp/README.md +49 -0
  25. crackerjack/adapters/lsp/__init__.py +27 -0
  26. crackerjack/adapters/{rust_tool_manager.py → lsp/_manager.py} +3 -3
  27. crackerjack/adapters/{skylos_adapter.py → lsp/skylos.py} +59 -7
  28. crackerjack/adapters/{zuban_adapter.py → lsp/zuban.py} +3 -6
  29. crackerjack/adapters/refactor/README.md +59 -0
  30. crackerjack/adapters/refactor/__init__.py +12 -0
  31. crackerjack/adapters/refactor/creosote.py +318 -0
  32. crackerjack/adapters/refactor/refurb.py +406 -0
  33. crackerjack/adapters/refactor/skylos.py +494 -0
  34. crackerjack/adapters/sast/README.md +132 -0
  35. crackerjack/adapters/sast/__init__.py +32 -0
  36. crackerjack/adapters/sast/_base.py +201 -0
  37. crackerjack/adapters/sast/bandit.py +423 -0
  38. crackerjack/adapters/sast/pyscn.py +405 -0
  39. crackerjack/adapters/sast/semgrep.py +241 -0
  40. crackerjack/adapters/security/README.md +111 -0
  41. crackerjack/adapters/security/__init__.py +17 -0
  42. crackerjack/adapters/security/gitleaks.py +339 -0
  43. crackerjack/adapters/type/README.md +52 -0
  44. crackerjack/adapters/type/__init__.py +12 -0
  45. crackerjack/adapters/type/pyrefly.py +402 -0
  46. crackerjack/adapters/type/ty.py +402 -0
  47. crackerjack/adapters/type/zuban.py +522 -0
  48. crackerjack/adapters/utility/README.md +51 -0
  49. crackerjack/adapters/utility/__init__.py +10 -0
  50. crackerjack/adapters/utility/checks.py +884 -0
  51. crackerjack/agents/README.md +264 -0
  52. crackerjack/agents/__init__.py +40 -12
  53. crackerjack/agents/base.py +1 -0
  54. crackerjack/agents/claude_code_bridge.py +641 -0
  55. crackerjack/agents/coordinator.py +49 -53
  56. crackerjack/agents/dry_agent.py +187 -3
  57. crackerjack/agents/enhanced_coordinator.py +279 -0
  58. crackerjack/agents/enhanced_proactive_agent.py +185 -0
  59. crackerjack/agents/error_middleware.py +53 -0
  60. crackerjack/agents/formatting_agent.py +6 -8
  61. crackerjack/agents/helpers/__init__.py +9 -0
  62. crackerjack/agents/helpers/performance/__init__.py +22 -0
  63. crackerjack/agents/helpers/performance/performance_ast_analyzer.py +357 -0
  64. crackerjack/agents/helpers/performance/performance_pattern_detector.py +909 -0
  65. crackerjack/agents/helpers/performance/performance_recommender.py +572 -0
  66. crackerjack/agents/helpers/refactoring/__init__.py +22 -0
  67. crackerjack/agents/helpers/refactoring/code_transformer.py +536 -0
  68. crackerjack/agents/helpers/refactoring/complexity_analyzer.py +344 -0
  69. crackerjack/agents/helpers/refactoring/dead_code_detector.py +437 -0
  70. crackerjack/agents/helpers/test_creation/__init__.py +19 -0
  71. crackerjack/agents/helpers/test_creation/test_ast_analyzer.py +216 -0
  72. crackerjack/agents/helpers/test_creation/test_coverage_analyzer.py +643 -0
  73. crackerjack/agents/helpers/test_creation/test_template_generator.py +1031 -0
  74. crackerjack/agents/performance_agent.py +121 -1152
  75. crackerjack/agents/refactoring_agent.py +156 -655
  76. crackerjack/agents/semantic_agent.py +479 -0
  77. crackerjack/agents/semantic_helpers.py +356 -0
  78. crackerjack/agents/test_creation_agent.py +19 -1605
  79. crackerjack/api.py +5 -7
  80. crackerjack/cli/README.md +394 -0
  81. crackerjack/cli/__init__.py +1 -1
  82. crackerjack/cli/cache_handlers.py +23 -18
  83. crackerjack/cli/cache_handlers_enhanced.py +1 -4
  84. crackerjack/cli/facade.py +70 -8
  85. crackerjack/cli/formatting.py +13 -0
  86. crackerjack/cli/handlers/__init__.py +85 -0
  87. crackerjack/cli/handlers/advanced.py +103 -0
  88. crackerjack/cli/handlers/ai_features.py +62 -0
  89. crackerjack/cli/handlers/analytics.py +479 -0
  90. crackerjack/cli/handlers/changelog.py +271 -0
  91. crackerjack/cli/handlers/config_handlers.py +16 -0
  92. crackerjack/cli/handlers/coverage.py +84 -0
  93. crackerjack/cli/handlers/documentation.py +280 -0
  94. crackerjack/cli/handlers/main_handlers.py +497 -0
  95. crackerjack/cli/handlers/monitoring.py +371 -0
  96. crackerjack/cli/handlers.py +249 -49
  97. crackerjack/cli/interactive.py +8 -5
  98. crackerjack/cli/options.py +203 -110
  99. crackerjack/cli/semantic_handlers.py +292 -0
  100. crackerjack/cli/version.py +19 -0
  101. crackerjack/code_cleaner.py +60 -24
  102. crackerjack/config/README.md +472 -0
  103. crackerjack/config/__init__.py +256 -0
  104. crackerjack/config/global_lock_config.py +191 -54
  105. crackerjack/config/hooks.py +188 -16
  106. crackerjack/config/loader.py +239 -0
  107. crackerjack/config/settings.py +141 -0
  108. crackerjack/config/tool_commands.py +331 -0
  109. crackerjack/core/README.md +393 -0
  110. crackerjack/core/async_workflow_orchestrator.py +79 -53
  111. crackerjack/core/autofix_coordinator.py +22 -9
  112. crackerjack/core/container.py +10 -9
  113. crackerjack/core/enhanced_container.py +9 -9
  114. crackerjack/core/performance.py +1 -1
  115. crackerjack/core/performance_monitor.py +5 -3
  116. crackerjack/core/phase_coordinator.py +1018 -634
  117. crackerjack/core/proactive_workflow.py +3 -3
  118. crackerjack/core/retry.py +275 -0
  119. crackerjack/core/service_watchdog.py +167 -23
  120. crackerjack/core/session_coordinator.py +187 -382
  121. crackerjack/core/timeout_manager.py +161 -44
  122. crackerjack/core/workflow/__init__.py +21 -0
  123. crackerjack/core/workflow/workflow_ai_coordinator.py +863 -0
  124. crackerjack/core/workflow/workflow_event_orchestrator.py +1107 -0
  125. crackerjack/core/workflow/workflow_issue_parser.py +714 -0
  126. crackerjack/core/workflow/workflow_phase_executor.py +1158 -0
  127. crackerjack/core/workflow/workflow_security_gates.py +400 -0
  128. crackerjack/core/workflow_orchestrator.py +1247 -953
  129. crackerjack/data/README.md +11 -0
  130. crackerjack/data/__init__.py +8 -0
  131. crackerjack/data/models.py +79 -0
  132. crackerjack/data/repository.py +210 -0
  133. crackerjack/decorators/README.md +180 -0
  134. crackerjack/decorators/__init__.py +35 -0
  135. crackerjack/decorators/error_handling.py +649 -0
  136. crackerjack/decorators/error_handling_decorators.py +334 -0
  137. crackerjack/decorators/helpers.py +58 -0
  138. crackerjack/decorators/patterns.py +281 -0
  139. crackerjack/decorators/utils.py +58 -0
  140. crackerjack/docs/README.md +11 -0
  141. crackerjack/docs/generated/api/CLI_REFERENCE.md +1 -1
  142. crackerjack/documentation/README.md +11 -0
  143. crackerjack/documentation/ai_templates.py +1 -1
  144. crackerjack/documentation/dual_output_generator.py +11 -9
  145. crackerjack/documentation/reference_generator.py +104 -59
  146. crackerjack/dynamic_config.py +52 -61
  147. crackerjack/errors.py +1 -1
  148. crackerjack/events/README.md +11 -0
  149. crackerjack/events/__init__.py +16 -0
  150. crackerjack/events/telemetry.py +175 -0
  151. crackerjack/events/workflow_bus.py +346 -0
  152. crackerjack/exceptions/README.md +301 -0
  153. crackerjack/exceptions/__init__.py +5 -0
  154. crackerjack/exceptions/config.py +4 -0
  155. crackerjack/exceptions/tool_execution_error.py +245 -0
  156. crackerjack/executors/README.md +591 -0
  157. crackerjack/executors/__init__.py +2 -0
  158. crackerjack/executors/async_hook_executor.py +539 -77
  159. crackerjack/executors/cached_hook_executor.py +3 -3
  160. crackerjack/executors/hook_executor.py +967 -102
  161. crackerjack/executors/hook_lock_manager.py +31 -22
  162. crackerjack/executors/individual_hook_executor.py +66 -32
  163. crackerjack/executors/lsp_aware_hook_executor.py +136 -57
  164. crackerjack/executors/progress_hook_executor.py +282 -0
  165. crackerjack/executors/tool_proxy.py +23 -7
  166. crackerjack/hooks/README.md +485 -0
  167. crackerjack/hooks/lsp_hook.py +8 -9
  168. crackerjack/intelligence/README.md +557 -0
  169. crackerjack/interactive.py +37 -10
  170. crackerjack/managers/README.md +369 -0
  171. crackerjack/managers/async_hook_manager.py +41 -57
  172. crackerjack/managers/hook_manager.py +449 -79
  173. crackerjack/managers/publish_manager.py +81 -36
  174. crackerjack/managers/test_command_builder.py +290 -12
  175. crackerjack/managers/test_executor.py +93 -8
  176. crackerjack/managers/test_manager.py +1082 -75
  177. crackerjack/managers/test_progress.py +118 -26
  178. crackerjack/mcp/README.md +374 -0
  179. crackerjack/mcp/cache.py +25 -2
  180. crackerjack/mcp/client_runner.py +35 -18
  181. crackerjack/mcp/context.py +9 -9
  182. crackerjack/mcp/dashboard.py +24 -8
  183. crackerjack/mcp/enhanced_progress_monitor.py +34 -23
  184. crackerjack/mcp/file_monitor.py +27 -6
  185. crackerjack/mcp/progress_components.py +45 -34
  186. crackerjack/mcp/progress_monitor.py +6 -9
  187. crackerjack/mcp/rate_limiter.py +11 -7
  188. crackerjack/mcp/server.py +2 -0
  189. crackerjack/mcp/server_core.py +187 -55
  190. crackerjack/mcp/service_watchdog.py +12 -9
  191. crackerjack/mcp/task_manager.py +2 -2
  192. crackerjack/mcp/tools/README.md +27 -0
  193. crackerjack/mcp/tools/__init__.py +2 -0
  194. crackerjack/mcp/tools/core_tools.py +75 -52
  195. crackerjack/mcp/tools/execution_tools.py +87 -31
  196. crackerjack/mcp/tools/intelligence_tools.py +2 -2
  197. crackerjack/mcp/tools/proactive_tools.py +1 -1
  198. crackerjack/mcp/tools/semantic_tools.py +584 -0
  199. crackerjack/mcp/tools/utility_tools.py +180 -132
  200. crackerjack/mcp/tools/workflow_executor.py +87 -46
  201. crackerjack/mcp/websocket/README.md +31 -0
  202. crackerjack/mcp/websocket/app.py +11 -1
  203. crackerjack/mcp/websocket/event_bridge.py +188 -0
  204. crackerjack/mcp/websocket/jobs.py +27 -4
  205. crackerjack/mcp/websocket/monitoring/__init__.py +25 -0
  206. crackerjack/mcp/websocket/monitoring/api/__init__.py +19 -0
  207. crackerjack/mcp/websocket/monitoring/api/dependencies.py +141 -0
  208. crackerjack/mcp/websocket/monitoring/api/heatmap.py +154 -0
  209. crackerjack/mcp/websocket/monitoring/api/intelligence.py +199 -0
  210. crackerjack/mcp/websocket/monitoring/api/metrics.py +203 -0
  211. crackerjack/mcp/websocket/monitoring/api/telemetry.py +101 -0
  212. crackerjack/mcp/websocket/monitoring/dashboard.py +18 -0
  213. crackerjack/mcp/websocket/monitoring/factory.py +109 -0
  214. crackerjack/mcp/websocket/monitoring/filters.py +10 -0
  215. crackerjack/mcp/websocket/monitoring/metrics.py +64 -0
  216. crackerjack/mcp/websocket/monitoring/models.py +90 -0
  217. crackerjack/mcp/websocket/monitoring/utils.py +171 -0
  218. crackerjack/mcp/websocket/monitoring/websocket_manager.py +78 -0
  219. crackerjack/mcp/websocket/monitoring/websockets/__init__.py +17 -0
  220. crackerjack/mcp/websocket/monitoring/websockets/dependencies.py +126 -0
  221. crackerjack/mcp/websocket/monitoring/websockets/heatmap.py +176 -0
  222. crackerjack/mcp/websocket/monitoring/websockets/intelligence.py +291 -0
  223. crackerjack/mcp/websocket/monitoring/websockets/metrics.py +291 -0
  224. crackerjack/mcp/websocket/monitoring_endpoints.py +16 -2930
  225. crackerjack/mcp/websocket/server.py +1 -3
  226. crackerjack/mcp/websocket/websocket_handler.py +107 -6
  227. crackerjack/models/README.md +308 -0
  228. crackerjack/models/__init__.py +10 -1
  229. crackerjack/models/config.py +639 -22
  230. crackerjack/models/config_adapter.py +6 -6
  231. crackerjack/models/protocols.py +1167 -23
  232. crackerjack/models/pydantic_models.py +320 -0
  233. crackerjack/models/qa_config.py +145 -0
  234. crackerjack/models/qa_results.py +134 -0
  235. crackerjack/models/results.py +35 -0
  236. crackerjack/models/semantic_models.py +258 -0
  237. crackerjack/models/task.py +19 -3
  238. crackerjack/models/test_models.py +60 -0
  239. crackerjack/monitoring/README.md +11 -0
  240. crackerjack/monitoring/ai_agent_watchdog.py +5 -4
  241. crackerjack/monitoring/metrics_collector.py +4 -3
  242. crackerjack/monitoring/regression_prevention.py +4 -3
  243. crackerjack/monitoring/websocket_server.py +4 -241
  244. crackerjack/orchestration/README.md +340 -0
  245. crackerjack/orchestration/__init__.py +43 -0
  246. crackerjack/orchestration/advanced_orchestrator.py +20 -67
  247. crackerjack/orchestration/cache/README.md +312 -0
  248. crackerjack/orchestration/cache/__init__.py +37 -0
  249. crackerjack/orchestration/cache/memory_cache.py +338 -0
  250. crackerjack/orchestration/cache/tool_proxy_cache.py +340 -0
  251. crackerjack/orchestration/config.py +297 -0
  252. crackerjack/orchestration/coverage_improvement.py +13 -6
  253. crackerjack/orchestration/execution_strategies.py +6 -6
  254. crackerjack/orchestration/hook_orchestrator.py +1398 -0
  255. crackerjack/orchestration/strategies/README.md +401 -0
  256. crackerjack/orchestration/strategies/__init__.py +39 -0
  257. crackerjack/orchestration/strategies/adaptive_strategy.py +630 -0
  258. crackerjack/orchestration/strategies/parallel_strategy.py +237 -0
  259. crackerjack/orchestration/strategies/sequential_strategy.py +299 -0
  260. crackerjack/orchestration/test_progress_streamer.py +1 -1
  261. crackerjack/plugins/README.md +11 -0
  262. crackerjack/plugins/hooks.py +3 -2
  263. crackerjack/plugins/loader.py +3 -3
  264. crackerjack/plugins/managers.py +1 -1
  265. crackerjack/py313.py +191 -0
  266. crackerjack/security/README.md +11 -0
  267. crackerjack/services/README.md +374 -0
  268. crackerjack/services/__init__.py +8 -21
  269. crackerjack/services/ai/README.md +295 -0
  270. crackerjack/services/ai/__init__.py +7 -0
  271. crackerjack/services/ai/advanced_optimizer.py +878 -0
  272. crackerjack/services/{contextual_ai_assistant.py → ai/contextual_ai_assistant.py} +5 -3
  273. crackerjack/services/ai/embeddings.py +444 -0
  274. crackerjack/services/ai/intelligent_commit.py +328 -0
  275. crackerjack/services/ai/predictive_analytics.py +510 -0
  276. crackerjack/services/api_extractor.py +5 -3
  277. crackerjack/services/bounded_status_operations.py +45 -5
  278. crackerjack/services/cache.py +249 -318
  279. crackerjack/services/changelog_automation.py +7 -3
  280. crackerjack/services/command_execution_service.py +305 -0
  281. crackerjack/services/config_integrity.py +83 -39
  282. crackerjack/services/config_merge.py +9 -6
  283. crackerjack/services/config_service.py +198 -0
  284. crackerjack/services/config_template.py +13 -26
  285. crackerjack/services/coverage_badge_service.py +6 -4
  286. crackerjack/services/coverage_ratchet.py +53 -27
  287. crackerjack/services/debug.py +18 -7
  288. crackerjack/services/dependency_analyzer.py +4 -4
  289. crackerjack/services/dependency_monitor.py +13 -13
  290. crackerjack/services/documentation_generator.py +4 -2
  291. crackerjack/services/documentation_service.py +62 -33
  292. crackerjack/services/enhanced_filesystem.py +81 -27
  293. crackerjack/services/enterprise_optimizer.py +1 -1
  294. crackerjack/services/error_pattern_analyzer.py +10 -10
  295. crackerjack/services/file_filter.py +221 -0
  296. crackerjack/services/file_hasher.py +5 -7
  297. crackerjack/services/file_io_service.py +361 -0
  298. crackerjack/services/file_modifier.py +615 -0
  299. crackerjack/services/filesystem.py +80 -109
  300. crackerjack/services/git.py +99 -5
  301. crackerjack/services/health_metrics.py +4 -6
  302. crackerjack/services/heatmap_generator.py +12 -3
  303. crackerjack/services/incremental_executor.py +380 -0
  304. crackerjack/services/initialization.py +101 -49
  305. crackerjack/services/log_manager.py +2 -2
  306. crackerjack/services/logging.py +120 -68
  307. crackerjack/services/lsp_client.py +12 -12
  308. crackerjack/services/memory_optimizer.py +27 -22
  309. crackerjack/services/monitoring/README.md +30 -0
  310. crackerjack/services/monitoring/__init__.py +9 -0
  311. crackerjack/services/monitoring/dependency_monitor.py +678 -0
  312. crackerjack/services/monitoring/error_pattern_analyzer.py +676 -0
  313. crackerjack/services/monitoring/health_metrics.py +716 -0
  314. crackerjack/services/monitoring/metrics.py +587 -0
  315. crackerjack/services/{performance_benchmarks.py → monitoring/performance_benchmarks.py} +100 -14
  316. crackerjack/services/{performance_cache.py → monitoring/performance_cache.py} +21 -15
  317. crackerjack/services/{performance_monitor.py → monitoring/performance_monitor.py} +10 -6
  318. crackerjack/services/parallel_executor.py +166 -55
  319. crackerjack/services/patterns/__init__.py +142 -0
  320. crackerjack/services/patterns/agents.py +107 -0
  321. crackerjack/services/patterns/code/__init__.py +15 -0
  322. crackerjack/services/patterns/code/detection.py +118 -0
  323. crackerjack/services/patterns/code/imports.py +107 -0
  324. crackerjack/services/patterns/code/paths.py +159 -0
  325. crackerjack/services/patterns/code/performance.py +119 -0
  326. crackerjack/services/patterns/code/replacement.py +36 -0
  327. crackerjack/services/patterns/core.py +212 -0
  328. crackerjack/services/patterns/documentation/__init__.py +14 -0
  329. crackerjack/services/patterns/documentation/badges_markdown.py +96 -0
  330. crackerjack/services/patterns/documentation/comments_blocks.py +83 -0
  331. crackerjack/services/patterns/documentation/docstrings.py +89 -0
  332. crackerjack/services/patterns/formatting.py +226 -0
  333. crackerjack/services/patterns/operations.py +339 -0
  334. crackerjack/services/patterns/security/__init__.py +23 -0
  335. crackerjack/services/patterns/security/code_injection.py +122 -0
  336. crackerjack/services/patterns/security/credentials.py +190 -0
  337. crackerjack/services/patterns/security/path_traversal.py +221 -0
  338. crackerjack/services/patterns/security/unsafe_operations.py +216 -0
  339. crackerjack/services/patterns/templates.py +62 -0
  340. crackerjack/services/patterns/testing/__init__.py +18 -0
  341. crackerjack/services/patterns/testing/error_patterns.py +107 -0
  342. crackerjack/services/patterns/testing/pytest_output.py +126 -0
  343. crackerjack/services/patterns/tool_output/__init__.py +16 -0
  344. crackerjack/services/patterns/tool_output/bandit.py +72 -0
  345. crackerjack/services/patterns/tool_output/other.py +97 -0
  346. crackerjack/services/patterns/tool_output/pyright.py +67 -0
  347. crackerjack/services/patterns/tool_output/ruff.py +44 -0
  348. crackerjack/services/patterns/url_sanitization.py +114 -0
  349. crackerjack/services/patterns/utilities.py +42 -0
  350. crackerjack/services/patterns/utils.py +339 -0
  351. crackerjack/services/patterns/validation.py +46 -0
  352. crackerjack/services/patterns/versioning.py +62 -0
  353. crackerjack/services/predictive_analytics.py +21 -8
  354. crackerjack/services/profiler.py +280 -0
  355. crackerjack/services/quality/README.md +415 -0
  356. crackerjack/services/quality/__init__.py +11 -0
  357. crackerjack/services/quality/anomaly_detector.py +392 -0
  358. crackerjack/services/quality/pattern_cache.py +333 -0
  359. crackerjack/services/quality/pattern_detector.py +479 -0
  360. crackerjack/services/quality/qa_orchestrator.py +491 -0
  361. crackerjack/services/{quality_baseline.py → quality/quality_baseline.py} +163 -2
  362. crackerjack/services/{quality_baseline_enhanced.py → quality/quality_baseline_enhanced.py} +4 -1
  363. crackerjack/services/{quality_intelligence.py → quality/quality_intelligence.py} +180 -16
  364. crackerjack/services/regex_patterns.py +58 -2987
  365. crackerjack/services/regex_utils.py +55 -29
  366. crackerjack/services/secure_status_formatter.py +42 -15
  367. crackerjack/services/secure_subprocess.py +35 -2
  368. crackerjack/services/security.py +16 -8
  369. crackerjack/services/server_manager.py +40 -51
  370. crackerjack/services/smart_scheduling.py +46 -6
  371. crackerjack/services/status_authentication.py +3 -3
  372. crackerjack/services/thread_safe_status_collector.py +1 -0
  373. crackerjack/services/tool_filter.py +368 -0
  374. crackerjack/services/tool_version_service.py +9 -5
  375. crackerjack/services/unified_config.py +43 -351
  376. crackerjack/services/vector_store.py +689 -0
  377. crackerjack/services/version_analyzer.py +6 -4
  378. crackerjack/services/version_checker.py +14 -8
  379. crackerjack/services/zuban_lsp_service.py +5 -4
  380. crackerjack/slash_commands/README.md +11 -0
  381. crackerjack/slash_commands/init.md +2 -12
  382. crackerjack/slash_commands/run.md +84 -50
  383. crackerjack/tools/README.md +11 -0
  384. crackerjack/tools/__init__.py +30 -0
  385. crackerjack/tools/_git_utils.py +105 -0
  386. crackerjack/tools/check_added_large_files.py +139 -0
  387. crackerjack/tools/check_ast.py +105 -0
  388. crackerjack/tools/check_json.py +103 -0
  389. crackerjack/tools/check_jsonschema.py +297 -0
  390. crackerjack/tools/check_toml.py +103 -0
  391. crackerjack/tools/check_yaml.py +110 -0
  392. crackerjack/tools/codespell_wrapper.py +72 -0
  393. crackerjack/tools/end_of_file_fixer.py +202 -0
  394. crackerjack/tools/format_json.py +128 -0
  395. crackerjack/tools/mdformat_wrapper.py +114 -0
  396. crackerjack/tools/trailing_whitespace.py +198 -0
  397. crackerjack/tools/validate_regex_patterns.py +7 -3
  398. crackerjack/ui/README.md +11 -0
  399. crackerjack/ui/dashboard_renderer.py +28 -0
  400. crackerjack/ui/templates/README.md +11 -0
  401. crackerjack/utils/console_utils.py +13 -0
  402. crackerjack/utils/dependency_guard.py +230 -0
  403. crackerjack/utils/retry_utils.py +275 -0
  404. crackerjack/workflows/README.md +590 -0
  405. crackerjack/workflows/__init__.py +46 -0
  406. crackerjack/workflows/actions.py +811 -0
  407. crackerjack/workflows/auto_fix.py +444 -0
  408. crackerjack/workflows/container_builder.py +499 -0
  409. crackerjack/workflows/definitions.py +443 -0
  410. crackerjack/workflows/engine.py +177 -0
  411. crackerjack/workflows/event_bridge.py +242 -0
  412. {crackerjack-0.37.9.dist-info → crackerjack-0.45.2.dist-info}/METADATA +678 -98
  413. crackerjack-0.45.2.dist-info/RECORD +478 -0
  414. {crackerjack-0.37.9.dist-info → crackerjack-0.45.2.dist-info}/WHEEL +1 -1
  415. crackerjack/managers/test_manager_backup.py +0 -1075
  416. crackerjack/mcp/tools/execution_tools_backup.py +0 -1011
  417. crackerjack/mixins/__init__.py +0 -3
  418. crackerjack/mixins/error_handling.py +0 -145
  419. crackerjack/services/config.py +0 -358
  420. crackerjack/ui/server_panels.py +0 -125
  421. crackerjack-0.37.9.dist-info/RECORD +0 -231
  422. /crackerjack/adapters/{rust_tool_adapter.py → lsp/_base.py} +0 -0
  423. /crackerjack/adapters/{lsp_client.py → lsp/_client.py} +0 -0
  424. {crackerjack-0.37.9.dist-info → crackerjack-0.45.2.dist-info}/entry_points.txt +0 -0
  425. {crackerjack-0.37.9.dist-info → crackerjack-0.45.2.dist-info}/licenses/LICENSE +0 -0
@@ -3,34 +3,44 @@ import typing as t
3
3
  from contextlib import suppress
4
4
  from pathlib import Path
5
5
 
6
- from rich.console import Console
6
+ from acb.console import Console
7
+ from acb.depends import Inject, depends
7
8
 
8
- from crackerjack.models.protocols import FileSystemInterface, SecurityServiceProtocol
9
+ from crackerjack.core.retry import retry_api_call
10
+ from crackerjack.models.protocols import (
11
+ ChangelogGeneratorProtocol,
12
+ FileSystemInterface,
13
+ GitServiceProtocol,
14
+ RegexPatternsProtocol,
15
+ SecurityServiceProtocol,
16
+ VersionAnalyzerProtocol,
17
+ )
9
18
 
10
19
 
11
20
  class PublishManagerImpl:
21
+ @depends.inject # type: ignore[misc]
12
22
  def __init__(
13
23
  self,
14
- console: Console,
15
- pkg_path: Path,
24
+ git_service: Inject[GitServiceProtocol],
25
+ version_analyzer: Inject[VersionAnalyzerProtocol],
26
+ changelog_generator: Inject[ChangelogGeneratorProtocol],
27
+ filesystem: Inject[FileSystemInterface],
28
+ security: Inject[SecurityServiceProtocol],
29
+ regex_patterns: Inject[RegexPatternsProtocol],
30
+ console: Inject[Console],
31
+ pkg_path: Inject[Path],
16
32
  dry_run: bool = False,
17
- filesystem: FileSystemInterface | None = None,
18
- security: SecurityServiceProtocol | None = None,
19
33
  ) -> None:
34
+ # Foundation dependencies
20
35
  self.console = console
21
36
  self.pkg_path = pkg_path
22
37
  self.dry_run = dry_run
23
38
 
24
- if filesystem is None:
25
- from crackerjack.services.filesystem import FileSystemService
26
-
27
- filesystem = FileSystemService()
28
-
29
- if security is None:
30
- from crackerjack.services.security import SecurityService
31
-
32
- security = SecurityService()
33
-
39
+ # Services injected via ACB DI
40
+ self._git_service = git_service
41
+ self._version_analyzer = version_analyzer
42
+ self._changelog_generator = changelog_generator
43
+ self._regex_patterns = regex_patterns
34
44
  self.filesystem = filesystem
35
45
  self.security = security
36
46
 
@@ -77,9 +87,20 @@ class PublishManagerImpl:
77
87
  pyproject_path = self.pkg_path / "pyproject.toml"
78
88
  try:
79
89
  content = self.filesystem.read_file(pyproject_path)
80
- from crackerjack.services.regex_patterns import update_pyproject_version
81
90
 
82
- new_content = update_pyproject_version(content, new_version)
91
+ # Use injected service or get through ACB DI
92
+ if self._regex_patterns is not None:
93
+ update_pyproject_version_func = (
94
+ self._regex_patterns.update_pyproject_version
95
+ )
96
+ else:
97
+ from acb.depends import depends
98
+
99
+ update_pyproject_version_func = depends.get_sync(
100
+ RegexPatternsProtocol
101
+ ).update_pyproject_version
102
+
103
+ new_content = update_pyproject_version_func(content, new_version)
83
104
  if content != new_content:
84
105
  if not self.dry_run:
85
106
  self.filesystem.write_file(pyproject_path, new_content)
@@ -156,7 +177,7 @@ class PublishManagerImpl:
156
177
  self.console.print(f"[red]❌[/ red] Version bump failed: {e}")
157
178
  raise
158
179
 
159
- def _prompt_for_version_type(self, recommendation=None) -> str:
180
+ def _prompt_for_version_type(self, recommendation: t.Any = None) -> str:
160
181
  try:
161
182
  from rich.prompt import Prompt
162
183
 
@@ -178,17 +199,13 @@ class PublishManagerImpl:
178
199
  )
179
200
  return "patch"
180
201
 
181
- def _get_version_recommendation(self):
202
+ def _get_version_recommendation(self) -> t.Any:
182
203
  """Get AI-powered version bump recommendation based on git history."""
183
204
  try:
184
205
  import asyncio
185
206
 
186
- from crackerjack.services.git import GitService
187
- from crackerjack.services.version_analyzer import VersionAnalyzer
188
-
189
- # Initialize services
190
- git_service = GitService(self.console, self.pkg_path)
191
- version_analyzer = VersionAnalyzer(self.console, git_service)
207
+ # Use injected version analyzer service
208
+ version_analyzer = self._version_analyzer
192
209
 
193
210
  # Get recommendation asynchronously
194
211
  try:
@@ -217,7 +234,7 @@ class PublishManagerImpl:
217
234
  self.console.print(f"[yellow]⚠️[/yellow] Version analysis failed: {e}")
218
235
  return None
219
236
 
220
- def _display_version_analysis(self, recommendation):
237
+ def _display_version_analysis(self, recommendation: t.Any) -> None:
221
238
  """Display version analysis in a compact format."""
222
239
  if not recommendation:
223
240
  return
@@ -323,7 +340,7 @@ class PublishManagerImpl:
323
340
 
324
341
  def build_package(self) -> bool:
325
342
  try:
326
- self.console.print("[yellow]🔨[/ yellow] Building package...")
343
+ self.console.print("[yellow]🔨[/ yellow] Building package")
327
344
 
328
345
  if self.dry_run:
329
346
  return self._handle_dry_run_build()
@@ -390,8 +407,8 @@ class PublishManagerImpl:
390
407
  return False
391
408
 
392
409
  try:
393
- self.console.print("[yellow]🚀[/ yellow] Publishing to PyPI...")
394
- return self._perform_publish_workflow()
410
+ self.console.print("[yellow]🚀[/ yellow] Publishing to PyPI")
411
+ return self._perform_publish_workflow_with_retry()
395
412
  except Exception as e:
396
413
  self.console.print(f"[red]❌[/ red] Publish error: {e}")
397
414
  return False
@@ -408,6 +425,17 @@ class PublishManagerImpl:
408
425
 
409
426
  return self._execute_publish()
410
427
 
428
+ @retry_api_call(max_attempts=3, delay=2.0, backoff=2.0, max_delay=60.0)
429
+ def _perform_publish_workflow_with_retry(self) -> bool:
430
+ """Perform the publish workflow with retry logic for API connection errors."""
431
+ if self.dry_run:
432
+ return self._handle_dry_run_publish()
433
+
434
+ if not self.build_package():
435
+ return False
436
+
437
+ return self._execute_publish()
438
+
411
439
  def _handle_dry_run_publish(self) -> bool:
412
440
  self.console.print("[yellow]🔍[/ yellow] Would publish package to PyPI")
413
441
  return True
@@ -501,7 +529,28 @@ class PublishManagerImpl:
501
529
  self.console.print(f"[red]❌[/ red] Cleanup error: {e}")
502
530
  return False
503
531
 
532
+ def create_git_tag_local(self, version: str) -> bool:
533
+ """Create git tag locally without pushing (for use with push_with_tags)."""
534
+ try:
535
+ if self.dry_run:
536
+ self.console.print(
537
+ f"[yellow]🔍[/ yellow] Would create git tag: v{version}",
538
+ )
539
+ return True
540
+ result = self._run_command(["git", "tag", f"v{version}"])
541
+ if result.returncode == 0:
542
+ self.console.print(f"[green]🏷️[/ green] Created git tag: v{version}")
543
+ return True
544
+ self.console.print(
545
+ f"[red]❌[/ red] Failed to create tag: {result.stderr}",
546
+ )
547
+ return False
548
+ except Exception as e:
549
+ self.console.print(f"[red]❌[/ red] Tag creation error: {e}")
550
+ return False
551
+
504
552
  def create_git_tag(self, version: str) -> bool:
553
+ """Create git tag and push it immediately (legacy method for standalone use)."""
505
554
  try:
506
555
  if self.dry_run:
507
556
  self.console.print(
@@ -556,12 +605,8 @@ class PublishManagerImpl:
556
605
  def _update_changelog_for_version(self, old_version: str, new_version: str) -> None:
557
606
  """Update changelog with entries from git commits since last version."""
558
607
  try:
559
- from crackerjack.services.changelog_automation import ChangelogGenerator
560
- from crackerjack.services.git import GitService
561
-
562
- # Initialize services
563
- git_service = GitService(self.console, self.pkg_path)
564
- changelog_generator = ChangelogGenerator(self.console, git_service)
608
+ # Use injected changelog generator service
609
+ changelog_generator = self._changelog_generator
565
610
 
566
611
  # Look for changelog file
567
612
  changelog_path = self.pkg_path / "CHANGELOG.md"
@@ -1,11 +1,30 @@
1
+ import os
1
2
  from pathlib import Path
2
3
 
4
+ import psutil
5
+ from acb.console import Console
6
+ from acb.depends import Inject, depends
7
+
8
+ from crackerjack.config.settings import CrackerjackSettings
3
9
  from crackerjack.models.protocols import OptionsProtocol
4
10
 
5
11
 
6
12
  class TestCommandBuilder:
7
- def __init__(self, pkg_path: Path) -> None:
8
- self.pkg_path = pkg_path
13
+ @depends.inject
14
+ def __init__(
15
+ self,
16
+ pkg_path: Inject[Path],
17
+ console: Inject[Console],
18
+ settings: Inject[CrackerjackSettings],
19
+ ) -> None:
20
+ # Normalize to pathlib.Path to avoid async path methods
21
+ try:
22
+ self.pkg_path = Path(str(pkg_path))
23
+ except Exception:
24
+ self.pkg_path = Path(pkg_path)
25
+
26
+ self.console = console
27
+ self.settings = settings
9
28
 
10
29
  def build_command(self, options: OptionsProtocol) -> list[str]:
11
30
  cmd = ["uv", "run", "python", "-m", "pytest"]
@@ -19,11 +38,185 @@ class TestCommandBuilder:
19
38
 
20
39
  return cmd
21
40
 
22
- def get_optimal_workers(self, options: OptionsProtocol) -> int:
23
- if hasattr(options, "test_workers") and options.test_workers:
41
+ def _handle_not_implemented_error(self, print_info: bool) -> int:
42
+ """Handle NotImplementedError specifically."""
43
+ if print_info and self.console:
44
+ self.console.print(
45
+ "[yellow]⚠️ CPU detection unavailable, using 2 workers[/yellow]"
46
+ )
47
+ return 2
48
+
49
+ def _handle_general_error(self, print_info: bool, e: Exception) -> int:
50
+ """Handle general exceptions gracefully."""
51
+ if print_info and self.console:
52
+ self.console.print(
53
+ f"[yellow]⚠️ Worker detection failed: {e}. Using 2 workers.[/yellow]"
54
+ )
55
+ return 2
56
+
57
+ def get_optimal_workers(
58
+ self, options: OptionsProtocol, print_info: bool = True
59
+ ) -> int | str:
60
+ """Calculate optimal worker count using pytest-xdist.
61
+
62
+ This method leverages pytest-xdist's built-in '-n auto' for CPU detection
63
+ while adding memory safety checks and support for custom worker configurations.
64
+
65
+ Worker Selection Logic:
66
+ ----------------------
67
+ 1. Emergency rollback: CRACKERJACK_DISABLE_AUTO_WORKERS=1 → 1 worker
68
+ 2. Explicit value (test_workers > 0): Use as-is
69
+ 3. Auto-detect (test_workers = 0 AND auto_detect_workers=True): Return "auto"
70
+ 4. Legacy mode (test_workers = 0 AND auto_detect_workers=False): 1 worker
71
+ 5. Fractional (test_workers < 0): Divide CPU count by abs(value)
72
+
73
+ Safety Bounds:
74
+ -------------
75
+ - Minimum: 1 worker (sequential execution)
76
+ - Maximum: 8 workers (configurable via settings.testing.max_workers)
77
+ - Memory: 2GB per worker minimum (configurable)
78
+
79
+ Examples:
80
+ --------
81
+ >>> options = Options(test_workers=4)
82
+ >>> builder.get_optimal_workers(options)
83
+ 4 # Explicit value
84
+
85
+ >>> options = Options(test_workers=0) # auto_detect_workers=True
86
+ >>> builder.get_optimal_workers(options)
87
+ "auto" # Delegates to pytest-xdist
88
+
89
+ >>> options = Options(test_workers=-2) # 8-core machine
90
+ >>> builder.get_optimal_workers(options)
91
+ 4 # 8 // 2 = 4 (with memory safety check)
92
+
93
+ Returns:
94
+ int | str: Number of workers (1-8) or "auto" for pytest-xdist detection
95
+
96
+ Raises:
97
+ Never raises - returns safe default (2) on any error
98
+ """
99
+ try:
100
+ # Check for emergency rollback
101
+ if self._check_emergency_rollback(print_info):
102
+ return 1
103
+
104
+ # Check explicit worker count
105
+ explicit_result = self._check_explicit_workers(options, print_info)
106
+ if explicit_result is not None:
107
+ return explicit_result
108
+
109
+ # Check auto-detection
110
+ auto_result = self._check_auto_detection(options, print_info)
111
+ if auto_result is not None:
112
+ return auto_result
113
+
114
+ # Check fractional workers
115
+ fractional_result = self._check_fractional_workers(options, print_info)
116
+ if fractional_result is not None:
117
+ return fractional_result
118
+
119
+ # Safe default if no conditions match
120
+ return 2
121
+
122
+ except NotImplementedError:
123
+ return self._handle_not_implemented_error(print_info)
124
+ except Exception as e:
125
+ return self._handle_general_error(print_info, e)
126
+
127
+ def _check_emergency_rollback(self, print_info: bool) -> bool:
128
+ """Check for emergency rollback via environment variable."""
129
+ if os.getenv("CRACKERJACK_DISABLE_AUTO_WORKERS") == "1":
130
+ if print_info and self.console:
131
+ self.console.print(
132
+ "[yellow]⚠️ Auto-detection disabled via environment variable[/yellow]"
133
+ )
134
+ return True
135
+ return False
136
+
137
+ def _check_explicit_workers(
138
+ self, options: OptionsProtocol, print_info: bool
139
+ ) -> int | None:
140
+ """Check for explicit worker count."""
141
+ if hasattr(options, "test_workers") and options.test_workers > 0:
24
142
  return options.test_workers
143
+ return None
144
+
145
+ def _check_auto_detection(
146
+ self, options: OptionsProtocol, print_info: bool
147
+ ) -> str | int | None:
148
+ """Check for auto-detection setting."""
149
+ if hasattr(options, "test_workers") and options.test_workers == 0:
150
+ # Check if auto-detection is enabled in settings
151
+ if self.settings and self.settings.testing.auto_detect_workers:
152
+ # Show message only when getting optimal workers with print_info=True
153
+ if print_info and self.console:
154
+ self.console.print(
155
+ "[cyan]🔧 Using pytest-xdist auto-detection for workers[/cyan]"
156
+ )
157
+ return "auto" # pytest-xdist will handle CPU detection
158
+
159
+ # Legacy behavior: auto_detect_workers=False
160
+ return 1
161
+ return None
162
+
163
+ def _check_fractional_workers(
164
+ self, options: OptionsProtocol, print_info: bool
165
+ ) -> int | None:
166
+ """Check for fractional worker setting."""
167
+ if hasattr(options, "test_workers") and options.test_workers < 0:
168
+ import multiprocessing
169
+
170
+ cpu_count = multiprocessing.cpu_count()
171
+ divisor = abs(options.test_workers)
172
+ workers = max(1, cpu_count // divisor)
25
173
 
26
- return 1
174
+ # Apply memory safety check
175
+ workers = self._apply_memory_limit(workers)
176
+
177
+ if print_info and self.console:
178
+ self.console.print(
179
+ f"[cyan]🔧 Fractional workers: {cpu_count} cores ÷ {divisor} = {workers} workers[/cyan]"
180
+ )
181
+
182
+ return workers
183
+ return None
184
+
185
+ def _apply_memory_limit(self, workers: int) -> int:
186
+ """Limit workers based on available memory to prevent OOM.
187
+
188
+ Args:
189
+ workers: Desired number of workers
190
+
191
+ Returns:
192
+ int: Worker count limited by available memory
193
+ """
194
+ try:
195
+ # Get memory threshold from settings (default 2GB per worker)
196
+ memory_per_worker = (
197
+ self.settings.testing.memory_per_worker_gb if self.settings else 2.0
198
+ )
199
+
200
+ # Calculate available memory in GB
201
+ available_gb = psutil.virtual_memory().available / (1024**3)
202
+
203
+ # Calculate max workers based on memory
204
+ max_by_memory = max(1, int(available_gb / memory_per_worker))
205
+
206
+ # Return the minimum of desired workers and memory-limited workers
207
+ limited_workers = min(workers, max_by_memory)
208
+
209
+ # Log if we're limiting due to memory
210
+ if limited_workers < workers and self.console:
211
+ self.console.print(
212
+ f"[yellow]⚠️ Limited to {limited_workers} workers (available memory: {available_gb:.1f}GB)[/yellow]"
213
+ )
214
+
215
+ return limited_workers
216
+
217
+ except Exception:
218
+ # Conservative fallback if psutil fails
219
+ return min(workers, 4)
27
220
 
28
221
  def get_test_timeout(self, options: OptionsProtocol) -> int:
29
222
  if hasattr(options, "test_timeout") and options.test_timeout:
@@ -33,20 +226,86 @@ class TestCommandBuilder:
33
226
  return 900
34
227
  return 300
35
228
 
229
+ def _detect_package_name(self) -> str:
230
+ """Detect the main package name for coverage reporting."""
231
+ # Method 1: Try to read from pyproject.toml
232
+ pyproject_path = self.pkg_path / "pyproject.toml"
233
+ if pyproject_path.exists():
234
+ from contextlib import suppress
235
+
236
+ with suppress(Exception):
237
+ import tomllib
238
+
239
+ with pyproject_path.open("rb") as f:
240
+ data = tomllib.load(f)
241
+ project_name = data.get("project", {}).get("name")
242
+ if project_name:
243
+ # Convert project name to package name (hyphens to underscores)
244
+ return project_name.replace("-", "_")
245
+ # Fall back to directory detection
246
+
247
+ # Method 2: Look for Python packages in the project root
248
+ for item in self.pkg_path.iterdir():
249
+ if (
250
+ item.is_dir()
251
+ and not item.name.startswith(".")
252
+ and item.name not in ("tests", "docs", "build", "dist", "__pycache__")
253
+ and (item / "__init__.py").exists()
254
+ ):
255
+ return item.name
256
+
257
+ # Method 3: Fallback to crackerjack if nothing found (for crackerjack itself)
258
+ return "crackerjack"
259
+
36
260
  def _add_coverage_options(self, cmd: list[str], options: OptionsProtocol) -> None:
261
+ # Determine package name from project structure
262
+ package_name = self._detect_package_name()
263
+
37
264
  cmd.extend(
38
265
  [
39
- "--cov=crackerjack",
266
+ f"--cov={package_name}",
40
267
  "--cov-report=term-missing",
41
268
  "--cov-report=html",
269
+ "--cov-report=json", # Required for badge updates
42
270
  "--cov-fail-under=0",
43
271
  ]
44
272
  )
45
273
 
46
274
  def _add_worker_options(self, cmd: list[str], options: OptionsProtocol) -> None:
275
+ """Add pytest-xdist worker options with proper distribution strategy.
276
+
277
+ Args:
278
+ cmd: Command list to append worker options to
279
+ options: Test options containing worker configuration
280
+ """
47
281
  workers = self.get_optimal_workers(options)
48
- if workers > 1:
49
- cmd.extend(["-n", str(workers)])
282
+
283
+ # Skip benchmarks for parallelization (results get skewed)
284
+ if hasattr(options, "benchmark") and options.benchmark:
285
+ if self.console:
286
+ self.console.print(
287
+ "[yellow]⚠️ Benchmarks running sequentially (parallel execution skews results)[/yellow]"
288
+ )
289
+ return
290
+
291
+ if workers == "auto":
292
+ # Use pytest-xdist's native auto-detection
293
+ cmd.extend(["-n", "auto", "--dist=loadfile"])
294
+ if self.console:
295
+ self.console.print(
296
+ "[cyan]🚀 Tests running with auto-detected workers (--dist=loadfile)[/cyan]"
297
+ )
298
+ elif isinstance(workers, int) and workers > 1:
299
+ # Explicit worker count
300
+ cmd.extend(["-n", str(workers), "--dist=loadfile"])
301
+ if self.console:
302
+ self.console.print(
303
+ f"[cyan]🚀 Tests running with {workers} workers (--dist=loadfile)[/cyan]"
304
+ )
305
+ else:
306
+ # Sequential execution (workers == 1)
307
+ if self.console:
308
+ self.console.print("[cyan]🧪 Tests running sequentially[/cyan]")
50
309
 
51
310
  def _add_benchmark_options(self, cmd: list[str], options: OptionsProtocol) -> None:
52
311
  if hasattr(options, "benchmark") and options.benchmark:
@@ -63,11 +322,30 @@ class TestCommandBuilder:
63
322
  cmd.extend(["--timeout", str(timeout)])
64
323
 
65
324
  def _add_verbosity_options(self, cmd: list[str], options: OptionsProtocol) -> None:
66
- cmd.append("-v")
325
+ """Add verbosity options with enhanced detail levels.
326
+
327
+ Verbosity Levels:
328
+ - Standard (-v): Basic test names
329
+ - Verbose (-vv): Assertions, captured output, test details
330
+ - Extra verbose (-vvv): Full locals, all test internals (ai_debug mode)
331
+ """
332
+ # Determine verbosity level
333
+ if options.verbose:
334
+ if getattr(options, "ai_debug", False):
335
+ cmd.append("-vvv") # Extra verbose for AI debugging
336
+ self.console.print("[cyan]🔍 Using extra verbose mode (-vvv)[/cyan]")
337
+ else:
338
+ cmd.append("-vv") # Double verbose shows more context
339
+ self.console.print("[cyan]🔍 Using verbose mode (-vv)[/cyan]")
340
+ else:
341
+ cmd.append("-v") # Standard verbose
67
342
 
68
343
  cmd.extend(
69
344
  [
70
- "--tb=short",
345
+ # Longer tracebacks in verbose mode
346
+ "--tb=long" if options.verbose else "--tb=short",
347
+ # Show all test outcomes summary (not just failures)
348
+ "-ra",
71
349
  "--strict-markers",
72
350
  "--strict-config",
73
351
  ]
@@ -85,7 +363,7 @@ class TestCommandBuilder:
85
363
  cmd.append(str(self.pkg_path))
86
364
 
87
365
  def build_specific_test_command(self, test_pattern: str) -> list[str]:
88
- cmd = ["uv", "run", "python", "-m", "pytest", "-v"]
366
+ cmd = ["uv", "run", "python", "-m", "pytest", "-v"] # Always use verbose mode
89
367
 
90
368
  cmd.extend(
91
369
  [
@@ -108,6 +386,6 @@ class TestCommandBuilder:
108
386
  "-m",
109
387
  "pytest",
110
388
  "--collect-only",
111
- "--quiet",
389
+ # Removed --quiet to ensure collection headers are visible
112
390
  "tests" if (self.pkg_path / "tests").exists() else ".",
113
391
  ]