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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (425) hide show
  1. crackerjack/README.md +19 -0
  2. crackerjack/__init__.py +30 -1
  3. crackerjack/__main__.py +342 -1263
  4. crackerjack/adapters/README.md +18 -0
  5. crackerjack/adapters/__init__.py +27 -5
  6. crackerjack/adapters/_output_paths.py +167 -0
  7. crackerjack/adapters/_qa_adapter_base.py +309 -0
  8. crackerjack/adapters/_tool_adapter_base.py +706 -0
  9. crackerjack/adapters/ai/README.md +65 -0
  10. crackerjack/adapters/ai/__init__.py +5 -0
  11. crackerjack/adapters/ai/claude.py +853 -0
  12. crackerjack/adapters/complexity/README.md +53 -0
  13. crackerjack/adapters/complexity/__init__.py +10 -0
  14. crackerjack/adapters/complexity/complexipy.py +641 -0
  15. crackerjack/adapters/dependency/__init__.py +22 -0
  16. crackerjack/adapters/dependency/pip_audit.py +418 -0
  17. crackerjack/adapters/format/README.md +72 -0
  18. crackerjack/adapters/format/__init__.py +11 -0
  19. crackerjack/adapters/format/mdformat.py +313 -0
  20. crackerjack/adapters/format/ruff.py +516 -0
  21. crackerjack/adapters/lint/README.md +47 -0
  22. crackerjack/adapters/lint/__init__.py +11 -0
  23. crackerjack/adapters/lint/codespell.py +273 -0
  24. crackerjack/adapters/lsp/README.md +49 -0
  25. crackerjack/adapters/lsp/__init__.py +27 -0
  26. crackerjack/adapters/{rust_tool_manager.py → lsp/_manager.py} +3 -3
  27. crackerjack/adapters/{skylos_adapter.py → lsp/skylos.py} +59 -7
  28. crackerjack/adapters/{zuban_adapter.py → lsp/zuban.py} +3 -6
  29. crackerjack/adapters/refactor/README.md +59 -0
  30. crackerjack/adapters/refactor/__init__.py +12 -0
  31. crackerjack/adapters/refactor/creosote.py +318 -0
  32. crackerjack/adapters/refactor/refurb.py +406 -0
  33. crackerjack/adapters/refactor/skylos.py +494 -0
  34. crackerjack/adapters/sast/README.md +132 -0
  35. crackerjack/adapters/sast/__init__.py +32 -0
  36. crackerjack/adapters/sast/_base.py +201 -0
  37. crackerjack/adapters/sast/bandit.py +423 -0
  38. crackerjack/adapters/sast/pyscn.py +405 -0
  39. crackerjack/adapters/sast/semgrep.py +241 -0
  40. crackerjack/adapters/security/README.md +111 -0
  41. crackerjack/adapters/security/__init__.py +17 -0
  42. crackerjack/adapters/security/gitleaks.py +339 -0
  43. crackerjack/adapters/type/README.md +52 -0
  44. crackerjack/adapters/type/__init__.py +12 -0
  45. crackerjack/adapters/type/pyrefly.py +402 -0
  46. crackerjack/adapters/type/ty.py +402 -0
  47. crackerjack/adapters/type/zuban.py +522 -0
  48. crackerjack/adapters/utility/README.md +51 -0
  49. crackerjack/adapters/utility/__init__.py +10 -0
  50. crackerjack/adapters/utility/checks.py +884 -0
  51. crackerjack/agents/README.md +264 -0
  52. crackerjack/agents/__init__.py +40 -12
  53. crackerjack/agents/base.py +1 -0
  54. crackerjack/agents/claude_code_bridge.py +641 -0
  55. crackerjack/agents/coordinator.py +49 -53
  56. crackerjack/agents/dry_agent.py +187 -3
  57. crackerjack/agents/enhanced_coordinator.py +279 -0
  58. crackerjack/agents/enhanced_proactive_agent.py +185 -0
  59. crackerjack/agents/error_middleware.py +53 -0
  60. crackerjack/agents/formatting_agent.py +6 -8
  61. crackerjack/agents/helpers/__init__.py +9 -0
  62. crackerjack/agents/helpers/performance/__init__.py +22 -0
  63. crackerjack/agents/helpers/performance/performance_ast_analyzer.py +357 -0
  64. crackerjack/agents/helpers/performance/performance_pattern_detector.py +909 -0
  65. crackerjack/agents/helpers/performance/performance_recommender.py +572 -0
  66. crackerjack/agents/helpers/refactoring/__init__.py +22 -0
  67. crackerjack/agents/helpers/refactoring/code_transformer.py +536 -0
  68. crackerjack/agents/helpers/refactoring/complexity_analyzer.py +344 -0
  69. crackerjack/agents/helpers/refactoring/dead_code_detector.py +437 -0
  70. crackerjack/agents/helpers/test_creation/__init__.py +19 -0
  71. crackerjack/agents/helpers/test_creation/test_ast_analyzer.py +216 -0
  72. crackerjack/agents/helpers/test_creation/test_coverage_analyzer.py +643 -0
  73. crackerjack/agents/helpers/test_creation/test_template_generator.py +1031 -0
  74. crackerjack/agents/performance_agent.py +121 -1152
  75. crackerjack/agents/refactoring_agent.py +156 -655
  76. crackerjack/agents/semantic_agent.py +479 -0
  77. crackerjack/agents/semantic_helpers.py +356 -0
  78. crackerjack/agents/test_creation_agent.py +19 -1605
  79. crackerjack/api.py +5 -7
  80. crackerjack/cli/README.md +394 -0
  81. crackerjack/cli/__init__.py +1 -1
  82. crackerjack/cli/cache_handlers.py +23 -18
  83. crackerjack/cli/cache_handlers_enhanced.py +1 -4
  84. crackerjack/cli/facade.py +70 -8
  85. crackerjack/cli/formatting.py +13 -0
  86. crackerjack/cli/handlers/__init__.py +85 -0
  87. crackerjack/cli/handlers/advanced.py +103 -0
  88. crackerjack/cli/handlers/ai_features.py +62 -0
  89. crackerjack/cli/handlers/analytics.py +479 -0
  90. crackerjack/cli/handlers/changelog.py +271 -0
  91. crackerjack/cli/handlers/config_handlers.py +16 -0
  92. crackerjack/cli/handlers/coverage.py +84 -0
  93. crackerjack/cli/handlers/documentation.py +280 -0
  94. crackerjack/cli/handlers/main_handlers.py +497 -0
  95. crackerjack/cli/handlers/monitoring.py +371 -0
  96. crackerjack/cli/handlers.py +249 -49
  97. crackerjack/cli/interactive.py +8 -5
  98. crackerjack/cli/options.py +203 -110
  99. crackerjack/cli/semantic_handlers.py +292 -0
  100. crackerjack/cli/version.py +19 -0
  101. crackerjack/code_cleaner.py +60 -24
  102. crackerjack/config/README.md +472 -0
  103. crackerjack/config/__init__.py +256 -0
  104. crackerjack/config/global_lock_config.py +191 -54
  105. crackerjack/config/hooks.py +188 -16
  106. crackerjack/config/loader.py +239 -0
  107. crackerjack/config/settings.py +141 -0
  108. crackerjack/config/tool_commands.py +331 -0
  109. crackerjack/core/README.md +393 -0
  110. crackerjack/core/async_workflow_orchestrator.py +79 -53
  111. crackerjack/core/autofix_coordinator.py +22 -9
  112. crackerjack/core/container.py +10 -9
  113. crackerjack/core/enhanced_container.py +9 -9
  114. crackerjack/core/performance.py +1 -1
  115. crackerjack/core/performance_monitor.py +5 -3
  116. crackerjack/core/phase_coordinator.py +1018 -634
  117. crackerjack/core/proactive_workflow.py +3 -3
  118. crackerjack/core/retry.py +275 -0
  119. crackerjack/core/service_watchdog.py +167 -23
  120. crackerjack/core/session_coordinator.py +187 -382
  121. crackerjack/core/timeout_manager.py +161 -44
  122. crackerjack/core/workflow/__init__.py +21 -0
  123. crackerjack/core/workflow/workflow_ai_coordinator.py +863 -0
  124. crackerjack/core/workflow/workflow_event_orchestrator.py +1107 -0
  125. crackerjack/core/workflow/workflow_issue_parser.py +714 -0
  126. crackerjack/core/workflow/workflow_phase_executor.py +1158 -0
  127. crackerjack/core/workflow/workflow_security_gates.py +400 -0
  128. crackerjack/core/workflow_orchestrator.py +1247 -953
  129. crackerjack/data/README.md +11 -0
  130. crackerjack/data/__init__.py +8 -0
  131. crackerjack/data/models.py +79 -0
  132. crackerjack/data/repository.py +210 -0
  133. crackerjack/decorators/README.md +180 -0
  134. crackerjack/decorators/__init__.py +35 -0
  135. crackerjack/decorators/error_handling.py +649 -0
  136. crackerjack/decorators/error_handling_decorators.py +334 -0
  137. crackerjack/decorators/helpers.py +58 -0
  138. crackerjack/decorators/patterns.py +281 -0
  139. crackerjack/decorators/utils.py +58 -0
  140. crackerjack/docs/README.md +11 -0
  141. crackerjack/docs/generated/api/CLI_REFERENCE.md +1 -1
  142. crackerjack/documentation/README.md +11 -0
  143. crackerjack/documentation/ai_templates.py +1 -1
  144. crackerjack/documentation/dual_output_generator.py +11 -9
  145. crackerjack/documentation/reference_generator.py +104 -59
  146. crackerjack/dynamic_config.py +52 -61
  147. crackerjack/errors.py +1 -1
  148. crackerjack/events/README.md +11 -0
  149. crackerjack/events/__init__.py +16 -0
  150. crackerjack/events/telemetry.py +175 -0
  151. crackerjack/events/workflow_bus.py +346 -0
  152. crackerjack/exceptions/README.md +301 -0
  153. crackerjack/exceptions/__init__.py +5 -0
  154. crackerjack/exceptions/config.py +4 -0
  155. crackerjack/exceptions/tool_execution_error.py +245 -0
  156. crackerjack/executors/README.md +591 -0
  157. crackerjack/executors/__init__.py +2 -0
  158. crackerjack/executors/async_hook_executor.py +539 -77
  159. crackerjack/executors/cached_hook_executor.py +3 -3
  160. crackerjack/executors/hook_executor.py +967 -102
  161. crackerjack/executors/hook_lock_manager.py +31 -22
  162. crackerjack/executors/individual_hook_executor.py +66 -32
  163. crackerjack/executors/lsp_aware_hook_executor.py +136 -57
  164. crackerjack/executors/progress_hook_executor.py +282 -0
  165. crackerjack/executors/tool_proxy.py +23 -7
  166. crackerjack/hooks/README.md +485 -0
  167. crackerjack/hooks/lsp_hook.py +8 -9
  168. crackerjack/intelligence/README.md +557 -0
  169. crackerjack/interactive.py +37 -10
  170. crackerjack/managers/README.md +369 -0
  171. crackerjack/managers/async_hook_manager.py +41 -57
  172. crackerjack/managers/hook_manager.py +449 -79
  173. crackerjack/managers/publish_manager.py +81 -36
  174. crackerjack/managers/test_command_builder.py +290 -12
  175. crackerjack/managers/test_executor.py +93 -8
  176. crackerjack/managers/test_manager.py +1082 -75
  177. crackerjack/managers/test_progress.py +118 -26
  178. crackerjack/mcp/README.md +374 -0
  179. crackerjack/mcp/cache.py +25 -2
  180. crackerjack/mcp/client_runner.py +35 -18
  181. crackerjack/mcp/context.py +9 -9
  182. crackerjack/mcp/dashboard.py +24 -8
  183. crackerjack/mcp/enhanced_progress_monitor.py +34 -23
  184. crackerjack/mcp/file_monitor.py +27 -6
  185. crackerjack/mcp/progress_components.py +45 -34
  186. crackerjack/mcp/progress_monitor.py +6 -9
  187. crackerjack/mcp/rate_limiter.py +11 -7
  188. crackerjack/mcp/server.py +2 -0
  189. crackerjack/mcp/server_core.py +187 -55
  190. crackerjack/mcp/service_watchdog.py +12 -9
  191. crackerjack/mcp/task_manager.py +2 -2
  192. crackerjack/mcp/tools/README.md +27 -0
  193. crackerjack/mcp/tools/__init__.py +2 -0
  194. crackerjack/mcp/tools/core_tools.py +75 -52
  195. crackerjack/mcp/tools/execution_tools.py +87 -31
  196. crackerjack/mcp/tools/intelligence_tools.py +2 -2
  197. crackerjack/mcp/tools/proactive_tools.py +1 -1
  198. crackerjack/mcp/tools/semantic_tools.py +584 -0
  199. crackerjack/mcp/tools/utility_tools.py +180 -132
  200. crackerjack/mcp/tools/workflow_executor.py +87 -46
  201. crackerjack/mcp/websocket/README.md +31 -0
  202. crackerjack/mcp/websocket/app.py +11 -1
  203. crackerjack/mcp/websocket/event_bridge.py +188 -0
  204. crackerjack/mcp/websocket/jobs.py +27 -4
  205. crackerjack/mcp/websocket/monitoring/__init__.py +25 -0
  206. crackerjack/mcp/websocket/monitoring/api/__init__.py +19 -0
  207. crackerjack/mcp/websocket/monitoring/api/dependencies.py +141 -0
  208. crackerjack/mcp/websocket/monitoring/api/heatmap.py +154 -0
  209. crackerjack/mcp/websocket/monitoring/api/intelligence.py +199 -0
  210. crackerjack/mcp/websocket/monitoring/api/metrics.py +203 -0
  211. crackerjack/mcp/websocket/monitoring/api/telemetry.py +101 -0
  212. crackerjack/mcp/websocket/monitoring/dashboard.py +18 -0
  213. crackerjack/mcp/websocket/monitoring/factory.py +109 -0
  214. crackerjack/mcp/websocket/monitoring/filters.py +10 -0
  215. crackerjack/mcp/websocket/monitoring/metrics.py +64 -0
  216. crackerjack/mcp/websocket/monitoring/models.py +90 -0
  217. crackerjack/mcp/websocket/monitoring/utils.py +171 -0
  218. crackerjack/mcp/websocket/monitoring/websocket_manager.py +78 -0
  219. crackerjack/mcp/websocket/monitoring/websockets/__init__.py +17 -0
  220. crackerjack/mcp/websocket/monitoring/websockets/dependencies.py +126 -0
  221. crackerjack/mcp/websocket/monitoring/websockets/heatmap.py +176 -0
  222. crackerjack/mcp/websocket/monitoring/websockets/intelligence.py +291 -0
  223. crackerjack/mcp/websocket/monitoring/websockets/metrics.py +291 -0
  224. crackerjack/mcp/websocket/monitoring_endpoints.py +16 -2930
  225. crackerjack/mcp/websocket/server.py +1 -3
  226. crackerjack/mcp/websocket/websocket_handler.py +107 -6
  227. crackerjack/models/README.md +308 -0
  228. crackerjack/models/__init__.py +10 -1
  229. crackerjack/models/config.py +639 -22
  230. crackerjack/models/config_adapter.py +6 -6
  231. crackerjack/models/protocols.py +1167 -23
  232. crackerjack/models/pydantic_models.py +320 -0
  233. crackerjack/models/qa_config.py +145 -0
  234. crackerjack/models/qa_results.py +134 -0
  235. crackerjack/models/results.py +35 -0
  236. crackerjack/models/semantic_models.py +258 -0
  237. crackerjack/models/task.py +19 -3
  238. crackerjack/models/test_models.py +60 -0
  239. crackerjack/monitoring/README.md +11 -0
  240. crackerjack/monitoring/ai_agent_watchdog.py +5 -4
  241. crackerjack/monitoring/metrics_collector.py +4 -3
  242. crackerjack/monitoring/regression_prevention.py +4 -3
  243. crackerjack/monitoring/websocket_server.py +4 -241
  244. crackerjack/orchestration/README.md +340 -0
  245. crackerjack/orchestration/__init__.py +43 -0
  246. crackerjack/orchestration/advanced_orchestrator.py +20 -67
  247. crackerjack/orchestration/cache/README.md +312 -0
  248. crackerjack/orchestration/cache/__init__.py +37 -0
  249. crackerjack/orchestration/cache/memory_cache.py +338 -0
  250. crackerjack/orchestration/cache/tool_proxy_cache.py +340 -0
  251. crackerjack/orchestration/config.py +297 -0
  252. crackerjack/orchestration/coverage_improvement.py +13 -6
  253. crackerjack/orchestration/execution_strategies.py +6 -6
  254. crackerjack/orchestration/hook_orchestrator.py +1398 -0
  255. crackerjack/orchestration/strategies/README.md +401 -0
  256. crackerjack/orchestration/strategies/__init__.py +39 -0
  257. crackerjack/orchestration/strategies/adaptive_strategy.py +630 -0
  258. crackerjack/orchestration/strategies/parallel_strategy.py +237 -0
  259. crackerjack/orchestration/strategies/sequential_strategy.py +299 -0
  260. crackerjack/orchestration/test_progress_streamer.py +1 -1
  261. crackerjack/plugins/README.md +11 -0
  262. crackerjack/plugins/hooks.py +3 -2
  263. crackerjack/plugins/loader.py +3 -3
  264. crackerjack/plugins/managers.py +1 -1
  265. crackerjack/py313.py +191 -0
  266. crackerjack/security/README.md +11 -0
  267. crackerjack/services/README.md +374 -0
  268. crackerjack/services/__init__.py +8 -21
  269. crackerjack/services/ai/README.md +295 -0
  270. crackerjack/services/ai/__init__.py +7 -0
  271. crackerjack/services/ai/advanced_optimizer.py +878 -0
  272. crackerjack/services/{contextual_ai_assistant.py → ai/contextual_ai_assistant.py} +5 -3
  273. crackerjack/services/ai/embeddings.py +444 -0
  274. crackerjack/services/ai/intelligent_commit.py +328 -0
  275. crackerjack/services/ai/predictive_analytics.py +510 -0
  276. crackerjack/services/api_extractor.py +5 -3
  277. crackerjack/services/bounded_status_operations.py +45 -5
  278. crackerjack/services/cache.py +249 -318
  279. crackerjack/services/changelog_automation.py +7 -3
  280. crackerjack/services/command_execution_service.py +305 -0
  281. crackerjack/services/config_integrity.py +83 -39
  282. crackerjack/services/config_merge.py +9 -6
  283. crackerjack/services/config_service.py +198 -0
  284. crackerjack/services/config_template.py +13 -26
  285. crackerjack/services/coverage_badge_service.py +6 -4
  286. crackerjack/services/coverage_ratchet.py +53 -27
  287. crackerjack/services/debug.py +18 -7
  288. crackerjack/services/dependency_analyzer.py +4 -4
  289. crackerjack/services/dependency_monitor.py +13 -13
  290. crackerjack/services/documentation_generator.py +4 -2
  291. crackerjack/services/documentation_service.py +62 -33
  292. crackerjack/services/enhanced_filesystem.py +81 -27
  293. crackerjack/services/enterprise_optimizer.py +1 -1
  294. crackerjack/services/error_pattern_analyzer.py +10 -10
  295. crackerjack/services/file_filter.py +221 -0
  296. crackerjack/services/file_hasher.py +5 -7
  297. crackerjack/services/file_io_service.py +361 -0
  298. crackerjack/services/file_modifier.py +615 -0
  299. crackerjack/services/filesystem.py +80 -109
  300. crackerjack/services/git.py +99 -5
  301. crackerjack/services/health_metrics.py +4 -6
  302. crackerjack/services/heatmap_generator.py +12 -3
  303. crackerjack/services/incremental_executor.py +380 -0
  304. crackerjack/services/initialization.py +101 -49
  305. crackerjack/services/log_manager.py +2 -2
  306. crackerjack/services/logging.py +120 -68
  307. crackerjack/services/lsp_client.py +12 -12
  308. crackerjack/services/memory_optimizer.py +27 -22
  309. crackerjack/services/monitoring/README.md +30 -0
  310. crackerjack/services/monitoring/__init__.py +9 -0
  311. crackerjack/services/monitoring/dependency_monitor.py +678 -0
  312. crackerjack/services/monitoring/error_pattern_analyzer.py +676 -0
  313. crackerjack/services/monitoring/health_metrics.py +716 -0
  314. crackerjack/services/monitoring/metrics.py +587 -0
  315. crackerjack/services/{performance_benchmarks.py → monitoring/performance_benchmarks.py} +100 -14
  316. crackerjack/services/{performance_cache.py → monitoring/performance_cache.py} +21 -15
  317. crackerjack/services/{performance_monitor.py → monitoring/performance_monitor.py} +10 -6
  318. crackerjack/services/parallel_executor.py +166 -55
  319. crackerjack/services/patterns/__init__.py +142 -0
  320. crackerjack/services/patterns/agents.py +107 -0
  321. crackerjack/services/patterns/code/__init__.py +15 -0
  322. crackerjack/services/patterns/code/detection.py +118 -0
  323. crackerjack/services/patterns/code/imports.py +107 -0
  324. crackerjack/services/patterns/code/paths.py +159 -0
  325. crackerjack/services/patterns/code/performance.py +119 -0
  326. crackerjack/services/patterns/code/replacement.py +36 -0
  327. crackerjack/services/patterns/core.py +212 -0
  328. crackerjack/services/patterns/documentation/__init__.py +14 -0
  329. crackerjack/services/patterns/documentation/badges_markdown.py +96 -0
  330. crackerjack/services/patterns/documentation/comments_blocks.py +83 -0
  331. crackerjack/services/patterns/documentation/docstrings.py +89 -0
  332. crackerjack/services/patterns/formatting.py +226 -0
  333. crackerjack/services/patterns/operations.py +339 -0
  334. crackerjack/services/patterns/security/__init__.py +23 -0
  335. crackerjack/services/patterns/security/code_injection.py +122 -0
  336. crackerjack/services/patterns/security/credentials.py +190 -0
  337. crackerjack/services/patterns/security/path_traversal.py +221 -0
  338. crackerjack/services/patterns/security/unsafe_operations.py +216 -0
  339. crackerjack/services/patterns/templates.py +62 -0
  340. crackerjack/services/patterns/testing/__init__.py +18 -0
  341. crackerjack/services/patterns/testing/error_patterns.py +107 -0
  342. crackerjack/services/patterns/testing/pytest_output.py +126 -0
  343. crackerjack/services/patterns/tool_output/__init__.py +16 -0
  344. crackerjack/services/patterns/tool_output/bandit.py +72 -0
  345. crackerjack/services/patterns/tool_output/other.py +97 -0
  346. crackerjack/services/patterns/tool_output/pyright.py +67 -0
  347. crackerjack/services/patterns/tool_output/ruff.py +44 -0
  348. crackerjack/services/patterns/url_sanitization.py +114 -0
  349. crackerjack/services/patterns/utilities.py +42 -0
  350. crackerjack/services/patterns/utils.py +339 -0
  351. crackerjack/services/patterns/validation.py +46 -0
  352. crackerjack/services/patterns/versioning.py +62 -0
  353. crackerjack/services/predictive_analytics.py +21 -8
  354. crackerjack/services/profiler.py +280 -0
  355. crackerjack/services/quality/README.md +415 -0
  356. crackerjack/services/quality/__init__.py +11 -0
  357. crackerjack/services/quality/anomaly_detector.py +392 -0
  358. crackerjack/services/quality/pattern_cache.py +333 -0
  359. crackerjack/services/quality/pattern_detector.py +479 -0
  360. crackerjack/services/quality/qa_orchestrator.py +491 -0
  361. crackerjack/services/{quality_baseline.py → quality/quality_baseline.py} +163 -2
  362. crackerjack/services/{quality_baseline_enhanced.py → quality/quality_baseline_enhanced.py} +4 -1
  363. crackerjack/services/{quality_intelligence.py → quality/quality_intelligence.py} +180 -16
  364. crackerjack/services/regex_patterns.py +58 -2987
  365. crackerjack/services/regex_utils.py +55 -29
  366. crackerjack/services/secure_status_formatter.py +42 -15
  367. crackerjack/services/secure_subprocess.py +35 -2
  368. crackerjack/services/security.py +16 -8
  369. crackerjack/services/server_manager.py +40 -51
  370. crackerjack/services/smart_scheduling.py +46 -6
  371. crackerjack/services/status_authentication.py +3 -3
  372. crackerjack/services/thread_safe_status_collector.py +1 -0
  373. crackerjack/services/tool_filter.py +368 -0
  374. crackerjack/services/tool_version_service.py +9 -5
  375. crackerjack/services/unified_config.py +43 -351
  376. crackerjack/services/vector_store.py +689 -0
  377. crackerjack/services/version_analyzer.py +6 -4
  378. crackerjack/services/version_checker.py +14 -8
  379. crackerjack/services/zuban_lsp_service.py +5 -4
  380. crackerjack/slash_commands/README.md +11 -0
  381. crackerjack/slash_commands/init.md +2 -12
  382. crackerjack/slash_commands/run.md +84 -50
  383. crackerjack/tools/README.md +11 -0
  384. crackerjack/tools/__init__.py +30 -0
  385. crackerjack/tools/_git_utils.py +105 -0
  386. crackerjack/tools/check_added_large_files.py +139 -0
  387. crackerjack/tools/check_ast.py +105 -0
  388. crackerjack/tools/check_json.py +103 -0
  389. crackerjack/tools/check_jsonschema.py +297 -0
  390. crackerjack/tools/check_toml.py +103 -0
  391. crackerjack/tools/check_yaml.py +110 -0
  392. crackerjack/tools/codespell_wrapper.py +72 -0
  393. crackerjack/tools/end_of_file_fixer.py +202 -0
  394. crackerjack/tools/format_json.py +128 -0
  395. crackerjack/tools/mdformat_wrapper.py +114 -0
  396. crackerjack/tools/trailing_whitespace.py +198 -0
  397. crackerjack/tools/validate_regex_patterns.py +7 -3
  398. crackerjack/ui/README.md +11 -0
  399. crackerjack/ui/dashboard_renderer.py +28 -0
  400. crackerjack/ui/templates/README.md +11 -0
  401. crackerjack/utils/console_utils.py +13 -0
  402. crackerjack/utils/dependency_guard.py +230 -0
  403. crackerjack/utils/retry_utils.py +275 -0
  404. crackerjack/workflows/README.md +590 -0
  405. crackerjack/workflows/__init__.py +46 -0
  406. crackerjack/workflows/actions.py +811 -0
  407. crackerjack/workflows/auto_fix.py +444 -0
  408. crackerjack/workflows/container_builder.py +499 -0
  409. crackerjack/workflows/definitions.py +443 -0
  410. crackerjack/workflows/engine.py +177 -0
  411. crackerjack/workflows/event_bridge.py +242 -0
  412. {crackerjack-0.37.9.dist-info → crackerjack-0.45.2.dist-info}/METADATA +678 -98
  413. crackerjack-0.45.2.dist-info/RECORD +478 -0
  414. {crackerjack-0.37.9.dist-info → crackerjack-0.45.2.dist-info}/WHEEL +1 -1
  415. crackerjack/managers/test_manager_backup.py +0 -1075
  416. crackerjack/mcp/tools/execution_tools_backup.py +0 -1011
  417. crackerjack/mixins/__init__.py +0 -3
  418. crackerjack/mixins/error_handling.py +0 -145
  419. crackerjack/services/config.py +0 -358
  420. crackerjack/ui/server_panels.py +0 -125
  421. crackerjack-0.37.9.dist-info/RECORD +0 -231
  422. /crackerjack/adapters/{rust_tool_adapter.py → lsp/_base.py} +0 -0
  423. /crackerjack/adapters/{lsp_client.py → lsp/_client.py} +0 -0
  424. {crackerjack-0.37.9.dist-info → crackerjack-0.45.2.dist-info}/entry_points.txt +0 -0
  425. {crackerjack-0.37.9.dist-info → crackerjack-0.45.2.dist-info}/licenses/LICENSE +0 -0
