auto-coder 1.0.0__py3-none-any.whl → 2.0.1__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.1.dist-info/LICENSE +158 -0
  2. auto_coder-2.0.1.dist-info/METADATA +558 -0
  3. auto_coder-2.0.1.dist-info/RECORD +795 -0
  4. {auto_coder-1.0.0.dist-info → auto_coder-2.0.1.dist-info}/WHEEL +1 -1
  5. {auto_coder-1.0.0.dist-info → auto_coder-2.0.1.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 +77 -73
  19. autocoder/auto_coder.py +31 -40
  20. autocoder/auto_coder_rag.py +11 -1084
  21. autocoder/auto_coder_runner.py +962 -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 +409 -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 +316 -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 +356 -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 +1094 -0
  398. autocoder/default_project/__init__.py +501 -0
  399. autocoder/dispacher/__init__.py +4 -12
  400. autocoder/dispacher/actions/action.py +400 -129
  401. autocoder/dispacher/actions/plugins/action_regex_project.py +2 -2
  402. autocoder/index/entry.py +117 -125
  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 +923 -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 +665 -0
  536. autocoder/workflow_agents/loader.py +749 -0
  537. autocoder/workflow_agents/runner.py +267 -0
  538. autocoder/workflow_agents/types.py +173 -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.1.dist-info}/top_level.txt +0 -0
  574. /autocoder/{sdk/example.py → common/agent_query_queue/__init__.py} +0 -0
@@ -1,34 +1,21 @@
1
- from autocoder.run_context import get_run_context,RunMode
1
+ from loguru import logger
2
+
3
+ logger.remove() # 把默认 sink 去掉,彻底静音
4
+ from autocoder.run_context import get_run_context, RunMode
2
5
 
3
6
  # 设置运行模式为终端模式
4
7
  get_run_context().set_mode(RunMode.TERMINAL)
5
8
 
6
- import argparse
7
- import os
8
- from prompt_toolkit import PromptSession
9
- from prompt_toolkit.key_binding import KeyBindings
10
- from prompt_toolkit.history import FileHistory
11
- from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
12
- from prompt_toolkit.styles import Style
13
- from autocoder.version import __version__
14
- from autocoder.chat_auto_coder_lang import get_message
15
- from prompt_toolkit.formatted_text import FormattedText
16
- from prompt_toolkit.completion import Completer, Completion
17
- from autocoder.plugins import PluginManager
18
- from autocoder.events.event_manager_singleton import gengerate_event_file_path
19
- from autocoder.common.global_cancel import global_cancel
20
- from autocoder.chat.models_command import handle_models_command
21
- from autocoder.common.conversations.get_conversation_manager import (
22
- get_conversation_manager,
23
- get_conversation_manager_config,
24
- reset_conversation_manager
25
- )
9
+ import sys
10
+ import asyncio
11
+ from autocoder.chat.conf_command import handle_conf_command
26
12
  from autocoder.auto_coder_runner import (
27
- auto_command,
28
- configure, # Keep configure if it's used elsewhere or by handle_conf_command internally (though we adapted handle_conf_command not to)
13
+ auto_command,
14
+ run_agentic,
15
+ # Keep configure if it's used elsewhere or by handle_conf_command internally (though we adapted handle_conf_command not to)
16
+ configure,
29
17
  # manage_models, # Removed
30
18
  # print_conf, # Removed
31
- save_memory,
32
19
  exclude_dirs,
33
20
  exclude_files,
34
21
  ask,
@@ -55,14 +42,86 @@ from autocoder.auto_coder_runner import (
55
42
  get_mcp_server,
56
43
  completer,
57
44
  summon,
58
- get_memory,
59
45
  active_context,
60
46
  rules,
61
47
  start as start_engine,
62
- stop as stop_engine
48
+ stop as stop_engine,
49
+ )
50
+
51
+ # Import memory and mode management from core_config module
52
+ from autocoder.common.core_config import (
53
+ cycle_mode,
54
+ get_mode,
55
+ set_mode,
56
+ toggle_human_as_model,
57
+ get_human_as_model_string,
58
+ get_memory_manager,
59
+ )
60
+ from autocoder.chat.models_command import handle_models_command
61
+ from autocoder.common.global_cancel import global_cancel, CancelRequestedException
62
+ from autocoder.events.event_manager_singleton import gengerate_event_file_path
63
+ from autocoder.plugins import PluginManager
64
+ from prompt_toolkit.completion import Completer, Completion
65
+ from prompt_toolkit.formatted_text import FormattedText
66
+ from autocoder.chat_auto_coder_lang import (
67
+ get_message,
68
+ get_message_with_format as get_message_with_format_local,
69
+ )
70
+ from autocoder.common.international import (
71
+ get_message as get_i18n_message,
72
+ get_message_with_format,
63
73
  )
74
+ from autocoder.version import __version__
75
+ from prompt_toolkit.styles import Style
76
+ from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
77
+ from prompt_toolkit.history import FileHistory
78
+ from prompt_toolkit.key_binding import KeyBindings
79
+ from prompt_toolkit import PromptSession
80
+ from autocoder.common.terminal_paste import (
81
+ register_paste_handler,
82
+ resolve_paste_placeholders,
83
+ )
84
+ import os
85
+ import argparse
86
+ import time
87
+
88
+
89
+ class TaskEvent:
90
+ def __init__(self):
91
+ self.state = "idle" # idle, pending, started, running, completed
92
+ self._event = asyncio.Event()
93
+ self._event.set() # 初始状态为可用
94
+
95
+ def set_state(self, state):
96
+ """设置任务状态"""
97
+ self.state = state
98
+ if state == "completed":
99
+ self._event.set()
100
+ else:
101
+ self._event.clear()
102
+
103
+ def get_state(self):
104
+ """获取当前状态"""
105
+ return self.state
106
+
107
+ def is_completed(self):
108
+ """检查是否完成"""
109
+ return self.state == "completed"
110
+
111
+ def is_running(self):
112
+ """检查是否正在运行"""
113
+ return self.state in ["started", "running"]
114
+
115
+ async def wait(self):
116
+ """等待任务完成"""
117
+ await self._event.wait()
118
+
119
+ def clear(self):
120
+ """清除完成状态,重置为pending"""
121
+ self.set_state("idle")
122
+
123
+
64
124
  # Ensure the correct import is present
65
- from autocoder.chat.conf_command import handle_conf_command
66
125
 
67
126
  # Create a global plugin manager
68
127
  plugin_manager = PluginManager()
@@ -75,6 +134,7 @@ original_functions = {
75
134
  "design": design,
76
135
  "voice_input": voice_input,
77
136
  "auto_command": auto_command,
137
+ "run_agentic": run_agentic,
78
138
  "execute_shell_command": execute_shell_command,
79
139
  "active_context": active_context,
80
140
  }
@@ -118,65 +178,86 @@ def show_help():
118
178
  f" \033[94m{get_message('commands')}\033[0m - \033[93m{get_message('description')}\033[0m"
119
179
  )
120
180
  print(
121
- f" \033[94m/add_files\033[0m \033[93m<file1> <file2> ...\033[0m - \033[92m{get_message('add_files_desc')}\033[0m"
181
+ f" \033[94m/auto\033[0m \033[93m<query>\033[0m - \033[92m{get_message('auto_desc')}\033[0m"
122
182
  )
123
183
  print(
124
- f" \033[94m/remove_files\033[0m \033[93m<file1>,<file2> ...\033[0m - \033[92m{get_message('remove_files_desc')}\033[0m"
184
+ f" \033[94m/auto /new\033[0m \033[93m<query>\033[0m - \033[92m{get_message('auto_new_desc')}\033[0m"
125
185
  )
126
186
  print(
127
- f" \033[94m/chat\033[0m \033[93m<query>\033[0m - \033[92m{get_message('chat_desc')}\033[0m"
187
+ f" \033[94m/auto /resume\033[0m \033[93m<id> <query>\033[0m - \033[92m{get_message('auto_resume_desc')}\033[0m"
128
188
  )
129
189
  print(
130
- f" \033[94m/coding\033[0m \033[93m<query>\033[0m - \033[92m{get_message('coding_desc')}\033[0m"
131
- )
190
+ f" \033[94m/auto /list\033[0m - \033[92m{get_message('auto_list_desc')}\033[0m"
191
+ )
132
192
  print(
133
- f" \033[94m/summon\033[0m \033[93m<query>\033[0m - \033[92m{get_message('summon_desc')}\033[0m"
193
+ f" \033[94m/auto /command\033[0m \033[93m<file>\033[0m - \033[92m{get_message('auto_command_desc')}\033[0m"
134
194
  )
