auto-coder 1.0.0__py3-none-any.whl → 2.0.0__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.

Potentially problematic release.


This version of auto-coder might be problematic. Click here for more details.

Files changed (574) hide show
  1. auto_coder-2.0.0.dist-info/LICENSE +158 -0
  2. auto_coder-2.0.0.dist-info/METADATA +558 -0
  3. auto_coder-2.0.0.dist-info/RECORD +795 -0
  4. {auto_coder-1.0.0.dist-info → auto_coder-2.0.0.dist-info}/WHEEL +1 -1
  5. {auto_coder-1.0.0.dist-info → auto_coder-2.0.0.dist-info}/entry_points.txt +3 -3
  6. autocoder/__init__.py +31 -0
  7. autocoder/agent/auto_filegroup.py +32 -13
  8. autocoder/agent/auto_learn_from_commit.py +9 -1
  9. autocoder/agent/base_agentic/__init__.py +3 -0
  10. autocoder/agent/base_agentic/agent_hub.py +1 -1
  11. autocoder/agent/base_agentic/base_agent.py +235 -136
  12. autocoder/agent/base_agentic/default_tools.py +119 -118
  13. autocoder/agent/base_agentic/test_base_agent.py +1 -1
  14. autocoder/agent/base_agentic/tool_registry.py +32 -20
  15. autocoder/agent/base_agentic/tools/read_file_tool_resolver.py +24 -3
  16. autocoder/agent/base_agentic/tools/write_to_file_tool_resolver.py +24 -11
  17. autocoder/agent/base_agentic/types.py +42 -0
  18. autocoder/agent/entry_command_agent/chat.py +73 -59
  19. autocoder/auto_coder.py +31 -40
  20. autocoder/auto_coder_rag.py +11 -1084
  21. autocoder/auto_coder_runner.py +970 -2345
  22. autocoder/auto_coder_terminal.py +26 -0
  23. autocoder/auto_coder_terminal_v3.py +190 -0
  24. autocoder/chat/conf_command.py +224 -124
  25. autocoder/chat/models_command.py +361 -299
  26. autocoder/chat/rules_command.py +79 -31
  27. autocoder/chat_auto_coder.py +988 -398
  28. autocoder/chat_auto_coder_lang.py +23 -732
  29. autocoder/commands/auto_command.py +25 -8
  30. autocoder/commands/auto_web.py +1 -1
  31. autocoder/commands/tools.py +44 -44
  32. autocoder/common/__init__.py +150 -128
  33. autocoder/common/ac_style_command_parser/__init__.py +39 -2
  34. autocoder/common/ac_style_command_parser/config.py +422 -0
  35. autocoder/common/ac_style_command_parser/parser.py +292 -78
  36. autocoder/common/ac_style_command_parser/test_parser.py +241 -16
  37. autocoder/common/ac_style_command_parser/test_typed_parser.py +342 -0
  38. autocoder/common/ac_style_command_parser/typed_parser.py +653 -0
  39. autocoder/common/action_yml_file_manager.py +25 -13
  40. autocoder/common/agent_events/__init__.py +52 -0
  41. autocoder/common/agent_events/agent_event_emitter.py +193 -0
  42. autocoder/common/agent_events/event_factory.py +177 -0
  43. autocoder/common/agent_events/examples.py +307 -0
  44. autocoder/common/agent_events/types.py +113 -0
  45. autocoder/common/agent_events/utils.py +68 -0
  46. autocoder/common/agent_hooks/__init__.py +44 -0
  47. autocoder/common/agent_hooks/examples.py +582 -0
  48. autocoder/common/agent_hooks/hook_executor.py +217 -0
  49. autocoder/common/agent_hooks/hook_manager.py +288 -0
  50. autocoder/common/agent_hooks/types.py +133 -0
  51. autocoder/common/agent_hooks/utils.py +99 -0
  52. autocoder/common/agent_query_queue/queue_executor.py +324 -0
  53. autocoder/common/agent_query_queue/queue_manager.py +325 -0
  54. autocoder/common/agents/__init__.py +11 -0
  55. autocoder/common/agents/agent_manager.py +323 -0
  56. autocoder/common/agents/agent_parser.py +189 -0
  57. autocoder/common/agents/example_usage.py +344 -0
  58. autocoder/common/agents/integration_example.py +330 -0
  59. autocoder/common/agents/test_agent_parser.py +545 -0
  60. autocoder/common/async_utils.py +101 -0
  61. autocoder/common/auto_coder_lang.py +23 -972
  62. autocoder/common/autocoderargs_parser/__init__.py +14 -0
  63. autocoder/common/autocoderargs_parser/parser.py +184 -0
  64. autocoder/common/autocoderargs_parser/tests/__init__.py +1 -0
  65. autocoder/common/autocoderargs_parser/tests/test_args_parser.py +235 -0
  66. autocoder/common/autocoderargs_parser/tests/test_token_parser.py +195 -0
  67. autocoder/common/autocoderargs_parser/token_parser.py +290 -0
  68. autocoder/common/buildin_tokenizer.py +2 -4
  69. autocoder/common/code_auto_generate.py +149 -74
  70. autocoder/common/code_auto_generate_diff.py +163 -70
  71. autocoder/common/code_auto_generate_editblock.py +179 -89
  72. autocoder/common/code_auto_generate_strict_diff.py +167 -72
  73. autocoder/common/code_auto_merge_editblock.py +13 -6
  74. autocoder/common/code_modification_ranker.py +1 -1
  75. autocoder/common/command_completer.py +3 -3
  76. autocoder/common/command_file_manager/manager.py +183 -47
  77. autocoder/common/command_file_manager/test_command_file_manager.py +507 -0
  78. autocoder/common/command_templates.py +1 -1
  79. autocoder/common/conf_utils.py +2 -4
  80. autocoder/common/conversations/config.py +11 -3
  81. autocoder/common/conversations/get_conversation_manager.py +100 -2
  82. autocoder/common/conversations/llm_stats_models.py +264 -0
  83. autocoder/common/conversations/manager.py +112 -28
  84. autocoder/common/conversations/models.py +16 -2
  85. autocoder/common/conversations/storage/index_manager.py +134 -10
  86. autocoder/common/core_config/__init__.py +63 -0
  87. autocoder/common/core_config/agentic_mode_manager.py +109 -0
  88. autocoder/common/core_config/base_manager.py +123 -0
  89. autocoder/common/core_config/compatibility.py +151 -0
  90. autocoder/common/core_config/config_manager.py +156 -0
  91. autocoder/common/core_config/conversation_manager.py +31 -0
  92. autocoder/common/core_config/exclude_manager.py +72 -0
  93. autocoder/common/core_config/file_manager.py +177 -0
  94. autocoder/common/core_config/human_as_model_manager.py +129 -0
  95. autocoder/common/core_config/lib_manager.py +54 -0
  96. autocoder/common/core_config/main_manager.py +81 -0
  97. autocoder/common/core_config/mode_manager.py +126 -0
  98. autocoder/common/core_config/models.py +70 -0
  99. autocoder/common/core_config/test_memory_manager.py +1056 -0
  100. autocoder/common/env_manager.py +282 -0
  101. autocoder/common/env_manager_usage_example.py +211 -0
  102. autocoder/common/file_checkpoint/conversation_checkpoint.py +19 -19
  103. autocoder/common/file_checkpoint/manager.py +264 -48
  104. autocoder/common/file_checkpoint/test_backup.py +1 -18
  105. autocoder/common/file_checkpoint/test_manager.py +270 -1
  106. autocoder/common/file_checkpoint/test_store.py +1 -17
  107. autocoder/common/file_handler/__init__.py +23 -0
  108. autocoder/common/file_handler/active_context_handler.py +159 -0
  109. autocoder/common/file_handler/add_files_handler.py +409 -0
  110. autocoder/common/file_handler/chat_handler.py +180 -0
  111. autocoder/common/file_handler/coding_handler.py +401 -0
  112. autocoder/common/file_handler/commit_handler.py +200 -0
  113. autocoder/common/file_handler/lib_handler.py +156 -0
  114. autocoder/common/file_handler/list_files_handler.py +111 -0
  115. autocoder/common/file_handler/mcp_handler.py +268 -0
  116. autocoder/common/file_handler/models_handler.py +493 -0
  117. autocoder/common/file_handler/remove_files_handler.py +172 -0
  118. autocoder/common/git_utils.py +44 -8
  119. autocoder/common/global_cancel.py +15 -6
  120. autocoder/common/ignorefiles/test_ignore_file_utils.py +1 -1
  121. autocoder/common/international/__init__.py +31 -0
  122. autocoder/common/international/demo_international.py +92 -0
  123. autocoder/common/international/message_manager.py +157 -0
  124. autocoder/common/international/messages/__init__.py +56 -0
  125. autocoder/common/international/messages/async_command_messages.py +507 -0
  126. autocoder/common/international/messages/auto_coder_messages.py +2208 -0
  127. autocoder/common/international/messages/chat_auto_coder_messages.py +1547 -0
  128. autocoder/common/international/messages/command_help_messages.py +986 -0
  129. autocoder/common/international/messages/conversation_command_messages.py +191 -0
  130. autocoder/common/international/messages/git_helper_plugin_messages.py +159 -0
  131. autocoder/common/international/messages/queue_command_messages.py +751 -0
  132. autocoder/common/international/messages/rules_command_messages.py +77 -0
  133. autocoder/common/international/messages/sdk_messages.py +1707 -0
  134. autocoder/common/international/messages/token_helper_plugin_messages.py +361 -0
  135. autocoder/common/international/messages/tool_display_messages.py +1212 -0
  136. autocoder/common/international/messages/workflow_exception_messages.py +473 -0
  137. autocoder/common/international/test_international.py +612 -0
  138. autocoder/common/linter_core/__init__.py +28 -0
  139. autocoder/common/linter_core/base_linter.py +61 -0
  140. autocoder/common/linter_core/config_loader.py +271 -0
  141. autocoder/common/linter_core/formatters/__init__.py +0 -0
  142. autocoder/common/linter_core/formatters/base_formatter.py +38 -0
  143. autocoder/common/linter_core/formatters/raw_formatter.py +17 -0
  144. autocoder/common/linter_core/linter.py +166 -0
  145. autocoder/common/linter_core/linter_factory.py +216 -0
  146. autocoder/common/linter_core/linter_manager.py +333 -0
  147. autocoder/common/linter_core/linters/__init__.py +9 -0
  148. autocoder/common/linter_core/linters/java_linter.py +342 -0
  149. autocoder/common/linter_core/linters/python_linter.py +115 -0
  150. autocoder/common/linter_core/linters/typescript_linter.py +119 -0
  151. autocoder/common/linter_core/models/__init__.py +7 -0
  152. autocoder/common/linter_core/models/lint_result.py +91 -0
  153. autocoder/common/linter_core/models.py +33 -0
  154. autocoder/common/linter_core/tests/__init__.py +3 -0
  155. autocoder/common/linter_core/tests/test_config_loader.py +323 -0
  156. autocoder/common/linter_core/tests/test_config_loading.py +308 -0
  157. autocoder/common/linter_core/tests/test_factory_manager.py +234 -0
  158. autocoder/common/linter_core/tests/test_formatters.py +147 -0
  159. autocoder/common/linter_core/tests/test_integration.py +317 -0
  160. autocoder/common/linter_core/tests/test_java_linter.py +496 -0
  161. autocoder/common/linter_core/tests/test_linters.py +265 -0
  162. autocoder/common/linter_core/tests/test_models.py +81 -0
  163. autocoder/common/linter_core/tests/verify_config_loading.py +296 -0
  164. autocoder/common/linter_core/tests/verify_fixes.py +183 -0
  165. autocoder/common/llm_friendly_package/__init__.py +31 -0
  166. autocoder/common/llm_friendly_package/base_manager.py +102 -0
  167. autocoder/common/llm_friendly_package/docs_manager.py +121 -0
  168. autocoder/common/llm_friendly_package/library_manager.py +171 -0
  169. autocoder/common/{llm_friendly_package.py → llm_friendly_package/main_manager.py} +204 -231
  170. autocoder/common/llm_friendly_package/models.py +40 -0
  171. autocoder/common/llm_friendly_package/test_llm_friendly_package.py +536 -0
  172. autocoder/common/llms/__init__.py +15 -0
  173. autocoder/common/llms/demo_error_handling.py +85 -0
  174. autocoder/common/llms/factory.py +142 -0
  175. autocoder/common/llms/manager.py +264 -0
  176. autocoder/common/llms/pricing.py +121 -0
  177. autocoder/common/llms/registry.py +288 -0
  178. autocoder/common/llms/schema.py +77 -0
  179. autocoder/common/llms/simple_demo.py +45 -0
  180. autocoder/common/llms/test_quick_model.py +116 -0
  181. autocoder/common/llms/test_remove_functionality.py +182 -0
  182. autocoder/common/llms/tests/__init__.py +1 -0
  183. autocoder/common/llms/tests/test_manager.py +330 -0
  184. autocoder/common/llms/tests/test_registry.py +364 -0
  185. autocoder/common/mcp_tools/__init__.py +62 -0
  186. autocoder/common/{mcp_tools.py → mcp_tools/executor.py} +49 -40
  187. autocoder/common/{mcp_hub.py → mcp_tools/hub.py} +42 -68
  188. autocoder/common/{mcp_server_install.py → mcp_tools/installer.py} +16 -28
  189. autocoder/common/{mcp_server.py → mcp_tools/server.py} +176 -48
  190. autocoder/common/mcp_tools/test_keyboard_interrupt.py +93 -0
  191. autocoder/common/mcp_tools/test_mcp_tools.py +391 -0
  192. autocoder/common/{mcp_server_types.py → mcp_tools/types.py} +121 -48
  193. autocoder/common/mcp_tools/verify_functionality.py +202 -0
  194. autocoder/common/model_speed_tester.py +32 -26
  195. autocoder/common/priority_directory_finder/__init__.py +142 -0
  196. autocoder/common/priority_directory_finder/examples.py +230 -0
  197. autocoder/common/priority_directory_finder/finder.py +283 -0
  198. autocoder/common/priority_directory_finder/models.py +236 -0
  199. autocoder/common/priority_directory_finder/test_priority_directory_finder.py +431 -0
  200. autocoder/common/project_scanner/__init__.py +18 -0
  201. autocoder/common/project_scanner/compat.py +77 -0
  202. autocoder/common/project_scanner/scanner.py +436 -0
  203. autocoder/common/project_tracker/__init__.py +27 -0
  204. autocoder/common/project_tracker/api.py +228 -0
  205. autocoder/common/project_tracker/demo.py +272 -0
  206. autocoder/common/project_tracker/tracker.py +487 -0
  207. autocoder/common/project_tracker/types.py +53 -0
  208. autocoder/common/pruner/__init__.py +67 -0
  209. autocoder/common/pruner/agentic_conversation_pruner.py +651 -102
  210. autocoder/common/pruner/conversation_message_ids_api.py +386 -0
  211. autocoder/common/pruner/conversation_message_ids_manager.py +347 -0
  212. autocoder/common/pruner/conversation_message_ids_pruner.py +473 -0
  213. autocoder/common/pruner/conversation_normalizer.py +347 -0
  214. autocoder/common/pruner/conversation_pruner.py +26 -6
  215. autocoder/common/pruner/test_agentic_conversation_pruner.py +554 -112
  216. autocoder/common/pruner/test_conversation_normalizer.py +502 -0
  217. autocoder/common/pruner/test_tool_content_detector.py +324 -0
  218. autocoder/common/pruner/tool_content_detector.py +227 -0
  219. autocoder/common/pruner/tools/__init__.py +18 -0
  220. autocoder/common/pruner/tools/query_message_ids.py +264 -0
  221. autocoder/common/pruner/tools/test_agentic_pruning_logic.py +432 -0
  222. autocoder/common/pruner/tools/test_message_ids_pruning_only.py +192 -0
  223. autocoder/common/pull_requests/__init__.py +9 -1
  224. autocoder/common/pull_requests/utils.py +122 -1
  225. autocoder/common/rag_manager/rag_manager.py +36 -40
  226. autocoder/common/rulefiles/__init__.py +53 -1
  227. autocoder/common/rulefiles/api.py +250 -0
  228. autocoder/common/rulefiles/core/__init__.py +14 -0
  229. autocoder/common/rulefiles/core/manager.py +241 -0
  230. autocoder/common/rulefiles/core/selector.py +805 -0
  231. autocoder/common/rulefiles/models/__init__.py +20 -0
  232. autocoder/common/rulefiles/models/index.py +16 -0
  233. autocoder/common/rulefiles/models/init_rule.py +18 -0
  234. autocoder/common/rulefiles/models/rule_file.py +18 -0
  235. autocoder/common/rulefiles/models/rule_relevance.py +14 -0
  236. autocoder/common/rulefiles/models/summary.py +16 -0
  237. autocoder/common/rulefiles/test_rulefiles.py +776 -0
  238. autocoder/common/rulefiles/utils/__init__.py +34 -0
  239. autocoder/common/rulefiles/utils/monitor.py +86 -0
  240. autocoder/common/rulefiles/utils/parser.py +230 -0
  241. autocoder/common/save_formatted_log.py +67 -10
  242. autocoder/common/search_replace.py +8 -1
  243. autocoder/common/search_replace_patch/__init__.py +24 -0
  244. autocoder/common/search_replace_patch/base.py +115 -0
  245. autocoder/common/search_replace_patch/manager.py +248 -0
  246. autocoder/common/search_replace_patch/patch_replacer.py +304 -0
  247. autocoder/common/search_replace_patch/similarity_replacer.py +306 -0
  248. autocoder/common/search_replace_patch/string_replacer.py +181 -0
  249. autocoder/common/search_replace_patch/tests/__init__.py +3 -0
  250. autocoder/common/search_replace_patch/tests/run_tests.py +126 -0
  251. autocoder/common/search_replace_patch/tests/test_base.py +188 -0
  252. autocoder/common/search_replace_patch/tests/test_empty_line_insert.py +233 -0
  253. autocoder/common/search_replace_patch/tests/test_integration.py +389 -0
  254. autocoder/common/search_replace_patch/tests/test_manager.py +351 -0
  255. autocoder/common/search_replace_patch/tests/test_patch_replacer.py +316 -0
  256. autocoder/common/search_replace_patch/tests/test_regex_replacer.py +306 -0
  257. autocoder/common/search_replace_patch/tests/test_similarity_replacer.py +384 -0
  258. autocoder/common/shell_commands/__init__.py +197 -0
  259. autocoder/common/shell_commands/background_process_notifier.py +346 -0
  260. autocoder/common/shell_commands/command_executor.py +1127 -0
  261. autocoder/common/shell_commands/error_recovery.py +541 -0
  262. autocoder/common/shell_commands/exceptions.py +120 -0
  263. autocoder/common/shell_commands/interactive_executor.py +476 -0
  264. autocoder/common/shell_commands/interactive_pexpect_process.py +623 -0
  265. autocoder/common/shell_commands/interactive_process.py +744 -0
  266. autocoder/common/shell_commands/interactive_session_manager.py +1014 -0
  267. autocoder/common/shell_commands/monitoring.py +529 -0
  268. autocoder/common/shell_commands/process_cleanup.py +386 -0
  269. autocoder/common/shell_commands/process_manager.py +606 -0
  270. autocoder/common/shell_commands/test_interactive_pexpect_process.py +281 -0
  271. autocoder/common/shell_commands/tests/__init__.py +6 -0
  272. autocoder/common/shell_commands/tests/conftest.py +118 -0
  273. autocoder/common/shell_commands/tests/test_background_process_notifier.py +703 -0
  274. autocoder/common/shell_commands/tests/test_command_executor.py +448 -0
  275. autocoder/common/shell_commands/tests/test_error_recovery.py +305 -0
  276. autocoder/common/shell_commands/tests/test_exceptions.py +299 -0
  277. autocoder/common/shell_commands/tests/test_execute_batch.py +588 -0
  278. autocoder/common/shell_commands/tests/test_indented_batch_commands.py +244 -0
  279. autocoder/common/shell_commands/tests/test_integration.py +664 -0
  280. autocoder/common/shell_commands/tests/test_monitoring.py +546 -0
  281. autocoder/common/shell_commands/tests/test_performance.py +632 -0
  282. autocoder/common/shell_commands/tests/test_process_cleanup.py +397 -0
  283. autocoder/common/shell_commands/tests/test_process_manager.py +606 -0
  284. autocoder/common/shell_commands/tests/test_timeout_config.py +343 -0
  285. autocoder/common/shell_commands/tests/test_timeout_manager.py +520 -0
  286. autocoder/common/shell_commands/timeout_config.py +315 -0
  287. autocoder/common/shell_commands/timeout_manager.py +352 -0
  288. autocoder/common/terminal_paste/__init__.py +14 -0
  289. autocoder/common/terminal_paste/demo.py +145 -0
  290. autocoder/common/terminal_paste/demo_paste_functionality.py +95 -0
  291. autocoder/common/terminal_paste/paste_handler.py +200 -0
  292. autocoder/common/terminal_paste/paste_manager.py +118 -0
  293. autocoder/common/terminal_paste/tests/__init__.py +1 -0
  294. autocoder/common/terminal_paste/tests/test_paste_handler.py +182 -0
  295. autocoder/common/terminal_paste/tests/test_paste_manager.py +126 -0
  296. autocoder/common/terminal_paste/utils.py +163 -0
  297. autocoder/common/test_autocoder_args.py +232 -0
  298. autocoder/common/test_env_manager.py +173 -0
  299. autocoder/common/test_env_manager_integration.py +159 -0
  300. autocoder/common/text_similarity/__init__.py +9 -0
  301. autocoder/common/text_similarity/demo.py +216 -0
  302. autocoder/common/text_similarity/examples.py +266 -0
  303. autocoder/common/text_similarity/test_text_similarity.py +306 -0
  304. autocoder/common/text_similarity/text_similarity.py +194 -0
  305. autocoder/common/text_similarity/utils.py +125 -0
  306. autocoder/common/todos/__init__.py +61 -0
  307. autocoder/common/todos/cache/__init__.py +16 -0
  308. autocoder/common/todos/cache/base_cache.py +89 -0
  309. autocoder/common/todos/cache/cache_manager.py +228 -0
  310. autocoder/common/todos/cache/memory_cache.py +225 -0
  311. autocoder/common/todos/config.py +155 -0
  312. autocoder/common/todos/exceptions.py +35 -0
  313. autocoder/common/todos/get_todo_manager.py +161 -0
  314. autocoder/common/todos/manager.py +537 -0
  315. autocoder/common/todos/models.py +239 -0
  316. autocoder/common/todos/storage/__init__.py +14 -0
  317. autocoder/common/todos/storage/base_storage.py +76 -0
  318. autocoder/common/todos/storage/file_storage.py +278 -0
  319. autocoder/common/tokens/counter.py +24 -2
  320. autocoder/common/tools_manager/__init__.py +17 -0
  321. autocoder/common/tools_manager/examples.py +162 -0
  322. autocoder/common/tools_manager/manager.py +385 -0
  323. autocoder/common/tools_manager/models.py +39 -0
  324. autocoder/common/tools_manager/test_tools_manager.py +303 -0
  325. autocoder/common/tools_manager/utils.py +191 -0
  326. autocoder/common/v2/agent/agentic_callbacks.py +270 -0
  327. autocoder/common/v2/agent/agentic_edit.py +2699 -1856
  328. autocoder/common/v2/agent/agentic_edit_change_manager.py +474 -0
  329. autocoder/common/v2/agent/agentic_edit_tools/__init__.py +35 -1
  330. autocoder/common/v2/agent/agentic_edit_tools/ac_mod_list_tool_resolver.py +279 -0
  331. autocoder/common/v2/agent/agentic_edit_tools/ac_mod_write_tool_resolver.py +10 -1
  332. autocoder/common/v2/agent/agentic_edit_tools/background_task_tool_resolver.py +1167 -0
  333. autocoder/common/v2/agent/agentic_edit_tools/base_tool_resolver.py +2 -2
  334. autocoder/common/v2/agent/agentic_edit_tools/conversation_message_ids_read_tool_resolver.py +214 -0
  335. autocoder/common/v2/agent/agentic_edit_tools/conversation_message_ids_write_tool_resolver.py +299 -0
  336. autocoder/common/v2/agent/agentic_edit_tools/count_tokens_tool_resolver.py +290 -0
  337. autocoder/common/v2/agent/agentic_edit_tools/execute_command_tool_resolver.py +564 -29
  338. autocoder/common/v2/agent/agentic_edit_tools/execute_workflow_tool_resolver.py +485 -0
  339. autocoder/common/v2/agent/agentic_edit_tools/extract_to_text_tool_resolver.py +225 -0
  340. autocoder/common/v2/agent/agentic_edit_tools/lint_report.py +79 -0
  341. autocoder/common/v2/agent/agentic_edit_tools/linter_config_models.py +343 -0
  342. autocoder/common/v2/agent/agentic_edit_tools/linter_enabled_tool_resolver.py +189 -0
  343. autocoder/common/v2/agent/agentic_edit_tools/list_files_tool_resolver.py +169 -101
  344. autocoder/common/v2/agent/agentic_edit_tools/load_extra_document_tool_resolver.py +349 -0
  345. autocoder/common/v2/agent/agentic_edit_tools/read_file_tool_resolver.py +243 -50
  346. autocoder/common/v2/agent/agentic_edit_tools/replace_in_file_tool_resolver.py +667 -147
  347. autocoder/common/v2/agent/agentic_edit_tools/run_named_subagents_tool_resolver.py +691 -0
  348. autocoder/common/v2/agent/agentic_edit_tools/search_files_tool_resolver.py +410 -86
  349. autocoder/common/v2/agent/agentic_edit_tools/session_interactive_tool_resolver.py +115 -0
  350. autocoder/common/v2/agent/agentic_edit_tools/session_start_tool_resolver.py +190 -0
  351. autocoder/common/v2/agent/agentic_edit_tools/session_stop_tool_resolver.py +76 -0
  352. autocoder/common/v2/agent/agentic_edit_tools/test_write_to_file_tool_resolver.py +207 -192
  353. autocoder/common/v2/agent/agentic_edit_tools/todo_read_tool_resolver.py +80 -63
  354. autocoder/common/v2/agent/agentic_edit_tools/todo_write_tool_resolver.py +237 -233
  355. autocoder/common/v2/agent/agentic_edit_tools/use_mcp_tool_resolver.py +2 -2
  356. autocoder/common/v2/agent/agentic_edit_tools/web_crawl_tool_resolver.py +557 -0
  357. autocoder/common/v2/agent/agentic_edit_tools/web_search_tool_resolver.py +600 -0
  358. autocoder/common/v2/agent/agentic_edit_tools/write_to_file_tool_resolver.py +56 -121
  359. autocoder/common/v2/agent/agentic_edit_types.py +343 -9
  360. autocoder/common/v2/agent/runner/__init__.py +3 -3
  361. autocoder/common/v2/agent/runner/base_runner.py +12 -26
  362. autocoder/common/v2/agent/runner/{event_runner.py → file_based_event_runner.py} +3 -2
  363. autocoder/common/v2/agent/runner/sdk_runner.py +150 -8
  364. autocoder/common/v2/agent/runner/terminal_runner.py +170 -57
  365. autocoder/common/v2/agent/runner/tool_display.py +557 -159
  366. autocoder/common/v2/agent/test_agentic_callbacks.py +265 -0
  367. autocoder/common/v2/agent/test_agentic_edit.py +194 -0
  368. autocoder/common/v2/agent/tool_caller/__init__.py +24 -0
  369. autocoder/common/v2/agent/tool_caller/default_tool_resolver_map.py +135 -0
  370. autocoder/common/v2/agent/tool_caller/integration_test.py +172 -0
  371. autocoder/common/v2/agent/tool_caller/plugins/__init__.py +14 -0
  372. autocoder/common/v2/agent/tool_caller/plugins/base_plugin.py +126 -0
  373. autocoder/common/v2/agent/tool_caller/plugins/examples/__init__.py +13 -0
  374. autocoder/common/v2/agent/tool_caller/plugins/examples/logging_plugin.py +164 -0
  375. autocoder/common/v2/agent/tool_caller/plugins/examples/security_filter_plugin.py +198 -0
  376. autocoder/common/v2/agent/tool_caller/plugins/plugin_interface.py +141 -0
  377. autocoder/common/v2/agent/tool_caller/test_tool_caller.py +278 -0
  378. autocoder/common/v2/agent/tool_caller/tool_call_plugin_manager.py +331 -0
  379. autocoder/common/v2/agent/tool_caller/tool_caller.py +337 -0
  380. autocoder/common/v2/agent/tool_caller/usage_example.py +193 -0
  381. autocoder/common/v2/code_agentic_editblock_manager.py +4 -4
  382. autocoder/common/v2/code_auto_generate.py +136 -78
  383. autocoder/common/v2/code_auto_generate_diff.py +135 -79
  384. autocoder/common/v2/code_auto_generate_editblock.py +174 -99
  385. autocoder/common/v2/code_auto_generate_strict_diff.py +151 -71
  386. autocoder/common/v2/code_auto_merge.py +1 -1
  387. autocoder/common/v2/code_auto_merge_editblock.py +13 -1
  388. autocoder/common/v2/code_diff_manager.py +3 -3
  389. autocoder/common/v2/code_editblock_manager.py +4 -14
  390. autocoder/common/v2/code_manager.py +1 -1
  391. autocoder/common/v2/code_strict_diff_manager.py +2 -2
  392. autocoder/common/wrap_llm_hint/__init__.py +10 -0
  393. autocoder/common/wrap_llm_hint/test_wrap_llm_hint.py +1067 -0
  394. autocoder/common/wrap_llm_hint/utils.py +432 -0
  395. autocoder/common/wrap_llm_hint/wrap_llm_hint.py +323 -0
  396. autocoder/completer/__init__.py +8 -0
  397. autocoder/completer/command_completer_v2.py +1051 -0
  398. autocoder/default_project/__init__.py +501 -0
  399. autocoder/dispacher/__init__.py +4 -12
  400. autocoder/dispacher/actions/action.py +165 -7
  401. autocoder/dispacher/actions/plugins/action_regex_project.py +2 -2
  402. autocoder/index/entry.py +116 -124
  403. autocoder/{agent → index/filter}/agentic_filter.py +322 -333
  404. autocoder/index/filter/normal_filter.py +5 -11
  405. autocoder/index/filter/quick_filter.py +1 -1
  406. autocoder/index/index.py +36 -9
  407. autocoder/index/tests/__init__.py +1 -0
  408. autocoder/index/tests/run_tests.py +195 -0
  409. autocoder/index/tests/test_entry.py +303 -0
  410. autocoder/index/tests/test_index_manager.py +314 -0
  411. autocoder/index/tests/test_module_integration.py +300 -0
  412. autocoder/index/tests/test_symbols_utils.py +183 -0
  413. autocoder/inner/__init__.py +4 -0
  414. autocoder/inner/agentic.py +932 -0
  415. autocoder/inner/async_command_handler.py +992 -0
  416. autocoder/inner/conversation_command_handlers.py +623 -0
  417. autocoder/inner/merge_command_handler.py +213 -0
  418. autocoder/inner/queue_command_handler.py +684 -0
  419. autocoder/models.py +95 -266
  420. autocoder/plugins/git_helper_plugin.py +31 -29
  421. autocoder/plugins/token_helper_plugin.py +65 -46
  422. autocoder/pyproject/__init__.py +32 -29
  423. autocoder/rag/agentic_rag.py +215 -75
  424. autocoder/rag/cache/simple_cache.py +1 -2
  425. autocoder/rag/loaders/image_loader.py +1 -1
  426. autocoder/rag/long_context_rag.py +42 -26
  427. autocoder/rag/qa_conversation_strategy.py +1 -1
  428. autocoder/rag/terminal/__init__.py +17 -0
  429. autocoder/rag/terminal/args.py +581 -0
  430. autocoder/rag/terminal/bootstrap.py +61 -0
  431. autocoder/rag/terminal/command_handlers.py +653 -0
  432. autocoder/rag/terminal/formatters/__init__.py +20 -0
  433. autocoder/rag/terminal/formatters/base.py +70 -0
  434. autocoder/rag/terminal/formatters/json_format.py +66 -0
  435. autocoder/rag/terminal/formatters/stream_json.py +95 -0
  436. autocoder/rag/terminal/formatters/text.py +28 -0
  437. autocoder/rag/terminal/init.py +120 -0
  438. autocoder/rag/terminal/utils.py +106 -0
  439. autocoder/rag/test_agentic_rag.py +389 -0
  440. autocoder/rag/test_doc_filter.py +3 -3
  441. autocoder/rag/test_long_context_rag.py +1 -1
  442. autocoder/rag/test_token_limiter.py +517 -10
  443. autocoder/rag/token_counter.py +3 -0
  444. autocoder/rag/token_limiter.py +19 -15
  445. autocoder/rag/tools/__init__.py +26 -2
  446. autocoder/rag/tools/bochaai_example.py +343 -0
  447. autocoder/rag/tools/bochaai_sdk.py +541 -0
  448. autocoder/rag/tools/metaso_example.py +268 -0
  449. autocoder/rag/tools/metaso_sdk.py +417 -0
  450. autocoder/rag/tools/recall_tool.py +28 -7
  451. autocoder/rag/tools/run_integration_tests.py +204 -0
  452. autocoder/rag/tools/test_all_providers.py +318 -0
  453. autocoder/rag/tools/test_bochaai_integration.py +482 -0
  454. autocoder/rag/tools/test_final_integration.py +215 -0
  455. autocoder/rag/tools/test_metaso_integration.py +424 -0
  456. autocoder/rag/tools/test_metaso_real.py +171 -0
  457. autocoder/rag/tools/test_web_crawl_tool.py +639 -0
  458. autocoder/rag/tools/test_web_search_tool.py +509 -0
  459. autocoder/rag/tools/todo_read_tool.py +202 -0
  460. autocoder/rag/tools/todo_write_tool.py +412 -0
  461. autocoder/rag/tools/web_crawl_tool.py +634 -0
  462. autocoder/rag/tools/web_search_tool.py +558 -0
  463. autocoder/rag/tools/web_tools_example.py +119 -0
  464. autocoder/rag/types.py +16 -0
  465. autocoder/rag/variable_holder.py +4 -2
  466. autocoder/rags.py +86 -79
  467. autocoder/regexproject/__init__.py +23 -21
  468. autocoder/sdk/__init__.py +46 -190
  469. autocoder/sdk/api.py +370 -0
  470. autocoder/sdk/async_runner/__init__.py +26 -0
  471. autocoder/sdk/async_runner/async_executor.py +650 -0
  472. autocoder/sdk/async_runner/async_handler.py +356 -0
  473. autocoder/sdk/async_runner/markdown_processor.py +595 -0
  474. autocoder/sdk/async_runner/task_metadata.py +284 -0
  475. autocoder/sdk/async_runner/worktree_manager.py +438 -0
  476. autocoder/sdk/cli/__init__.py +2 -5
  477. autocoder/sdk/cli/formatters.py +28 -204
  478. autocoder/sdk/cli/handlers.py +77 -44
  479. autocoder/sdk/cli/main.py +154 -171
  480. autocoder/sdk/cli/options.py +95 -22
  481. autocoder/sdk/constants.py +139 -51
  482. autocoder/sdk/core/auto_coder_core.py +484 -109
  483. autocoder/sdk/core/bridge.py +297 -115
  484. autocoder/sdk/exceptions.py +18 -12
  485. autocoder/sdk/formatters/__init__.py +19 -0
  486. autocoder/sdk/formatters/input.py +64 -0
  487. autocoder/sdk/formatters/output.py +247 -0
  488. autocoder/sdk/formatters/stream.py +54 -0
  489. autocoder/sdk/models/__init__.py +6 -5
  490. autocoder/sdk/models/options.py +55 -18
  491. autocoder/sdk/utils/formatters.py +27 -195
  492. autocoder/suffixproject/__init__.py +28 -25
  493. autocoder/terminal/__init__.py +14 -0
  494. autocoder/terminal/app.py +454 -0
  495. autocoder/terminal/args.py +32 -0
  496. autocoder/terminal/bootstrap.py +178 -0
  497. autocoder/terminal/command_processor.py +521 -0
  498. autocoder/terminal/command_registry.py +57 -0
  499. autocoder/terminal/help.py +97 -0
  500. autocoder/terminal/tasks/__init__.py +5 -0
  501. autocoder/terminal/tasks/background.py +77 -0
  502. autocoder/terminal/tasks/task_event.py +70 -0
  503. autocoder/terminal/ui/__init__.py +13 -0
  504. autocoder/terminal/ui/completer.py +268 -0
  505. autocoder/terminal/ui/keybindings.py +75 -0
  506. autocoder/terminal/ui/session.py +41 -0
  507. autocoder/terminal/ui/toolbar.py +64 -0
  508. autocoder/terminal/utils/__init__.py +13 -0
  509. autocoder/terminal/utils/errors.py +18 -0
  510. autocoder/terminal/utils/paths.py +19 -0
  511. autocoder/terminal/utils/shell.py +43 -0
  512. autocoder/terminal_v3/__init__.py +10 -0
  513. autocoder/terminal_v3/app.py +201 -0
  514. autocoder/terminal_v3/handlers/__init__.py +5 -0
  515. autocoder/terminal_v3/handlers/command_handler.py +131 -0
  516. autocoder/terminal_v3/models/__init__.py +6 -0
  517. autocoder/terminal_v3/models/conversation_buffer.py +214 -0
  518. autocoder/terminal_v3/models/message.py +50 -0
  519. autocoder/terminal_v3/models/tool_display.py +247 -0
  520. autocoder/terminal_v3/ui/__init__.py +7 -0
  521. autocoder/terminal_v3/ui/keybindings.py +56 -0
  522. autocoder/terminal_v3/ui/layout.py +141 -0
  523. autocoder/terminal_v3/ui/styles.py +43 -0
  524. autocoder/tsproject/__init__.py +23 -23
  525. autocoder/utils/auto_coder_utils/chat_stream_out.py +1 -1
  526. autocoder/utils/llms.py +88 -80
  527. autocoder/utils/math_utils.py +101 -0
  528. autocoder/utils/model_provider_selector.py +16 -4
  529. autocoder/utils/operate_config_api.py +33 -5
  530. autocoder/utils/thread_utils.py +2 -2
  531. autocoder/version.py +4 -2
  532. autocoder/workflow_agents/__init__.py +84 -0
  533. autocoder/workflow_agents/agent.py +143 -0
  534. autocoder/workflow_agents/exceptions.py +573 -0
  535. autocoder/workflow_agents/executor.py +489 -0
  536. autocoder/workflow_agents/loader.py +737 -0
  537. autocoder/workflow_agents/runner.py +267 -0
  538. autocoder/workflow_agents/types.py +172 -0
  539. autocoder/workflow_agents/utils.py +434 -0
  540. autocoder/workflow_agents/workflow_manager.py +211 -0
  541. auto_coder-1.0.0.dist-info/METADATA +0 -396
  542. auto_coder-1.0.0.dist-info/RECORD +0 -442
  543. auto_coder-1.0.0.dist-info/licenses/LICENSE +0 -201
  544. autocoder/auto_coder_server.py +0 -672
  545. autocoder/benchmark.py +0 -138
  546. autocoder/common/ac_style_command_parser/example.py +0 -7
  547. autocoder/common/cleaner.py +0 -31
  548. autocoder/common/command_completer_v2.py +0 -615
  549. autocoder/common/context_pruner.py +0 -477
  550. autocoder/common/conversation_pruner.py +0 -132
  551. autocoder/common/directory_cache/__init__.py +0 -1
  552. autocoder/common/directory_cache/cache.py +0 -192
  553. autocoder/common/directory_cache/test_cache.py +0 -190
  554. autocoder/common/file_checkpoint/examples.py +0 -217
  555. autocoder/common/llm_friendly_package_example.py +0 -138
  556. autocoder/common/llm_friendly_package_test.py +0 -63
  557. autocoder/common/pull_requests/test_module.py +0 -1
  558. autocoder/common/rulefiles/autocoderrules_utils.py +0 -484
  559. autocoder/common/text.py +0 -30
  560. autocoder/common/v2/agent/agentic_edit_tools/list_package_info_tool_resolver.py +0 -42
  561. autocoder/common/v2/agent/agentic_edit_tools/test_execute_command_tool_resolver.py +0 -70
  562. autocoder/common/v2/agent/agentic_edit_tools/test_search_files_tool_resolver.py +0 -163
  563. autocoder/common/v2/agent/agentic_tool_display.py +0 -183
  564. autocoder/plugins/dynamic_completion_example.py +0 -148
  565. autocoder/plugins/sample_plugin.py +0 -160
  566. autocoder/sdk/cli/__main__.py +0 -26
  567. autocoder/sdk/cli/completion_wrapper.py +0 -38
  568. autocoder/sdk/cli/install_completion.py +0 -301
  569. autocoder/sdk/models/messages.py +0 -209
  570. autocoder/sdk/session/__init__.py +0 -32
  571. autocoder/sdk/session/session.py +0 -106
  572. autocoder/sdk/session/session_manager.py +0 -56
  573. {auto_coder-1.0.0.dist-info → auto_coder-2.0.0.dist-info}/top_level.txt +0 -0
  574. /autocoder/{sdk/example.py → common/agent_query_queue/__init__.py} +0 -0