@@ -3,7 +3,8 @@
3
3
  import typing as t
4
4
  from pathlib import Path
5
5
 
6
- from rich.console import Console
6
+ from acb.console import Console
7
+ from acb.depends import Inject, depends
7
8
 
8
9
  from ..models.protocols import (
9
10
  APIExtractorProtocol,
@@ -17,17 +18,18 @@ from .documentation_generator import DocumentationGeneratorImpl
17
18
  class DocumentationServiceImpl(DocumentationServiceProtocol):
18
19
  """Main service for automated documentation generation and maintenance."""
19
20
 
21
+ @depends.inject
20
22
  def __init__(
21
23
  self,
22
- console: Console,
24
+ console: Inject[Console],
23
25
  pkg_path: Path,
24
26
  api_extractor: APIExtractorProtocol | None = None,
25
27
  doc_generator: DocumentationGeneratorProtocol | None = None,
26
28
  ) -> None:
27
29
  self.console = console
28
30
  self.pkg_path = pkg_path
29
- self.api_extractor = api_extractor or APIExtractorImpl(console)
30
- self.doc_generator = doc_generator or DocumentationGeneratorImpl(console)
31
+ self.api_extractor = api_extractor or APIExtractorImpl()
32
+ self.doc_generator = doc_generator or DocumentationGeneratorImpl()
31
33
 
32
34
  # Define standard paths
33
35
  self.docs_dir = pkg_path / "docs"
@@ -38,58 +40,85 @@ class DocumentationServiceImpl(DocumentationServiceProtocol):
38
40
  # Ensure directories exist
39
41
  self._ensure_directories()
40
42
 
41
- def extract_api_documentation(self, source_paths: list[Path]) -> dict[str, t.Any]:
42
- """Extract API documentation from source code files."""
43
- self.console.print(
44
- "[cyan]📖[/cyan] Extracting API documentation from source files..."
45
- )
46
-
47
- # Categorize source files
43
+ def _categorize_source_files(
44
+ self, source_paths: list[Path]
45
+ ) -> dict[str, list[Path]]:
46
+ """Categorize source files by type."""
48
47
  python_files = [p for p in source_paths if p.suffix == ".py"]
49
- protocol_files = [p for p in python_files if p.name == "protocols.py"]
50
- service_files = [p for p in python_files if "/services/" in str(p)]
51
- manager_files = [p for p in python_files if "/managers/" in str(p)]
52
- cli_files = [p for p in python_files if "/cli/" in str(p)]
53
- mcp_files = [
54
- p for p in source_paths if "/mcp/" in str(p) or p.suffix in (".py", ".md")
55
- ]
56
48
 
57
- api_data = {}
49
+ return {
50
+ "python": python_files,
51
+ "protocol": [p for p in python_files if p.name == "protocols.py"],
52
+ "service": [p for p in python_files if "/services/" in str(p)],
53
+ "manager": [p for p in python_files if "/managers/" in str(p)],
54
+ "cli": [p for p in python_files if "/cli/" in str(p)],
55
+ "mcp": [
56
+ p
57
+ for p in source_paths
58
+ if "/mcp/" in str(p) or p.suffix in (".py", ".md")
59
+ ],
60
+ }
58
61
 
59
- # Extract from Python files
60
- if python_files:
61
- python_data = self.api_extractor.extract_from_python_files(python_files)
62
- api_data.update(python_data)
62
+ def _extract_specialized_apis(
63
+ self, categorized_files: dict[str, list[Path]]
64
+ ) -> dict[str, t.Any]:
65
+ """Extract specialized API documentation."""
66
+ api_data = {}
63
67
 
64
68
  # Extract protocol definitions
65
- if protocol_files:
66
- for protocol_file in protocol_files:
69
+ if categorized_files["protocol"]:
70
+ for protocol_file in categorized_files["protocol"]:
67
71
  protocol_data = self.api_extractor.extract_protocol_definitions(
68
72
  protocol_file
69
73
  )
70
74
  api_data.update(protocol_data)
71
75
 
72
76
  # Extract service interfaces
73
- if service_files:
74
- service_data = self.api_extractor.extract_service_interfaces(service_files)
77
+ if categorized_files["service"]:
78
+ service_data = self.api_extractor.extract_service_interfaces(
79
+ categorized_files["service"]
80
+ )
75
81
  api_data.update(service_data)
76
82
 
77
83
  # Extract manager interfaces
78
- if manager_files:
79
- manager_data = self.api_extractor.extract_service_interfaces(manager_files)
84
+ if categorized_files["manager"]:
85
+ manager_data = self.api_extractor.extract_service_interfaces(
86
+ categorized_files["manager"]
87
+ )
80
88
  if "services" in manager_data:
81
89
  api_data["managers"] = manager_data["services"]
82
90
 
83
91
  # Extract CLI commands
84
- if cli_files:
85
- cli_data = self.api_extractor.extract_cli_commands(cli_files)
92
+ if categorized_files["cli"]:
93
+ cli_data = self.api_extractor.extract_cli_commands(categorized_files["cli"])
86
94
  api_data.update(cli_data)
87
95
 
88
96
  # Extract MCP tools
89
- if mcp_files:
90
- mcp_data = self.api_extractor.extract_mcp_tools(mcp_files)
97
+ if categorized_files["mcp"]:
98
+ mcp_data = self.api_extractor.extract_mcp_tools(categorized_files["mcp"])
91
99
  api_data.update(mcp_data)
92
100
 
101
+ return api_data
102
+
103
+ def extract_api_documentation(self, source_paths: list[Path]) -> dict[str, t.Any]:
104
+ """Extract API documentation from source code files."""
105
+ self.console.print(
106
+ "[cyan]📖[/cyan] Extracting API documentation from source files..."
107
+ )
108
+
109
+ categorized_files = self._categorize_source_files(source_paths)
110
+ api_data = {}
111
+
112
+ # Extract from Python files
113
+ if categorized_files["python"]:
114
+ python_data = self.api_extractor.extract_from_python_files(
115
+ categorized_files["python"]
116
+ )
117
+ api_data.update(python_data)
118
+
119
+ # Extract specialized APIs
120
+ api_data.update(self._extract_specialized_apis(categorized_files))
121
+
93
122
  self.console.print(
94
123
  f"[green]✅[/green] Extracted documentation from {len(source_paths)} files"
95
124
  )
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  import asyncio
2
4
  import hashlib
3
5
  import time
@@ -6,19 +8,30 @@ from pathlib import Path
6
8
  from typing import Any
7
9
 
8
10
  import aiofiles
11
+ from acb.depends import Inject, depends
12
+ from acb.logger import Logger
9
13
 
10
14
  from crackerjack.errors import FileError
11
- from crackerjack.models.protocols import FileSystemInterface
12
- from crackerjack.services.logging import LoggingContext, get_logger
15
+ from crackerjack.models.protocols import (
16
+ EnhancedFileSystemServiceProtocol,
17
+ ServiceProtocol,
18
+ )
19
+ from crackerjack.services.logging import LoggingContext
13
20
 
14
21
 
15
22
  class FileCache:
16
- def __init__(self, max_size: int = 1000, default_ttl: float = 300.0) -> None:
23
+ @depends.inject
24
+ def __init__(
25
+ self,
26
+ logger: Inject[Logger],
27
+ max_size: int = 1000,
28
+ default_ttl: float = 300.0,
29
+ ) -> None:
17
30
  self.max_size = max_size
18
31
  self.default_ttl = default_ttl
19
32
  self._cache: dict[str, dict[str, Any]] = {}
20
33
  self._access_times: dict[str, float] = {}
21
- self.logger = get_logger("crackerjack.filesystem.cache")
34
+ self.logger = logger
22
35
 
23
36
  def get(self, key: str) -> str | None:
24
37
  if key not in self._cache:
@@ -78,11 +91,16 @@ class FileCache:
78
91
 
79
92
 
80
93
  class BatchFileOperations:
81
- def __init__(self, batch_size: int = 10) -> None:
94
+ @depends.inject
95
+ def __init__(
96
+ self,
97
+ logger: Inject[Logger],
98
+ batch_size: int = 10,
99
+ ) -> None:
82
100
  self.batch_size = batch_size
83
101
  self.read_queue: list[tuple[Path, asyncio.Future[str]]] = []
84
102
  self.write_queue: list[tuple[Path, str, asyncio.Future[None]]] = []
85
- self.logger = get_logger("crackerjack.filesystem.batch")
103
+ self.logger = logger
86
104
 
87
105
  async def queue_read(self, path: Path) -> str:
88
106
  future: asyncio.Future[str] = asyncio.Future()
@@ -161,18 +179,21 @@ class BatchFileOperations:
161
179
  future.set_exception(e)
162
180
 
163
181
 
164
- class EnhancedFileSystemService(FileSystemInterface):
182
+ class EnhancedFileSystemService(EnhancedFileSystemServiceProtocol, ServiceProtocol):
183
+ @depends.inject
165
184
  def __init__(
166
185
  self,
186
+ logger: Inject[Logger],
167
187
  cache_size: int = 1000,
168
188
  cache_ttl: float = 300.0,
169
189
  batch_size: int = 10,
170
190
  enable_async: bool = True,
171
191
  ) -> None:
172
- self.cache = FileCache(cache_size, cache_ttl)
192
+ # Use keyword args to avoid DI/positional ambiguity
193
+ self.cache = FileCache(max_size=cache_size, default_ttl=cache_ttl)
173
194
  self.batch_ops = BatchFileOperations(batch_size) if enable_async else None
174
195
  self.enable_async = enable_async
175
- self.logger = get_logger("crackerjack.filesystem.enhanced")
196
+ self.logger = logger
176
197
 
177
198
  self._file_timestamps: dict[str, float] = {}
178
199
 
@@ -195,6 +216,9 @@ class EnhancedFileSystemService(FileSystemInterface):
195
216
 
196
217
  def write_file(self, path: str | Path, content: str) -> None:
197
218
  path_obj = Path(path) if isinstance(path, str) else path
219
+ # Validate content type before logging/length computation
220
+ if not isinstance(content, str):
221
+ raise TypeError("Content must be a string")
198
222
 
199
223
  with LoggingContext("write_file", path=str(path_obj), size=len(content)):
200
224
  self._write_file_direct(path_obj, content)
@@ -307,33 +331,45 @@ class EnhancedFileSystemService(FileSystemInterface):
307
331
  return self.cache.get(cache_key)
308
332
 
309
333
  @staticmethod
310
- def _read_file_direct(path: Path) -> str:
311
- try:
312
- if not path.exists():
313
- raise FileError(
314
- message=f"File does not exist: {path}",
315
- details=f"Attempted to read file at {path.absolute()}",
316
- recovery="Check file path and ensure file exists",
317
- )
318
- return path.read_text(encoding="utf-8")
319
- except PermissionError as e:
334
+ def _validate_file_exists(path: Path) -> None:
335
+ """Validate that a file exists."""
336
+ if not path.exists():
337
+ raise FileError(
338
+ message=f"File does not exist: {path}",
339
+ details=f"Attempted to read file at {path.absolute()}",
340
+ recovery="Check file path and ensure file exists",
341
+ )
342
+
343
+ @staticmethod
344
+ def _handle_read_error(error: Exception, path: Path) -> None:
345
+ """Handle file read errors."""
346
+ if isinstance(error, PermissionError):
320
347
  raise FileError(
321
348
  message=f"Permission denied reading file: {path}",
322
- details=str(e),
349
+ details=str(error),
323
350
  recovery="Check file permissions and user access rights",
324
- ) from e
325
- except UnicodeDecodeError as e:
351
+ ) from error
352
+ elif isinstance(error, UnicodeDecodeError):
326
353
  raise FileError(
327
354
  message=f"Unable to decode file as UTF-8: {path}",
328
- details=str(e),
355
+ details=str(error),
329
356
  recovery="Ensure file is text - based and UTF-8 encoded",
330
- ) from e
331
- except OSError as e:
357
+ ) from error
358
+ elif isinstance(error, OSError):
332
359
  raise FileError(
333
360
  message=f"System error reading file: {path}",
334
- details=str(e),
361
+ details=str(error),
335
362
  recovery="Check disk space and file system integrity",
336
- ) from e
363
+ ) from error
364
+
365
+ @staticmethod
366
+ def _read_file_direct(path: Path) -> str:
367
+ try:
368
+ EnhancedFileSystemService._validate_file_exists(path)
369
+ return path.read_text(encoding="utf-8")
370
+ except (PermissionError, UnicodeDecodeError, OSError) as e:
371
+ EnhancedFileSystemService._handle_read_error(e, path)
372
+ raise # Ensure type checker knows this doesn't return
337
373
 