135
- print(f" \033[94m/revert\033[0m - \033[92m{get_message('revert_desc')}\033[0m")
195
+
136
196
  print(f" \033[94m/commit\033[0m - \033[92m{get_message('commit_desc')}\033[0m")
197
+
137
198
  print(
138
199
  f" \033[94m/conf\033[0m \033[93m<key>:<value>\033[0m - \033[92m{get_message('conf_desc')}\033[0m"
139
200
  )
201
+
140
202
  print(
141
- f" \033[94m/index/query\033[0m \033[93m<args>\033[0m - \033[92m{get_message('index_query_desc')}\033[0m"
203
+ f" \033[94m/shell\033[0m \033[93m<command>\033[0m - \033[92m{get_message('shell_desc')}\033[0m"
142
204
  )
143
205
  print(
144
- f" \033[94m/index/build\033[0m - \033[92m{get_message('index_build_desc')}\033[0m"
206
+ f" \033[94m/shell\033[0m - \033[92m{get_message('shell_interactive_desc')}\033[0m"
145
207
  )
146
208
  print(
147
- f" \033[94m/list_files\033[0m - \033[92m{get_message('list_files_desc')}\033[0m"
209
+ f" \033[94m!\033[0m\033[93m<command>\033[0m - \033[92m{get_message('shell_single_command_desc')}\033[0m"
148
210
  )
149
- print(f" \033[94m/help\033[0m - \033[92m{get_message('help_desc')}\033[0m")
211
+
150
212
  print(
151
- f" \033[94m/exclude_dirs\033[0m \033[93m<dir1>,<dir2> ...\033[0m - \033[92m{get_message('exclude_dirs_desc')}\033[0m"
213
+ f" \033[94m/add_files\033[0m \033[93m<file1> <file2> ...\033[0m - \033[92m{get_message('add_files_desc')}\033[0m"
152
214
  )
153
215
  print(
154
- f" \033[94m/shell\033[0m \033[93m<command>\033[0m - \033[92m{get_message('shell_desc')}\033[0m"
216
+ f" \033[94m/remove_files\033[0m \033[93m<file1>,<file2> ...\033[0m - \033[92m{get_message('remove_files_desc')}\033[0m"
217
+ )
218
+ print(
219
+ f" \033[94m/chat\033[0m \033[93m<query>\033[0m - \033[92m{get_message('chat_desc')}\033[0m"
220
+ )
221
+ print(
222
+ f" \033[94m/coding\033[0m \033[93m<query>\033[0m - \033[92m{get_message('coding_desc')}\033[0m"
223
+ )
224
+
225
+ print(f" \033[94m/revert\033[0m - \033[92m{get_message('revert_desc')}\033[0m")
226
+ print(
227
+ f" \033[94m/index/query\033[0m \033[93m<args>\033[0m - \033[92m{get_message('index_query_desc')}\033[0m"
228
+ )
229
+ print(
230
+ f" \033[94m/index/build\033[0m - \033[92m{get_message('index_build_desc')}\033[0m"
155
231
  )
156
232
  print(
157
- f" \033[94m/voice_input\033[0m - \033[92m{get_message('voice_input_desc')}\033[0m"
233
+ f" \033[94m/list_files\033[0m - \033[92m{get_message('list_files_desc')}\033[0m"
158
234
  )
235
+ print(f" \033[94m/help\033[0m - \033[92m{get_message('help_desc')}\033[0m")
159
236
  print(f" \033[94m/mode\033[0m - \033[92m{get_message('mode_desc')}\033[0m")
160
237
  print(f" \033[94m/lib\033[0m - \033[92m{get_message('lib_desc')}\033[0m")
161
238
  print(f" \033[94m/models\033[0m - \033[92m{get_message('models_desc')}\033[0m")
162
239
  print(f" \033[94m/plugins\033[0m - \033[92m{get_message('plugins_desc')}\033[0m")
163
- print(f" \033[94m/active_context\033[0m - \033[92m{get_message('active_context_desc')}\033[0m")
240
+ print(
241
+ f" \033[94m/active_context\033[0m - \033[92m{get_message('active_context_desc')}\033[0m"
242
+ )
164
243
  print(f" \033[94m/exit\033[0m - \033[92m{get_message('exit_desc')}\033[0m")
165
244
  print()
166
245
 
167
246
  # 显示插件命令
168
247
  if plugin_manager.command_handlers:
169
- print("\033[1mPlugin Commands:\033[0m")
170
- print(" \033[94mCommand\033[0m - \033[93mDescription\033[0m")
248
+ print(f"\033[1m{get_message('plugin_commands_title')}\033[0m")
249
+ print(
250
+ f" \033[94m{get_message('plugin_command_header')}\033[0m - \033[93m{get_message('plugin_description_header')}\033[0m"
251
+ )
171
252
  for cmd, (_, desc, plugin_id) in plugin_manager.command_handlers.items():
172
253
  plugin = plugin_manager.get_plugin(plugin_id)
173
254
  if plugin:
174
255
  print(
175
- f" \033[94m{cmd}\033[0m - \033[92m{desc} (from {plugin.plugin_name()})\033[0m"
256
+ f" \033[94m{cmd}\033[0m - \033[92m{desc} ({get_message('plugin_from')} {plugin.plugin_name()})\033[0m"
176
257
  )
177
258
  else:
178
259
  print(
179
- f" \033[94m{cmd}\033[0m - \033[92m{desc} (from unknown plugin)\033[0m"
260
+ f" \033[94m{cmd}\033[0m - \033[92m{desc} ({get_message('plugin_from_unknown')})\033[0m"
180
261
  )
181
262
  print()
182
263
 
@@ -187,6 +268,41 @@ class EnhancedCompleter(Completer):
187
268
  def __init__(self, base_completer: Completer, plugin_manager: PluginManager):
188
269
  self.base_completer: Completer = base_completer
189
270
  self.plugin_manager: PluginManager = plugin_manager
271
+ self._custom_commands_cache = set()
272
+ self._cache_valid = False
273
+
274
+ def _get_custom_commands(self):
275
+ """获取自定义命令列表(从 .autocodercommands 目录)"""
276
+ if self._cache_valid and self._custom_commands_cache:
277
+ return sorted(list(self._custom_commands_cache))
278
+
279
+ try:
280
+ from autocoder.common.command_file_manager.manager import CommandManager
281
+
282
+ # 创建命令管理器
283
+ command_manager = CommandManager()
284
+
285
+ # 列出所有命令文件
286
+ result = command_manager.list_command_files(recursive=True)
287
+
288
+ if result.success:
289
+ commands = set()
290
+ for file_name in result.command_files:
291
+ # 去掉 .md 后缀和路径前缀,只保留命令名
292
+ command_name = os.path.basename(file_name)
293
+ if command_name.endswith('.md'):
294
+ command_name = command_name[:-3]
295
+ # 添加 / 前缀形成完整命令
296
+ commands.add(f"/{command_name}")
297
+
298
+ self._custom_commands_cache = commands
299
+ self._cache_valid = True
300
+ return sorted(list(commands))
301
+ except Exception:
302
+ # 静默处理异常,返回空列表
303
+ pass
304
+
305
+ return []
190
306
 
191
307
  def get_completions(self, document, complete_event):
192
308
  # 获取当前输入的文本
@@ -231,12 +347,25 @@ class EnhancedCompleter(Completer):
231
347
  )
232
348
  return
233
349
  # 处理直接命令补全 - 如果输入不包含空格,匹配整个命令
234
- for command in self.plugin_manager.get_all_commands_with_prefix(current_input):
350
+ # 1. 插件和内置命令
351
+ for command in self.plugin_manager.get_all_commands_with_prefix(
352
+ current_input
353
+ ):
235
354
  yield Completion(
236
355
  command[len(current_input) :],
237
356
  start_position=0,
238
357
  display=command,
239
358
  )
359
+
360
+ # 2. 自定义命令(从 .autocodercommands 目录)
361
+ custom_commands = self._get_custom_commands()
362
+ for command in custom_commands:
363
+ if command.startswith(current_input):
364
+ yield Completion(
365
+ command[len(current_input) :],
366
+ start_position=0,
367
+ display=command,
368
+ )
240
369
 
241
370
  # 获取并返回基础补全器的补全
242
371
  if self.base_completer:
@@ -269,11 +398,132 @@ class EnhancedCompleter(Completer):
269
398
  async def get_completions_async(self, document, complete_event):