@@ -0,0 +1,234 @@
1
+ """
2
+ Tests for linter factory and manager components.
3
+ """
4
+
5
+ import pytest
6
+ from unittest.mock import Mock, patch
7
+ from pathlib import Path
8
+
9
+ from autocoder.common.linter_core.linter_factory import LinterFactory
10
+ from autocoder.common.linter_core.linter_manager import LinterManager
11
+ from autocoder.common.linter_core.models.lint_result import LintResult
12
+ from autocoder.common.linter_core.linters.python_linter import PythonLinter
13
+ from autocoder.common.linter_core.linters.typescript_linter import TypeScriptLinter
14
+
15
+
16
+ class TestLinterFactory:
17
+ """Test cases for LinterFactory."""
18
+
19
+ def test_get_supported_languages(self):
20
+ """Test getting supported languages."""
21
+ languages = LinterFactory.get_supported_languages()
22
+ assert isinstance(languages, list)
23
+ assert 'python' in languages
24
+ assert 'typescript' in languages
25
+ assert 'java' in languages
26
+
27
+ def test_get_supported_extensions(self):
28
+ """Test getting supported file extensions."""
29
+ extensions = LinterFactory.get_supported_extensions()
30
+ assert isinstance(extensions, list)
31
+ assert '.py' in extensions
32
+ assert '.ts' in extensions
33
+ assert '.tsx' in extensions
34
+ assert '.java' in extensions
35
+
36
+ def test_create_linter_python(self):
37
+ """Test creating Python linter."""
38
+ linter = LinterFactory.create_linter('python')
39
+ assert isinstance(linter, PythonLinter)
40
+ assert linter.language_name == "Python"
41
+
42
+ def test_create_linter_typescript(self):
43
+ """Test creating TypeScript linter."""
44
+ linter = LinterFactory.create_linter('typescript')
45
+ assert isinstance(linter, TypeScriptLinter)
46
+ assert linter.language_name == "TypeScript"
47
+
48
+ def test_create_linter_with_config(self):
49
+ """Test creating linter with custom config."""
50
+ config = {'use_mypy': False}
51
+ linter = LinterFactory.create_linter('python', config)
52
+ assert isinstance(linter, PythonLinter)
53
+ assert linter.use_mypy is False
54
+
55
+ def test_create_linter_unsupported(self):
56
+ """Test creating linter for unsupported language."""
57
+ linter = LinterFactory.create_linter('unsupported')
58
+ assert linter is None
59
+
60
+ def test_create_linter_for_file_python(self):
61
+ """Test creating linter for Python file."""
62
+ linter = LinterFactory.create_linter_for_file('test.py')
63
+ assert isinstance(linter, PythonLinter)
64
+
65
+ def test_create_linter_for_file_typescript(self):
66
+ """Test creating linter for TypeScript file."""
67
+ linter = LinterFactory.create_linter_for_file('test.ts')
68
+ assert isinstance(linter, TypeScriptLinter)
69
+
70
+ def test_create_linter_for_file_java(self):
71
+ """Test creating linter for Java file."""
72
+ from autocoder.common.linter_core.linters.java_linter import JavaLinter
73
+ linter = LinterFactory.create_linter_for_file('Test.java')
74
+ assert isinstance(linter, JavaLinter)
75
+
76
+ def test_create_linter_for_file_unsupported(self):
77
+ """Test creating linter for unsupported file."""
78
+ linter = LinterFactory.create_linter_for_file('test.txt')
79
+ assert linter is None
80
+
81
+ def test_is_file_supported_true(self):
82
+ """Test checking if file is supported."""
83
+ assert LinterFactory.is_file_supported('test.py') is True
84
+ assert LinterFactory.is_file_supported('test.ts') is True
85
+ assert LinterFactory.is_file_supported('test.tsx') is True
86
+
87
+ def test_is_file_supported_false(self):
88
+ """Test checking if file is not supported."""
89
+ assert LinterFactory.is_file_supported('test.txt') is False
90
+ assert LinterFactory.is_file_supported('test.md') is False
91
+
92
+
93
+ class TestLinterManager:
94
+ """Test cases for LinterManager."""
95
+
96
+ @pytest.fixture
97
+ def manager(self):
98
+ """Create a linter manager instance."""
99
+ return LinterManager()
100
+
101
+ @pytest.fixture
102
+ def mock_linter(self):
103
+ """Create a mock linter."""
104
+ linter = Mock()
105
+ linter.name = "MockLinter"
106
+ linter.supported_extensions = ['.mock']
107
+ linter.is_available.return_value = True
108
+ return linter
109
+
110
+ def test_manager_initialization(self, manager):
111
+ """Test manager initialization."""
112
+ assert isinstance(manager, LinterManager)
113
+ assert hasattr(manager, 'linters')
114
+ assert hasattr(manager, 'max_workers')
115
+ assert hasattr(manager, 'timeout')
116
+
117
+ def test_manager_with_config(self):
118
+ """Test manager with custom config."""
119
+ config = {
120
+ 'max_workers': 8,
121
+ 'timeout': 600,
122
+ 'python_config': {'use_mypy': False}
123
+ }
124
+ manager = LinterManager(config)
125
+ assert manager.max_workers == 8
126
+ assert manager.timeout == 600
127
+
128
+ def test_get_available_linters(self, manager):
129
+ """Test getting available linters."""
130
+ available = manager.get_available_linters()
131
+ assert isinstance(available, dict)
132
+
133
+ def test_add_custom_linter(self, manager, mock_linter):
134
+ """Test adding custom linter."""
135
+ manager.add_linter('mock', mock_linter)
136
+ assert 'mock' in manager.linters
137
+ assert manager.linters['mock'] == mock_linter
138
+
139
+ def test_remove_linter(self, manager, mock_linter):
140
+ """Test removing linter."""
141
+ manager.add_linter('mock', mock_linter)
142
+ manager.remove_linter('mock')
143
+ assert 'mock' not in manager.linters
144
+
145
+ def test_lint_file_not_found(self, manager):
146
+ """Test linting non-existent file."""
147
+ result = manager.lint_file('nonexistent.py')
148
+ assert isinstance(result, LintResult)
149
+ assert result.success is False
150
+ assert "File not found" in result.error_message
151
+
152
+ @patch('pathlib.Path.exists')
153
+ def test_lint_file_no_linter(self, mock_exists, manager):
154
+ """Test linting file with no available linter."""
155
+ mock_exists.return_value = True
156
+ result = manager.lint_file('test.unsupported')
157
+ assert isinstance(result, LintResult)
158
+ assert result.success is False
159
+ assert "No available linter" in result.error_message
160
+
161
+ def test_lint_files_empty(self, manager):
162
+ """Test linting empty file list."""
163
+ results = manager.lint_files([])
164
+ assert isinstance(results, dict)
165
+ assert len(results) == 0
166
+
167
+ def test_get_summary_report_empty(self, manager):
168
+ """Test summary report for empty results."""
169
+ summary = manager.get_summary_report({})
170
+ assert summary['total_files'] == 0
171
+ assert summary['successful_files'] == 0
172
+ assert summary['failed_files'] == 0
173
+ assert summary['total_issues'] == 0
174
+
175
+ def test_get_summary_report_with_results(self, manager):
176
+ """Test summary report with results."""
177
+ results = {
178
+ 'file1.py': LintResult(
179
+ linter_name='TestLinter',
180
+ files_checked=['file1.py'],
181
+ success=True,
182
+ execution_time=1.0
183
+ ),
184
+ 'file2.py': LintResult(
185
+ linter_name='TestLinter',
186
+ files_checked=['file2.py'],
187
+ success=False,
188
+ execution_time=0.5
189
+ )
190
+ }
191
+
192
+ summary = manager.get_summary_report(results)
193
+ assert summary['total_files'] == 2
194
+ assert summary['successful_files'] == 1
195
+ assert summary['failed_files'] == 1
196
+ assert summary['total_execution_time'] == 1.0 # Only successful files counted
197
+
198
+ def test_lint_output_filtering(self, manager):
199
+ """Test filtering based on lint output content."""
200
+ # Create test results with different lint outputs
201
+ result1 = LintResult(
202
+ linter_name='TestLinter',
203
+ files_checked=['test1.py'],
204
+ lint_output='test1.py:1:1: E301 expected 1 blank line, found 0'
205
+ )
206
+ result2 = LintResult(
207
+ linter_name='TestLinter',
208
+ files_checked=['test2.py'],
209
+ lint_output='test2.py:2:1: W291 trailing whitespace'
210
+ )
211
+
212
+ results = {'test1.py': result1, 'test2.py': result2}
213
+
214
+ # Test that results with lint output are correctly identified
215
+ files_with_issues = [
216
+ path for path, result in results.items()
217
+ if result.has_issues
218
+ ]
219
+
220
+ assert len(files_with_issues) == 2
221
+ assert 'test1.py' in files_with_issues
222
+ assert 'test2.py' in files_with_issues
223
+
224
+ def test_format_results(self, manager):
225
+ """Test formatting results."""
226
+ result = LintResult(
227
+ linter_name='TestLinter',
228
+ files_checked=['test.py']
229
+ )
230
+ results = {'test.py': result}
231
+
232
+ formatted = manager.format_results(results)
233
+ assert isinstance(formatted, dict)
234
+ assert 'test.py' in formatted
@@ -0,0 +1,147 @@
1
+ """
2
+ Tests for linter output formatters.
3
+ """
4
+
5
+ import pytest
6
+ from typing import Dict, Any
7
+
8
+ from autocoder.common.linter_core.formatters.base_formatter import BaseLintOutputFormatter
9
+ from autocoder.common.linter_core.formatters.raw_formatter import RawLintOutputFormatter
10
+ from autocoder.common.linter_core.models.lint_result import LintResult
11
+
12
+
13
+ class CustomTestFormatter(BaseLintOutputFormatter):
14
+ """Test implementation of formatter for testing abstract base class."""
15
+
16
+ def format_result(self, result: LintResult) -> str:
17
+ """Format as a simple string."""
18
+ return f"{result.linter_name}: {result.file_name} - {result.lint_result}"
19
+
20
+ def format_results(self, results: Dict[str, LintResult]) -> str:
21
+ """Override to return concatenated string."""
22
+ lines = []
23
+ for path, result in results.items():
24
+ lines.append(f"{path}: {self.format_result(result)}")
25
+ return "\n".join(lines)
26
+
27
+
28
+ class TestBaseLintOutputFormatter:
29
+ """Test the base formatter abstract class."""
30
+
31
+ def test_abstract_methods(self):
32
+ """Test that abstract methods must be implemented."""
33
+ with pytest.raises(TypeError):
34
+ # Cannot instantiate abstract class
35
+ BaseLintOutputFormatter()
36
+
37
+ def test_custom_implementation(self):
38
+ """Test custom formatter implementation."""
39
+ formatter = CustomTestFormatter()
40
+ result = LintResult(
41
+ linter_name="TestLinter",
42
+ files_checked=["test.py"]
43
+ )
44
+ result.lint_result = "No issues found"
45
+
46
+ formatted = formatter.format_result(result)
47
+ assert formatted == "TestLinter: test.py - No issues found"
48
+
49
+ def test_format_results_default_behavior(self):
50
+ """Test default format_results implementation."""
51
+ formatter = CustomTestFormatter()
52
+ result1 = LintResult(
53
+ linter_name="Linter1",
54
+ files_checked=["file1.py"]
55
+ )
56
+ result1.lint_result = "Issue 1"
57
+
58
+ result2 = LintResult(
59
+ linter_name="Linter2",
60
+ files_checked=["file2.py"]
61
+ )
62
+ result2.lint_result = "Issue 2"
63
+
64
+ results = {
65
+ "file1.py": result1,
66
+ "file2.py": result2
67
+ }
68
+
69
+ formatted = formatter.format_results(results)
70
+ assert "file1.py: Linter1: file1.py - Issue 1" in formatted
71
+ assert "file2.py: Linter2: file2.py - Issue 2" in formatted
72
+
73
+
74
+ class TestRawLintOutputFormatter:
75
+ """Test the raw formatter implementation."""
76
+
77
+ @pytest.fixture
78
+ def formatter(self):
79
+ """Create a raw formatter instance."""
80
+ return RawLintOutputFormatter()
81
+
82
+ @pytest.fixture
83
+ def sample_result(self):
84
+ """Create a sample lint result."""
85
+ result = LintResult(
86
+ linter_name="PythonLinter",
87
+ files_checked=["example.py"],
88
+ metadata={"tool": "flake8", "severity": "error"}
89
+ )
90
+ result.lint_result = "line 10: undefined variable"
91
+ return result
92
+
93
+ def test_format_result_returns_dict(self, formatter, sample_result):
94
+ """Test that format_result returns a dictionary."""
95
+ formatted = formatter.format_result(sample_result)
96
+
97
+ assert isinstance(formatted, dict)
98
+ assert formatted["linter_name"] == "PythonLinter"
99
+ assert formatted["file_name"] == "example.py"
100
+ assert formatted["lint_result"] == "line 10: undefined variable"
101
+ assert formatted["metadata"]["tool"] == "flake8"
102
+
103
+ def test_format_results_returns_dict_of_dicts(self, formatter):
104
+ """Test formatting multiple results."""
105
+ result1 = LintResult(
106
+ linter_name="Linter1",
107
+ files_checked=["file1.py"],
108
+ metadata={"line": 5}
109
+ )
110
+ result1.lint_result = "Issue 1"
111
+
112
+ result2 = LintResult(
113
+ linter_name="Linter2",
114
+ files_checked=["file2.py"],
115
+ metadata={"line": 10}
116
+ )
117
+ result2.lint_result = "Issue 2"
118
+
119
+ results = {
120
+ "file1.py": result1,
121
+ "file2.py": result2
122
+ }
123
+
124
+ formatted = formatter.format_results(results)
125
+
126
+ assert isinstance(formatted, dict)
127
+ assert len(formatted) == 2
128
+ assert "file1.py" in formatted
129
+ assert "file2.py" in formatted
130
+ assert formatted["file1.py"]["lint_result"] == "Issue 1"
131
+ assert formatted["file2.py"]["metadata"]["line"] == 10
132
+
133
+ def test_empty_results(self, formatter):
134
+ """Test formatting empty results."""
135
+ formatted = formatter.format_results({})
136
+ assert formatted == {}
137
+
138
+ def test_result_with_empty_metadata(self, formatter):
139
+ """Test result with no metadata."""
140
+ result = LintResult(
141
+ linter_name="TestLinter",
142
+ files_checked=["test.py"]
143
+ )
144
+
145
+ formatted = formatter.format_result(result)
146
+ assert formatted["metadata"] == {}
147
+ assert formatted["lint_result"] == ""
@@ -0,0 +1,317 @@
1
+
2
+ """
3
+ Integration tests for the linter core module.
4
+ """
5
+
6
+ import pytest
7
+ import tempfile
8
+ import os
9
+ from pathlib import Path
10
+ from unittest.mock import patch, MagicMock, Mock
11
+
12
+ from autocoder.common.linter_core import LinterManager, LinterFactory
13
+ from autocoder.common.linter_core.models.lint_result import LintResult
14
+
15
+
16
+ class TestIntegration:
17
+ """Integration tests with temporary project files."""
18
+
19
+ @pytest.fixture
20
+ def temp_dir(self):
21
+ """Create a temporary directory for test files."""
22
+ with tempfile.TemporaryDirectory() as temp_dir:
23
+ yield Path(temp_dir)
24
+
25
+ @pytest.fixture
26
+ def python_file(self, temp_dir):
27
+ """Create a temporary Python file."""
28
+ python_content = '''
29
+ def hello_world():
30
+ print("Hello, World!")
31
+ return True
32
+
33
+ if __name__ == "__main__":
34
+ hello_world()
35
+ '''
36
+ python_file = temp_dir / "test.py"
37
+ python_file.write_text(python_content)
38
+ return python_file
39
+
40
+ @pytest.fixture
41
+ def typescript_file(self, temp_dir):
42
+ """Create a temporary TypeScript file."""
43
+ ts_content = '''
44
+ function greet(name: string): string {
45
+ return `Hello, ${name}!`;
46
+ }
47
+
48
+ export { greet };
49
+ '''
50
+ ts_file = temp_dir / "test.ts"
51
+ ts_file.write_text(ts_content)
52
+ return ts_file
53
+
54
+ @pytest.fixture
55
+ def mixed_project(self, temp_dir):
56
+ """Create a mixed project with multiple file types."""
57
+ # Python file
58
+ py_content = '''
59
+ def calculate(x, y):
60
+ return x + y
61
+ '''
62
+ (temp_dir / "calculator.py").write_text(py_content)
63
+
64
+ # TypeScript file
65
+ ts_content = '''
66
+ interface User {
67
+ name: string;
68
+ age: number;
69
+ }
70
+
71
+ function createUser(name: string, age: number): User {
72
+ return { name, age };
73
+ }
74
+ '''
75
+ (temp_dir / "user.ts").write_text(ts_content)
76
+
77
+ # Java file
78
+ java_content = '''
79
+ public class HelloWorld {
80
+ public static void main(String[] args) {
81
+ System.out.println("Hello, World!");
82
+ }
83
+ }
84
+ '''
85
+ (temp_dir / "HelloWorld.java").write_text(java_content)
86
+
87
+ # Unsupported file
88
+ (temp_dir / "readme.txt").write_text("This is a readme file.")
89
+
90
+ return temp_dir
91
+
92
+ def test_factory_creates_appropriate_linters(self):
93
+ """Test that factory creates correct linters for different languages."""
94
+ python_linter = LinterFactory.create_linter('python')
95
+ typescript_linter = LinterFactory.create_linter('typescript')
96
+ java_linter = LinterFactory.create_linter('java')
97
+
98
+ assert python_linter is not None
99
+ assert typescript_linter is not None
100
+ assert java_linter is not None
101
+ assert python_linter.language_name == "Python"
102
+ assert typescript_linter.language_name == "TypeScript"
103
+ assert java_linter.language_name == "Java"
104
+
105
+ def test_factory_file_detection(self, python_file, typescript_file):
106
+ """Test that factory correctly detects file types."""
107
+ python_linter = LinterFactory.create_linter_for_file(python_file)
108
+ typescript_linter = LinterFactory.create_linter_for_file(typescript_file)
109
+
110
+ assert python_linter is not None
111
+ assert typescript_linter is not None
112
+ assert python_linter.language_name == "Python"
113
+ assert typescript_linter.language_name == "TypeScript"
114
+
115
+ @patch('subprocess.run')
116
+ def test_manager_lint_single_file(self, mock_run, python_file):
117
+ """Test manager linting a single file."""
118
+ # Mock flake8 output
119
+ mock_run.return_value = MagicMock(stdout="", stderr="", returncode=0)
120
+
121
+ manager = LinterManager()
122
+ result = manager.lint_file(python_file)
123
+
124
+ assert isinstance(result, LintResult)
125
+ assert result.linter_name == "PythonLinter"
126
+ assert str(python_file) in result.files_checked
127
+
128
+ @patch('subprocess.run')
129
+ def test_manager_lint_directory(self, mock_run, mixed_project):
130
+ """Test manager linting an entire directory."""
131
+ # Mock subprocess calls
132
+ mock_run.return_value = MagicMock(stdout="", stderr="", returncode=0)
133
+
134
+ manager = LinterManager()
135
+ results = manager.lint_directory(mixed_project)
136
+
137
+ assert isinstance(results, dict)
138
+ # Should have results for .py, .ts, and .java files, but not .txt
139
+ assert len(results) >= 3
140
+
141
+ # Check that we have results for supported files
142
+ py_files = [path for path in results.keys() if path.endswith('.py')]
143
+ ts_files = [path for path in results.keys() if path.endswith('.ts')]
144
+ java_files = [path for path in results.keys() if path.endswith('.java')]
145
+
146
+ assert len(py_files) >= 1
147
+ assert len(ts_files) >= 1
148
+ assert len(java_files) >= 1
149
+
150
+ @patch('subprocess.run')
151
+ def test_manager_parallel_processing(self, mock_run, mixed_project):
152
+ """Test manager with parallel processing."""
153
+ mock_run.return_value = MagicMock(stdout="", stderr="", returncode=0)
154
+
155
+ manager = LinterManager({'max_workers': 2})
156
+ results = manager.lint_directory(mixed_project, parallel=True)
157
+
158
+ assert isinstance(results, dict)
159
+ assert len(results) >= 2
160
+
161
+ @patch('subprocess.run')
162
+ def test_manager_sequential_processing(self, mock_run, mixed_project):
163
+ """Test manager with sequential processing."""
164
+ mock_run.return_value = MagicMock(stdout="", stderr="", returncode=0)
165
+
166
+ manager = LinterManager()
167
+ results = manager.lint_directory(mixed_project, parallel=False)
168
+
169
+ assert isinstance(results, dict)
170
+ assert len(results) >= 2
171
+
172
+ @patch('subprocess.run')
173
+ def test_manager_include_exclude_patterns(self, mock_run, mixed_project):
174
+ """Test manager with include/exclude patterns."""
175
+ mock_run.return_value = MagicMock(stdout="", stderr="", returncode=0)
176
+
177
+ manager = LinterManager()
178
+
179
+ # Test include pattern - only Python files
180
+ results = manager.lint_directory(
181
+ mixed_project,
182
+ include_patterns=['*.py']
183
+ )
184
+
185
+ py_files = [path for path in results.keys() if path.endswith('.py')]
186
+ ts_files = [path for path in results.keys() if path.endswith('.ts')]
187
+
188
+ assert len(py_files) >= 1
189
+ assert len(ts_files) == 0
190
+
191
+ def test_manager_summary_report(self):
192
+ """Test manager summary report generation."""
193
+ manager = LinterManager()
194
+
195
+ # Create mock results
196
+ results = {
197
+ 'file1.py': LintResult(
198
+ linter_name='PythonLinter',
199
+ files_checked=['file1.py'],
200
+ success=True,
201
+ execution_time=1.0
202
+ ),
203
+ 'file2.ts': LintResult(
204
+ linter_name='TypeScriptLinter',
205
+ files_checked=['file2.ts'],
206
+ success=True,
207
+ execution_time=1.5
208
+ ),
209
+ 'file3.py': LintResult(
210
+ linter_name='PythonLinter',
211
+ files_checked=['file3.py'],
212
+ success=False,
213
+ execution_time=0.0
214
+ )
215
+ }
216
+
217
+ summary = manager.get_summary_report(results)
218
+
219
+ assert summary['total_files'] == 3
220
+ assert summary['successful_files'] == 2
221
+ assert summary['failed_files'] == 1
222
+ assert summary['total_execution_time'] == 2.5
223
+ assert summary['average_execution_time'] == 1.25
224
+
225
+ @patch('subprocess.run')
226
+ def test_end_to_end_workflow(self, mock_run, mixed_project):
227
+ """Test complete end-to-end workflow."""
228
+ # Mock subprocess calls with some lint output
229
+ mock_run.return_value = MagicMock(
230
+ stdout="test.py:1:1: E302 expected 2 blank lines",
231
+ stderr="",
232
+ returncode=1
233
+ )
234
+
235
+ # Initialize manager
236
+ manager = LinterManager({
237
+ 'max_workers': 2,
238
+ 'timeout': 60,
239
+ 'python_config': {'use_mypy': False}
240
+ })
241
+
242
+ # Lint directory
243
+ results = manager.lint_directory(mixed_project, recursive=True)
244
+
245
+ # Generate summary
246
+ summary = manager.get_summary_report(results)
247
+
248
+ # Format results
249
+ formatted = manager.format_results(results)
250
+
251
+ # Assertions
252
+ assert isinstance(results, dict)
253
+ assert isinstance(summary, dict)
254
+ assert isinstance(formatted, dict)
255
+ assert summary['total_files'] >= 2
256
+ assert len(formatted) == len(results)
257
+
258
+ def test_linter_availability_check(self):
259
+ """Test checking linter availability."""
260
+ manager = LinterManager()
261
+ available = manager.get_available_linters()
262
+
263
+ assert isinstance(available, dict)
264
+ # The dictionary should contain linter availability status
265
+ # Note: In test environment, linters may not be available
266
+ # but the structure should be correct
267
+ for language, is_available in available.items():
268
+ assert isinstance(is_available, bool)
269
+
270
+ def test_error_handling_integration(self, python_file):
271
+ """Test error handling in integration scenario."""
272
+ # Create manager first, then patch the specific linter's lint_file method
273
+ manager = LinterManager()
274
+
275
+ # Mock a linter to raise exception during linting
276
+ with patch.object(manager, '_get_linter_for_file') as mock_get_linter:
277
+ mock_linter = Mock()
278
+ mock_linter.lint_file.side_effect = Exception("Tool not found")
279
+ mock_get_linter.return_value = mock_linter
280
+
281
+ result = manager.lint_file(python_file)
282
+
283
+ assert isinstance(result, LintResult)
284
+ assert result.success is False
285
+ assert "Tool not found" in result.error_message
286
+
287
+ def test_configuration_propagation(self):
288
+ """Test that configuration is properly propagated."""
289
+ config = {
290
+ 'max_workers': 8,
291
+ 'timeout': 120,
292
+ 'python_config': {
293
+ 'use_mypy': False,
294
+ 'flake8_args': ['--max-line-length=120']
295
+ },
296
+ 'typescript_config': {
297
+ 'use_eslint': False,
298
+ 'tsc_args': ['--strict']
299
+ }
300
+ }
301
+
302
+ manager = LinterManager(config)
303
+
304
+ assert manager.max_workers == 8
305
+ assert manager.timeout == 120
306
+
307
+ # Check that linter configs are applied
308
+ if 'python' in manager.linters:
309
+ python_linter = manager.linters['python']
310
+ assert python_linter.use_mypy is False
311
+ assert '--max-line-length=120' in python_linter.flake8_args
312
+
313
+ if 'typescript' in manager.linters:
314
+ ts_linter = manager.linters['typescript']
315
+ assert ts_linter.use_eslint is False
316
+ assert '--strict' in ts_linter.tsc_args
317
+