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
crackerjack/api.py ADDED
@@ -0,0 +1,647 @@
1
+ import asyncio
2
+ import typing as t
3
+ from dataclasses import dataclass
4
+ from pathlib import Path
5
+
6
+ from acb.console import Console
7
+ from acb.depends import depends
8
+
9
+ from .code_cleaner import CleaningResult, CodeCleaner, PackageCleaningResult
10
+ from .core.workflow_orchestrator import WorkflowOrchestrator
11
+ from .errors import CrackerjackError, ErrorCode
12
+ from .interactive import InteractiveCLI, InteractiveWorkflowOptions
13
+ from .models.config import WorkflowOptions
14
+ from .services.regex_patterns import SAFE_PATTERNS
15
+
16
+
17
+ @dataclass
18
+ class QualityCheckResult:
19
+ success: bool
20
+ fast_hooks_passed: bool
21
+ comprehensive_hooks_passed: bool
22
+ errors: list[str]
23
+ warnings: list[str]
24
+ duration: float
25
+
26
+
27
+ @dataclass
28
+ class TestResult:
29
+ success: bool
30
+ passed_count: int
31
+ failed_count: int
32
+ coverage_percentage: float
33
+ duration: float
34
+ errors: list[str]
35
+
36
+
37
+ @dataclass
38
+ class PublishResult:
39
+ success: bool
40
+ version: str
41
+ published_to: list[str]
42
+ errors: list[str]
43
+
44
+
45
+ class CrackerjackAPI:
46
+ def __init__(
47
+ self,
48
+ project_path: Path | None = None,
49
+ console: Console | None = None,
50
+ verbose: bool = False,
51
+ ) -> None:
52
+ self.project_path = project_path or Path.cwd()
53
+ self.console = console or depends.get_sync(Console)
54
+ self.verbose = verbose
55
+
56
+ self.orchestrator = WorkflowOrchestrator(
57
+ pkg_path=self.project_path,
58
+ verbose=self.verbose,
59
+ )
60
+
61
+ self.container = t.cast(t.Any, getattr(self.orchestrator, "container", None))
62
+
63
+ self._code_cleaner: CodeCleaner | None = None
64
+ self._interactive_cli: InteractiveCLI | None = None
65
+
66
+ import logging
67
+
68
+ self.logger = logging.getLogger("crackerjack.api")
69
+
70
+ @property
71
+ def code_cleaner(self) -> CodeCleaner:
72
+ if self._code_cleaner is None:
73
+ self._code_cleaner = CodeCleaner(
74
+ console=self.console, base_directory=self.project_path
75
+ )
76
+ return self._code_cleaner
77
+
78
+ @property
79
+ def interactive_cli(self) -> InteractiveCLI:
80
+ if self._interactive_cli is None:
81
+ self._interactive_cli = InteractiveCLI(console=self.console)
82
+ return self._interactive_cli
83
+
84
+ def run_quality_checks(
85
+ self,
86
+ fast_only: bool = False,
87
+ autofix: bool = True,
88
+ ) -> QualityCheckResult:
89
+ import asyncio
90
+ import time
91
+
92
+ start_time = time.time()
93
+
94
+ try:
95
+ self.logger.info("Starting quality checks")
96
+
97
+ options = self._create_options(autofix=autofix, skip_hooks=False)
98
+
99
+ success = asyncio.run(
100
+ self.orchestrator.pipeline.run_complete_workflow(options),
101
+ )
102
+
103
+ duration = time.time() - start_time
104
+
105
+ return QualityCheckResult(
106
+ success=success,
107
+ fast_hooks_passed=success,
108
+ comprehensive_hooks_passed=success if not fast_only else True,
109
+ errors=[] if success else ["Quality checks failed"],
110
+ warnings=[],
111
+ duration=duration,
112
+ )
113
+
114
+ except Exception as e:
115
+ duration = time.time() - start_time
116
+ self.logger.exception(f"Quality checks failed: {e}")
117
+
118
+ return QualityCheckResult(
119
+ success=False,
120
+ fast_hooks_passed=False,
121
+ comprehensive_hooks_passed=False,
122
+ errors=[str(e)],
123
+ warnings=[],
124
+ duration=duration,
125
+ )
126
+
127
+ def clean_code(
128
+ self,
129
+ target_dir: Path | None = None,
130
+ backup: bool = True,
131
+ safe_mode: bool = True,
132
+ ) -> list[CleaningResult] | PackageCleaningResult:
133
+ target_dir = target_dir or self._get_package_root()
134
+ self.logger.info(f"Cleaning code in {target_dir} (safe_mode={safe_mode})")
135
+
136
+ self._validate_code_before_cleaning(target_dir)
137
+
138
+ if safe_mode:
139
+ self.console.print(
140
+ "[green]🛡️ Using safe mode with comprehensive backup protection[/green]"
141
+ )
142
+ return self._execute_safe_code_cleaning(target_dir)
143
+ else:
144
+ self.console.print(
145
+ "[yellow]⚠️ Legacy mode - backup protection still enabled for safety[/yellow]"
146
+ )
147
+ self._notify_backup_status(backup)
148
+ return self._execute_code_cleaning(target_dir)
149
+
150
+ def _validate_code_before_cleaning(self, target_dir: Path) -> None:
151
+ todos_found = self._check_for_todos(target_dir)
152
+ if todos_found:
153
+ self._handle_todos_found(todos_found, target_dir)
154
+
155
+ def _handle_todos_found(
156
+ self,
157
+ todos_found: list[tuple[Path, int, str]],
158
+ target_dir: Path,
159
+ ) -> None:
160
+ todo_count = len(todos_found)
161
+ self.console.print(f"[red]❌ Found {todo_count} TODO(s) in codebase[/ red]")
162
+ self.console.print(
163
+ "[yellow]Please resolve all TODOs before running code cleaning (-x)[/ yellow]",
164
+ )
165
+
166
+ self._display_todo_summary(todos_found, target_dir, todo_count)
167
+
168
+ raise CrackerjackError(
169
+ message=f"Found {todo_count} TODO(s) in codebase. Resolve them before cleaning.",
170
+ error_code=ErrorCode.VALIDATION_ERROR,
171
+ )
172
+
173
+ def _display_todo_summary(
174
+ self,
175
+ todos_found: list[tuple[Path, int, str]],
176
+ target_dir: Path,
177
+ todo_count: int,
178
+ ) -> None:
179
+ for _i, (file_path, line_no, content) in enumerate(todos_found[:5]):
180
+ relative_path = file_path.relative_to(target_dir)
181
+ self.console.print(f" {relative_path}: {line_no}: {content.strip()}")
182
+
183
+ if todo_count > 5:
184
+ self.console.print(f" ... and {todo_count - 5} more")
185
+
186
+ def _notify_backup_status(self, backup: bool) -> None:
187
+ if backup:
188
+ self.console.print("[yellow]Note: Backup files will be created[/ yellow]")
189
+
190
+ def _execute_safe_code_cleaning(self, target_dir: Path) -> PackageCleaningResult:
191
+ try:
192
+ result = self.code_cleaner.clean_files_with_backup(target_dir)
193
+ self._report_safe_cleaning_results(result)
194
+ return result
195
+ except Exception as e:
196
+ self._handle_cleaning_error(e)
197
+
198
+ def _execute_code_cleaning(self, target_dir: Path) -> list[CleaningResult]:
199
+ try:
200
+ results = self.code_cleaner.clean_files(target_dir, use_backup=True)
201
+
202
+ if isinstance(results, list):
203
+ self._report_cleaning_results(results)
204
+ else:
205
+ self._report_safe_cleaning_results(results)
206
+ results = results.file_results
207
+
208
+ return results
209
+ except Exception as e:
210
+ self._handle_cleaning_error(e)
211
+
212
+ def _report_safe_cleaning_results(self, result: PackageCleaningResult) -> None:
213
+ if result.overall_success:
214
+ self.console.print(
215
+ f"[green]🎉 Package cleaning completed successfully![/green] "
216
+ f"({result.successful_files}/{result.total_files} files cleaned)"
217
+ )
218
+ else:
219
+ self.console.print(
220
+ f"[red]❌ Package cleaning failed![/red] "
221
+ f"({result.failed_files}/{result.total_files} files failed)"
222
+ )
223
+
224
+ if result.backup_restored:
225
+ self.console.print(
226
+ "[yellow]⚠️ Files were automatically restored from backup[/yellow]"
227
+ )
228
+
229
+ if result.backup_metadata:
230
+ self.console.print(
231
+ f"[blue]📦 Backup available at: {result.backup_metadata.backup_directory}[/blue]"
232
+ )
233
+
234
+ def _report_cleaning_results(self, results: list[CleaningResult]) -> None:
235
+ successful = sum(1 for r in results if r.success)
236
+ failed = len(results) - successful
237
+
238
+ if successful > 0:
239
+ self.console.print(
240
+ f"[green]✅ Successfully cleaned {successful} files[/ green]",
241
+ )
242
+ if failed > 0:
243
+ self.console.print(f"[red]❌ Failed to clean {failed} files[/ red]")
244
+
245
+ def _handle_cleaning_error(self, error: Exception) -> t.NoReturn:
246
+ self.logger.error(f"Code cleaning failed: {error}")
247
+ raise CrackerjackError(
248
+ message=f"Code cleaning failed: {error}",
249
+ error_code=ErrorCode.CODE_CLEANING_ERROR,
250
+ ) from error
251
+
252
+ def run_tests(
253
+ self,
254
+ coverage: bool = False,
255
+ workers: int | None = None,
256
+ timeout: int | None = None,
257
+ ) -> TestResult:
258
+ import time
259
+
260
+ start_time = time.time()
261
+
262
+ try:
263
+ self.logger.info("Running tests")
264
+
265
+ options = self._create_options(
266
+ test=True,
267
+ test_workers=workers or 0,
268
+ test_timeout=timeout or 0,
269
+ )
270
+
271
+ success = asyncio.run(
272
+ self.orchestrator.pipeline.run_complete_workflow(options),
273
+ )
274
+
275
+ duration = time.time() - start_time
276
+
277
+ return TestResult(
278
+ success=success,
279
+ passed_count=self._extract_test_passed_count(),
280
+ failed_count=self._extract_test_failed_count(),
281
+ coverage_percentage=self._extract_coverage_percentage(),
282
+ duration=duration,
283
+ errors=[] if success else ["Test execution failed"],
284
+ )
285
+
286
+ except Exception as e:
287
+ duration = time.time() - start_time
288
+ self.logger.exception(f"Test execution failed: {e}")
289
+
290
+ return TestResult(
291
+ success=False,
292
+ passed_count=0,
293
+ failed_count=0,
294
+ coverage_percentage=0.0,
295
+ duration=duration,
296
+ errors=[str(e)],
297
+ )
298
+
299
+ def publish_package(
300
+ self,
301
+ version_bump: str | None = None,
302
+ dry_run: bool = False,
303
+ ) -> PublishResult:
304
+ try:
305
+ self.logger.info(
306
+ f"Publishing package (version_bump={version_bump}, dry_run={dry_run})",
307
+ )
308
+
309
+ options = self._create_options(
310
+ bump=version_bump,
311
+ publish="pypi" if not dry_run else None,
312
+ )
313
+
314
+ success = asyncio.run(
315
+ self.orchestrator.pipeline.run_complete_workflow(options),
316
+ )
317
+
318
+ return PublishResult(
319
+ success=success,
320
+ version=self._extract_current_version(),
321
+ published_to=["pypi"] if success and not dry_run else [],
322
+ errors=[] if success else ["Publishing failed"],
323
+ )
324
+
325
+ except Exception as e:
326
+ self.logger.exception(f"Package publishing failed: {e}")
327
+
328
+ return PublishResult(
329
+ success=False,
330
+ version="",
331
+ published_to=[],
332
+ errors=[str(e)],
333
+ )
334
+
335
+ def run_interactive_workflow(
336
+ self,
337
+ options: InteractiveWorkflowOptions | None = None,
338
+ ) -> bool:
339
+ options = options or InteractiveWorkflowOptions()
340
+
341
+ self.logger.info("Starting interactive workflow")
342
+
343
+ try:
344
+ return self.interactive_cli.run_interactive_workflow(options)
345
+ except Exception as e:
346
+ self.logger.exception(f"Interactive workflow failed: {e}")
347
+ self.console.print(f"[red]❌ Interactive workflow failed: {e}[/ red]")
348
+ return False
349
+
350
+ def create_workflow_options(
351
+ self,
352
+ clean: bool = False,
353
+ test: bool = False,
354
+ publish: str | None = None,
355
+ bump: str | None = None,
356
+ commit: bool = False,
357
+ create_pr: bool = False,
358
+ **kwargs: t.Any,
359
+ ) -> WorkflowOptions:
360
+ from .models.config import (
361
+ CleaningConfig,
362
+ ExecutionConfig,
363
+ GitConfig,
364
+ PublishConfig,
365
+ TestConfig,
366
+ )
367
+ from .models.config import (
368
+ WorkflowOptions as ModelsWorkflowOptions,
369
+ )
370
+
371
+ verbose = kwargs.pop("verbose", False)
372
+
373
+ options = ModelsWorkflowOptions()
374
+
375
+ if clean:
376
+ options.cleaning = CleaningConfig(clean=True)
377
+ if test:
378
+ options.testing = TestConfig(test=True)
379
+ if publish or bump:
380
+ options.publishing = PublishConfig(publish=publish, bump=bump)
381
+ if commit or create_pr:
382
+ options.git = GitConfig(commit=commit, create_pr=create_pr)
383
+ if verbose:
384
+ options.execution = ExecutionConfig(verbose=True)
385
+
386
+ for key, value in kwargs.items():
387
+ if not hasattr(options, key):
388
+ setattr(options, key, value)
389
+
390
+ return options
391
+
392
+ def get_project_info(self) -> dict[str, t.Any]:
393
+ try:
394
+ pyproject_path = self.project_path / "pyproject.toml"
395
+ setup_py_path = self.project_path / "setup.py"
396
+
397
+ is_python_project = pyproject_path.exists() or setup_py_path.exists()
398
+
399
+ git_dir = self.project_path / ".git"
400
+ is_git_repo = git_dir.exists()
401
+
402
+ python_files = list[t.Any](self.project_path.rglob("*.py"))
403
+
404
+ return {
405
+ "project_path": str(self.project_path),
406
+ "is_python_project": is_python_project,
407
+ "is_git_repo": is_git_repo,
408
+ "python_files_count": len(python_files),
409
+ "has_pyproject_toml": pyproject_path.exists(),
410
+ "has_setup_py": setup_py_path.exists(),
411
+ "has_requirements_txt": (
412
+ self.project_path / "requirements.txt"
413
+ ).exists(),
414
+ "has_tests": any(self.project_path.rglob("test *.py")),
415
+ }
416
+
417
+ except Exception as e:
418
+ self.logger.exception(f"Failed to get project info: {e}")
419
+ return {"error": str(e)}
420
+
421
+ def _create_options(self, **kwargs: t.Any) -> t.Any:
422
+ class Options:
423
+ def __init__(self, **kwargs: t.Any) -> None:
424
+ self.commit = False
425
+ self.interactive = False
426
+ self.no_config_updates = False
427
+ self.verbose = False
428
+ self.clean = False
429
+ self.test = False
430
+ self.autofix = True
431
+ self.publish = None
432
+ self.bump = None
433
+ self.test_workers = 0
434
+ self.test_timeout = 0
435
+
436
+ for key, value in kwargs.items():
437
+ setattr(self, key, value)
438
+
439
+ return Options(**kwargs)
440
+
441
+ def _extract_test_passed_count(self) -> int:
442
+ try:
443
+ test_manager = self.orchestrator.phases.test_manager
444
+ if hasattr(test_manager, "get_test_results"):
445
+ results = t.cast(t.Any, test_manager).get_test_results()
446
+ return getattr(results, "passed_count", 0)
447
+ return 0
448
+ except Exception:
449
+ return 0
450
+
451
+ def _extract_test_failed_count(self) -> int:
452
+ try:
453
+ test_manager = self.orchestrator.phases.test_manager
454
+ if hasattr(test_manager, "get_test_results"):
455
+ results = t.cast(t.Any, test_manager).get_test_results()
456
+ return getattr(results, "failed_count", 0)
457
+ return 0
458
+ except Exception:
459
+ return 0
460
+
461
+ def _extract_coverage_percentage(self) -> float:
462
+ try:
463
+ test_manager = self.orchestrator.phases.test_manager
464
+ if hasattr(test_manager, "get_test_results"):
465
+ results = t.cast(t.Any, test_manager).get_test_results()
466
+ return getattr(results, "coverage_percentage", 0.0)
467
+ return 0.0
468
+ except Exception:
469
+ return 0.0
470
+
471
+ def _extract_current_version(self) -> str:
472
+ try:
473
+ pyproject_path = self.project_path / "pyproject.toml"
474
+ if pyproject_path.exists():
475
+ import tomllib
476
+
477
+ with pyproject_path.open("rb") as f:
478
+ data = tomllib.load(f)
479
+
480
+ if "project" in data and "version" in data["project"]:
481
+ return str(data["project"]["version"])
482
+ if (
483
+ "tool" in data
484
+ and "poetry" in data["tool"]
485
+ and "version" in data["tool"]["poetry"]
486
+ ):
487
+ return str(data["tool"]["poetry"]["version"])
488
+
489
+ import importlib.metadata
490
+
491
+ try:
492
+ return importlib.metadata.version("crackerjack")
493
+ except importlib.metadata.PackageNotFoundError:
494
+ pass
495
+
496
+ return "unknown"
497
+ except Exception:
498
+ return "unknown"
499
+
500
+ def _check_for_todos(self, target_dir: Path) -> list[tuple[Path, int, str]]:
501
+ task_pattern = SAFE_PATTERNS["todo_pattern"]
502
+ python_files = self._get_python_files_for_todo_check(target_dir)
503
+ return self._scan_files_for_todos(python_files, task_pattern)
504
+
505
+ def _get_python_files_for_todo_check(self, target_dir: Path) -> list[Path]:
506
+ python_files: list[Path] = []
507
+ ignore_patterns = self._get_ignore_patterns()
508
+
509
+ for py_file in target_dir.rglob("*.py"):
510
+ if not self._should_skip_file(py_file, ignore_patterns):
511
+ python_files.append(py_file)
512
+
513
+ return python_files
514
+
515
+ def _get_ignore_patterns(self) -> set[str]:
516
+ return {
517
+ "__pycache__",
518
+ ".git",
519
+ ".venv",
520
+ "site-packages",
521
+ ".pytest_cache",
522
+ "build",
523
+ "dist",
524
+ "tests",
525
+ "test",
526
+ "examples",
527
+ "example",
528
+ }
529
+
530
+ def _should_skip_file(self, py_file: Path, ignore_patterns: set[str]) -> bool:
531
+ if py_file.name.startswith("."):
532
+ return True
533
+
534
+ return any(parent.name in ignore_patterns for parent in py_file.parents)
535
+
536
+ def _scan_files_for_todos(
537
+ self,
538
+ python_files: list[Path],
539
+ todo_pattern: t.Any,
540
+ ) -> list[tuple[Path, int, str]]:
541
+ todos_found: list[tuple[Path, int, str]] = []
542
+
543
+ for file_path in python_files:
544
+ file_todos = self._scan_single_file_for_todos(file_path, todo_pattern)
545
+ todos_found.extend(file_todos)
546
+
547
+ return todos_found
548
+
549
+ def _scan_single_file_for_todos(
550
+ self,
551
+ file_path: Path,
552
+ todo_pattern: t.Any,
553
+ ) -> list[tuple[Path, int, str]]:
554
+ todos: list[tuple[Path, int, str]] = []
555
+ from contextlib import suppress
556
+
557
+ with suppress(UnicodeDecodeError, PermissionError):
558
+ with file_path.open() as f:
559
+ for line_no, line in enumerate(f, 1):
560
+ original = line.strip()
561
+ processed = todo_pattern.apply(original)
562
+
563
+ if "todo" in original.lower() and original == processed:
564
+ todos.append((file_path, line_no, line))
565
+
566
+ return todos
567
+
568
+ def _get_package_root(self) -> Path:
569
+ package_name = self._read_package_name_from_pyproject()
570
+ if package_name:
571
+ package_dir = self._find_package_directory_by_name(package_name)
572
+ if package_dir:
573
+ return package_dir
574
+
575
+ fallback_dir = self._find_fallback_package_directory()
576
+ return fallback_dir or self.project_path
577
+
578
+ def _read_package_name_from_pyproject(self) -> str | None:
579
+ pyproject_path = self.project_path / "pyproject.toml"
580
+ if not pyproject_path.exists():
581
+ return None
582
+
583
+ from contextlib import suppress
584
+
585
+ with suppress(Exception):
586
+ import tomllib
587
+
588
+ with pyproject_path.open("rb") as f:
589
+ data = tomllib.load(f)
590
+
591
+ if "project" in data and "name" in data["project"]:
592
+ return str(data["project"]["name"])
593
+
594
+ return None
595
+
596
+ def _find_package_directory_by_name(self, package_name: str) -> Path | None:
597
+ package_dir = self.project_path / package_name
598
+ if package_dir.exists() and package_dir.is_dir():
599
+ return package_dir
600
+ return None
601
+
602
+ def _find_fallback_package_directory(self) -> Path | None:
603
+ package_dir = self.project_path / self.project_path.name
604
+ if self._is_valid_python_package_directory(package_dir):
605
+ return package_dir
606
+ return None
607
+
608
+ def _is_valid_python_package_directory(self, directory: Path) -> bool:
609
+ if not (directory.exists() and directory.is_dir()):
610
+ return False
611
+ return any(directory.glob("*.py"))
612
+
613
+
614
+ def run_quality_checks(
615
+ project_path: Path | None = None,
616
+ fast_only: bool = False,
617
+ autofix: bool = True,
618
+ ) -> QualityCheckResult:
619
+ return CrackerjackAPI(project_path=project_path).run_quality_checks(
620
+ fast_only=fast_only,
621
+ autofix=autofix,
622
+ )
623
+
624
+
625
+ def clean_code(
626
+ project_path: Path | None = None,
627
+ backup: bool = True,
628
+ safe_mode: bool = True,
629
+ ) -> list[CleaningResult] | PackageCleaningResult:
630
+ return CrackerjackAPI(project_path=project_path).clean_code(
631
+ backup=backup, safe_mode=safe_mode
632
+ )
633
+
634
+
635
+ def run_tests(project_path: Path | None = None, coverage: bool = False) -> TestResult:
636
+ return CrackerjackAPI(project_path=project_path).run_tests(coverage=coverage)
637
+
638
+
639
+ def publish_package(
640
+ project_path: Path | None = None,
641
+ version_bump: str | None = None,
642
+ dry_run: bool = False,
643
+ ) -> PublishResult:
644
+ return CrackerjackAPI(project_path=project_path).publish_package(
645
+ version_bump=version_bump,
646
+ dry_run=dry_run,
647
+ )