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,306 @@
1
+ """
2
+ Similarity-based text replacer implementation
3
+ """
4
+
5
+ from typing import List, Tuple
6
+ from loguru import logger
7
+
8
+ from .base import BaseReplacer, ReplaceResult, ReplaceStrategy
9
+ from ..text_similarity import TextSimilarity
10
+
11
+
12
+ class SimilarityReplacer(BaseReplacer):
13
+ """基于文本相似度的替换器"""
14
+
15
+ def __init__(self, similarity_threshold: float = 0.9):
16
+ """
17
+ 初始化相似度替换器
18
+
19
+ Args:
20
+ similarity_threshold: 相似度阈值,超过此值才进行替换
21
+ """
22
+ super().__init__(ReplaceStrategy.SIMILARITY)
23
+ self.similarity_threshold = similarity_threshold
24
+
25
+ def _find_line_numbers(self, content: str, text_block: str) -> Tuple[int, int]:
26
+ """
27
+ 找到文本块在内容中的行号
28
+
29
+ Args:
30
+ content: 完整文件内容
31
+ text_block: 要查找的文本块
32
+
33
+ Returns:
34
+ Tuple[int, int]: (起始行号, 结束行号),1-based,如果未找到返回 (-1, -1)
35
+ """
36
+ lines = content.splitlines()
37
+ block_lines = text_block.splitlines()
38
+
39
+ # 找到文本块在内容中的位置
40
+ block_start_idx = content.find(text_block)
41
+ if block_start_idx == -1:
42
+ return (-1, -1)
43
+
44
+ # 计算到文本块开始位置的行数
45
+ lines_before = content[:block_start_idx].count('\n')
46
+ start_line = lines_before + 1
47
+
48
+ # 计算文本块的行数
49
+ lines_in_block = len(block_lines)
50
+ end_line = start_line + lines_in_block - 1
51
+
52
+ return (start_line, end_line)
53
+
54
+ def _replace_by_line_numbers(self, content: str, start_line: int, end_line: int,
55
+ replace_text: str) -> str:
56
+ """
57
+ 根据行号替换文本
58
+
59
+ Args:
60
+ content: 原始内容
61
+ start_line: 起始行号(1-based)
62
+ end_line: 结束行号(1-based)
63
+ replace_text: 替换的文本
64
+
65
+ Returns:
66
+ 替换后的内容
67
+ """
68
+ lines = content.splitlines(keepends=True)
69
+
70
+ # 转换为0-based索引
71
+ start_idx = start_line - 1
72
+ end_idx = end_line - 1
73
+
74
+ # 确保索引有效
75
+ if start_idx < 0 or end_idx >= len(lines) or start_idx > end_idx:
76
+ return content
77
+
78
+ # 构建新内容
79
+ new_lines = []
80
+ new_lines.extend(lines[:start_idx])
81
+
82
+ # 添加替换文本
83
+ replace_lines = replace_text.splitlines(keepends=True)
84
+ # 如果替换文本最后没有换行符,但原始文本有,则添加换行符
85
+ if replace_lines and not replace_lines[-1].endswith('\n') and end_idx < len(lines) - 1:
86
+ replace_lines[-1] += '\n'
87
+ new_lines.extend(replace_lines)
88
+
89
+ new_lines.extend(lines[end_idx + 1:])
90
+
91
+ return ''.join(new_lines)
92
+
93
+ def _build_similarity_error_message(self, block_index: int, search_text: str, similarity: float,
94
+ threshold: float, best_match: str, start_line: int, end_line: int) -> str:
95
+ """
96
+ 构建针对大模型的详细相似度错误信息
97
+ """
98
+ message_parts = []
99
+
100
+ message_parts.append(f"🔍 Block {block_index} Similarity Analysis:")
101
+ message_parts.append(f" 📏 Found similarity: {similarity:.1%} (threshold: {threshold:.1%})")
102
+
103
+ if similarity > 0.8:
104
+ message_parts.append(f" ✅ Very close match found at lines {start_line}-{end_line}")
105
+ message_parts.append(f" 📝 Expected: {repr(search_text[:80])}{'...' if len(search_text) > 80 else ''}")
106
+ message_parts.append(f" 📝 Actual: {repr(best_match[:80])}{'...' if len(best_match) > 80 else ''}")
107
+ message_parts.append(" 💡 Use the exact content shown as 'Actual' in your SEARCH block")
108
+ elif similarity > 0.6:
109
+ message_parts.append(f" ⚠️ Moderate similarity at lines {start_line}-{end_line}")
110
+ message_parts.append(f" 📝 Your search: {repr(search_text[:60])}{'...' if len(search_text) > 60 else ''}")
111
+ message_parts.append(f" 📝 Best match: {repr(best_match[:60])}{'...' if len(best_match) > 60 else ''}")
112
+ message_parts.append(" 💡 Check for whitespace, line ending, or formatting differences")
113
+ else:
114
+ message_parts.append(f" ❌ Low similarity - content may not exist as expected")
115
+ message_parts.append(f" 📝 Searched for: {repr(search_text[:60])}{'...' if len(search_text) > 60 else ''}")
116
+ message_parts.append(" 💡 Verify the content exists or try a smaller, more unique search phrase")
117
+
118
+ return "\n".join(message_parts)
119
+
120
+ def replace(self, content: str, search_blocks: List[Tuple[str, str]]) -> ReplaceResult:
121
+ """
122
+ 执行基于相似度的替换(行级替换)
123
+
124
+ Args:
125
+ content: 原始文件内容
126
+ search_blocks: 搜索替换块列表
127
+
128
+ Returns:
129
+ ReplaceResult: 替换结果
130
+ """
131
+ if not self.validate_search_blocks(search_blocks):
132
+ return ReplaceResult(
133
+ success=False,
134
+ message="Invalid search blocks provided. 只支持行级替换。",
135
+ total_count=len(search_blocks)
136
+ )
137
+
138
+ current_content = content
139
+ applied_count = 0
140
+ errors = []
141
+ similarity_info = []
142
+
143
+ for i, (search_text, replace_text) in enumerate(search_blocks):
144
+ try:
145
+ # ----- 插入操作 -----
146
+ if search_text == "":
147
+ # 插入到文件开头
148
+ insert_text = replace_text
149
+ # 如果插入文本不以换行符结尾,自动补一个,保持行级语义
150
+ if not insert_text.endswith(("\n", "\r\n")):
151
+ insert_text += "\n"
152
+
153
+ current_content = insert_text + current_content
154
+ applied_count += 1
155
+ logger.info(f"Similarity replacer inserted block {i+1}/{len(search_blocks)} at file head")
156
+ continue
157
+
158
+ # ----- 正常替换操作 -----
159
+ # 硬约束:检查是否为行级替换
160
+ if not self._is_line_level_search(search_text, content):
161
+ error_msg = f"🔍 Block {i+1}: 只支持行级替换\n 📝 Search text: {repr(search_text[:60])}{'...' if len(search_text) > 60 else ''}\n 💡 请确保搜索文本匹配完整行"
162
+ errors.append(error_msg)
163
+ continue
164
+
165
+ # 使用TextSimilarity查找最佳匹配
166
+ similarity_finder = TextSimilarity(search_text, current_content)
167
+ similarity, best_window = similarity_finder.get_best_matching_window()
168
+
169
+ logger.info(f"Block {i+1}: Found similarity {similarity:.3f} with threshold {self.similarity_threshold}")
170
+
171
+ if similarity >= self.similarity_threshold:
172
+ # 找到行号
173
+ start_line, end_line = self._find_line_numbers(current_content, best_window)
174
+
175
+ if start_line > 0 and end_line > 0:
176
+ # 执行替换
177
+ new_content = self._replace_by_line_numbers(
178
+ current_content, start_line, end_line, replace_text
179
+ )
180
+
181
+ if new_content != current_content:
182
+ current_content = new_content
183
+ applied_count += 1
184
+ similarity_info.append({
185
+ 'block_index': i + 1,
186
+ 'similarity': similarity,
187
+ 'start_line': start_line,
188
+ 'end_line': end_line,
189
+ 'matched_text': best_window[:100] + '...' if len(best_window) > 100 else best_window
190
+ })
191
+ logger.info(f"Applied block {i+1} at lines {start_line}-{end_line}")
192
+ else:
193
+ error_msg = f"Block {i+1}: Replacement did not change content"
194
+ errors.append(error_msg)
195
+ logger.warning(error_msg)
196
+ else:
197
+ error_msg = f"Block {i+1}: Could not determine line numbers for matched text"
198
+ errors.append(error_msg)
199
+ logger.warning(error_msg)
200
+ else:
201
+ # 构建详细的错误信息给大模型
202
+ start_line, end_line = self._find_line_numbers(current_content, best_window)
203
+ error_msg = self._build_similarity_error_message(
204
+ i + 1, search_text, similarity, self.similarity_threshold,
205
+ best_window, start_line, end_line
206
+ )
207
+ errors.append(error_msg)
208
+ logger.warning(f"Block {i+1}: Similarity {similarity:.3f} below threshold {self.similarity_threshold:.3f}")
209
+
210
+ # 提供调试信息
211
+ similarity_info.append({
212
+ 'block_index': i + 1,
213
+ 'similarity': similarity,
214
+ 'threshold': self.similarity_threshold,
215
+ 'best_match': best_window[:100] + '...' if len(best_window) > 100 else best_window,
216
+ 'location': f"lines {start_line}-{end_line}" if start_line > 0 else "unknown"
217
+ })
218
+
219
+ except Exception as e:
220
+ error_msg = f"Block {i+1}: Error during similarity matching - {str(e)}"
221
+ errors.append(error_msg)
222
+ logger.error(error_msg)
223
+
224
+ success = applied_count > 0
225
+
226
+ if success:
227
+ if errors:
228
+ message = f"Partial success: Applied {applied_count}/{len(search_blocks)} blocks with {len(errors)} errors"
229
+ else:
230
+ message = f"Success: Applied {applied_count}/{len(search_blocks)} blocks using similarity matching"
231
+ else:
232
+ message = f"Failed: No blocks were applied using similarity matching. {len(errors)} errors occurred"
233
+
234
+ return ReplaceResult(
235
+ success=success,
236
+ message=message,
237
+ new_content=current_content if success else None,
238
+ applied_count=applied_count,
239
+ total_count=len(search_blocks),
240
+ errors=errors,
241
+ metadata={
242
+ 'strategy': self.get_strategy_name(),
243
+ 'similarity_threshold': self.similarity_threshold,
244
+ 'similarity_info': similarity_info
245
+ }
246
+ )
247
+
248
+ def can_handle(self, content: str, search_blocks: List[Tuple[str, str]]) -> bool:
249
+ """
250
+ 检查是否能处理给定的内容和搜索块
251
+
252
+ Args:
253
+ content: 原始文件内容
254
+ search_blocks: 搜索替换块列表
255
+
256
+ Returns:
257
+ bool: 总是返回 True,因为相似度替换器可以处理所有文本
258
+ """
259
+ return self.validate_search_blocks(search_blocks)
260
+
261
+ def set_similarity_threshold(self, threshold: float):
262
+ """
263
+ 设置相似度阈值
264
+
265
+ Args:
266
+ threshold: 新的相似度阈值 (0.0 - 1.0)
267
+ """
268
+ if 0.0 <= threshold <= 1.0:
269
+ self.similarity_threshold = threshold
270
+ logger.info(f"Similarity threshold set to {threshold}")
271
+ else:
272
+ logger.warning(f"Invalid similarity threshold {threshold}, must be between 0.0 and 1.0")
273
+
274
+ def _is_line_level_search(self, search_text: str, content: str) -> bool:
275
+ """
276
+ 检查搜索文本是否为行级搜索
277
+
278
+ Args:
279
+ search_text: 搜索文本
280
+ content: 文件内容
281
+
282
+ Returns:
283
+ bool: 是否为行级搜索
284
+ """
285
+ # 如果搜索文本包含换行符,认为是多行搜索,允许
286
+ if '\n' in search_text:
287
+ return True
288
+
289
+ # 对于单行文本,使用TextSimilarity检查是否能找到完整行匹配
290
+ try:
291
+ similarity_finder = TextSimilarity(search_text, content)
292
+ similarity, best_window = similarity_finder.get_best_matching_window()
293
+
294
+ # 检查最佳匹配是否为完整行
295
+ if similarity >= self.similarity_threshold:
296
+ content_lines = content.splitlines()
297
+ best_window_stripped = best_window.strip()
298
+
299
+ # 检查最佳匹配是否等于某一完整行
300
+ for line in content_lines:
301
+ if line.strip() == best_window_stripped:
302
+ return True
303
+
304
+ return False
305
+ except Exception:
306
+ return False
@@ -0,0 +1,181 @@
1
+ """
2
+ String-based text replacer implementation (formerly regex-based)
3
+ """
4
+
5
+ from typing import List, Tuple
6
+ from loguru import logger
7
+
8
+ from .base import BaseReplacer, ReplaceResult, ReplaceStrategy
9
+
10
+
11
+ class StringReplacer(BaseReplacer):
12
+ """基于字符串匹配的文本替换器(严格匹配模式)"""
13
+
14
+ def __init__(self, lenient_mode: bool = False):
15
+ """
16
+ 初始化字符串替换器
17
+
18
+ Args:
19
+ lenient_mode: 保留此参数以兼容现有代码,但在严格模式下不生效
20
+ """
21
+ super().__init__(ReplaceStrategy.STRING)
22
+ self.lenient_mode = lenient_mode # 保留但不使用
23
+
24
+ def _find_line_boundaries(self, content: str, search_text: str) -> List[Tuple[int, int]]:
25
+ """
26
+ 查找所有匹配的位置,确保是行级匹配
27
+
28
+ Args:
29
+ content: 文件内容
30
+ search_text: 搜索文本
31
+
32
+ Returns:
33
+ 匹配位置列表 [(start_pos, end_pos), ...]
34
+ """
35
+ matches = []
36
+ lines = content.splitlines(keepends=True)
37
+ search_lines = search_text.splitlines()
38
+
39
+ if not search_lines:
40
+ return matches
41
+
42
+ # 对于单行搜索
43
+ if len(search_lines) == 1:
44
+ search_line = search_lines[0]
45
+ current_pos = 0
46
+
47
+ for i, line in enumerate(lines):
48
+ line_content = line.rstrip('\r\n')
49
+ if line_content == search_line:
50
+ # 找到匹配的完整行
51
+ line_start = current_pos
52
+ line_end = current_pos + len(line)
53
+ matches.append((line_start, line_end))
54
+ current_pos += len(line)
55
+
56
+ # 对于多行搜索
57
+ else:
58
+ for i in range(len(lines) - len(search_lines) + 1):
59
+ match_found = True
60
+ for j, search_line in enumerate(search_lines):
61
+ if i + j >= len(lines):
62
+ match_found = False
63
+ break
64
+ line_content = lines[i + j].rstrip('\r\n')
65
+ if line_content != search_line:
66
+ match_found = False
67
+ break
68
+
69
+ if match_found:
70
+ # 计算多行匹配的起始和结束位置
71
+ start_pos = sum(len(lines[k]) for k in range(i))
72
+ end_pos = sum(len(lines[k]) for k in range(i + len(search_lines)))
73
+ matches.append((start_pos, end_pos))
74
+
75
+ return matches
76
+
77
+ def replace(self, content: str, search_blocks: List[Tuple[str, str]]) -> ReplaceResult:
78
+ """
79
+ 执行字符串替换(行级替换)
80
+
81
+ Args:
82
+ content: 原始文件内容
83
+ search_blocks: 搜索替换块列表
84
+
85
+ Returns:
86
+ ReplaceResult: 替换结果
87
+ """
88
+ if not self.validate_search_blocks(search_blocks):
89
+ return ReplaceResult(
90
+ success=False,
91
+ message="Invalid search blocks provided",
92
+ total_count=len(search_blocks)
93
+ )
94
+
95
+ current_content = content
96
+ applied_count = 0
97
+ errors = []
98
+
99
+ for i, (search_text, replace_text) in enumerate(search_blocks):
100
+ try:
101
+ # ----- 插入操作 -----
102
+ if search_text == "":
103
+ # 插入到文件开头
104
+ insert_text = replace_text
105
+ # 如果插入文本不以换行符结尾,自动补一个,保持行级语义
106
+ if not insert_text.endswith(("\n", "\r\n")):
107
+ insert_text += "\n"
108
+
109
+ current_content = insert_text + current_content
110
+ applied_count += 1
111
+ logger.info(f"String replacer inserted block {i+1}/{len(search_blocks)} at file head")
112
+ continue
113
+
114
+ # ----- 正常替换操作 -----
115
+ # 查找匹配位置(确保行级匹配)
116
+ matches = self._find_line_boundaries(current_content, search_text)
117
+
118
+ if matches:
119
+ # 只替换第一个匹配项,从后往前替换避免位置偏移
120
+ start_pos, end_pos = matches[0]
121
+
122
+ # 构建替换后的内容
123
+ before = current_content[:start_pos]
124
+ after = current_content[end_pos:]
125
+
126
+ # 处理替换文本的换行符
127
+ replacement = replace_text
128
+ if '\n' not in search_text and current_content[end_pos-1:end_pos] == '\n':
129
+ # 如果原文本是单行且以换行符结尾,替换文本也应该以换行符结尾
130
+ if not replacement.endswith(('\n', '\r\n')):
131
+ replacement += '\n'
132
+
133
+ current_content = before + replacement + after
134
+ applied_count += 1
135
+ logger.info(f"String replacer applied block {i+1}/{len(search_blocks)}")
136
+ else:
137
+ error_msg = f"🔍 Block {i+1}: No exact line match found\n 📝 Search text: {repr(search_text[:60])}{'...' if len(search_text) > 60 else ''}\n 💡 只支持行级精确匹配,请确保搜索文本完全匹配目标行"
138
+ errors.append(error_msg)
139
+ logger.warning(f"Block {i+1}: No exact match found for search text")
140
+
141
+ except Exception as e:
142
+ error_msg = f"Block {i+1}: Unexpected error - {str(e)}"
143
+ errors.append(error_msg)
144
+ logger.error(error_msg)
145
+
146
+ success = applied_count > 0
147
+
148
+ if success:
149
+ if errors:
150
+ message = f"Partial success: Applied {applied_count}/{len(search_blocks)} blocks with {len(errors)} errors"
151
+ else:
152
+ message = f"Success: Applied {applied_count}/{len(search_blocks)} blocks"
153
+ else:
154
+ message = f"Failed: No blocks were applied. {len(errors)} errors occurred"
155
+
156
+ return ReplaceResult(
157
+ success=success,
158
+ message=message,
159
+ new_content=current_content if success else None,
160
+ applied_count=applied_count,
161
+ total_count=len(search_blocks),
162
+ errors=errors,
163
+ metadata={
164
+ 'strategy': self.get_strategy_name(),
165
+ 'strict_mode': True, # 现在总是严格模式
166
+ 'lenient_mode': False # 保留兼容性
167
+ }
168
+ )
169
+
170
+ def can_handle(self, content: str, search_blocks: List[Tuple[str, str]]) -> bool:
171
+ """
172
+ 检查是否能处理给定的内容和搜索块
173
+
174
+ Args:
175
+ content: 原始文件内容
176
+ search_blocks: 搜索替换块列表
177
+
178
+ Returns:
179
+ bool: 总是返回 True,因为字符串替换器可以处理所有文本
180
+ """
181
+ return self.validate_search_blocks(search_blocks)
@@ -0,0 +1,3 @@
1
+ """
2
+ Tests for Search Replace Patch module
3
+ """
@@ -0,0 +1,126 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Test runner for Search Replace Patch module
4
+ """
5
+
6
+ import unittest
7
+ import sys
8
+ import os
9
+
10
+ # Add the parent directory to the Python path
11
+ sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
12
+
13
+ from .test_base import TestReplaceStrategy, TestReplaceResult, TestBaseReplacer
14
+ from .test_regex_replacer import TestRegexReplacer
15
+ from .test_similarity_replacer import TestSimilarityReplacer
16
+ from .test_patch_replacer import TestPatchReplacer
17
+ from .test_manager import TestSearchReplaceManager
18
+ from .test_integration import TestSearchReplacePatchIntegration
19
+
20
+
21
+ def create_test_suite():
22
+ """Create a test suite with all tests"""
23
+ suite = unittest.TestSuite()
24
+
25
+ # Add base tests
26
+ suite.addTest(unittest.makeSuite(TestReplaceStrategy))
27
+ suite.addTest(unittest.makeSuite(TestReplaceResult))
28
+ suite.addTest(unittest.makeSuite(TestBaseReplacer))
29
+
30
+ # Add replacer tests
31
+ suite.addTest(unittest.makeSuite(TestRegexReplacer))
32
+ suite.addTest(unittest.makeSuite(TestSimilarityReplacer))
33
+ suite.addTest(unittest.makeSuite(TestPatchReplacer))
34
+
35
+ # Add manager tests
36
+ suite.addTest(unittest.makeSuite(TestSearchReplaceManager))
37
+
38
+ # Add integration tests
39
+ suite.addTest(unittest.makeSuite(TestSearchReplacePatchIntegration))
40
+
41
+ return suite
42
+
43
+
44
+ def run_specific_test(test_class_name=None, test_method_name=None):
45
+ """Run a specific test class or method"""
46
+ if test_class_name:
47
+ # Map test class names to actual classes
48
+ test_classes = {
49
+ 'TestReplaceStrategy': TestReplaceStrategy,
50
+ 'TestReplaceResult': TestReplaceResult,
51
+ 'TestBaseReplacer': TestBaseReplacer,
52
+ 'TestRegexReplacer': TestRegexReplacer,
53
+ 'TestSimilarityReplacer': TestSimilarityReplacer,
54
+ 'TestPatchReplacer': TestPatchReplacer,
55
+ 'TestSearchReplaceManager': TestSearchReplaceManager,
56
+ 'TestSearchReplacePatchIntegration': TestSearchReplacePatchIntegration
57
+ }
58
+
59
+ if test_class_name in test_classes:
60
+ test_class = test_classes[test_class_name]
61
+
62
+ if test_method_name:
63
+ # Run specific method
64
+ suite = unittest.TestSuite()
65
+ suite.addTest(test_class(test_method_name))
66
+ return suite
67
+ else:
68
+ # Run all methods in the class
69
+ return unittest.makeSuite(test_class)
70
+ else:
71
+ print(f"Test class '{test_class_name}' not found")
72
+ print(f"Available test classes: {list(test_classes.keys())}")
73
+ return None
74
+ else:
75
+ return create_test_suite()
76
+
77
+
78
+ def main():
79
+ """Main function to run tests"""
80
+ import argparse
81
+
82
+ parser = argparse.ArgumentParser(description='Run Search Replace Patch tests')
83
+ parser.add_argument('--test-class', help='Run specific test class')
84
+ parser.add_argument('--test-method', help='Run specific test method (requires --test-class)')
85
+ parser.add_argument('--verbose', '-v', action='store_true', help='Verbose output')
86
+ parser.add_argument('--failfast', '-f', action='store_true', help='Stop on first failure')
87
+
88
+ args = parser.parse_args()
89
+
90
+ # Create test suite
91
+ suite = run_specific_test(args.test_class, args.test_method)
92
+
93
+ if suite is None:
94
+ return 1
95
+
96
+ # Configure test runner
97
+ runner = unittest.TextTestRunner(
98
+ verbosity=2 if args.verbose else 1,
99
+ failfast=args.failfast
100
+ )
101
+
102
+ # Run tests
103
+ result = runner.run(suite)
104
+
105
+ # Print summary
106
+ print(f"\nTests run: {result.testsRun}")
107
+ print(f"Failures: {len(result.failures)}")
108
+ print(f"Errors: {len(result.errors)}")
109
+ print(f"Skipped: {len(result.skipped)}")
110
+
111
+ if result.failures:
112
+ print("\nFailures:")
113
+ for test, traceback in result.failures:
114
+ print(f" {test}: {traceback}")
115
+
116
+ if result.errors:
117
+ print("\nErrors:")
118
+ for test, traceback in result.errors:
119
+ print(f" {test}: {traceback}")
120
+
121
+ # Return appropriate exit code
122
+ return 0 if result.wasSuccessful() else 1
123
+
124
+
125
+ if __name__ == '__main__':
126
+ sys.exit(main())