270
399
  """异步获取补全内容。
271
400
 
272
- 这个方法在最新版本的prompt_toolkit中是必需的,
273
- 它简单地调用同步版本并以异步方式yield结果。
401
+ 使用 asyncio.run_in_executor 来异步执行耗时的补全操作,
402
+ 避免阻塞主线程导致输入卡顿。
274
403
  """
275
- for completion in self.get_completions(document, complete_event):
276
- yield completion
404
+ import asyncio
405
+ from concurrent.futures import ThreadPoolExecutor
406
+
407
+ # 获取当前输入的文本
408
+ text_before_cursor = document.text_before_cursor.lstrip()
409
+
410
+ # 只有当我们需要处理命令补全时才进行处理
411
+ if text_before_cursor.startswith("/"):
412
+ # 获取当前输入的命令前缀
413
+ current_input = text_before_cursor
414
+
415
+ # 使用线程池执行器来异步执行耗时操作
416
+ loop = asyncio.get_event_loop()
417
+ executor = ThreadPoolExecutor(max_workers=1)
418
+
419
+ try:
420
+ # 检查是否需要动态补全
421
+ if " " in current_input:
422
+ # 将连续的空格替换为单个空格
423
+ _input_one_space = " ".join(current_input.split())
424
+
425
+ # 异步获取动态命令列表
426
+ dynamic_cmds = await loop.run_in_executor(
427
+ executor, self.plugin_manager.get_dynamic_cmds
428
+ )
429
+
430
+ for dynamic_cmd in dynamic_cmds:
431
+ if _input_one_space.startswith(dynamic_cmd):
432
+ # 异步处理动态补全
433
+ completions = await loop.run_in_executor(
434
+ executor,
435
+ self.plugin_manager.process_dynamic_completions,
436
+ dynamic_cmd,
437
+ current_input,
438
+ )
439
+ for completion_text, display_text in completions:
440
+ yield Completion(
441
+ completion_text,
442
+ start_position=0,
443
+ display=display_text,
444
+ )
445
+ return
446
+
447
+ # 如果不是特定命令,检查一般命令 + 空格的情况
448
+ cmd_parts = current_input.split(maxsplit=1)
449
+ base_cmd = cmd_parts[0]
450
+
451
+ # 异步获取插件命令补全
452
+ plugin_completions_dict = await loop.run_in_executor(
453
+ executor, self.plugin_manager.get_plugin_completions
454
+ )
455
+
456
+ # 如果命令存在于补全字典中,进行处理
457
+ if base_cmd in plugin_completions_dict:
458
+ # 异步处理命令补全
459
+ completions_list = await loop.run_in_executor(
460
+ executor,
461
+ self._get_command_completions_list,
462
+ base_cmd,
463
+ current_input,
464
+ plugin_completions_dict[base_cmd],
465
+ )
466
+ for completion in completions_list:
467
+ yield completion
468
+ return
469
+ else:
470
+ # 处理直接命令补全 - 异步获取所有匹配的命令
471
+ # 1. 插件和内置命令
472
+ commands = await loop.run_in_executor(
473
+ executor,
474
+ self.plugin_manager.get_all_commands_with_prefix,
475
+ current_input,
476
+ )
477
+ for command in commands:
478
+ yield Completion(
479
+ command[len(current_input) :],
480
+ start_position=0,
481
+ display=command,
482
+ )
483
+
484
+ # 2. 自定义命令(从 .autocodercommands 目录)
485
+ custom_commands = await loop.run_in_executor(
486
+ executor,
487
+ self._get_custom_commands,
488
+ )
489
+ for command in custom_commands:
490
+ if command.startswith(current_input):
491
+ yield Completion(
492
+ command[len(current_input) :],
493
+ start_position=0,
494
+ display=command,
495
+ )
496
+ finally:
497
+ executor.shutdown(wait=False)
498
+
499
+ # 异步获取基础补全器的补全
500
+ if self.base_completer:
501
+ # 如果基础补全器支持异步方法,优先使用
502
+ if hasattr(self.base_completer, "get_completions_async"):
503
+ async for completion in self.base_completer.get_completions_async(
504
+ document, complete_event
505
+ ):
506
+ yield completion
507
+ else:
508
+ # 否则在线程池中运行同步方法
509
+ loop = asyncio.get_event_loop()
510
+ executor = ThreadPoolExecutor(max_workers=1)
511
+ try:
512
+ completions = await loop.run_in_executor(
513
+ executor,
514
+ list,
515
+ self.base_completer.get_completions(document, complete_event),
516
+ )
517
+ for completion in completions:
518
+ yield completion
519
+ finally:
520
+ executor.shutdown(wait=False)
521
+
522
+ def _get_command_completions_list(self, command, current_input, completions):
523
+ """获取命令补全列表(用于异步执行)"""
524
+ return list(
525
+ self._process_command_completions(command, current_input, completions)
526
+ )
277
527
 
278
528
 
279
529
  ARGS = None
@@ -284,92 +534,526 @@ def load_builtin_plugins():
284
534
  try:
285
535
  # 发现所有可用的插件
286
536
  discovered_plugins = plugin_manager.discover_plugins()
287
-
537
+
288
538
  # 排除的示例插件列表
289
539
  excluded_plugins = {
290
540
  "autocoder.plugins.dynamic_completion_example",
291
- "autocoder.plugins.sample_plugin"
541
+ "autocoder.plugins.sample_plugin",
292
542
  }
293
-
543
+
294
544
  # 自动加载内置插件(在autocoder.plugins模块中的插件)
295
545
  builtin_loaded = 0
296
546
  for plugin_class in discovered_plugins:
297
547
  module_name = plugin_class.__module__
298
- if (module_name.startswith("autocoder.plugins.")
548
+ if (
549
+ module_name.startswith("autocoder.plugins.")
299
550
  and not module_name.endswith(".__init__")
300
- and module_name not in excluded_plugins):
551
+ and module_name not in excluded_plugins
552
+ ):
301
553
  try:
302
554
  if plugin_manager.load_plugin(plugin_class):
303
555
  builtin_loaded += 1
304
556
  print(f"✓ Loaded builtin plugin: {plugin_class.plugin_name()}")
305
557
  except Exception as e:
306
- print(f"✗ Failed to load builtin plugin {plugin_class.plugin_name()}: {e}")
307
-
558
+ print(
559
+ f"✗ Failed to load builtin plugin {plugin_class.plugin_name()}: {e}"
560
+ )
561
+
308
562
  if builtin_loaded > 0:
309
- print(f"Loaded {builtin_loaded} builtin plugin(s)")
563
+ print(
564
+ get_message_with_format_local(
565
+ "loaded_plugins_builtin", count=builtin_loaded
566
+ )
567
+ )
310
568
  else:
311
- print("No builtin plugins loaded")
312
-
569
+ print(get_message("no_builtin_plugins_loaded"))
570
+
313
571
  except Exception as e:
314
572
  print(f"Error loading builtin plugins: {e}")
315
573
 
316
574
 
317
- def main():
318
- load_tokenizer()
319
- ARGS = parse_arguments()
575
+ # 后台任务:监控全局状态或执行其他后台逻辑
576
+ async def background_task(stop_event: asyncio.Event, session=None):
577
+ """后台任务:可以用于监控系统状态、清理任务等"""
578
+ counter = 0
579
+ toolbar_refresh_counter = 0
580
+ last_async_task_count = 0
320
581
 
321
- if ARGS.lite:
322
- ARGS.product_mode = "lite"
582
+ # 配置刷新频率(秒)
583
+ TOOLBAR_REFRESH_INTERVAL = 5 # 默认5秒刷新一次
584
+ FAST_REFRESH_INTERVAL = 1 # 有异步任务时1秒刷新一次
323
585
 
324
- if ARGS.pro:
325
- ARGS.product_mode = "pro"
586
+ while not stop_event.is_set():
587
+ try:
588
+ # 检查是否有需要处理的后台任务
589
+ # 这里可以添加系统监控逻辑
590
+ counter += 1
591
+ toolbar_refresh_counter += 1
326
592
 
327
- if not ARGS.quick:
328
- initialize_system(
329
- InitializeSystemRequest(
330
- product_mode=ARGS.product_mode,
331
- skip_provider_selection=ARGS.skip_provider_selection,
332
- debug=ARGS.debug,
333
- quick=ARGS.quick,
334
- lite=ARGS.lite,
335
- pro=ARGS.pro,
336
- )
593
+ # 检查当前异步任务状态,决定刷新频率
594
+ current_async_task_count = 0
595
+ try:
596
+ from pathlib import Path
597
+ from autocoder.sdk.async_runner.task_metadata import TaskMetadataManager
598
+
599
+ async_agent_dir = Path.home() / ".auto-coder" / "async_agent"
600
+ meta_dir = async_agent_dir / "meta"
601
+
602
+ if meta_dir.exists():
603
+ metadata_manager = TaskMetadataManager(str(meta_dir))
604
+ summary = metadata_manager.get_task_summary()
605
+ current_async_task_count = summary.get("running", 0)
606
+ except Exception:
607
+ # 静默处理异常
608
+ pass
609
+
610
+ # 智能刷新:有异步任务时更频繁刷新,无任务时降低刷新频率
611
+ should_refresh = False
612
+ if current_async_task_count > 0:
613
+ # 有异步任务时,每秒刷新
614
+ should_refresh = toolbar_refresh_counter >= FAST_REFRESH_INTERVAL
615
+ else:
616
+ # 无异步任务时,每5秒刷新
617
+ should_refresh = toolbar_refresh_counter >= TOOLBAR_REFRESH_INTERVAL
618
+
619
+ # 任务数量变化时立即刷新
620
+ if current_async_task_count != last_async_task_count:
621
+ should_refresh = True
622
+ last_async_task_count = current_async_task_count
623
+
624
+ # 执行工具栏刷新
625
+ if should_refresh and session and hasattr(session, "app"):
626
+ try:
627
+ session.app.invalidate()
628
+ toolbar_refresh_counter = 0
629
+ except Exception:
630
+ # 静默处理刷新异常,不影响后台任务运行
631
+ pass
632
+
633
+ # 每60秒执行一次清理
634
+ if counter % 60 == 0:
635
+ # 执行一些后台清理任务
636
+ pass
637
+
638
+ await asyncio.sleep(1)
639
+ except asyncio.CancelledError:
640
+ break
641
+ except Exception as e:
642
+ # 后台任务出错时,不要让整个应用崩溃
643
+ if ARGS and ARGS.debug:
644
+ print(f"Background task error: {e}")
645
+ await asyncio.sleep(5) # 出错后等待5秒再继续
646
+
647
+
648
+ async def process_user_input(user_input: str, new_prompt_callback, session=None):
649
+ """处理用户输入的异步函数"""
650
+ try:
651
+ # 首先解析粘贴占位符
652
+ user_input = resolve_paste_placeholders(user_input)
653
+
654
+ # 处理 user_input 的空格
655
+ if user_input:
656
+ temp_user_input = user_input.lstrip() # 去掉左侧空格
657
+ if temp_user_input.startswith("/"):
658
+ user_input = temp_user_input
659
+
660
+ # 获取当前shell类型
661
+ import platform
662
+
663
+ shell = "/bin/bash" if platform.system() != "Windows" else "cmd.exe"
664
+
665
+ # 1. 如果用户输入 /shell,启动一个子 shell
666
+ if user_input == "/shell":
667
+ if session and hasattr(session, "app"):
668
+ try:
669
+ # 正确地等待异步方法
670
+ await session.app.run_system_command(shell, wait_for_enter=False)
671
+ except Exception:
672
+ # 如果异步调用失败,回退到同步方式
673
+ import subprocess
674
+
675
+ subprocess.call([shell])
676
+ else:
677
+ import subprocess
678
+
679
+ subprocess.call([shell])
680
+ return
681
+
682
+ # 2. 如果以 ! 开头,当作单行 shell 命令执行
683
+ if user_input.startswith("!"):
684
+ command = user_input[1:] # 去掉 ! 前缀
685
+ if session and hasattr(session, "app"):
686
+ try:
687
+ # 正确地等待异步方法
688
+ await session.app.run_system_command(command, wait_for_enter=False)
689
+ except Exception:
690
+ # 如果异步调用失败,回退到同步方式
691
+ import subprocess
692
+
693
+ subprocess.call([shell, "-c", command])
694
+ else:
695
+ import subprocess
696
+
697
+ subprocess.call([shell, "-c", command])
698
+ return
699
+
700
+ # 修复插件命令处理逻辑
701
+ plugin_handled = False
702
+ if user_input.startswith("/"):
703
+ plugin_result = plugin_manager.process_command(user_input)
704
+ if plugin_result:
705
+ plugin_name, handler, args = plugin_result
706
+ if handler:
707
+ handler(*args)
708
+ plugin_handled = True
709
+
710
+ # 如果插件已处理命令,直接返回
711
+ if plugin_handled:
712
+ return
713
+
714
+ # 如果插件未处理,继续处理内置命令
715
+ memory_manager = get_memory_manager()
716
+
717
+ # Shell 模式处理 - 优先级最高
718
+ if (
719
+ memory_manager.is_shell_mode()
720
+ and user_input
721
+ and not user_input.startswith("/")
722
+ ):
723
+ if session and hasattr(session, "app"):
724
+ try:
725
+ # 正确地等待异步方法
726
+ await session.app.run_system_command(
727
+ user_input, wait_for_enter=False
728
+ )
729
+ except Exception:
730
+ # 如果异步调用失败,回退到同步方式
731
+ import subprocess
732
+
733
+ subprocess.call([shell, "-c", user_input])
734
+ else:
735
+ output = execute_shell_command(user_input)
736
+ if output:
737
+ print(output)
738
+ return
739
+
740
+ if (
741
+ memory_manager.is_auto_detect_mode()
742
+ and user_input
743
+ and not user_input.startswith("/")
744
+ ):
745
+ event_file, file_id = gengerate_event_file_path()
746
+ configure(f"event_file:{event_file}")
747
+ global_cancel.register_token(event_file)
748
+ run_agentic(user_input, cancel_token=event_file)
749
+
750
+ elif memory_manager.is_voice_input_mode() and not user_input.startswith("/"):
751
+ text = voice_input()
752
+ if text: # Check if text is not None
753
+ new_prompt_callback("/coding " + text)
754
+
755
+ elif user_input.startswith("/voice_input"):
756
+ text = voice_input()
757
+ if text: # Check if text is not None
758
+ new_prompt_callback("/coding " + text)
759
+
760
+ elif user_input.startswith("/clear") or user_input.startswith("/cls"):
761
+ print("\033c")
762
+
763
+ elif user_input.startswith("/add_files"):
764
+ args = user_input[len("/add_files") :].strip().split()
765
+ add_files(args)
766
+ elif user_input.startswith("/remove_files"):
767
+ file_names = user_input[len("/remove_files") :].strip().split(",")
768
+ remove_files(file_names)
769
+ elif user_input.startswith("/index/query"):
770
+ query = user_input[len("/index/query") :].strip()
771
+ index_query(query)
772
+
773
+ elif user_input.startswith("/index/build"):
774
+ event_file, file_id = gengerate_event_file_path()
775
+ configure(f"event_file:{event_file}")
776
+ global_cancel.register_token(event_file)
777
+ index_build()
778
+
779
+ elif user_input.startswith("/index/export"):
780
+ export_path = user_input[len("/index/export") :].strip()
781
+ index_export(export_path)
782
+
783
+ elif user_input.startswith("/index/import"):
784
+ import_path = user_input[len("/index/import") :].strip()
785
+ index_import(import_path)
786
+
787
+ elif user_input.startswith("/list_files"):
788
+ list_files()
789
+
790
+ elif user_input.startswith("/models"):
791
+ query = user_input[len("/models") :].strip()
792
+ handle_models_command(query)
793
+
794
+ elif user_input.startswith("/mode"):
795
+ conf = user_input[len("/mode") :].strip()
796
+ if not conf:
797
+ print(get_mode())
798
+ else:
799
+ set_mode(conf)
800
+
801
+ elif user_input.startswith("/conf/export"):
802
+ from autocoder.common.conf_import_export import export_conf
803
+
804
+ export_conf(os.getcwd(), user_input[len("/conf/export") :].strip() or ".")
805
+
806
+ elif user_input.startswith("/plugins"):
807
+ # 提取命令参数并交由 plugin_manager 处理
808
+ args = user_input[len("/plugins") :].strip().split()
809
+ result = plugin_manager.handle_plugins_command(args)
810
+ print(result, end="")
811
+
812
+ # Handle /conf and its subcommands like /conf /export, /conf /import
813
+ elif user_input.startswith("/conf"):
814
+ # Extract everything after "/conf"
815
+ command_args = user_input[len("/conf") :].strip()
816
+ # Call the handler from conf_command.py and print its string result
817
+ result_message = handle_conf_command(command_args)
818
+ print(result_message)
819
+ elif user_input.startswith("/revert"):
820
+ revert()
821
+ elif user_input.startswith("/commit"):
822
+ query = user_input[len("/commit") :].strip()
823
+ commit(query)
824
+ elif user_input.startswith("/help"):
825
+ query = user_input[len("/help") :].strip()
826
+ if not query:
827
+ show_help()
828
+ else:
829
+ from autocoder.auto_coder_runner import help
830
+
831
+ help(query)
832
+
833
+ elif user_input.startswith("/exclude_dirs"):
834
+ dir_names = user_input[len("/exclude_dirs") :].strip().split(",")
835
+ exclude_dirs(dir_names)
836
+
837
+ elif user_input.startswith("/exclude_files"):
838
+ query = user_input[len("/exclude_files") :].strip()
839
+ exclude_files(query)
840
+
841
+ elif user_input.startswith("/exit"):
842
+ # 退出应用
843
+ raise EOFError()
844
+
845
+ elif user_input.startswith("/coding"):
846
+ event_file, file_id = gengerate_event_file_path()
847
+ configure(f"event_file:{event_file}")
848
+ global_cancel.register_token(event_file)
849
+ query = user_input[len("/coding") :].strip()
850
+ if not query:
851
+ print(f"\033[91m{get_message('please_enter_request')}\033[0m")
852
+ return
853
+ coding(query, cancel_token=event_file)
854
+ elif user_input.startswith("/chat"):
855
+ event_file, file_id = gengerate_event_file_path()
856
+ configure(f"event_file:{event_file}")
857
+ global_cancel.register_token(event_file)
858
+ query = user_input[len("/chat") :].strip()
859
+ if not query:
860
+ print(f"\033[91m{get_message('please_enter_request')}\033[0m")
861
+ else:
862
+ chat(query)
863
+
864
+ elif user_input.startswith("/design"):
865
+ query = user_input[len("/design") :].strip()
866
+ if not query:
867
+ print(f"\033[91m{get_message('please_enter_design_request')}\033[0m")
868
+ else:
869
+ design(query)
870
+
871
+ elif user_input.startswith("/summon"):
872
+ query = user_input[len("/summon") :].strip()
873
+ if not query:
874
+ print(f"\033[91m{get_message('please_enter_request')}\033[0m")
875
+ else:
876
+ summon(query)
877
+
878
+ elif user_input.startswith("/lib"):
879
+ args = user_input[len("/lib") :].strip().split()
880
+ lib_command(args)
881
+
882
+ elif user_input.startswith("/rules"):
883
+ query = user_input[len("/rules") :].strip()
884
+ rules(query)
885
+
886
+ elif user_input.startswith("/mcp"):
887
+ query = user_input[len("/mcp") :].strip()
888
+ if not query:
889
+ print(get_message("please_enter_query"))
890
+ else:
891
+ mcp(query)
892
+
893
+ elif user_input.startswith("/active_context"):
894
+ query = user_input[len("/active_context") :].strip()
895
+ active_context(query)
896
+
897
+ elif user_input.startswith("/auto"):
898
+ query = user_input[len("/auto") :].strip()
899
+ event_file, _ = gengerate_event_file_path()
900
+ global_cancel.register_token(event_file)
901
+ configure(f"event_file:{event_file}")
902
+ run_agentic(query, cancel_token=event_file)
903
+ elif user_input.startswith("/debug"):
904
+ code = user_input[len("/debug") :].strip()
905
+ try:
906
+ result = eval(code)
907
+ print(f"Debug result: {result}")
908
+ except Exception as e:
909
+ print(f"Debug error: {str(e)}")
910
+
911
+ elif user_input.startswith("/shell"):
912
+ command = user_input[len("/shell") :].strip()
913
+ if not command:
914
+ # 如果没有命令参数,切换到 shell 模式
915
+ memory_manager.set_mode("shell")
916
+ print(get_message("switched_to_shell_mode"))
917
+ else:
918
+ if command.startswith("/chat"):
919
+ event_file, file_id = gengerate_event_file_path()
920
+ global_cancel.register_token(event_file)
921
+ configure(f"event_file:{event_file}")
922
+ command = command[len("/chat") :].strip()
923
+ gen_and_exec_shell_command(command)
924
+ else:
925
+ execute_shell_command(command)
926
+ else:
927
+ # 对于未识别的命令,显示提示信息而不是执行auto_command
928
+ if user_input and user_input.strip():
929
+ if user_input.startswith("/"):
930
+ command = user_input.split(" ")[0][1:]
931
+ query = user_input[len(command) + 1:].strip()
932
+ user_input = f"/command {command}.md {query}"
933
+
934
+ # 只有非命令输入才执行auto_command
935
+ event_file, _ = gengerate_event_file_path()
936
+ global_cancel.register_token(event_file)
937
+ configure(f"event_file:{event_file}")
938
+ run_agentic(user_input, cancel_token=event_file)
939
+
940
+ except EOFError:
941
+ # 重新抛出这些异常,让主循环处理
942
+ raise
943
+ except (CancelRequestedException, KeyboardInterrupt):
944
+ pass
945
+ except Exception as e:
946
+ print(
947
+ f"\033[91m 1. An error occurred:\033[0m \033[93m{type(e).__name__}\033[0m - {str(e)}"
337
948
  )
338
-
339
- start_engine()
949
+ if ARGS and ARGS.debug:
950
+ import traceback
340
951
 
341
- # Initialize plugin system
342
- # Add default plugin directory into global plugin dirs
343
- plugin_manager.load_global_plugin_dirs()
344
- plugin_manager.add_global_plugin_directory(os.path.join(os.path.dirname(__file__), "plugins"))
952
+ traceback.print_exc()
345
953
 
346
- # 加载保存的运行时配置
347
- plugin_manager.load_runtime_cfg()
348
-
349
- # 自动加载内置插件(如果还没有被配置文件加载)
350
- load_builtin_plugins()
351
954
 
352
- memory = get_memory()
955
+ async def run_app():
956
+ """运行聊天应用"""
957
+ global ask, coding, chat, design, voice_input, auto_command, run_agentic, active_context, execute_shell_command
353
958
 
354
- configure(f"product_mode:{ARGS.product_mode}")
959
+ # 创建输入队列和忙碌状态
960
+ input_queue = asyncio.Queue()
961
+ busy_event = asyncio.Event()
962
+ busy_event.set() # 初始状态为空闲
355
963
 
356
- MODES = {
357
- "normal": "normal",
358
- "auto_detect": "nature language auto detect",
359
- "voice_input": "voice input",
360
- }
964
+ task_event = TaskEvent()
965
+ task_completion_callbacks = []
361
966
 
967
+ # 触发所有任务完成回调
968
+ async def trigger_task_completion_callbacks():
969
+ """触发所有注册的任务完成回调"""
970
+ for callback in task_completion_callbacks:
971
+ try:
972
+ if asyncio.iscoroutinefunction(callback):
973
+ await callback()
974
+ else:
975
+ callback()
976
+ except Exception as e:
977
+ print(
978
+ f"\033[91mError in task completion callback:\033[0m {type(e).__name__} - {str(e)}"
979
+ )
980
+ if ARGS and ARGS.debug:
981
+ import traceback
982
+
983
+ traceback.print_exc()
984
+ task_completion_callbacks.clear()
985
+
986
+ # 创建后台消费者协程
987
+ async def consumer_loop():
988
+ """后台处理用户输入的消费者协程"""
989
+ nonlocal session
990
+ while True:
991
+ is_queue_geted = False
992
+ try:
993
+ # 给队列获取操作添加超时,让消费者有机会响应取消请求
994
+ try:
995
+ user_input, new_prompt_callback, session = await asyncio.wait_for(
996
+ input_queue.get(), timeout=1.0
997
+ )
998
+ is_queue_geted = True
999
+ except asyncio.TimeoutError:
1000
+ # 超时后短暂休眠,然后继续循环等待
1001
+ await asyncio.sleep(0.1)
1002
+ continue
1003
+
1004
+ # 设置任务状态为已开始
1005
+ task_event.set_state("started")
1006
+ busy_event.clear() # 标记为忙碌
1007
+
1008
+ # 设置任务状态为运行中
1009
+ task_event.set_state("running")
1010
+
1011
+ # 直接调用异步的 process_user_input 函数
1012
+ await process_user_input(user_input, new_prompt_callback, session)
1013
+
1014
+ await trigger_task_completion_callbacks()
1015
+
1016
+ # 设置任务状态为已完成
1017
+ task_event.set_state("completed")
1018
+
1019
+ except KeyboardInterrupt:
1020
+ global_cancel.set_active_tokens()
1021
+ task_event.set_state("completed")
1022
+ continue
1023
+ except asyncio.CancelledError:
1024
+ break
1025
+ except Exception as e:
1026
+ if ARGS and ARGS.debug:
1027
+ import traceback
1028
+
1029
+ traceback.print_exc()
1030
+ continue
1031
+ finally:
1032
+ busy_event.set() # 标记为空闲
1033
+ if is_queue_geted:
1034
+ input_queue.task_done()
1035
+ # 确保任务状态最终被重置
1036
+ if task_event.get_state() != "completed":
1037
+ task_event.set_state("completed")
1038
+
1039
+ # 启动消费者协程
1040
+ consumer_task = asyncio.create_task(consumer_loop())
1041
+
1042
+ # 创建键盘绑定
362
1043
  kb = KeyBindings()
363
1044
 
1045
+ # 捕获 Ctrl+C 和 Ctrl+D
364
1046
  @kb.add("c-c")
365
1047
  def _(event):
366
- # 如果在历史搜索模式中
367
1048
  if event.app.layout.is_searching:
368
1049
  event.app.current_buffer.history_search_text = None
369
- # 清除当前缓冲区
370
1050
  event.app.current_buffer.reset()
371
- else:
372
- event.app.exit()
1051
+ # else:
1052
+ # event.app.exit(exception=KeyboardInterrupt)
1053
+
1054
+ @kb.add("c-d")
1055
+ def _(event):
1056
+ event.app.exit(exception=EOFError)
373
1057
 
374
1058
  @kb.add("tab")
375
1059
  def _(event):
@@ -387,38 +1071,31 @@ def main():
387
1071
 
388
1072
  @kb.add("c-k")
389
1073
  def _(event):
390
- if "mode" not in memory:
391
- memory["mode"] = "auto_detect"
392
-
393
- current_mode = memory["mode"]
394
- if current_mode == "normal":
395
- memory["mode"] = "auto_detect"
396
- elif current_mode == "auto_detect":
397
- memory["mode"] = "voice_input"
398
- else: # voice_input
399
- memory["mode"] = "normal"
400
-
401
- save_memory()
1074
+ cycle_mode()
402
1075
  event.app.invalidate()
403
1076
 
404
1077
  @kb.add("c-n")
405
1078
  def _(event):
406
- if "human_as_model" not in memory["conf"]:
407
- memory["conf"]["human_as_model"] = "false"
408
-
409
- current_status = memory["conf"]["human_as_model"]
410
- new_status = "true" if current_status == "false" else "false"
1079
+ new_status_bool = toggle_human_as_model()
1080
+ new_status = "true" if new_status_bool else "false"
411
1081
  configure(f"human_as_model:{new_status}", skip_print=True)
412
1082
  event.app.invalidate()
413
1083
 
1084
+ # 注册粘贴处理器
1085
+ register_paste_handler(kb)
1086
+
414
1087
  # 应用插件的键盘绑定
415
1088
  plugin_manager.apply_keybindings(kb)
416
1089
 
417
1090
  def get_bottom_toolbar():
418
- if "mode" not in memory:
419
- memory["mode"] = "auto_detect"
420
- mode = memory["mode"]
421
- human_as_model = memory["conf"].get("human_as_model", "false")
1091
+ mode = get_mode()
1092
+ human_as_model = get_human_as_model_string()
1093
+ MODES = {
1094
+ "normal": "normal",
1095
+ "auto_detect": "nature language auto detect",
1096
+ "voice_input": "voice input",
1097
+ "shell": "shell",
1098
+ }
422
1099
  if mode not in MODES:
423
1100
  mode = "auto_detect"
424
1101
  pwd = os.getcwd()
@@ -426,340 +1103,253 @@ def main():
426
1103
  if len(pwd_parts) > 3:
427
1104
  pwd = os.sep.join(pwd_parts[-3:])
428
1105
 
429
- # Add plugin information to toolbar
430
1106
  plugin_info = (
431
1107
  f"Plugins: {len(plugin_manager.plugins)}" if plugin_manager.plugins else ""
432
1108
  )
433
- return f"Current Dir: {pwd} \nMode: {MODES[mode]}(ctrl+k) | Human as Model: {human_as_model}(ctrl+n) | {plugin_info}"
434
1109
 
435
- # 创建一个继承Completer的增强补全器
1110
+ # 获取正在运行的 async 任务数量
1111
+ async_tasks_info = ""
1112
+ try:
1113
+ from pathlib import Path
1114
+ from autocoder.sdk.async_runner.task_metadata import TaskMetadataManager
1115
+
1116
+ async_agent_dir = Path.home() / ".auto-coder" / "async_agent"
1117
+ meta_dir = os.path.join(async_agent_dir, "meta")
1118
+
1119
+ if os.path.exists(meta_dir):
1120
+ metadata_manager = TaskMetadataManager(meta_dir)
1121
+ summary = metadata_manager.get_task_summary()
1122
+ running_count = summary.get("running", 0)
1123
+
1124
+ if running_count > 0:
1125
+ async_tasks_info = f" | Async Tasks: 🔄 {running_count}"
1126
+ except Exception:
1127
+ # 静默处理异常,不影响底部工具栏的显示
1128
+ pass
1129
+
1130
+ return f"Current Dir: {pwd} \nMode: {MODES[mode]}(ctrl+k) | Human as Model: {human_as_model}(ctrl+n) | {plugin_info}{async_tasks_info}"
1131
+
1132
+ # 创建增强补全器
436
1133
  enhanced_completer = EnhancedCompleter(completer, plugin_manager)
437
1134
 
438
- # Define the path for the history file
439
- history_file_path = os.path.join(os.getcwd(), ".auto-coder", "auto-coder.chat", "history", "command_history.txt")
440
- # Ensure the directory exists
1135
+ # 定义历史文件路径
1136
+ history_file_path = os.path.join(
1137
+ os.getcwd(), ".auto-coder", "auto-coder.chat", "history", "command_history.txt"
1138
+ )
441
1139
  os.makedirs(os.path.dirname(history_file_path), exist_ok=True)
442
1140
 
1141
+ # 创建会话
443
1142
  session = PromptSession(
444
- history=FileHistory(history_file_path), # Use FileHistory
1143
+ history=FileHistory(history_file_path),
445
1144
  auto_suggest=AutoSuggestFromHistory(),
446
1145
  enable_history_search=False,
447
1146
  completer=enhanced_completer,
448
- complete_while_typing=True,
1147
+ complete_while_typing=False,
449
1148
  key_bindings=kb,
450
1149
  bottom_toolbar=get_bottom_toolbar,
1150
+ # 注意:bracketed paste 通过 Keys.BracketedPaste 键绑定处理
451
1151
  )
452
- print(
453
- f"""
454
- \033[1;32m ____ _ _ _ _ ____ _
455
- / ___| |__ __ _| |_ / \ _ _| |_ ___ / ___|___ __| | ___ _ __
456
- | | | '_ \ / _` | __|____ / _ \| | | | __/ _ \ _____| | / _ \ / _` |/ _ \ '__|
457
- | |___| | | | (_| | ||_____/ ___ \ |_| | || (_) |_____| |__| (_) | (_| | __/ |
458
- \____|_| |_|\__,_|\__| /_/ \_\__,_|\__\___/ \____\___/ \__,_|\___|_|
459
- v{__version__}
460
- \033[0m"""
461
- )
462
- print("\033[1;34mType /help to see available commands.\033[0m\n")
463
-
464
- # Add plugin information to startup message
465
- if plugin_manager.plugins:
466
- print("\033[1;34mLoaded Plugins:\033[0m")
467
- for name, plugin in plugin_manager.plugins.items():
468
- print(f" - {name} (v{plugin.version}): {plugin.description}")
469
- print()
470
-
471
- show_help()
472
-
473
- style = Style.from_dict(
474
- {
475
- "username": "#884444",
476
- "at": "#00aa00",
477
- "colon": "#0000aa",
478
- "pound": "#00aa00",
479
- "host": "#00ffff bg:#444400",
480
- }
481
- )
482
-
483
- new_prompt = ""
484
1152
 
485
- # Create wrapped versions of functions that plugins want to intercept
1153
+ # 创建 wrapped functions
486
1154
  wrapped_functions = {}
487
1155
  for func_name, original_func in original_functions.items():
488
1156
  wrapped_functions[func_name] = plugin_manager.wrap_function(
489
1157
  original_func, func_name
490
1158
  )
491
1159
 
492
- # Replace original functions with wrapped versions
493
- global ask, coding, chat, design, voice_input, auto_command, execute_shell_command, active_context
1160
+ # 替换原始函数
494
1161
  ask = wrapped_functions.get("ask", ask)
495
1162
  coding = wrapped_functions.get("coding", coding)
496
1163
  chat = wrapped_functions.get("chat", chat)
497
1164
  design = wrapped_functions.get("design", design)
498
1165
  voice_input = wrapped_functions.get("voice_input", voice_input)
499
1166
  auto_command = wrapped_functions.get("auto_command", auto_command)
1167
+ run_agentic = wrapped_functions.get("run_agentic", run_agentic)
500
1168
  active_context = wrapped_functions.get("active_context", active_context)
501
1169
  execute_shell_command = wrapped_functions.get(
502
1170
  "execute_shell_command", execute_shell_command
503
1171
  )
504
1172
 
1173
+ stop_ev = asyncio.Event()
1174
+ new_prompt = ""
1175
+
1176
+ # 用于设置新提示的回调函数
1177
+ def set_new_prompt(prompt):
1178
+ nonlocal new_prompt
1179
+ new_prompt = prompt
1180
+
1181
+ # 样式定义
1182
+ style = Style.from_dict(
1183
+ {
1184
+ "username": "#884444",
1185
+ "at": "#00aa00",
1186
+ "colon": "#0000aa",
1187
+ "pound": "#00aa00",
1188
+ "host": "#00ffff bg:#444400",
1189
+ "busy": "#ff6600 italic",
1190
+ }
1191
+ )
1192
+
1193
+ # 显示启动信息
1194
+ print(
1195
+ f"""
1196
+ \033[1;32m ____ _ _ _ _ ____ _
1197
+ / ___| |__ __ _| |_ / \\ _ _| |_ ___ / ___|___ __| | ___ _ __
1198
+ | | | '_ \\ / _` | __|____ / _ \\| | | | __/ _ \\ _____| | / _ \\ / _` |/ _ \\ '__|
1199
+ | |___| | | | (_| | ||_____/ ___ \\ |_| | || (_) |_____| |__| (_) | (_| | __/ |
1200
+ \\____|_| |_|\\__,_|\\__| /_/ \\_\\__,_|\\__\\___/ \\____\\___/ \\__,_|\\___|_|
1201
+ v{__version__}
1202
+ \033[0m"""
1203
+ )
1204
+ print(f"\033[1;34m{get_message('type_help_to_see_commands')}\033[0m\n")
1205
+
1206
+ # 显示插件信息
1207
+ if plugin_manager.plugins:
1208
+ print(f"\033[1;34m{get_message('loaded_plugins_title')}\033[0m")
1209
+ for name, plugin in plugin_manager.plugins.items():
1210
+ print(f" - {name} (v{plugin.version}): {plugin.description}")
1211
+ print()
1212
+
1213
+ show_help()
1214
+
1215
+ # 启动后台任务(传递 session 对象以便刷新工具栏)
1216
+ background_task_coro = asyncio.create_task(background_task(stop_ev, session))
1217
+
1218
+ # 主交互循环
505
1219
  while True:
1220
+ task_state = task_event.get_state()
506
1221
  try:
507
- prompt_message = [
508
- ("class:username", "coding"),
509
- ("class:at", "@"),
510
- ("class:host", "auto-coder.chat"),
511
- ("class:colon", ":"),
512
- ("class:path", "~"),
513
- ("class:dollar", "$ "),
514
- ]
1222
+ # 根据任务状态控制是否渲染prompt
1223
+ if task_state in ["started", "running", "pending"]:
1224
+ # 任务运行中,不显示prompt,跳过此次循环
1225
+ await asyncio.sleep(0.1)
1226
+ continue
1227
+ else:
1228
+ prompt_message = [
1229
+ ("class:username", "coding"),
1230
+ ("class:at", "@"),
1231
+ ("class:host", "auto-coder.chat"),
1232
+ ("class:colon", ":"),
1233
+ ("class:path", "~"),
1234
+ ("class:dollar", "$ "),
1235
+ ]
515
1236
 
516
1237
  if new_prompt:
517
- user_input = session.prompt(
1238
+ user_input = await session.prompt_async(
518
1239
  FormattedText(prompt_message), default=new_prompt, style=style
519
1240
  )
1241
+ new_prompt = ""
520
1242
  else:
521
- user_input = session.prompt(FormattedText(prompt_message), style=style)
522
- new_prompt = ""
523
-
524
- if "mode" not in memory:
525
- memory["mode"] = "auto_detect"
526
-
527
- # 处理 user_input 的空格
528
- if user_input:
529
- temp_user_input = user_input.lstrip() # 去掉左侧空格
530
- if temp_user_input.startswith("/"):
531
- user_input = temp_user_input
532
-
533
- # 修复插件命令处理逻辑
534
- plugin_handled = False
535
- if user_input.startswith("/"):
536
- plugin_result = plugin_manager.process_command(user_input)
537
- if plugin_result:
538
- plugin_name, handler, args = plugin_result
539
- if handler:
540
- handler(*args)
541
- plugin_handled = True
542
-
543
- # 如果插件已处理命令,直接继续下一轮循环
544
- if plugin_handled:
545
- continue
546
-
547
- # 如果插件未处理,继续处理内置命令
548
- if (
549
- memory["mode"] == "auto_detect"
550
- and user_input
551
- and not user_input.startswith("/")
552
- ):
553
- event_file, file_id = gengerate_event_file_path()
554
- configure(f"event_file:{event_file}")
555
- global_cancel.register_token(event_file)
556
- auto_command(user_input)
557
-
558
- elif memory["mode"] == "voice_input" and not user_input.startswith("/"):
559
- text = voice_input()
560
- if text: # Check if text is not None
561
- new_prompt = "/coding " + text
562
-
563
- elif user_input.startswith("/voice_input"):
564
- text = voice_input()
565
- if text: # Check if text is not None
566
- new_prompt = "/coding " + text
567
-
568
- elif user_input.startswith("/clear") or user_input.startswith("/cls"):
569
- print("\033c")
570
-
571
- elif user_input.startswith("/add_files"):
572
- args = user_input[len("/add_files") :].strip().split()
573
- add_files(args)
574
- elif user_input.startswith("/remove_files"):
575
- file_names = user_input[len("/remove_files") :].strip().split(",")
576
- remove_files(file_names)
577
- elif user_input.startswith("/index/query"):
578
- query = user_input[len("/index/query") :].strip()
579
- index_query(query)
580
-
581
- elif user_input.startswith("/index/build"):
582
- event_file, file_id = gengerate_event_file_path()
583
- configure(f"event_file:{event_file}")
584
- global_cancel.register_token(event_file)
585
- index_build()
1243
+ user_input = await session.prompt_async(
1244
+ FormattedText(prompt_message), style=style
1245
+ )
586
1246
 
587
- elif user_input.startswith("/index/export"):
588
- export_path = user_input[len("/index/export") :].strip()
589
- index_export(export_path)
1247
+ if user_input.strip() == "/exit":
1248
+ raise EOFError()
590
1249
 
591
- elif user_input.startswith("/index/import"):
592
- import_path = user_input[len("/index/import") :].strip()
593
- index_import(import_path)
1250
+ # 将输入放入队列,包含完成回调
1251
+ if user_input.strip():
1252
+ await input_queue.put((user_input, set_new_prompt, session))
1253
+ task_event.set_state("pending")
594
1254
 
595
- elif user_input.startswith("/list_files"):
596
- list_files()
1255
+ except (KeyboardInterrupt, asyncio.CancelledError):
1256
+ global_cancel.set_active_tokens()
1257
+ continue
1258
+ except CancelRequestedException:
1259
+ continue
1260
+ except EOFError:
1261
+ break
1262
+ except Exception as e:
1263
+ print(
1264
+ f"\033[91m 2. An error occurred:\033[0m \033[93m{type(e).__name__}\033[0m - {str(e)}"
1265
+ )
1266
+ if ARGS and ARGS.debug:
1267
+ import traceback
597
1268
 
598
- elif user_input.startswith("/models"):
599
- query = user_input[len("/models") :].strip()
600
- handle_models_command(query, get_memory())
1269
+ traceback.print_exc()
601
1270
 
602
- elif user_input.startswith("/mode"):
603
- conf = user_input[len("/mode") :].strip()
604
- if not conf:
605
- print(memory["mode"])
606
- else:
607
- memory["mode"] = conf
608
- save_memory()
609
-
610
- elif user_input.startswith("/conf/export"):
611
- from autocoder.common.conf_import_export import export_conf
612
- export_conf(os.getcwd(), user_input[len("/conf/export") :].strip() or ".")
613
-
614
- elif user_input.startswith("/plugins"):
615
- # 提取命令参数并交由 plugin_manager 处理
616
- args = user_input[len("/plugins") :].strip().split()
617
- result = plugin_manager.handle_plugins_command(args)
618
- print(result, end="")
619
-
620
- # Handle /conf and its subcommands like /conf /export, /conf /import
621
- elif user_input.startswith("/conf"):
622
- # Extract everything after "/conf"
623
- command_args = user_input[len("/conf"):].strip()
624
- # Call the handler from conf_command.py and print its string result
625
- result_message = handle_conf_command(command_args, memory)
626
- print(result_message)
627
- elif user_input.startswith("/revert"):
628
- revert()
629
- elif user_input.startswith("/commit"):
630
- query = user_input[len("/commit") :].strip()
631
- commit(query)
632
- elif user_input.startswith("/help"):
633
- query = user_input[len("/help") :].strip()
634
- if not query:
635
- show_help()
636
- else:
637
- help(query)
1271
+ exit_msg = get_i18n_message("exit_ctrl_d")
1272
+ print(f"\n\033[93m{exit_msg}\033[0m")
638
1273
 
639
- elif user_input.startswith("/exclude_dirs"):
640
- dir_names = user_input[len("/exclude_dirs") :].strip().split(",")
641
- exclude_dirs(dir_names)
1274
+ # 通知后台任务停止
1275
+ stop_ev.set()
642
1276
 
643
- elif user_input.startswith("/exclude_files"):
644
- query = user_input[len("/exclude_files") :].strip()
645
- exclude_files(query)
1277
+ # 取消消费者任务
1278
+ consumer_task.cancel()
1279
+ try:
1280
+ await consumer_task
1281
+ except asyncio.CancelledError:
1282
+ pass
646
1283
 
647
- elif user_input.startswith("/exit"):
648
- raise EOFError()
1284
+ # 取消后台任务
1285
+ background_task_coro.cancel()
1286
+ try:
1287
+ await background_task_coro
1288
+ except asyncio.CancelledError:
1289
+ pass
649
1290
 
650
- elif user_input.startswith("/coding"):
651
- event_file, file_id = gengerate_event_file_path()
652
- configure(f"event_file:{event_file}")
653
- global_cancel.register_token(event_file)
654
- query = user_input[len("/coding") :].strip()
655
- if not query:
656
- print("\033[91mPlease enter your request.\033[0m")
657
- continue
658
- coding(query)
659
- elif user_input.startswith("/chat"):
660
- event_file, file_id = gengerate_event_file_path()
661
- configure(f"event_file:{event_file}")
662
- global_cancel.register_token(event_file)
663
- query = user_input[len("/chat") :].strip()
664
- if not query:
665
- print("\033[91mPlease enter your request.\033[0m")
666
- else:
667
- chat(query)
1291
+ # 清理资源
1292
+ try:
1293
+ # 关闭所有插件
1294
+ plugin_manager.shutdown_all()
1295
+ # 停止 MCP 服务器
1296
+ try:
1297
+ if get_mcp_server():
1298
+ get_mcp_server().stop()
1299
+ except Exception as e:
1300
+ pass
1301
+ # 停止引擎
1302
+ stop_engine()
1303
+ except Exception as e:
1304
+ print(
1305
+ f"\033[91m 3. An error occurred while cleaning up:\033[0m \033[93m{type(e).__name__}\033[0m - {str(e)}"
1306
+ )
668
1307
 
669
- elif user_input.startswith("/design"):
670
- query = user_input[len("/design") :].strip()
671
- if not query:
672
- print("\033[91mPlease enter your design request.\033[0m")
673
- else:
674
- design(query)
1308
+ goodbye_msg = get_i18n_message("goodbye")
1309
+ print(f"\n\033[93m{goodbye_msg}\033[0m")
675
1310
 
676
- elif user_input.startswith("/summon"):
677
- query = user_input[len("/summon") :].strip()
678
- if not query:
679
- print("\033[91mPlease enter your request.\033[0m")
680
- else:
681
- summon(query)
682
1311
 
683
- elif user_input.startswith("/lib"):
684
- args = user_input[len("/lib") :].strip().split()
685
- lib_command(args)
1312
+ def main():
1313
+ global ARGS
1314
+ load_tokenizer()
1315
+ ARGS = parse_arguments()
686
1316
 
687
- elif user_input.startswith("/rules"):
688
- query = user_input[len("/rules") :].strip()
689
- rules(query)
1317
+ if ARGS.lite:
1318
+ ARGS.product_mode = "lite"
690
1319
 
691
- elif user_input.startswith("/mcp"):
692
- query = user_input[len("/mcp") :].strip()
693
- if not query:
694
- print("Please enter your query.")
695
- else:
696
- mcp(query)
697
-
698
- elif user_input.startswith("/active_context"):
699
- query = user_input[len("/active_context") :].strip()
700
- active_context(query)
701
-
702
- elif user_input.startswith("/auto"):
703
- query = user_input[len("/auto") :].strip()
704
- auto_command(query)
705
- elif user_input.startswith("/debug"):
706
- code = user_input[len("/debug") :].strip()
707
- try:
708
- result = eval(code)
709
- print(f"Debug result: {result}")
710
- except Exception as e:
711
- print(f"Debug error: {str(e)}")
1320
+ if ARGS.pro:
1321
+ ARGS.product_mode = "pro"
712
1322
 
713
- elif user_input.startswith("/shell"):
714
- command = user_input[len("/shell") :].strip()
715
- if not command:
716
- print("Please enter a shell command to execute.")
717
- else:
718
- if command.startswith("/chat"):
719
- event_file, file_id = gengerate_event_file_path()
720
- global_cancel.register_token(event_file)
721
- configure(f"event_file:{event_file}")
722
- command = command[len("/chat") :].strip()
723
- gen_and_exec_shell_command(command)
724
- else:
725
- execute_shell_command(command)
726
- else:
727
- # 对于未识别的命令,显示提示信息而不是执行auto_command
728
- if user_input and user_input.strip():
729
- if user_input.startswith("/"):
730
- print(f"\033[91mUnknown command: {user_input}\033[0m")
731
- print("Type /help to see available commands.")
732
- else:
733
- # 只有非命令输入才执行auto_command
734
- auto_command(user_input)
735
-
736
- except KeyboardInterrupt:
737
- continue
738
- except EOFError:
739
- try:
740
- # Shutdown all plugins before exiting
741
- plugin_manager.shutdown_all()
742
- # save_memory()
743
- try:
744
- if get_mcp_server():
745
- get_mcp_server().stop()
746
- except Exception as e:
747
- pass
748
- stop_engine()
749
- except Exception as e:
750
- print(
751
- f"\033[91mAn error occurred while saving memory:\033[0m \033[93m{type(e).__name__}\033[0m - {str(e)}"
752
- )
753
- print("\n\033[93mExiting Chat Auto Coder...\033[0m")
754
- break
755
- except Exception as e:
756
- print(
757
- f"\033[91mAn error occurred:\033[0m \033[93m{type(e).__name__}\033[0m - {str(e)}"
1323
+ if not ARGS.quick:
1324
+ initialize_system(
1325
+ InitializeSystemRequest(
1326
+ product_mode=ARGS.product_mode,
1327
+ skip_provider_selection=ARGS.skip_provider_selection,
1328
+ debug=ARGS.debug,
1329
+ quick=ARGS.quick,
1330
+ lite=ARGS.lite,
1331
+ pro=ARGS.pro,
758
1332
  )
759
- if ARGS and ARGS.debug:
760
- import traceback
1333
+ )
761
1334
 
762
- traceback.print_exc()
1335
+ start_engine()
1336
+
1337
+ # 初始化插件系统
1338
+ plugin_manager.load_global_plugin_dirs()
1339
+ plugin_manager.add_global_plugin_directory(
1340
+ os.path.join(os.path.dirname(__file__), "plugins")
1341
+ )
1342
+
1343
+ # 加载保存的运行时配置
1344
+ plugin_manager.load_runtime_cfg()
1345
+
1346
+ # 自动加载内置插件
1347
+ load_builtin_plugins()
1348
+
1349
+ configure(f"product_mode:{ARGS.product_mode}")
1350
+
1351
+ # 运行应用
1352
+ asyncio.run(run_app())
763
1353
 
764
1354
 
765
1355
  if __name__ == "__main__":