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,497 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ import hashlib
5
+ import time
6
+ from collections.abc import Iterator
7
+ from pathlib import Path
8
+ from typing import Any
9
+
10
+ import aiofiles
11
+ from acb.depends import Inject, depends
12
+ from acb.logger import Logger
13
+
14
+ from crackerjack.errors import FileError
15
+ from crackerjack.models.protocols import (
16
+ EnhancedFileSystemServiceProtocol,
17
+ ServiceProtocol,
18
+ )
19
+ from crackerjack.services.logging import LoggingContext
20
+
21
+
22
+ class FileCache:
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:
30
+ self.max_size = max_size
31
+ self.default_ttl = default_ttl
32
+ self._cache: dict[str, dict[str, Any]] = {}
33
+ self._access_times: dict[str, float] = {}
34
+ self.logger = logger
35
+
36
+ def get(self, key: str) -> str | None:
37
+ if key not in self._cache:
38
+ return None
39
+
40
+ cache_entry = self._cache[key]
41
+ now = time.time()
42
+
43
+ if now - cache_entry["timestamp"] > cache_entry["ttl"]:
44
+ self._evict(key)
45
+ return None
46
+
47
+ self._access_times[key] = now
48
+ self.logger.debug("Cache hit", key=key)
49
+ content: str | None = cache_entry["content"]
50
+ return content
51
+
52
+ def put(self, key: str, content: str, ttl: float | None = None) -> None:
53
+ if len(self._cache) >= self.max_size:
54
+ self._evict_lru()
55
+
56
+ now = time.time()
57
+ self._cache[key] = {
58
+ "content": content,
59
+ "timestamp": now,
60
+ "ttl": ttl or self.default_ttl,
61
+ "size": len(content),
62
+ }
63
+ self._access_times[key] = now
64
+ self.logger.debug("Cache put", key=key, size=len(content))
65
+
66
+ def _evict(self, key: str) -> None:
67
+ self._cache.pop(key, None)
68
+ self._access_times.pop(key, None)
69
+
70
+ def _evict_lru(self) -> None:
71
+ if not self._access_times:
72
+ return
73
+
74
+ lru_key = min(self._access_times, key=lambda k: self._access_times.get(k, 0.0))
75
+ self._evict(lru_key)
76
+ self.logger.debug("Cache LRU eviction", key=lru_key)
77
+
78
+ def clear(self) -> None:
79
+ self._cache.clear()
80
+ self._access_times.clear()
81
+ self.logger.debug("Cache cleared")
82
+
83
+ def get_stats(self) -> dict[str, Any]:
84
+ total_size = sum(entry["size"] for entry in self._cache.values())
85
+ return {
86
+ "entries": len(self._cache),
87
+ "max_size": self.max_size,
88
+ "total_content_size": total_size,
89
+ "memory_usage_mb": total_size / (1024 * 1024),
90
+ }
91
+
92
+
93
+ class BatchFileOperations:
94
+ @depends.inject
95
+ def __init__(
96
+ self,
97
+ logger: Inject[Logger],
98
+ batch_size: int = 10,
99
+ ) -> None:
100
+ self.batch_size = batch_size
101
+ self.read_queue: list[tuple[Path, asyncio.Future[str]]] = []
102
+ self.write_queue: list[tuple[Path, str, asyncio.Future[None]]] = []
103
+ self.logger = logger
104
+
105
+ async def queue_read(self, path: Path) -> str:
106
+ future: asyncio.Future[str] = asyncio.Future()
107
+ self.read_queue.append((path, future))
108
+
109
+ if len(self.read_queue) >= self.batch_size:
110
+ await self._flush_reads()
111
+
112
+ return await future
113
+
114
+ async def queue_write(self, path: Path, content: str) -> None:
115
+ future: asyncio.Future[None] = asyncio.Future[None]()
116
+ self.write_queue.append((path, content, future))
117
+
118
+ if len(self.write_queue) >= self.batch_size:
119
+ await self._flush_writes()
120
+
121
+ await future
122
+
123
+ async def flush_all(self) -> None:
124
+ await asyncio.gather(
125
+ self._flush_reads(),
126
+ self._flush_writes(),
127
+ return_exceptions=True,
128
+ )
129
+
130
+ async def _flush_reads(self) -> None:
131
+ if not self.read_queue:
132
+ return
133
+
134
+ with LoggingContext("batch_file_reads", count=len(self.read_queue)):
135
+ batch = self.read_queue.copy()
136
+ self.read_queue.clear()
137
+
138
+ from itertools import starmap
139
+
140
+ tasks = list(starmap(self._read_single_async, batch))
141
+
142
+ await asyncio.gather(*tasks, return_exceptions=True)
143
+
144
+ async def _flush_writes(self) -> None:
145
+ if not self.write_queue:
146
+ return
147
+
148
+ with LoggingContext("batch_file_writes", count=len(self.write_queue)):
149
+ batch = self.write_queue.copy()
150
+ self.write_queue.clear()
151
+
152
+ from itertools import starmap
153
+
154
+ tasks = list(starmap(self._write_single_async, batch))
155
+
156
+ await asyncio.gather(*tasks, return_exceptions=True)
157
+
158
+ @staticmethod
159
+ async def _read_single_async(path: Path, future: asyncio.Future[str]) -> None:
160
+ try:
161
+ async with aiofiles.open(path, encoding="utf-8") as f:
162
+ content = await f.read()
163
+ future.set_result(content)
164
+ except Exception as e:
165
+ future.set_exception(e)
166
+
167
+ @staticmethod
168
+ async def _write_single_async(
169
+ path: Path,
170
+ content: str,
171
+ future: asyncio.Future[None],
172
+ ) -> None:
173
+ try:
174
+ path.parent.mkdir(parents=True, exist_ok=True)
175
+ async with aiofiles.open(path, "w", encoding="utf-8") as f:
176
+ await f.write(content)
177
+ future.set_result(None)
178
+ except Exception as e:
179
+ future.set_exception(e)
180
+
181
+
182
+ class EnhancedFileSystemService(EnhancedFileSystemServiceProtocol, ServiceProtocol):
183
+ @depends.inject
184
+ def __init__(
185
+ self,
186
+ logger: Inject[Logger],
187
+ cache_size: int = 1000,
188
+ cache_ttl: float = 300.0,
189
+ batch_size: int = 10,
190
+ enable_async: bool = True,
191
+ ) -> None:
192
+ # Use keyword args to avoid DI/positional ambiguity
193
+ self.cache = FileCache(max_size=cache_size, default_ttl=cache_ttl)
194
+ self.batch_ops = BatchFileOperations(batch_size) if enable_async else None
195
+ self.enable_async = enable_async
196
+ self.logger = logger
197
+
198
+ self._file_timestamps: dict[str, float] = {}
199
+
200
+ def read_file(self, path: str | Path) -> str:
201
+ path_obj = Path(path) if isinstance(path, str) else path
202
+
203
+ with LoggingContext("read_file", path=str(path_obj)):
204
+ cache_key = self._get_cache_key(path_obj)
205
+ cached_content = self._get_from_cache(cache_key, path_obj)
206
+
207
+ if cached_content is not None:
208
+ return cached_content
209
+
210
+ content = self._read_file_direct(path_obj)
211
+
212
+ self.cache.put(cache_key, content)
213
+ self._file_timestamps[str(path_obj)] = path_obj.stat().st_mtime
214
+
215
+ return content
216
+
217
+ def write_file(self, path: str | Path, content: str) -> None:
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")
222
+
223
+ with LoggingContext("write_file", path=str(path_obj), size=len(content)):
224
+ self._write_file_direct(path_obj, content)
225
+
226
+ cache_key = self._get_cache_key(path_obj)
227
+ self.cache._evict(cache_key)
228
+ self._file_timestamps[str(path_obj)] = time.time()
229
+
230
+ async def read_file_async(self, path: Path) -> str:
231
+ if not self.enable_async or not self.batch_ops:
232
+ return self.read_file(path)
233
+
234
+ cache_key = self._get_cache_key(path)
235
+ cached_content = self._get_from_cache(cache_key, path)
236
+
237
+ if cached_content is not None:
238
+ return cached_content
239
+
240
+ content = await self.batch_ops.queue_read(path)
241
+
242
+ self.cache.put(cache_key, content)
243
+ self._file_timestamps[str(path)] = path.stat().st_mtime
244
+
245
+ return content
246
+
247
+ async def write_file_async(self, path: Path, content: str) -> None:
248
+ if not self.enable_async or not self.batch_ops:
249
+ self.write_file(path, content)
250
+ return
251
+
252
+ await self.batch_ops.queue_write(path, content)
253
+
254
+ cache_key = self._get_cache_key(path)
255
+ self.cache._evict(cache_key)
256
+ self._file_timestamps[str(path)] = time.time()
257
+
258
+ async def read_multiple_files(self, paths: list[Path]) -> dict[Path, str]:
259
+ results = {}
260
+
261
+ if not self.enable_async or not self.batch_ops:
262
+ for path in paths:
263
+ try:
264
+ results[path] = self.read_file(path)
265
+ except Exception as e:
266
+ self.logger.exception(
267
+ "Failed to read file",
268
+ path=str(path),
269
+ error=str(e),
270
+ )
271
+ results[path] = ""
272
+ return results
273
+
274
+ with LoggingContext("read_multiple_files", count=len(paths)):
275
+ tasks = [self.read_file_async(path) for path in paths]
276
+
277
+ results_list = await asyncio.gather(*tasks, return_exceptions=True)
278
+
279
+ for path, result in zip(paths, results_list, strict=False):
280
+ if isinstance(result, Exception):
281
+ self.logger.error(
282
+ "Failed to read file",
283
+ path=str(path),
284
+ error=str(result),
285
+ )
286
+ results[path] = ""
287
+ elif isinstance(result, str): # Explicit check for mypy
288
+ results[path] = result
289
+
290
+ return results
291
+
292
+ async def write_multiple_files(self, file_data: dict[Path, str]) -> None:
293
+ if not self.enable_async or not self.batch_ops:
294
+ for path, content in file_data.items():
295
+ try:
296
+ self.write_file(path, content)
297
+ except Exception as e:
298
+ self.logger.exception(
299
+ "Failed to write file",
300
+ path=str(path),
301
+ error=str(e),
302
+ )
303
+ return
304
+
305
+ with LoggingContext("write_multiple_files", count=len(file_data)):
306
+ from itertools import starmap
307
+
308
+ tasks = list(starmap(self.write_file_async, file_data.items()))
309
+
310
+ await asyncio.gather(*tasks, return_exceptions=True)
311
+
312
+ @staticmethod
313
+ def _get_cache_key(path: Path) -> str:
314
+ path_str = str(path.resolve())
315
+ return hashlib.md5(path_str.encode(), usedforsecurity=False).hexdigest()
316
+
317
+ def _get_from_cache(self, cache_key: str, path: Path) -> str | None:
318
+ if not path.exists():
319
+ return None
320
+
321
+ path_str = str(path)
322
+ if path_str in self._file_timestamps:
323
+ current_mtime = path.stat().st_mtime
324
+ cached_mtime = self._file_timestamps[path_str]
325
+
326
+ if current_mtime > cached_mtime:
327
+ self.cache._evict(cache_key)
328
+ del self._file_timestamps[path_str]
329
+ return None
330
+
331
+ return self.cache.get(cache_key)
332
+
333
+ @staticmethod
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):
347
+ raise FileError(
348
+ message=f"Permission denied reading file: {path}",
349
+ details=str(error),
350
+ recovery="Check file permissions and user access rights",
351
+ ) from error
352
+ elif isinstance(error, UnicodeDecodeError):
353
+ raise FileError(
354
+ message=f"Unable to decode file as UTF-8: {path}",
355
+ details=str(error),
356
+ recovery="Ensure file is text - based and UTF-8 encoded",
357
+ ) from error
358
+ elif isinstance(error, OSError):
359
+ raise FileError(
360
+ message=f"System error reading file: {path}",
361
+ details=str(error),
362
+ recovery="Check disk space and file system integrity",
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
373
+
374
+ @staticmethod
375
+ def _write_file_direct(path: Path, content: str) -> None:
376
+ try:
377
+ try:
378
+ path.parent.mkdir(parents=True, exist_ok=True)
379
+ except OSError as e:
380
+ raise FileError(
381
+ message=f"Cannot create parent directory: {path.parent}",
382
+ details=str(e),
383
+ recovery="Check directory permissions and disk space",
384
+ ) from e
385
+
386
+ path.write_text(content, encoding="utf-8")
387
+
388
+ except PermissionError as e:
389
+ raise FileError(
390
+ message=f"Permission denied writing file: {path}",
391
+ details=str(e),
392
+ recovery="Check file and directory permissions",
393
+ ) from e
394
+ except OSError as e:
395
+ raise FileError(
396
+ message=f"System error writing file: {path}",
397
+ details=str(e),
398
+ recovery="Check disk space and file system integrity",
399
+ ) from e
400
+
401
+ @staticmethod
402
+ def file_exists(path: str | Path) -> bool:
403
+ return (Path(path) if isinstance(path, str) else path).exists()
404
+
405
+ def create_directory(self, path: str | Path) -> None:
406
+ path_obj = Path(path) if isinstance(path, str) else path
407
+ try:
408
+ path_obj.mkdir(parents=True, exist_ok=True)
409
+ self.logger.debug("Directory created", path=str(path_obj))
410
+ except OSError as e:
411
+ raise FileError(
412
+ message=f"Cannot create directory: {path_obj}",
413
+ details=str(e),
414
+ recovery="Check parent directory permissions and disk space",
415
+ ) from e
416
+
417
+ def delete_file(self, path: str | Path) -> None:
418
+ path_obj = Path(path) if isinstance(path, str) else path
419
+
420
+ try:
421
+ if path_obj.exists():
422
+ path_obj.unlink()
423
+
424
+ cache_key = self._get_cache_key(path_obj)
425
+ self.cache._evict(cache_key)
426
+ self._file_timestamps.pop(str(path_obj), None)
427
+
428
+ self.logger.debug("File deleted", path=str(path_obj))
429
+ except OSError as e:
430
+ raise FileError(
431
+ message=f"Cannot delete file: {path_obj}",
432
+ details=str(e),
433
+ recovery="Check file permissions",
434
+ ) from e
435
+
436
+ @staticmethod
437
+ def list_files(path: str | Path, pattern: str = "*") -> Iterator[Path]:
438
+ path_obj = Path(path) if isinstance(path, str) else path
439
+
440
+ if not path_obj.is_dir():
441
+ raise FileError(
442
+ message=f"Path is not a directory: {path_obj}",
443
+ details=f"Cannot list[t.Any] files in {path_obj}",
444
+ recovery="Ensure path points to a valid directory",
445
+ )
446
+
447
+ try:
448
+ yield from path_obj.glob(pattern)
449
+ except OSError as e:
450
+ raise FileError(
451
+ message=f"Cannot list[t.Any] files in directory: {path_obj}",
452
+ details=str(e),
453
+ recovery="Check directory permissions",
454
+ ) from e
455
+
456
+ async def flush_operations(self) -> None:
457
+ if self.batch_ops:
458
+ await self.batch_ops.flush_all()
459
+
460
+ def get_cache_stats(self) -> dict[str, Any]:
461
+ return self.cache.get_stats()
462
+
463
+ def clear_cache(self) -> None:
464
+ self.cache.clear()
465
+ self._file_timestamps.clear()
466
+
467
+ def exists(self, path: str | Path) -> bool:
468
+ return (Path(path) if isinstance(path, str) else path).exists()
469
+
470
+ def mkdir(self, path: str | Path, parents: bool = False) -> None:
471
+ path_obj = Path(path) if isinstance(path, str) else path
472
+ try:
473
+ path_obj.mkdir(parents=parents, exist_ok=True)
474
+ except OSError as e:
475
+ raise FileError(
476
+ message=f"Cannot create directory: {path_obj}",
477
+ details=str(e),
478
+ recovery="Check parent directory permissions",
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")