338
374
  @staticmethod
339
375
  def _write_file_direct(path: Path, content: str) -> None:
@@ -441,3 +477,21 @@ class EnhancedFileSystemService(FileSystemInterface):
441
477
  details=str(e),
442
478
  recovery="Check parent directory permissions",
443
479
  ) from e
480
+
481
+ async def _on_start(self) -> None:
482
+ """
483
+ Lifecycle method called when the service is started.
484
+ """
485
+ self.logger.debug("EnhancedFileSystemService started")
486
+
487
+ async def _on_stop(self) -> None:
488
+ """
489
+ Lifecycle method called when the service is stopped.
490
+ """
491
+ self.logger.debug("EnhancedFileSystemService stopped")
492
+
493
+ async def _on_reload(self) -> None:
494
+ """
495
+ Lifecycle method called when the service is reloaded.
496
+ """
497
+ self.logger.debug("EnhancedFileSystemService reloaded")
@@ -313,7 +313,7 @@ class DataCompactionManager:
313
313
  return file_mtime < cutoff_date
314
314
 
315
315
  def _build_compaction_result(
316
- self, data_type: str, rules: dict[str, t.Any], stats: dict[str, int]
316
+ self, data_type: str, rules: dict[str, t.Any], stats: dict[str, t.Any]
317
317
  ) -> dict[str, t.Any]:
