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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (533) hide show
  1. crackerjack/README.md +19 -0
  2. crackerjack/__init__.py +96 -2
  3. crackerjack/__main__.py +637 -138
  4. crackerjack/adapters/README.md +18 -0
  5. crackerjack/adapters/__init__.py +39 -0
  6. crackerjack/adapters/_output_paths.py +167 -0
  7. crackerjack/adapters/_qa_adapter_base.py +309 -0
  8. crackerjack/adapters/_tool_adapter_base.py +706 -0
  9. crackerjack/adapters/ai/README.md +65 -0
  10. crackerjack/adapters/ai/__init__.py +5 -0
  11. crackerjack/adapters/ai/claude.py +853 -0
  12. crackerjack/adapters/complexity/README.md +53 -0
  13. crackerjack/adapters/complexity/__init__.py +10 -0
  14. crackerjack/adapters/complexity/complexipy.py +641 -0
  15. crackerjack/adapters/dependency/__init__.py +22 -0
  16. crackerjack/adapters/dependency/pip_audit.py +418 -0
  17. crackerjack/adapters/format/README.md +72 -0
  18. crackerjack/adapters/format/__init__.py +11 -0
  19. crackerjack/adapters/format/mdformat.py +313 -0
  20. crackerjack/adapters/format/ruff.py +516 -0
  21. crackerjack/adapters/lint/README.md +47 -0
  22. crackerjack/adapters/lint/__init__.py +11 -0
  23. crackerjack/adapters/lint/codespell.py +273 -0
  24. crackerjack/adapters/lsp/README.md +49 -0
  25. crackerjack/adapters/lsp/__init__.py +27 -0
  26. crackerjack/adapters/lsp/_base.py +194 -0
  27. crackerjack/adapters/lsp/_client.py +358 -0
  28. crackerjack/adapters/lsp/_manager.py +193 -0
  29. crackerjack/adapters/lsp/skylos.py +283 -0
  30. crackerjack/adapters/lsp/zuban.py +557 -0
  31. crackerjack/adapters/refactor/README.md +59 -0
  32. crackerjack/adapters/refactor/__init__.py +12 -0
  33. crackerjack/adapters/refactor/creosote.py +318 -0
  34. crackerjack/adapters/refactor/refurb.py +406 -0
  35. crackerjack/adapters/refactor/skylos.py +494 -0
  36. crackerjack/adapters/sast/README.md +132 -0
  37. crackerjack/adapters/sast/__init__.py +32 -0
  38. crackerjack/adapters/sast/_base.py +201 -0
  39. crackerjack/adapters/sast/bandit.py +423 -0
  40. crackerjack/adapters/sast/pyscn.py +405 -0
  41. crackerjack/adapters/sast/semgrep.py +241 -0
  42. crackerjack/adapters/security/README.md +111 -0
  43. crackerjack/adapters/security/__init__.py +17 -0
  44. crackerjack/adapters/security/gitleaks.py +339 -0
  45. crackerjack/adapters/type/README.md +52 -0
  46. crackerjack/adapters/type/__init__.py +12 -0
  47. crackerjack/adapters/type/pyrefly.py +402 -0
  48. crackerjack/adapters/type/ty.py +402 -0
  49. crackerjack/adapters/type/zuban.py +522 -0
  50. crackerjack/adapters/utility/README.md +51 -0
  51. crackerjack/adapters/utility/__init__.py +10 -0
  52. crackerjack/adapters/utility/checks.py +884 -0
  53. crackerjack/agents/README.md +264 -0
  54. crackerjack/agents/__init__.py +66 -0
  55. crackerjack/agents/architect_agent.py +238 -0
  56. crackerjack/agents/base.py +167 -0
  57. crackerjack/agents/claude_code_bridge.py +641 -0
  58. crackerjack/agents/coordinator.py +600 -0
  59. crackerjack/agents/documentation_agent.py +520 -0
  60. crackerjack/agents/dry_agent.py +585 -0
  61. crackerjack/agents/enhanced_coordinator.py +279 -0
  62. crackerjack/agents/enhanced_proactive_agent.py +185 -0
  63. crackerjack/agents/error_middleware.py +53 -0
  64. crackerjack/agents/formatting_agent.py +230 -0
  65. crackerjack/agents/helpers/__init__.py +9 -0
  66. crackerjack/agents/helpers/performance/__init__.py +22 -0
  67. crackerjack/agents/helpers/performance/performance_ast_analyzer.py +357 -0
  68. crackerjack/agents/helpers/performance/performance_pattern_detector.py +909 -0
  69. crackerjack/agents/helpers/performance/performance_recommender.py +572 -0
  70. crackerjack/agents/helpers/refactoring/__init__.py +22 -0
  71. crackerjack/agents/helpers/refactoring/code_transformer.py +536 -0
  72. crackerjack/agents/helpers/refactoring/complexity_analyzer.py +344 -0
  73. crackerjack/agents/helpers/refactoring/dead_code_detector.py +437 -0
  74. crackerjack/agents/helpers/test_creation/__init__.py +19 -0
  75. crackerjack/agents/helpers/test_creation/test_ast_analyzer.py +216 -0
  76. crackerjack/agents/helpers/test_creation/test_coverage_analyzer.py +643 -0
  77. crackerjack/agents/helpers/test_creation/test_template_generator.py +1031 -0
  78. crackerjack/agents/import_optimization_agent.py +1181 -0
  79. crackerjack/agents/performance_agent.py +325 -0
  80. crackerjack/agents/performance_helpers.py +205 -0
  81. crackerjack/agents/proactive_agent.py +55 -0
  82. crackerjack/agents/refactoring_agent.py +511 -0
  83. crackerjack/agents/refactoring_helpers.py +247 -0
  84. crackerjack/agents/security_agent.py +793 -0
  85. crackerjack/agents/semantic_agent.py +479 -0
  86. crackerjack/agents/semantic_helpers.py +356 -0
  87. crackerjack/agents/test_creation_agent.py +570 -0
  88. crackerjack/agents/test_specialist_agent.py +526 -0
  89. crackerjack/agents/tracker.py +110 -0
  90. crackerjack/api.py +647 -0
  91. crackerjack/cli/README.md +394 -0
  92. crackerjack/cli/__init__.py +24 -0
  93. crackerjack/cli/cache_handlers.py +209 -0
  94. crackerjack/cli/cache_handlers_enhanced.py +680 -0
  95. crackerjack/cli/facade.py +162 -0
  96. crackerjack/cli/formatting.py +13 -0
  97. crackerjack/cli/handlers/__init__.py +85 -0
  98. crackerjack/cli/handlers/advanced.py +103 -0
  99. crackerjack/cli/handlers/ai_features.py +62 -0
  100. crackerjack/cli/handlers/analytics.py +479 -0
  101. crackerjack/cli/handlers/changelog.py +271 -0
  102. crackerjack/cli/handlers/config_handlers.py +16 -0
  103. crackerjack/cli/handlers/coverage.py +84 -0
  104. crackerjack/cli/handlers/documentation.py +280 -0
  105. crackerjack/cli/handlers/main_handlers.py +497 -0
  106. crackerjack/cli/handlers/monitoring.py +371 -0
  107. crackerjack/cli/handlers.py +700 -0
  108. crackerjack/cli/interactive.py +488 -0
  109. crackerjack/cli/options.py +1216 -0
  110. crackerjack/cli/semantic_handlers.py +292 -0
  111. crackerjack/cli/utils.py +19 -0
  112. crackerjack/cli/version.py +19 -0
  113. crackerjack/code_cleaner.py +1307 -0
  114. crackerjack/config/README.md +472 -0
  115. crackerjack/config/__init__.py +275 -0
  116. crackerjack/config/global_lock_config.py +207 -0
  117. crackerjack/config/hooks.py +390 -0
  118. crackerjack/config/loader.py +239 -0
  119. crackerjack/config/settings.py +141 -0
  120. crackerjack/config/tool_commands.py +331 -0
  121. crackerjack/core/README.md +393 -0
  122. crackerjack/core/__init__.py +0 -0
  123. crackerjack/core/async_workflow_orchestrator.py +738 -0
  124. crackerjack/core/autofix_coordinator.py +282 -0
  125. crackerjack/core/container.py +105 -0
  126. crackerjack/core/enhanced_container.py +583 -0
  127. crackerjack/core/file_lifecycle.py +472 -0
  128. crackerjack/core/performance.py +244 -0
  129. crackerjack/core/performance_monitor.py +357 -0
  130. crackerjack/core/phase_coordinator.py +1227 -0
  131. crackerjack/core/proactive_workflow.py +267 -0
  132. crackerjack/core/resource_manager.py +425 -0
  133. crackerjack/core/retry.py +275 -0
  134. crackerjack/core/service_watchdog.py +601 -0
  135. crackerjack/core/session_coordinator.py +239 -0
  136. crackerjack/core/timeout_manager.py +563 -0
  137. crackerjack/core/websocket_lifecycle.py +410 -0
  138. crackerjack/core/workflow/__init__.py +21 -0
  139. crackerjack/core/workflow/workflow_ai_coordinator.py +863 -0
  140. crackerjack/core/workflow/workflow_event_orchestrator.py +1107 -0
  141. crackerjack/core/workflow/workflow_issue_parser.py +714 -0
  142. crackerjack/core/workflow/workflow_phase_executor.py +1158 -0
  143. crackerjack/core/workflow/workflow_security_gates.py +400 -0
  144. crackerjack/core/workflow_orchestrator.py +2243 -0
  145. crackerjack/data/README.md +11 -0
  146. crackerjack/data/__init__.py +8 -0
  147. crackerjack/data/models.py +79 -0
  148. crackerjack/data/repository.py +210 -0
  149. crackerjack/decorators/README.md +180 -0
  150. crackerjack/decorators/__init__.py +35 -0
  151. crackerjack/decorators/error_handling.py +649 -0
  152. crackerjack/decorators/error_handling_decorators.py +334 -0
  153. crackerjack/decorators/helpers.py +58 -0
  154. crackerjack/decorators/patterns.py +281 -0
  155. crackerjack/decorators/utils.py +58 -0
  156. crackerjack/docs/INDEX.md +11 -0
  157. crackerjack/docs/README.md +11 -0
  158. crackerjack/docs/generated/api/API_REFERENCE.md +10895 -0
  159. crackerjack/docs/generated/api/CLI_REFERENCE.md +109 -0
  160. crackerjack/docs/generated/api/CROSS_REFERENCES.md +1755 -0
  161. crackerjack/docs/generated/api/PROTOCOLS.md +3 -0
  162. crackerjack/docs/generated/api/SERVICES.md +1252 -0
  163. crackerjack/documentation/README.md +11 -0
  164. crackerjack/documentation/__init__.py +31 -0
  165. crackerjack/documentation/ai_templates.py +756 -0
  166. crackerjack/documentation/dual_output_generator.py +767 -0
  167. crackerjack/documentation/mkdocs_integration.py +518 -0
  168. crackerjack/documentation/reference_generator.py +1065 -0
  169. crackerjack/dynamic_config.py +678 -0
  170. crackerjack/errors.py +378 -0
  171. crackerjack/events/README.md +11 -0
  172. crackerjack/events/__init__.py +16 -0
  173. crackerjack/events/telemetry.py +175 -0
  174. crackerjack/events/workflow_bus.py +346 -0
  175. crackerjack/exceptions/README.md +301 -0
  176. crackerjack/exceptions/__init__.py +5 -0
  177. crackerjack/exceptions/config.py +4 -0
  178. crackerjack/exceptions/tool_execution_error.py +245 -0
  179. crackerjack/executors/README.md +591 -0
  180. crackerjack/executors/__init__.py +13 -0
  181. crackerjack/executors/async_hook_executor.py +938 -0
  182. crackerjack/executors/cached_hook_executor.py +316 -0
  183. crackerjack/executors/hook_executor.py +1295 -0
  184. crackerjack/executors/hook_lock_manager.py +708 -0
  185. crackerjack/executors/individual_hook_executor.py +739 -0
  186. crackerjack/executors/lsp_aware_hook_executor.py +349 -0
  187. crackerjack/executors/progress_hook_executor.py +282 -0
  188. crackerjack/executors/tool_proxy.py +433 -0
  189. crackerjack/hooks/README.md +485 -0
  190. crackerjack/hooks/lsp_hook.py +93 -0
  191. crackerjack/intelligence/README.md +557 -0
  192. crackerjack/intelligence/__init__.py +37 -0
  193. crackerjack/intelligence/adaptive_learning.py +693 -0
  194. crackerjack/intelligence/agent_orchestrator.py +485 -0
  195. crackerjack/intelligence/agent_registry.py +377 -0
  196. crackerjack/intelligence/agent_selector.py +439 -0
  197. crackerjack/intelligence/integration.py +250 -0
  198. crackerjack/interactive.py +719 -0
  199. crackerjack/managers/README.md +369 -0
  200. crackerjack/managers/__init__.py +11 -0
  201. crackerjack/managers/async_hook_manager.py +135 -0
  202. crackerjack/managers/hook_manager.py +585 -0
  203. crackerjack/managers/publish_manager.py +631 -0
  204. crackerjack/managers/test_command_builder.py +391 -0
  205. crackerjack/managers/test_executor.py +474 -0
  206. crackerjack/managers/test_manager.py +1357 -0
  207. crackerjack/managers/test_progress.py +187 -0
  208. crackerjack/mcp/README.md +374 -0
  209. crackerjack/mcp/__init__.py +0 -0
  210. crackerjack/mcp/cache.py +352 -0
  211. crackerjack/mcp/client_runner.py +121 -0
  212. crackerjack/mcp/context.py +802 -0
  213. crackerjack/mcp/dashboard.py +657 -0
  214. crackerjack/mcp/enhanced_progress_monitor.py +493 -0
  215. crackerjack/mcp/file_monitor.py +394 -0
  216. crackerjack/mcp/progress_components.py +607 -0
  217. crackerjack/mcp/progress_monitor.py +1016 -0
  218. crackerjack/mcp/rate_limiter.py +336 -0
  219. crackerjack/mcp/server.py +24 -0
  220. crackerjack/mcp/server_core.py +526 -0
  221. crackerjack/mcp/service_watchdog.py +505 -0
  222. crackerjack/mcp/state.py +407 -0
  223. crackerjack/mcp/task_manager.py +259 -0
  224. crackerjack/mcp/tools/README.md +27 -0
  225. crackerjack/mcp/tools/__init__.py +19 -0
  226. crackerjack/mcp/tools/core_tools.py +469 -0
  227. crackerjack/mcp/tools/error_analyzer.py +283 -0
  228. crackerjack/mcp/tools/execution_tools.py +384 -0
  229. crackerjack/mcp/tools/intelligence_tool_registry.py +46 -0
  230. crackerjack/mcp/tools/intelligence_tools.py +264 -0
  231. crackerjack/mcp/tools/monitoring_tools.py +628 -0
  232. crackerjack/mcp/tools/proactive_tools.py +367 -0
  233. crackerjack/mcp/tools/progress_tools.py +222 -0
  234. crackerjack/mcp/tools/semantic_tools.py +584 -0
  235. crackerjack/mcp/tools/utility_tools.py +358 -0
  236. crackerjack/mcp/tools/workflow_executor.py +699 -0
  237. crackerjack/mcp/websocket/README.md +31 -0
  238. crackerjack/mcp/websocket/__init__.py +14 -0
  239. crackerjack/mcp/websocket/app.py +54 -0
  240. crackerjack/mcp/websocket/endpoints.py +492 -0
  241. crackerjack/mcp/websocket/event_bridge.py +188 -0
  242. crackerjack/mcp/websocket/jobs.py +406 -0
  243. crackerjack/mcp/websocket/monitoring/__init__.py +25 -0
  244. crackerjack/mcp/websocket/monitoring/api/__init__.py +19 -0
  245. crackerjack/mcp/websocket/monitoring/api/dependencies.py +141 -0
  246. crackerjack/mcp/websocket/monitoring/api/heatmap.py +154 -0
  247. crackerjack/mcp/websocket/monitoring/api/intelligence.py +199 -0
  248. crackerjack/mcp/websocket/monitoring/api/metrics.py +203 -0
  249. crackerjack/mcp/websocket/monitoring/api/telemetry.py +101 -0
  250. crackerjack/mcp/websocket/monitoring/dashboard.py +18 -0
  251. crackerjack/mcp/websocket/monitoring/factory.py +109 -0
  252. crackerjack/mcp/websocket/monitoring/filters.py +10 -0
  253. crackerjack/mcp/websocket/monitoring/metrics.py +64 -0
  254. crackerjack/mcp/websocket/monitoring/models.py +90 -0
  255. crackerjack/mcp/websocket/monitoring/utils.py +171 -0
  256. crackerjack/mcp/websocket/monitoring/websocket_manager.py +78 -0
  257. crackerjack/mcp/websocket/monitoring/websockets/__init__.py +17 -0
  258. crackerjack/mcp/websocket/monitoring/websockets/dependencies.py +126 -0
  259. crackerjack/mcp/websocket/monitoring/websockets/heatmap.py +176 -0
  260. crackerjack/mcp/websocket/monitoring/websockets/intelligence.py +291 -0
  261. crackerjack/mcp/websocket/monitoring/websockets/metrics.py +291 -0
  262. crackerjack/mcp/websocket/monitoring_endpoints.py +21 -0
  263. crackerjack/mcp/websocket/server.py +174 -0
  264. crackerjack/mcp/websocket/websocket_handler.py +276 -0
  265. crackerjack/mcp/websocket_server.py +10 -0
  266. crackerjack/models/README.md +308 -0
  267. crackerjack/models/__init__.py +40 -0
  268. crackerjack/models/config.py +730 -0
  269. crackerjack/models/config_adapter.py +265 -0
  270. crackerjack/models/protocols.py +1535 -0
  271. crackerjack/models/pydantic_models.py +320 -0
  272. crackerjack/models/qa_config.py +145 -0
  273. crackerjack/models/qa_results.py +134 -0
  274. crackerjack/models/resource_protocols.py +299 -0
  275. crackerjack/models/results.py +35 -0
  276. crackerjack/models/semantic_models.py +258 -0
  277. crackerjack/models/task.py +173 -0
  278. crackerjack/models/test_models.py +60 -0
  279. crackerjack/monitoring/README.md +11 -0
  280. crackerjack/monitoring/__init__.py +0 -0
  281. crackerjack/monitoring/ai_agent_watchdog.py +405 -0
  282. crackerjack/monitoring/metrics_collector.py +427 -0
  283. crackerjack/monitoring/regression_prevention.py +580 -0
  284. crackerjack/monitoring/websocket_server.py +406 -0
  285. crackerjack/orchestration/README.md +340 -0
  286. crackerjack/orchestration/__init__.py +43 -0
  287. crackerjack/orchestration/advanced_orchestrator.py +894 -0
  288. crackerjack/orchestration/cache/README.md +312 -0
  289. crackerjack/orchestration/cache/__init__.py +37 -0
  290. crackerjack/orchestration/cache/memory_cache.py +338 -0
  291. crackerjack/orchestration/cache/tool_proxy_cache.py +340 -0
  292. crackerjack/orchestration/config.py +297 -0
  293. crackerjack/orchestration/coverage_improvement.py +180 -0
  294. crackerjack/orchestration/execution_strategies.py +361 -0
  295. crackerjack/orchestration/hook_orchestrator.py +1398 -0
  296. crackerjack/orchestration/strategies/README.md +401 -0
  297. crackerjack/orchestration/strategies/__init__.py +39 -0
  298. crackerjack/orchestration/strategies/adaptive_strategy.py +630 -0
  299. crackerjack/orchestration/strategies/parallel_strategy.py +237 -0
  300. crackerjack/orchestration/strategies/sequential_strategy.py +299 -0
  301. crackerjack/orchestration/test_progress_streamer.py +647 -0
  302. crackerjack/plugins/README.md +11 -0
  303. crackerjack/plugins/__init__.py +15 -0
  304. crackerjack/plugins/base.py +200 -0
  305. crackerjack/plugins/hooks.py +254 -0
  306. crackerjack/plugins/loader.py +335 -0
  307. crackerjack/plugins/managers.py +264 -0
  308. crackerjack/py313.py +191 -0
  309. crackerjack/security/README.md +11 -0
  310. crackerjack/security/__init__.py +0 -0
  311. crackerjack/security/audit.py +197 -0
  312. crackerjack/services/README.md +374 -0
  313. crackerjack/services/__init__.py +9 -0
  314. crackerjack/services/ai/README.md +295 -0
  315. crackerjack/services/ai/__init__.py +7 -0
  316. crackerjack/services/ai/advanced_optimizer.py +878 -0
  317. crackerjack/services/ai/contextual_ai_assistant.py +542 -0
  318. crackerjack/services/ai/embeddings.py +444 -0
  319. crackerjack/services/ai/intelligent_commit.py +328 -0
  320. crackerjack/services/ai/predictive_analytics.py +510 -0
  321. crackerjack/services/anomaly_detector.py +392 -0
  322. crackerjack/services/api_extractor.py +617 -0
  323. crackerjack/services/backup_service.py +467 -0
  324. crackerjack/services/bounded_status_operations.py +530 -0
  325. crackerjack/services/cache.py +369 -0
  326. crackerjack/services/changelog_automation.py +399 -0
  327. crackerjack/services/command_execution_service.py +305 -0
  328. crackerjack/services/config_integrity.py +132 -0
  329. crackerjack/services/config_merge.py +546 -0
  330. crackerjack/services/config_service.py +198 -0
  331. crackerjack/services/config_template.py +493 -0
  332. crackerjack/services/coverage_badge_service.py +173 -0
  333. crackerjack/services/coverage_ratchet.py +381 -0
  334. crackerjack/services/debug.py +733 -0
  335. crackerjack/services/dependency_analyzer.py +460 -0
  336. crackerjack/services/dependency_monitor.py +622 -0
  337. crackerjack/services/documentation_generator.py +493 -0
  338. crackerjack/services/documentation_service.py +704 -0
  339. crackerjack/services/enhanced_filesystem.py +497 -0
  340. crackerjack/services/enterprise_optimizer.py +865 -0
  341. crackerjack/services/error_pattern_analyzer.py +676 -0
  342. crackerjack/services/file_filter.py +221 -0
  343. crackerjack/services/file_hasher.py +149 -0
  344. crackerjack/services/file_io_service.py +361 -0
  345. crackerjack/services/file_modifier.py +615 -0
  346. crackerjack/services/filesystem.py +381 -0
  347. crackerjack/services/git.py +422 -0
  348. crackerjack/services/health_metrics.py +615 -0
  349. crackerjack/services/heatmap_generator.py +744 -0
  350. crackerjack/services/incremental_executor.py +380 -0
  351. crackerjack/services/initialization.py +823 -0
  352. crackerjack/services/input_validator.py +668 -0
  353. crackerjack/services/intelligent_commit.py +327 -0
  354. crackerjack/services/log_manager.py +289 -0
  355. crackerjack/services/logging.py +228 -0
  356. crackerjack/services/lsp_client.py +628 -0
  357. crackerjack/services/memory_optimizer.py +414 -0
  358. crackerjack/services/metrics.py +587 -0
  359. crackerjack/services/monitoring/README.md +30 -0
  360. crackerjack/services/monitoring/__init__.py +9 -0
  361. crackerjack/services/monitoring/dependency_monitor.py +678 -0
  362. crackerjack/services/monitoring/error_pattern_analyzer.py +676 -0
  363. crackerjack/services/monitoring/health_metrics.py +716 -0
  364. crackerjack/services/monitoring/metrics.py +587 -0
  365. crackerjack/services/monitoring/performance_benchmarks.py +410 -0
  366. crackerjack/services/monitoring/performance_cache.py +388 -0
  367. crackerjack/services/monitoring/performance_monitor.py +569 -0
  368. crackerjack/services/parallel_executor.py +527 -0
  369. crackerjack/services/pattern_cache.py +333 -0
  370. crackerjack/services/pattern_detector.py +478 -0
  371. crackerjack/services/patterns/__init__.py +142 -0
  372. crackerjack/services/patterns/agents.py +107 -0
  373. crackerjack/services/patterns/code/__init__.py +15 -0
  374. crackerjack/services/patterns/code/detection.py +118 -0
  375. crackerjack/services/patterns/code/imports.py +107 -0
  376. crackerjack/services/patterns/code/paths.py +159 -0
  377. crackerjack/services/patterns/code/performance.py +119 -0
  378. crackerjack/services/patterns/code/replacement.py +36 -0
  379. crackerjack/services/patterns/core.py +212 -0
  380. crackerjack/services/patterns/documentation/__init__.py +14 -0
  381. crackerjack/services/patterns/documentation/badges_markdown.py +96 -0
  382. crackerjack/services/patterns/documentation/comments_blocks.py +83 -0
  383. crackerjack/services/patterns/documentation/docstrings.py +89 -0
  384. crackerjack/services/patterns/formatting.py +226 -0
  385. crackerjack/services/patterns/operations.py +339 -0
  386. crackerjack/services/patterns/security/__init__.py +23 -0
  387. crackerjack/services/patterns/security/code_injection.py +122 -0
  388. crackerjack/services/patterns/security/credentials.py +190 -0
  389. crackerjack/services/patterns/security/path_traversal.py +221 -0
  390. crackerjack/services/patterns/security/unsafe_operations.py +216 -0
  391. crackerjack/services/patterns/templates.py +62 -0
  392. crackerjack/services/patterns/testing/__init__.py +18 -0
  393. crackerjack/services/patterns/testing/error_patterns.py +107 -0
  394. crackerjack/services/patterns/testing/pytest_output.py +126 -0
  395. crackerjack/services/patterns/tool_output/__init__.py +16 -0
  396. crackerjack/services/patterns/tool_output/bandit.py +72 -0
  397. crackerjack/services/patterns/tool_output/other.py +97 -0
  398. crackerjack/services/patterns/tool_output/pyright.py +67 -0
  399. crackerjack/services/patterns/tool_output/ruff.py +44 -0
  400. crackerjack/services/patterns/url_sanitization.py +114 -0
  401. crackerjack/services/patterns/utilities.py +42 -0
  402. crackerjack/services/patterns/utils.py +339 -0
  403. crackerjack/services/patterns/validation.py +46 -0
  404. crackerjack/services/patterns/versioning.py +62 -0
  405. crackerjack/services/predictive_analytics.py +523 -0
  406. crackerjack/services/profiler.py +280 -0
  407. crackerjack/services/quality/README.md +415 -0
  408. crackerjack/services/quality/__init__.py +11 -0
  409. crackerjack/services/quality/anomaly_detector.py +392 -0
  410. crackerjack/services/quality/pattern_cache.py +333 -0
  411. crackerjack/services/quality/pattern_detector.py +479 -0
  412. crackerjack/services/quality/qa_orchestrator.py +491 -0
  413. crackerjack/services/quality/quality_baseline.py +395 -0
  414. crackerjack/services/quality/quality_baseline_enhanced.py +649 -0
  415. crackerjack/services/quality/quality_intelligence.py +949 -0
  416. crackerjack/services/regex_patterns.py +58 -0
  417. crackerjack/services/regex_utils.py +483 -0
  418. crackerjack/services/secure_path_utils.py +524 -0
  419. crackerjack/services/secure_status_formatter.py +450 -0
  420. crackerjack/services/secure_subprocess.py +635 -0
  421. crackerjack/services/security.py +239 -0
  422. crackerjack/services/security_logger.py +495 -0
  423. crackerjack/services/server_manager.py +411 -0
  424. crackerjack/services/smart_scheduling.py +167 -0
  425. crackerjack/services/status_authentication.py +460 -0
  426. crackerjack/services/status_security_manager.py +315 -0
  427. crackerjack/services/terminal_utils.py +0 -0
  428. crackerjack/services/thread_safe_status_collector.py +441 -0
  429. crackerjack/services/tool_filter.py +368 -0
  430. crackerjack/services/tool_version_service.py +43 -0
  431. crackerjack/services/unified_config.py +115 -0
  432. crackerjack/services/validation_rate_limiter.py +220 -0
  433. crackerjack/services/vector_store.py +689 -0
  434. crackerjack/services/version_analyzer.py +461 -0
  435. crackerjack/services/version_checker.py +223 -0
  436. crackerjack/services/websocket_resource_limiter.py +438 -0
  437. crackerjack/services/zuban_lsp_service.py +391 -0
  438. crackerjack/slash_commands/README.md +11 -0
  439. crackerjack/slash_commands/__init__.py +59 -0
  440. crackerjack/slash_commands/init.md +112 -0
  441. crackerjack/slash_commands/run.md +197 -0
  442. crackerjack/slash_commands/status.md +127 -0
  443. crackerjack/tools/README.md +11 -0
  444. crackerjack/tools/__init__.py +30 -0
  445. crackerjack/tools/_git_utils.py +105 -0
  446. crackerjack/tools/check_added_large_files.py +139 -0
  447. crackerjack/tools/check_ast.py +105 -0
  448. crackerjack/tools/check_json.py +103 -0
  449. crackerjack/tools/check_jsonschema.py +297 -0
  450. crackerjack/tools/check_toml.py +103 -0
  451. crackerjack/tools/check_yaml.py +110 -0
  452. crackerjack/tools/codespell_wrapper.py +72 -0
  453. crackerjack/tools/end_of_file_fixer.py +202 -0
  454. crackerjack/tools/format_json.py +128 -0
  455. crackerjack/tools/mdformat_wrapper.py +114 -0
  456. crackerjack/tools/trailing_whitespace.py +198 -0
  457. crackerjack/tools/validate_input_validator_patterns.py +236 -0
  458. crackerjack/tools/validate_regex_patterns.py +188 -0
  459. crackerjack/ui/README.md +11 -0
  460. crackerjack/ui/__init__.py +1 -0
  461. crackerjack/ui/dashboard_renderer.py +28 -0
  462. crackerjack/ui/templates/README.md +11 -0
  463. crackerjack/utils/console_utils.py +13 -0
  464. crackerjack/utils/dependency_guard.py +230 -0
  465. crackerjack/utils/retry_utils.py +275 -0
  466. crackerjack/workflows/README.md +590 -0
  467. crackerjack/workflows/__init__.py +46 -0
  468. crackerjack/workflows/actions.py +811 -0
  469. crackerjack/workflows/auto_fix.py +444 -0
  470. crackerjack/workflows/container_builder.py +499 -0
  471. crackerjack/workflows/definitions.py +443 -0
  472. crackerjack/workflows/engine.py +177 -0
  473. crackerjack/workflows/event_bridge.py +242 -0
  474. crackerjack-0.45.2.dist-info/METADATA +1678 -0
  475. crackerjack-0.45.2.dist-info/RECORD +478 -0
  476. {crackerjack-0.18.2.dist-info → crackerjack-0.45.2.dist-info}/WHEEL +1 -1
  477. crackerjack-0.45.2.dist-info/entry_points.txt +2 -0
  478. crackerjack/.gitignore +0 -14
  479. crackerjack/.libcst.codemod.yaml +0 -18
  480. crackerjack/.pdm.toml +0 -1
  481. crackerjack/.pre-commit-config.yaml +0 -91
  482. crackerjack/.pytest_cache/.gitignore +0 -2
  483. crackerjack/.pytest_cache/CACHEDIR.TAG +0 -4
  484. crackerjack/.pytest_cache/README.md +0 -8
  485. crackerjack/.pytest_cache/v/cache/nodeids +0 -1
  486. crackerjack/.pytest_cache/v/cache/stepwise +0 -1
  487. crackerjack/.ruff_cache/.gitignore +0 -1
  488. crackerjack/.ruff_cache/0.1.11/3256171999636029978 +0 -0
  489. crackerjack/.ruff_cache/0.1.14/602324811142551221 +0 -0
  490. crackerjack/.ruff_cache/0.1.4/10355199064880463147 +0 -0
  491. crackerjack/.ruff_cache/0.1.6/15140459877605758699 +0 -0
  492. crackerjack/.ruff_cache/0.1.7/1790508110482614856 +0 -0
  493. crackerjack/.ruff_cache/0.1.9/17041001205004563469 +0 -0
  494. crackerjack/.ruff_cache/0.11.2/4070660268492669020 +0 -0
  495. crackerjack/.ruff_cache/0.11.3/9818742842212983150 +0 -0
  496. crackerjack/.ruff_cache/0.11.4/9818742842212983150 +0 -0
  497. crackerjack/.ruff_cache/0.11.6/3557596832929915217 +0 -0
  498. crackerjack/.ruff_cache/0.11.7/10386934055395314831 +0 -0
  499. crackerjack/.ruff_cache/0.11.7/3557596832929915217 +0 -0
  500. crackerjack/.ruff_cache/0.11.8/530407680854991027 +0 -0
  501. crackerjack/.ruff_cache/0.2.0/10047773857155985907 +0 -0
  502. crackerjack/.ruff_cache/0.2.1/8522267973936635051 +0 -0
  503. crackerjack/.ruff_cache/0.2.2/18053836298936336950 +0 -0
  504. crackerjack/.ruff_cache/0.3.0/12548816621480535786 +0 -0
  505. crackerjack/.ruff_cache/0.3.3/11081883392474770722 +0 -0
  506. crackerjack/.ruff_cache/0.3.4/676973378459347183 +0 -0
  507. crackerjack/.ruff_cache/0.3.5/16311176246009842383 +0 -0
  508. crackerjack/.ruff_cache/0.5.7/1493622539551733492 +0 -0
  509. crackerjack/.ruff_cache/0.5.7/6231957614044513175 +0 -0
  510. crackerjack/.ruff_cache/0.5.7/9932762556785938009 +0 -0
  511. crackerjack/.ruff_cache/0.6.0/11982804814124138945 +0 -0
  512. crackerjack/.ruff_cache/0.6.0/12055761203849489982 +0 -0
  513. crackerjack/.ruff_cache/0.6.2/1206147804896221174 +0 -0
  514. crackerjack/.ruff_cache/0.6.4/1206147804896221174 +0 -0
  515. crackerjack/.ruff_cache/0.6.5/1206147804896221174 +0 -0
  516. crackerjack/.ruff_cache/0.6.7/3657366982708166874 +0 -0
  517. crackerjack/.ruff_cache/0.6.9/285614542852677309 +0 -0
  518. crackerjack/.ruff_cache/0.7.1/1024065805990144819 +0 -0
  519. crackerjack/.ruff_cache/0.7.1/285614542852677309 +0 -0
  520. crackerjack/.ruff_cache/0.7.3/16061516852537040135 +0 -0
  521. crackerjack/.ruff_cache/0.8.4/16354268377385700367 +0 -0
  522. crackerjack/.ruff_cache/0.9.10/12813592349865671909 +0 -0
  523. crackerjack/.ruff_cache/0.9.10/923908772239632759 +0 -0
  524. crackerjack/.ruff_cache/0.9.3/13948373885254993391 +0 -0
  525. crackerjack/.ruff_cache/0.9.9/12813592349865671909 +0 -0
  526. crackerjack/.ruff_cache/0.9.9/8843823720003377982 +0 -0
  527. crackerjack/.ruff_cache/CACHEDIR.TAG +0 -1
  528. crackerjack/crackerjack.py +0 -855
  529. crackerjack/pyproject.toml +0 -214
  530. crackerjack-0.18.2.dist-info/METADATA +0 -420
  531. crackerjack-0.18.2.dist-info/RECORD +0 -59
  532. crackerjack-0.18.2.dist-info/entry_points.txt +0 -4
  533. {crackerjack-0.18.2.dist-info → crackerjack-0.45.2.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,110 @@
1
+ """Validate YAML file syntax.
2
+
3
+ This tool is a native Python implementation replacing pre-commit's
4
+ check-yaml hook. It scans YAML files and validates their syntax.
5
+
6
+ Usage:
7
+ python -m crackerjack.tools.check_yaml [files...]
8
+
9
+ Exit Codes:
10
+ 0: All YAML files are valid
11
+ 1: One or more YAML files have syntax errors
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import argparse
17
+ import sys
18
+ from pathlib import Path
19
+
20
+ import yaml
21
+
22
+ from ._git_utils import get_files_by_extension
23
+
24
+
25
+ def validate_yaml_file(file_path: Path) -> tuple[bool, str | None]:
26
+ """Validate a YAML file's syntax.
27
+
28
+ Args:
29
+ file_path: Path to YAML file to validate
30
+
31
+ Returns:
32
+ Tuple of (is_valid, error_message)
33
+ - is_valid: True if file has valid YAML syntax
34
+ - error_message: Error description if is_valid is False, None otherwise
35
+ """
36
+ try:
37
+ with file_path.open(encoding="utf-8") as f:
38
+ # Load YAML and validate structure
39
+ yaml.safe_load(f)
40
+ return True, None
41
+ except yaml.YAMLError as e:
42
+ return False, str(e)
43
+ except Exception as e:
44
+ return False, f"Error reading file: {e}"
45
+
46
+
47
+ def main(argv: list[str] | None = None) -> int:
48
+ """Main entry point for check-yaml tool.
49
+
50
+ Args:
51
+ argv: Command-line arguments (defaults to sys.argv[1:])
52
+
53
+ Returns:
54
+ Exit code: 0 if all YAML valid, 1 if any errors found
55
+ """
56
+ parser = argparse.ArgumentParser(description="Validate YAML file syntax")
57
+ parser.add_argument(
58
+ "files",
59
+ nargs="*",
60
+ type=Path,
61
+ help="YAML files to check (default: all .yaml/.yml files)",
62
+ )
63
+ parser.add_argument(
64
+ "--unsafe",
65
+ action="store_true",
66
+ help="Use unsafe YAML loader (allows Python object instantiation)",
67
+ )
68
+
69
+ args = parser.parse_args(argv)
70
+
71
+ # Default to all git-tracked YAML files if none specified
72
+ if not args.files:
73
+ # Get all tracked YAML files (respects .gitignore via git ls-files)
74
+ files = get_files_by_extension([".yaml", ".yml"])
75
+ if not files:
76
+ # Fallback to rglob if not in git repo
77
+ files = list(Path.cwd().rglob("*.yaml"))
78
+ files.extend(Path.cwd().rglob("*.yml"))
79
+ else:
80
+ files = args.files
81
+
82
+ # Filter to existing files only
83
+ files = [f for f in files if f.is_file()]
84
+
85
+ if not files:
86
+ print("No YAML files to check") # noqa: T201
87
+ return 0
88
+
89
+ # Process files
90
+ error_count = 0
91
+ for file_path in files:
92
+ is_valid, error_msg = validate_yaml_file(file_path)
93
+
94
+ if not is_valid:
95
+ print(f"✗ {file_path}: {error_msg}", file=sys.stderr) # noqa: T201
96
+ error_count += 1
97
+ else:
98
+ print(f"✓ {file_path}: Valid YAML") # noqa: T201
99
+
100
+ # Return appropriate exit code
101
+ if error_count > 0:
102
+ print(f"\n{error_count} YAML file(s) with errors", file=sys.stderr) # noqa: T201
103
+ return 1
104
+
105
+ print(f"\nAll {len(files)} YAML file(s) are valid") # noqa: T201
106
+ return 0
107
+
108
+
109
+ if __name__ == "__main__":
110
+ sys.exit(main())
@@ -0,0 +1,72 @@
1
+ """Git-aware wrapper for codespell.
2
+
3
+ This wrapper ensures codespell only checks git-tracked files, automatically
4
+ respecting .gitignore patterns without needing manual skip configuration.
5
+
6
+ Usage:
7
+ python -m crackerjack.tools.codespell_wrapper [codespell args...]
8
+
9
+ Exit Codes:
10
+ Same as codespell (0 = no issues, 1 = issues found, etc.)
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import subprocess
16
+ import sys
17
+ from pathlib import Path
18
+
19
+ from ._git_utils import get_git_tracked_files
20
+
21
+
22
+ def main(argv: list[str] | None = None) -> int:
23
+ """Run codespell on git-tracked files only.
24
+
25
+ This wrapper automatically discovers git-tracked files and passes them
26
+ to codespell, ensuring .gitignore patterns are respected without manual
27
+ skip configuration.
28
+
29
+ Args:
30
+ argv: Optional arguments to pass to codespell
31
+
32
+ Returns:
33
+ Exit code from codespell command
34
+ """
35
+ # Get all git-tracked files (automatically respects .gitignore)
36
+ files = get_git_tracked_files()
37
+
38
+ if not files:
39
+ print("No git-tracked files found", file=sys.stderr) # noqa: T201
40
+ return 1
41
+
42
+ # Build codespell command with git-tracked files
43
+ cmd = ["codespell"]
44
+
45
+ # Add any additional arguments passed to wrapper
46
+ if argv:
47
+ cmd.extend(argv)
48
+
49
+ # Add file paths at the end
50
+ cmd.extend([str(f) for f in files])
51
+
52
+ # Execute codespell
53
+ try:
54
+ result = subprocess.run(
55
+ cmd,
56
+ cwd=Path.cwd(),
57
+ check=False, # Don't raise on non-zero exit (codespell returns 1 for issues found)
58
+ )
59
+ return result.returncode
60
+ except FileNotFoundError:
61
+ print(
62
+ "Error: codespell not found. Install with: uv pip install codespell",
63
+ file=sys.stderr,
64
+ ) # noqa: T201
65
+ return 127 # Command not found
66
+ except Exception as e:
67
+ print(f"Error running codespell: {e}", file=sys.stderr) # noqa: T201
68
+ return 1
69
+
70
+
71
+ if __name__ == "__main__":
72
+ sys.exit(main(sys.argv[1:]))
@@ -0,0 +1,202 @@
1
+ """Ensure files end with a newline.
2
+
3
+ This tool is a native Python implementation replacing pre-commit's
4
+ end-of-file-fixer hook. It scans files and ensures they end with exactly
5
+ one newline character.
6
+
7
+ Usage:
8
+ python -m crackerjack.tools.end_of_file_fixer [files...]
9
+
10
+ Exit Codes:
11
+ 0: All files end with newline (or successfully fixed)
12
+ 1: Files were modified to add/fix ending newline
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ import argparse
18
+ import sys
19
+ from pathlib import Path
20
+
21
+ from ._git_utils import get_files_by_extension
22
+
23
+
24
+ def needs_newline_fix(content: bytes) -> tuple[bool, bytes | None]:
25
+ """Check if file needs newline added or fixed.
26
+
27
+ Args:
28
+ content: File content as bytes
29
+
30
+ Returns:
31
+ Tuple of (needs_fix, fixed_content)
32
+ - needs_fix: True if file needs modification
33
+ - fixed_content: Fixed content if needs_fix is True, None otherwise
34
+ """
35
+ if not content:
36
+ # Empty file doesn't need newline
37
+ return False, None
38
+
39
+ # Check if file ends with newline
40
+ if content.endswith(b"\n"):
41
+ # Check for multiple trailing newlines
42
+ stripped = content.rstrip(b"\n")
43
+ if len(content) - len(stripped) > 1:
44
+ # Multiple trailing newlines, fix to exactly one
45
+ return True, stripped + b"\n"
46
+ # Exactly one newline, no fix needed
47
+ return False, None
48
+
49
+ # No trailing newline, add one
50
+ return True, content + b"\n"
51
+
52
+
53
+ def fix_end_of_file(file_path: Path) -> bool:
54
+ """Ensure file ends with exactly one newline.
55
+
56
+ Args:
57
+ file_path: Path to file to process
58
+
59
+ Returns:
60
+ True if file was modified, False if no changes needed
61
+ """
62
+ try:
63
+ # Read file content as bytes to preserve encoding
64
+ content = file_path.read_bytes()
65
+
66
+ # Check if fix is needed
67
+ needs_fix, fixed_content = needs_newline_fix(content)
68
+
69
+ if needs_fix and fixed_content is not None:
70
+ # Write fixed content
71
+ file_path.write_bytes(fixed_content)
72
+ print(f"Fixed end-of-file: {file_path}") # noqa: T201
73
+ return True
74
+
75
+ return False
76
+
77
+ except Exception as e:
78
+ print(f"Error processing {file_path}: {e}", file=sys.stderr) # noqa: T201
79
+ return False
80
+
81
+
82
+ def _collect_files_to_check(args: argparse.Namespace) -> list[Path]:
83
+ """Collect files to check for end-of-file issues.
84
+
85
+ Args:
86
+ args: Parsed command-line arguments
87
+
88
+ Returns:
89
+ List of file paths to process
90
+ """
91
+ # Default to all git-tracked text files if none specified
92
+ if not args.files:
93
+ # Get all tracked text files (respects .gitignore via git ls-files)
94
+ files = get_files_by_extension(
95
+ [".py", ".md", ".txt", ".yaml", ".yml", ".toml", ".json"]
96
+ )
97
+ if not files:
98
+ # Fallback to Python files if not in git repo
99
+ files = list(Path.cwd().rglob("*.py"))
100
+ else:
101
+ files = args.files
102
+
103
+ # Filter to existing files only
104
+ return [f for f in files if f.is_file()]
105
+
106
+
107
+ def _process_files_in_check_mode(files: list[Path]) -> int:
108
+ """Process files in check-only mode.
109
+
110
+ Args:
111
+ files: List of file paths to check
112
+
113
+ Returns:
114
+ Count of files with end-of-file issues
115
+ """
116
+ modified_count = 0
117
+ for file_path in files:
118
+ try:
119
+ content = file_path.read_bytes()
120
+ needs_fix, _ = needs_newline_fix(content)
121
+
122
+ if needs_fix:
123
+ print(f"Missing/incorrect end-of-file: {file_path}") # noqa: T201
124
+ modified_count += 1
125
+ except Exception as e:
126
+ print(f"Error processing {file_path}: {e}", file=sys.stderr) # noqa: T201
127
+ return modified_count
128
+
129
+
130
+ def _process_files_in_fix_mode(files: list[Path]) -> int:
131
+ """Process files in fix mode.
132
+
133
+ Args:
134
+ files: List of file paths to fix
135
+
136
+ Returns:
137
+ Count of files modified
138
+ """
139
+ modified_count = 0
140
+ for file_path in files:
141
+ try:
142
+ if fix_end_of_file(file_path):
143
+ modified_count += 1
144
+ except Exception as e:
145
+ print(f"Error processing {file_path}: {e}", file=sys.stderr) # noqa: T201
146
+ return modified_count
147
+
148
+
149
+ def main(argv: list[str] | None = None) -> int:
150
+ """Main entry point for end-of-file-fixer tool.
151
+
152
+ Args:
153
+ argv: Command-line arguments (defaults to sys.argv[1:])
154
+
155
+ Returns:
156
+ Exit code: 0 if no files modified, 1 if files were modified
157
+ """
158
+ parser = argparse.ArgumentParser(
159
+ description="Ensure files end with exactly one newline"
160
+ )
161
+ parser.add_argument(
162
+ "files",
163
+ nargs="*",
164
+ type=Path,
165
+ help="Files to check (default: all text files in current directory)",
166
+ )
167
+ parser.add_argument(
168
+ "--check",
169
+ action="store_true",
170
+ help="Check only, don't modify files",
171
+ )
172
+
173
+ args = parser.parse_args(argv)
174
+
175
+ files = _collect_files_to_check(args)
176
+
177
+ if not files:
178
+ print("No files to check") # noqa: T201
179
+ return 0
180
+
181
+ # Process files based on mode
182
+ if args.check:
183
+ modified_count = _process_files_in_check_mode(files)
184
+ else:
185
+ modified_count = _process_files_in_fix_mode(files)
186
+
187
+ # Return appropriate exit code
188
+ if modified_count > 0:
189
+ if args.check:
190
+ print(f"\n{modified_count} file(s) with incorrect end-of-file") # noqa: T201
191
+ else:
192
+ print(f"\nFixed {modified_count} file(s)") # noqa: T201
193
+ # Align with pre-commit semantics so HookExecutor treats this as pass
194
+ print("files were modified by this hook") # noqa: T201
195
+ return 1
196
+
197
+ print("All files end with correct newline") # noqa: T201
198
+ return 0
199
+
200
+
201
+ if __name__ == "__main__":
202
+ sys.exit(main())
@@ -0,0 +1,128 @@
1
+ """Format JSON files to ensure consistent style.
2
+
3
+ This tool is a native Python implementation for formatting JSON files
4
+ to ensure consistent indentation and style. It reads JSON files and
5
+ writes them back with standardized formatting.
6
+
7
+ Usage:
8
+ python -m crackerjack.tools.format_json [files...]
9
+
10
+ Exit Codes:
11
+ 0: All JSON files formatted successfully
12
+ 1: One or more JSON files have syntax errors or could not be formatted
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ import argparse
18
+ import json
19
+ import sys
20
+ from pathlib import Path
21
+
22
+ from ._git_utils import get_files_by_extension
23
+
24
+
25
+ def format_json_file(file_path: Path) -> tuple[bool, str | None]:
26
+ """Format a JSON file to ensure consistent style.
27
+
28
+ Args:
29
+ file_path: Path to JSON file to format
30
+
31
+ Returns:
32
+ Tuple of (is_success, error_message)
33
+ - is_success: True if file was formatted successfully
34
+ - error_message: Error description if is_success is False, None otherwise
35
+ """
36
+ try:
37
+ # Read the file content
38
+ with file_path.open(encoding="utf-8") as f:
39
+ content = f.read().strip()
40
+ if not content:
41
+ return True, "File is empty, nothing to format"
42
+
43
+ # Parse the JSON
44
+ data = json.loads(content)
45
+
46
+ # Format with consistent indentation
47
+ formatted_content = json.dumps(
48
+ data, indent=2, ensure_ascii=False, sort_keys=True
49
+ )
50
+
51
+ # Add a newline at the end to match common formatting practices
52
+ formatted_content += "\n"
53
+
54
+ # Write the formatted content back to the file
55
+ with file_path.open("w", encoding="utf-8") as f:
56
+ f.write(formatted_content)
57
+
58
+ return True, None
59
+
60
+ except json.JSONDecodeError as e:
61
+ return False, f"Invalid JSON syntax: {e}"
62
+ except Exception as e:
63
+ return False, f"Error formatting file: {e}"
64
+
65
+
66
+ def main(argv: list[str] | None = None) -> int:
67
+ """Main entry point for format-json tool.
68
+
69
+ Args:
70
+ argv: Command-line arguments (defaults to sys.argv[1:])
71
+
72
+ Returns:
73
+ Exit code: 0 if all JSON files formatted successfully, 1 if any errors
74
+ """
75
+ parser = argparse.ArgumentParser(
76
+ description="Format JSON files to ensure consistent style"
77
+ )
78
+ parser.add_argument(
79
+ "files",
80
+ nargs="*",
81
+ type=Path,
82
+ help="JSON files to format (default: all .json files)",
83
+ )
84
+
85
+ args = parser.parse_args(argv)
86
+
87
+ # Default to all git-tracked JSON files if none specified
88
+ if not args.files:
89
+ # Get all tracked JSON files (respects .gitignore via git ls-files)
90
+ files = get_files_by_extension([".json"])
91
+ if not files:
92
+ # Fallback to rglob if not in git repo
93
+ files = list(Path.cwd().rglob("*.json"))
94
+ else:
95
+ files = args.files
96
+
97
+ # Filter to existing files only
98
+ files = [f for f in files if f.is_file()]
99
+
100
+ if not files:
101
+ print("No JSON files to format") # noqa: T201
102
+ return 0
103
+
104
+ # Process files
105
+ error_count = 0
106
+ for file_path in files:
107
+ is_success, error_msg = format_json_file(file_path)
108
+
109
+ if not is_success:
110
+ print(f"✗ {file_path}: {error_msg}", file=sys.stderr) # noqa: T201
111
+ error_count += 1
112
+ else:
113
+ if error_msg: # File was empty
114
+ print(f"→ {file_path}: {error_msg}") # noqa: T201
115
+ else:
116
+ print(f"✓ {file_path}: Formatted successfully") # noqa: T201
117
+
118
+ # Return appropriate exit code
119
+ if error_count > 0:
120
+ print(f"\n{error_count} JSON file(s) failed to format", file=sys.stderr) # noqa: T201
121
+ return 1
122
+
123
+ print(f"\nAll {len(files)} JSON file(s) formatted successfully") # noqa: T201
124
+ return 0
125
+
126
+
127
+ if __name__ == "__main__":
128
+ sys.exit(main())
@@ -0,0 +1,114 @@
1
+ """Git-aware wrapper for mdformat.
2
+
3
+ This wrapper ensures mdformat only checks git-tracked markdown files,
4
+ automatically respecting .gitignore patterns without needing manual skip
5
+ configuration.
6
+
7
+ Usage:
8
+ python -m crackerjack.tools.mdformat_wrapper [mdformat args...]
9
+
10
+ Exit Codes:
11
+ Same as mdformat (0 = no issues, 1 = issues found, etc.)
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import subprocess
17
+ import sys
18
+ from pathlib import Path
19
+
20
+ from ._git_utils import get_git_tracked_files
21
+
22
+
23
+ def main(argv: list[str] | None = None) -> int:
24
+ """Run mdformat on git-tracked markdown files only.
25
+
26
+ This wrapper automatically discovers git-tracked .md and .markdown files
27
+ and passes them to mdformat, ensuring .gitignore patterns are respected.
28
+
29
+ Behavior:
30
+ - First run: Formats files and returns exit code 1 (fail to signal changes)
31
+ - Second run: Files already formatted, returns exit code 0 (pass)
32
+
33
+ Args:
34
+ argv: Optional arguments to pass to mdformat
35
+
36
+ Returns:
37
+ Exit code: 0 if no changes needed, 1 if files were formatted
38
+ """
39
+ # Get all git-tracked markdown files (automatically respects .gitignore)
40
+ md_files = get_git_tracked_files("*.md")
41
+ markdown_files = get_git_tracked_files("*.markdown")
42
+ files = md_files + markdown_files
43
+
44
+ if not files:
45
+ print("No git-tracked markdown files found", file=sys.stderr) # noqa: T201
46
+ return 0 # No files is not an error for formatters
47
+
48
+ # Build mdformat command with git-tracked files
49
+ cmd = ["mdformat"]
50
+
51
+ # Add any additional arguments passed to wrapper
52
+ if argv:
53
+ cmd.extend(argv)
54
+
55
+ # Add file paths at the end
56
+ cmd.extend([str(f) for f in files])
57
+
58
+ # Execute mdformat
59
+ try:
60
+ # First, check if files need formatting (dry-run)
61
+ check_cmd = cmd + ["--check"]
62
+ check_result = subprocess.run(
63
+ check_cmd,
64
+ cwd=Path.cwd(),
65
+ check=False,
66
+ capture_output=True,
67
+ text=True,
68
+ )
69
+
70
+ # If check passed (exit code 0), files are already formatted
71
+ if check_result.returncode == 0:
72
+ print(f"All {len(files)} markdown files already formatted correctly")
73
+ return 0
74
+
75
+ # Files need formatting - run mdformat to fix them
76
+ format_result = subprocess.run(
77
+ cmd,
78
+ cwd=Path.cwd(),
79
+ check=False,
80
+ capture_output=True,
81
+ text=True,
82
+ )
83
+
84
+ # Forward output to stdout/stderr
85
+ if format_result.stdout:
86
+ print(format_result.stdout, end="")
87
+ if format_result.stderr:
88
+ print(format_result.stderr, end="", file=sys.stderr)
89
+
90
+ # Return exit code 1 to indicate files were formatted (changes made)
91
+ # This causes the hook to fail on first run, pass on second run
92
+ files_formatted = (
93
+ check_result.returncode
94
+ ) # Non-zero means files needed formatting
95
+ if files_formatted:
96
+ print(
97
+ f"Formatted {len(files)} markdown files - run crackerjack again to verify"
98
+ )
99
+ return 1 # Fail to signal changes were made
100
+
101
+ return 0
102
+ except FileNotFoundError:
103
+ print(
104
+ "Error: mdformat not found. Install with: uv pip install mdformat mdformat-ruff",
105
+ file=sys.stderr,
106
+ ) # noqa: T201
107
+ return 127 # Command not found
108
+ except Exception as e:
109
+ print(f"Error running mdformat: {e}", file=sys.stderr) # noqa: T201
110
+ return 1
111
+
112
+
113
+ if __name__ == "__main__":
114
+ sys.exit(main(sys.argv[1:]))