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,585 @@
1
+ import typing as t
2
+ from pathlib import Path
3
+
4
+ from ..services.regex_patterns import SAFE_PATTERNS
5
+ from .base import (
6
+ AgentContext,
7
+ FixResult,
8
+ Issue,
9
+ IssueType,
10
+ SubAgent,
11
+ agent_registry,
12
+ )
13
+ from .semantic_helpers import (
14
+ SemanticInsight,
15
+ create_semantic_enhancer,
16
+ get_session_enhanced_recommendations,
17
+ )
18
+
19
+
20
+ class DRYAgent(SubAgent):
21
+ """Agent for detecting and fixing DRY (Don't Repeat Yourself) violations.
22
+
23
+ Enhanced with semantic context to detect conceptual duplicates beyond
24
+ just syntactic pattern matching.
25
+ """
26
+
27
+ def __init__(self, context: AgentContext) -> None:
28
+ super().__init__(context)
29
+ self.semantic_enhancer = create_semantic_enhancer(context.project_path)
30
+ self.semantic_insights: dict[str, SemanticInsight] = {}
31
+
32
+ def get_supported_types(self) -> set[IssueType]:
33
+ return {IssueType.DRY_VIOLATION}
34
+
35
+ async def can_handle(self, issue: Issue) -> float:
36
+ if issue.type == IssueType.DRY_VIOLATION:
37
+ return 0.9
38
+ return 0.0
39
+
40
+ async def analyze_and_fix(self, issue: Issue) -> FixResult:
41
+ self.log(f"Analyzing DRY violation: {issue.message}")
42
+
43
+ validation_result = self._validate_dry_issue(issue)
44
+ if validation_result:
45
+ return validation_result
46
+
47
+ if issue.file_path is None:
48
+ return self._create_dry_error_result(
49
+ ValueError("File path is required for DRY violation"),
50
+ )
51
+
52
+ file_path = Path(issue.file_path)
53
+
54
+ try:
55
+ return await self._process_dry_violation(file_path)
56
+ except Exception as e:
57
+ return self._create_dry_error_result(e)
58
+
59
+ def _validate_dry_issue(self, issue: Issue) -> FixResult | None:
60
+ if not issue.file_path:
61
+ return FixResult(
62
+ success=False,
63
+ confidence=0.0,
64
+ remaining_issues=["No file path specified for DRY violation"],
65
+ )
66
+
67
+ file_path = Path(issue.file_path)
68
+ if not file_path.exists():
69
+ return FixResult(
70
+ success=False,
71
+ confidence=0.0,
72
+ remaining_issues=[f"File not found: {file_path}"],
73
+ )
74
+
75
+ return None
76
+
77
+ async def _process_dry_violation(self, file_path: Path) -> FixResult:
78
+ content = self.context.get_file_content(file_path)
79
+ if not content:
80
+ return FixResult(
81
+ success=False,
82
+ confidence=0.0,
83
+ remaining_issues=[f"Could not read file: {file_path}"],
84
+ )
85
+
86
+ # Detect traditional pattern-based violations
87
+ violations = self._detect_dry_violations(content, file_path)
88
+
89
+ # Enhance with semantic duplicate detection
90
+ semantic_violations = await self._detect_semantic_violations(content, file_path)
91
+ violations.extend(semantic_violations)
92
+
93
+ if not violations:
94
+ return FixResult(
95
+ success=True,
96
+ confidence=0.7,
97
+ recommendations=["No DRY violations detected"],
98
+ )
99
+
100
+ return await self._apply_and_save_dry_fixes(file_path, content, violations)
101
+
102
+ async def _apply_and_save_dry_fixes(
103
+ self,
104
+ file_path: Path,
105
+ content: str,
106
+ violations: list[dict[str, t.Any]],
107
+ ) -> FixResult:
108
+ fixed_content = self._apply_dry_fixes(content, violations)
109
+
110
+ if fixed_content == content:
111
+ return self._create_no_fixes_result()
112
+
113
+ success = self.context.write_file_content(file_path, fixed_content)
114
+ if not success:
115
+ return FixResult(
116
+ success=False,
117
+ confidence=0.0,
118
+ remaining_issues=[f"Failed to write fixed file: {file_path}"],
119
+ )
120
+
121
+ # Enhance recommendations with semantic insights and session continuity
122
+ recommendations = ["Verify functionality after DRY fixes"]
123
+ if hasattr(self, "current_semantic_insight") and self.current_semantic_insight:
124
+ recommendations = self.semantic_enhancer.enhance_recommendations(
125
+ recommendations, self.current_semantic_insight
126
+ )
127
+ # Log semantic context for debugging
128
+ summary = self.semantic_enhancer.get_semantic_context_summary(
129
+ self.current_semantic_insight
130
+ )
131
+ self.log(f"Semantic context: {summary}")
132
+
133
+ # Store insight for session continuity
134
+ await self.semantic_enhancer.store_insight_to_session(
135
+ self.current_semantic_insight, "DRYAgent"
136
+ )
137
+
138
+ # Enhance with session-stored insights
139
+ recommendations = await get_session_enhanced_recommendations(
140
+ recommendations, "DRYAgent", self.context.project_path
141
+ )
142
+
143
+ return FixResult(
144
+ success=True,
145
+ confidence=0.8,
146
+ fixes_applied=[
147
+ f"Fixed {len(violations)} DRY violations",
148
+ "Consolidated repetitive patterns",
149
+ ],
150
+ files_modified=[str(file_path)],
151
+ recommendations=recommendations,
152
+ )
153
+
154
+ def _create_no_fixes_result(self) -> FixResult:
155
+ return FixResult(
156
+ success=False,
157
+ confidence=0.5,
158
+ remaining_issues=["Could not automatically fix DRY violations"],
159
+ recommendations=[
160
+ "Manual refactoring required",
161
+ "Consider extracting common patterns to utility functions",
162
+ "Create base classes or mixins for repeated functionality",
163
+ ],
164
+ )
165
+
166
+ def _create_dry_error_result(self, error: Exception) -> FixResult:
167
+ return FixResult(
168
+ success=False,
169
+ confidence=0.0,
170
+ remaining_issues=[f"Error processing file: {error}"],
171
+ )
172
+
173
+ def _detect_dry_violations(
174
+ self,
175
+ content: str,
176
+ file_path: Path,
177
+ ) -> list[dict[str, t.Any]]:
178
+ violations: list[dict[str, t.Any]] = []
179
+
180
+ violations.extend(self._detect_error_response_patterns(content))
181
+
182
+ violations.extend(self._detect_path_conversion_patterns(content))
183
+
184
+ violations.extend(self._detect_file_existence_patterns(content))
185
+
186
+ violations.extend(self._detect_exception_patterns(content))
187
+
188
+ return violations
189
+
190
+ def _detect_error_response_patterns(self, content: str) -> list[dict[str, t.Any]]:
191
+ violations: list[dict[str, t.Any]] = []
192
+ lines = content.split("\n")
193
+
194
+ error_pattern = SAFE_PATTERNS["detect_error_response_patterns"]
195
+
196
+ error_responses: list[dict[str, t.Any]] = []
197
+ for i, line in enumerate(lines):
198
+ if error_pattern.test(line.strip()):
199
+ compiled_pattern = error_pattern._get_compiled_pattern()
200
+ match = compiled_pattern.search(line.strip())
201
+ if match:
202
+ error_responses.append(
203
+ {
204
+ "line_number": i + 1,
205
+ "content": line.strip(),
206
+ "error_message": match.group(1),
207
+ },
208
+ )
209
+
210
+ if len(error_responses) >= 3:
211
+ violations.append(
212
+ {
213
+ "type": "error_response_pattern",
214
+ "instances": error_responses,
215
+ "suggestion": "Extract to error utility function",
216
+ },
217
+ )
218
+
219
+ return violations
220
+
221
+ def _detect_path_conversion_patterns(self, content: str) -> list[dict[str, t.Any]]:
222
+ violations: list[dict[str, t.Any]] = []
223
+ lines = content.split("\n")
224
+
225
+ path_pattern = SAFE_PATTERNS["detect_path_conversion_patterns"]
226
+
227
+ path_conversions: list[dict[str, t.Any]] = [
228
+ {
229
+ "line_number": i + 1,
230
+ "content": line.strip(),
231
+ }
232
+ for i, line in enumerate(lines)
233
+ if path_pattern.test(line)
234
+ ]
235
+
236
+ if len(path_conversions) >= 2:
237
+ violations.append(
238
+ {
239
+ "type": "path_conversion_pattern",
240
+ "instances": path_conversions,
241
+ "suggestion": "Extract to path utility function",
242
+ },
243
+ )
244
+
245
+ return violations
246
+
247
+ def _detect_file_existence_patterns(self, content: str) -> list[dict[str, t.Any]]:
248
+ violations: list[dict[str, t.Any]] = []
249
+ lines = content.split("\n")
250
+
251
+ existence_pattern = SAFE_PATTERNS["detect_file_existence_patterns"]
252
+
253
+ existence_checks: list[dict[str, t.Any]] = [
254
+ {
255
+ "line_number": i + 1,
256
+ "content": line.strip(),
257
+ }
258
+ for i, line in enumerate(lines)
259
+ if existence_pattern.test(line.strip())
260
+ ]
261
+
262
+ if len(existence_checks) >= 3:
263
+ violations.append(
264
+ {
265
+ "type": "file_existence_pattern",
266
+ "instances": existence_checks,
267
+ "suggestion": "Extract to file validation utility",
268
+ },
269
+ )
270
+
271
+ return violations
272
+
273
+ def _detect_exception_patterns(self, content: str) -> list[dict[str, t.Any]]:
274
+ violations: list[dict[str, t.Any]] = []
275
+ lines = content.split("\n")
276
+
277
+ exception_pattern = SAFE_PATTERNS["detect_exception_patterns"]
278
+
279
+ exception_handlers: list[dict[str, t.Any]] = []
280
+ for i, line in enumerate(lines):
281
+ if exception_pattern.test(line.strip()):
282
+ if (
283
+ i + 1 < len(lines)
284
+ and "error" in lines[i + 1]
285
+ and "str(" in lines[i + 1]
286
+ ):
287
+ exception_handlers.append(
288
+ {
289
+ "line_number": i + 1,
290
+ "content": line.strip(),
291
+ "next_line": lines[i + 1].strip(),
292
+ },
293
+ )
294
+
295
+ if len(exception_handlers) >= 3:
296
+ violations.append(
297
+ {
298
+ "type": "exception_handling_pattern",
299
+ "instances": exception_handlers,
300
+ "suggestion": "Extract to error handling utility or decorator",
301
+ },
302
+ )
303
+
304
+ return violations
305
+
306
+ def _apply_dry_fixes(self, content: str, violations: list[dict[str, t.Any]]) -> str:
307
+ lines = content.split("\n")
308
+ modified = False
309
+
310
+ for violation in violations:
311
+ lines, changed = self._apply_violation_fix(lines, violation)
312
+ modified = modified or changed
313
+
314
+ return "\n".join(lines) if modified else content
315
+
316
+ def _apply_violation_fix(
317
+ self, lines: list[str], violation: dict[str, t.Any]
318
+ ) -> tuple[list[str], bool]:
319
+ violation_type = violation["type"]
320
+
321
+ if violation_type == "error_response_pattern":
322
+ return self._fix_error_response_pattern(lines, violation)
323
+ elif violation_type == "path_conversion_pattern":
324
+ return self._fix_path_conversion_pattern(lines, violation)
325
+
326
+ return lines, False
327
+
328
+ def _fix_error_response_pattern(
329
+ self,
330
+ lines: list[str],
331
+ violation: dict[str, t.Any],
332
+ ) -> tuple[list[str], bool]:
333
+ utility_lines = self._add_error_response_utilities(lines)
334
+
335
+ self._apply_error_pattern_replacements(lines, violation, len(utility_lines))
336
+
337
+ return lines, True
338
+
339
+ def _add_error_response_utilities(self, lines: list[str]) -> list[str]:
340
+ utility_function = """
341
+ def _create_error_response(message: str, success: bool = False) -> str:
342
+
343
+ import json
344
+ return json.dumps({"error": message, "success": success})
345
+
346
+ def _ensure_path(path: str | Path) -> Path:
347
+
348
+ return Path(path) if isinstance(path, str) else path
349
+ """
350
+
351
+ insert_pos = self._find_utility_insert_position(lines)
352
+ utility_lines = utility_function.strip().split("\n")
353
+
354
+ for i, util_line in enumerate(utility_lines):
355
+ lines.insert(insert_pos + i, util_line)
356
+
357
+ return [line for line in utility_lines]
358
+
359
+ def _find_utility_insert_position(self, lines: list[str]) -> int:
360
+ insert_pos = 0
361
+ for i, line in enumerate(lines):
362
+ if line.strip().startswith(("import ", "from ")):
363
+ insert_pos = i + 1
364
+ elif line.strip() and not line.strip().startswith("#"):
365
+ break
366
+ return insert_pos
367
+
368
+ def _apply_error_pattern_replacements(
369
+ self, lines: list[str], violation: dict[str, t.Any], utility_lines_count: int
370
+ ) -> None:
371
+ path_pattern = SAFE_PATTERNS["fix_path_conversion_with_ensure_path"]
372
+
373
+ for instance in violation["instances"]:
374
+ line_number: int = int(instance["line_number"])
375
+ line_idx = line_number - 1 + utility_lines_count
376
+
377
+ if line_idx < len(lines):
378
+ original_line: str = lines[line_idx]
379
+ new_line: str = path_pattern.apply(original_line)
380
+ lines[line_idx] = new_line
381
+
382
+ def _fix_path_conversion_pattern(
383
+ self,
384
+ lines: list[str],
385
+ violation: dict[str, t.Any],
386
+ ) -> tuple[list[str], bool]:
387
+ utility_function_added = self._check_ensure_path_exists(lines)
388
+ adjustment = 0
389
+
390
+ if not utility_function_added:
391
+ adjustment = self._add_ensure_path_utility(lines)
392
+
393
+ modified = self._apply_path_pattern_replacements(
394
+ lines, violation, adjustment, utility_function_added
395
+ )
396
+
397
+ return lines, modified
398
+
399
+ def _check_ensure_path_exists(self, lines: list[str]) -> bool:
400
+ return any(
401
+ "_ensure_path" in line and "def _ensure_path" in line for line in lines
402
+ )
403
+
404
+ def _add_ensure_path_utility(self, lines: list[str]) -> int:
405
+ insert_pos = self._find_utility_insert_position(lines)
406
+
407
+ utility_lines = [
408
+ "",
409
+ "def _ensure_path(path: str | Path) -> Path: ",
410
+ ' """Convert string path to Path object if needed."""',
411
+ " return Path(path) if isinstance(path, str) else path",
412
+ "",
413
+ ]
414
+
415
+ for i, util_line in enumerate(utility_lines):
416
+ lines.insert(insert_pos + i, util_line)
417
+
418
+ return len(utility_lines)
419
+
420
+ def _apply_path_pattern_replacements(
421
+ self,
422
+ lines: list[str],
423
+ violation: dict[str, t.Any],
424
+ adjustment: int,
425
+ utility_function_added: bool,
426
+ ) -> bool:
427
+ path_pattern = SAFE_PATTERNS["fix_path_conversion_simple"]
428
+
429
+ modified = False
430
+ for instance in violation["instances"]:
431
+ line_number: int = int(instance["line_number"])
432
+ line_idx = line_number - 1 + (0 if utility_function_added else adjustment)
433
+
434
+ if line_idx < len(lines):
435
+ original_line: str = lines[line_idx]
436
+ new_line = path_pattern.apply(original_line)
437
+
438
+ if new_line != original_line:
439
+ lines[line_idx] = new_line
440
+ modified = True
441
+
442
+ return modified
443
+
444
+ async def _detect_semantic_violations(
445
+ self, content: str, file_path: Path
446
+ ) -> list[dict[str, t.Any]]:
447
+ """Detect semantic code duplicates using vector similarity."""
448
+ violations = []
449
+
450
+ try:
451
+ # Extract key code functions for semantic analysis
452
+ code_elements = self._extract_code_functions(content)
453
+
454
+ for element in code_elements:
455
+ if element["type"] == "function" and len(element["body"]) > 50:
456
+ # Search for semantically similar functions
457
+ insight = await self.semantic_enhancer.find_duplicate_patterns(
458
+ element["signature"]
459
+ + "\n"
460
+ + element["body"][:200], # Include body sample
461
+ current_file=file_path,
462
+ )
463
+
464
+ if insight.high_confidence_matches > 0:
465
+ violations.append(
466
+ {
467
+ "type": "semantic_duplicate",
468
+ "element": element,
469
+ "similar_patterns": insight.related_patterns[
470
+ :3
471
+ ], # Top 3 matches
472
+ "confidence_score": insight.high_confidence_matches
473
+ / insight.total_matches
474
+ if insight.total_matches > 0
475
+ else 0,
476
+ "suggestion": "Consider extracting common functionality to shared utility",
477
+ }
478
+ )
479
+
480
+ # Store insight for recommendation enhancement
481
+ self.current_semantic_insight = insight
482
+
483
+ except Exception as e:
484
+ self.log(f"Warning: Semantic violation detection failed: {e}")
485
+
486
+ return violations
487
+
488
+ def _extract_code_functions(self, content: str) -> list[dict[str, t.Any]]:
489
+ """Extract functions from code for semantic analysis."""
490
+ functions: list[dict[str, t.Any]] = []
491
+ lines = content.split("\n")
492
+ current_function = None
493
+
494
+ for i, line in enumerate(lines):
495
+ stripped = line.strip()
496
+
497
+ if self._should_skip_line(stripped, current_function, line):
498
+ continue
499
+
500
+ indent = len(line) - len(line.lstrip())
501
+
502
+ if self._is_function_definition(stripped):
503
+ current_function = self._handle_function_definition(
504
+ functions, current_function, stripped, indent, i
505
+ )
506
+ elif current_function:
507
+ current_function = self._handle_function_body_line(
508
+ functions, current_function, line, stripped, indent, i
509
+ )
510
+
511
+ # Add last function if exists
512
+ if current_function:
513
+ current_function["end_line"] = len(lines)
514
+ functions.append(current_function)
515
+
516
+ return functions
517
+
518
+ def _should_skip_line(
519
+ self, stripped: str, current_function: dict[str, t.Any] | None, line: str
520
+ ) -> bool:
521
+ """Check if line should be skipped during function extraction."""
522
+ if not stripped or stripped.startswith("#"):
523
+ if current_function:
524
+ current_function["body"] += line + "\n"
525
+ return True
526
+ return False
527
+
528
+ def _is_function_definition(self, stripped: str) -> bool:
529
+ """Check if line is a function definition."""
530
+ return stripped.startswith("def ") and "(" in stripped
531
+
532
+ def _handle_function_definition(
533
+ self,
534
+ functions: list[dict[str, t.Any]],
535
+ current_function: dict[str, t.Any] | None,
536
+ stripped: str,
537
+ indent: int,
538
+ line_index: int,
539
+ ) -> dict[str, t.Any]:
540
+ """Handle a new function definition."""
541
+ # Save previous function if exists
542
+ if current_function:
543
+ functions.append(current_function)
544
+
545
+ func_name = stripped.split("(")[0].replace("def ", "").strip()
546
+ return {
547
+ "type": "function",
548
+ "name": func_name,
549
+ "signature": stripped,
550
+ "start_line": line_index + 1,
551
+ "body": "",
552
+ "indent_level": indent,
553
+ }
554
+
555
+ def _handle_function_body_line(
556
+ self,
557
+ functions: list[dict[str, t.Any]],
558
+ current_function: dict[str, t.Any],
559
+ line: str,
560
+ stripped: str,
561
+ indent: int,
562
+ line_index: int,
563
+ ) -> dict[str, t.Any] | None:
564
+ """Handle a line within a function body."""
565
+ # Check if we're still inside the function
566
+ if self._is_line_inside_function(current_function, indent, stripped):
567
+ current_function["body"] += line + "\n"
568
+ return current_function
569
+ else:
570
+ # Function ended
571
+ current_function["end_line"] = line_index
572
+ functions.append(current_function)
573
+ return None
574
+
575
+ def _is_line_inside_function(
576
+ self, current_function: dict[str, t.Any], indent: int, stripped: str
577
+ ) -> bool:
578
+ """Check if line is still inside the current function."""
579
+ return indent > current_function["indent_level"] or (
580
+ indent == current_function["indent_level"]
581
+ and stripped.startswith(('"', "'", "@"))
582
+ )
583
+
584
+
585
+ agent_registry.register(DRYAgent)