318
318
  """Build the compaction result dictionary."""
319
319
  return {
@@ -157,7 +157,7 @@ class ErrorPatternAnalyzer:
157
157
  error_type = pattern.error_type
158
158
  count = pattern.count
159
159
 
160
- file_error_counts[file_path][error_type] += count
160
+ file_error_counts[file_path][error_type] += float(count)
161
161
  max_value = max(max_value, file_error_counts[file_path][error_type])
162
162
 
163
163
  # Create heat map cells
@@ -173,21 +173,21 @@ class ErrorPatternAnalyzer:
173
173
 
174
174
  for file_path in files:
175
175
  for error_type in error_types:
176
- count = file_error_counts[file_path].get(error_type, 0)
177
- if count > 0:
178
- intensity: float = count / max_value if max_value > 0 else 0
176
+ count_val = float(file_error_counts[file_path].get(error_type, 0))
177
+ if count_val > 0:
178
+ intensity = count_val / max_value if max_value > 0 else 0.0 # type: ignore[assignment]
179
179
  severity = self._get_severity_for_type(error_type)
180
180
 
181
181
  cells.append(
182
182
  HeatMapCell(
183
183
  x=file_path,
184
184
  y=error_type,
185
- value=count,
185
+ value=count_val,
186
186
  color_intensity=intensity,
187
187
  tooltip_data={
188
188
  "file": file_path,
189
189
  "error_type": error_type,
190
- "count": count,
190
+ "count": int(count_val),
191
191
  "severity": severity,
192
192
  },
193
193
  severity=severity,
@@ -300,7 +300,7 @@ class ErrorPatternAnalyzer:
300
300
  cells = []
301
301
  for time_label in time_labels:
302
302
  for error_type in error_types:
303
- count = temporal_counts[time_label].get(error_type, 0)
303
+ count = float(temporal_counts[time_label].get(error_type, 0))
304
304
  if count > 0:
305
305
  cell = self._create_temporal_cell(
306
306
  time_label, error_type, count, max_value
@@ -313,7 +313,7 @@ class ErrorPatternAnalyzer:
313
313
  self, time_label: str, error_type: str, count: float, max_value: float
314
314
  ) -> HeatMapCell:
315
315
  """Create a single temporal heatmap cell."""
316
- intensity: float = count / max_value if max_value > 0 else 0
316
+ intensity = count / max_value if max_value > 0 else 0.0 # type: ignore[assignment]
317
317
  severity = self._get_severity_for_type(error_type)
318
318
 
319
319
  return HeatMapCell(
@@ -392,7 +392,7 @@ class ErrorPatternAnalyzer:
392
392
  cells = []
393
393
  for function_id in functions:
394
394
  for error_type in error_types:
395
- count = function_error_counts[function_id].get(error_type, 0)
395
+ count = float(function_error_counts[function_id].get(error_type, 0))
396
396
  if count > 0:
397
397
  cell = self._create_function_cell(
398
398
  function_id, error_type, count, max_value
@@ -405,7 +405,7 @@ class ErrorPatternAnalyzer:
405
405
  self, function_id: str, error_type: str, count: float, max_value: float
406
406
  ) -> HeatMapCell:
407
407
  """Create a single function heatmap cell."""
408
- intensity: float = count / max_value if max_value > 0 else 0
408
+ intensity = count / max_value if max_value > 0 else 0.0 # type: ignore[assignment]
409
409
  severity = self._get_severity_for_type(error_type)
410
410
 
411
411
  return HeatMapCell(
@@ -0,0 +1,221 @@
1
+ """Smart file filtering for incremental tool execution.
2
+
3
+ Filters files based on git changes, patterns, and tool requirements.
4
+ Part of Phase 10.2: Development Velocity Improvements.
5
+ """
6
+
7
+ import typing as t
8
+ from fnmatch import fnmatch
9
+ from pathlib import Path
10
+
11
+ from crackerjack.models.protocols import (
12
+ GitServiceProtocol,
13
+ ServiceProtocol,
14
+ SmartFileFilterProtocol,
15
+ )
16
+
17
+
18
+ class SmartFileFilter(SmartFileFilterProtocol, ServiceProtocol):
19
+ """Filter files for tool execution based on git changes and patterns.
20
+
21
+ Provides intelligent file filtering to enable incremental execution,
22
+ reducing unnecessary tool runs and improving feedback loops.
23
+ """
24
+
25
+ def __init__(
26
+ self,
27
+ git_service: GitServiceProtocol,
28
+ project_root: Path | None = None,
29
+ ):
30
+ """Initialize file filter.
31
+
32
+ Args:
33
+ git_service: Git service for repository operations
34
+ project_root: Project root directory (defaults to cwd)
35
+ """
36
+ self._git_service = git_service
37
+ self.project_root = project_root or Path.cwd()
38
+
39
+ def initialize(self) -> None:
40
+ pass
41
+
42
+ def cleanup(self) -> None:
43
+ pass
44
+
45
+ def health_check(self) -> bool:
46
+ return True
47
+
48
+ def shutdown(self) -> None:
49
+ pass
50
+
51
+ def metrics(self) -> dict[str, t.Any]:
52
+ return {}
53
+
54
+ def is_healthy(self) -> bool:
55
+ return True
56
+
57
+ def register_resource(self, resource: t.Any) -> None:
58
+ pass
59
+
60
+ def cleanup_resource(self, resource: t.Any) -> None:
61
+ pass
62
+
63
+ def record_error(self, error: Exception) -> None:
64
+ pass
65
+
66
+ def increment_requests(self) -> None:
67
+ pass
68
+
69
+ def get_custom_metric(self, name: str) -> t.Any:
70
+ return None
71
+
72
+ def set_custom_metric(self, name: str, value: t.Any) -> None:
73
+ pass
74
+
75
+ def get_changed_files(self, since: str = "HEAD") -> list[Path]:
76
+ """Get files changed since a git reference.
77
+
78
+ Args:
79
+ since: Git reference (commit, branch, tag, or "HEAD")
80
+
81
+ Returns:
82
+ List of changed file paths relative to project root
83
+ """
84
+ return self._git_service.get_changed_files_since(since, self.project_root)
85
+
86
+ def get_staged_files(self) -> list[Path]:
87
+ """Get currently staged files (in git index).
88
+
89
+ Returns:
90
+ List of staged file paths relative to project root
91
+ """
92
+ return self._git_service.get_staged_files(self.project_root)
93
+
94
+ def get_unstaged_files(self) -> list[Path]:
95
+ """Get unstaged modified files (working tree changes).
96
+
97
+ Returns:
98
+ List of unstaged file paths relative to project root
99
+ """
100
+ return self._git_service.get_unstaged_files(self.project_root)
101
+
102
+ def filter_by_pattern(self, files: list[Path], pattern: str) -> list[Path]:
103
+ """Filter files by glob pattern.
104
+
105
+ Args:
106
+ files: List of file paths to filter
107
+ pattern: Glob pattern (e.g., '*.py', '**/*.ts')
108
+
109
+ Returns:
110
+ List of files matching the pattern
111
+ """
112
+ return [
113
+ file_path
114
+ for file_path in files
115
+ if fnmatch(str(file_path), pattern) or fnmatch(file_path.name, pattern)
116
+ ]
117
+
118
+ def filter_by_tool(self, files: list[Path], tool: str) -> list[Path]:
119
+ """Filter files relevant to a specific tool.
120
+
121
+ Args:
122
+ files: List of file paths to filter
123
+ tool: Tool name (e.g., 'ruff-check', 'zuban', 'skylos')
124
+
125
+ Returns:
126
+ List of files applicable to the tool
127
+ """
128
+ # Tool-specific file type mappings
129
+ tool_patterns = {
130
+ # Python tools
131
+ "ruff-check": ["*.py"],
132
+ "ruff-format": ["*.py"],
133
+ "zuban": ["*.py"],
134
+ "skylos": ["*.py"],
135
+ "bandit": ["*.py"],
136
+ "refurb": ["*.py"],
137
+ "complexipy": ["*.py"],
138
+ "creosote": ["*.py"],
139
+ # Markdown tools
140
+ "mdformat": ["*.md"],
141
+ # YAML/TOML tools
142
+ "check-yaml": ["*.yaml", "*.yml"],
143
+ "check-toml": ["*.toml"],
144
+ # Text tools (apply to most files)
145
+ "trailing-whitespace": ["*"],
146
+ "end-of-file-fixer": ["*"],
147
+ "codespell": ["*"],
148
+ # Special tools
149
+ "validate-regex-patterns": ["*.py"],
150
+ "gitleaks": ["*"],
151
+ "uv-lock": ["pyproject.toml"],
152
+ "check-added-large-files": ["*"],
153
+ }
154
+
155
+ patterns = tool_patterns.get(tool, ["*"])
156
+
157
+ # Apply all patterns for the tool
158
+ filtered = []
159
+ for pattern in patterns:
160
+ filtered.extend(self.filter_by_pattern(files, pattern))
161
+
162
+ # Remove duplicates while preserving order
163
+ seen = set()
164
+ result = []
165
+ for file_path in filtered:
166
+ if file_path not in seen:
167
+ seen.add(file_path)
168
+ result.append(file_path)
169
+
170
+ return result
171
+
172
+ def get_all_modified_files(self) -> list[Path]:
173
+ """Get all modified files (staged + unstaged).
174
+
175
+ Returns:
176
+ Combined list of staged and unstaged files
177
+ """
178
+ staged = set(self.get_staged_files())
179
+ unstaged = set(self.get_unstaged_files())
180
+ all_modified = staged | unstaged
181
+
182
+ return sorted(all_modified)
183
+
184
+ def filter_by_extensions(
185
+ self, files: list[Path], extensions: list[str]
186
+ ) -> list[Path]:
187
+ """Filter files by file extensions.
188
+
189
+ Args:
190
+ files: List of file paths to filter
191
+ extensions: List of extensions (e.g., ['.py', '.md'])
192
+
193
+ Returns:
194
+ List of files with matching extensions
195
+ """
196
+ # Normalize extensions to include leading dot
197
+ normalized = [ext if ext.startswith(".") else f".{ext}" for ext in extensions]
198
+
199
+ return [file_path for file_path in files if file_path.suffix in normalized]
200
+
201
+ def get_python_files(self, files: list[Path]) -> list[Path]:
202
+ """Convenience method to filter Python files.
203
+
204
+ Args:
205
+ files: List of file paths to filter
206
+
207
+ Returns:
208
+ List of Python files (.py)
209
+ """
210
+ return self.filter_by_extensions(files, [".py"])
211
+
212
+ def get_markdown_files(self, files: list[Path]) -> list[Path]:
213
+ """Convenience method to filter Markdown files.
214
+
215
+ Args:
216
+ files: List of file paths to filter
217
+
218
+ Returns:
219
+ List of Markdown files (.md)
220
+ """
221
+ return self.filter_by_extensions(files, [".md"])
@@ -107,13 +107,11 @@ class FileHasher:
107
107
  return any(pattern in path_str for pattern in ignore_patterns)
108
108
 
109
109
  def invalidate_cache(self, file_path: Path | None = None) -> None:
110
- if file_path:
111
- stat = file_path.stat() if file_path.exists() else None
112
- if stat:
113
- cache_key = f"file_hash: {file_path}: {stat.st_mtime}: {stat.st_size}"
114
- self.cache.file_hash_cache.invalidate(cache_key)
115
- else:
116
- self.cache.file_hash_cache.clear()
110
+ # CrackerjackCache doesn't have direct access to its underlying cache,
111
+ # so for targeted invalidation we would need to clear all file hashes
112
+ # For a specific file, we can't directly invalidate just that entry
113
+ # since the cache key contains mtime and size that would trigger invalidation naturally
114
+ pass # No direct way to clear individual cache entries in CrackerjackCache
117
115
 
118
116
 
119
117
  class SmartFileWatcher: