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,623 @@
1
+ """
2
+ Interactive process wrapper using pexpect for shell command execution.
3
+
4
+ This module provides pexpect-based interactive process functionality including:
5
+ - Real-time input/output streaming with pexpect
6
+ - Cross-platform support (Unix-like systems)
7
+ - Signal handling (Ctrl-C, etc.)
8
+ - Thread-safe operations
9
+ - Pattern matching and expect functionality
10
+ """
11
+
12
+ import os
13
+ import platform
14
+ import threading
15
+ import time
16
+ import queue
17
+ import signal
18
+ from typing import Optional, Dict, Any, Generator, Union, List, Tuple
19
+ from loguru import logger
20
+
21
+ from .exceptions import CommandExecutionError, ProcessCleanupError
22
+ from .process_cleanup import cleanup_process_tree
23
+
24
+ # Platform check
25
+ PLATFORM = platform.system()
26
+ PEXPECT_AVAILABLE = False
27
+
28
+ try:
29
+ import pexpect
30
+ if PLATFORM != "Windows":
31
+ PEXPECT_AVAILABLE = True
32
+ else:
33
+ # Try to import pexpect for Windows (pexpect-windows)
34
+ try:
35
+ import pexpect.popen_spawn
36
+ PEXPECT_AVAILABLE = True
37
+ except ImportError:
38
+ logger.debug("pexpect not fully available on Windows")
39
+ except ImportError:
40
+ logger.debug("pexpect not available")
41
+
42
+
43
+ class InteractivePexpectProcess:
44
+ """
45
+ Interactive process wrapper using pexpect for real-time command execution.
46
+
47
+ This class provides a pexpect-based interface for executing commands that
48
+ require interactive input/output, with built-in pattern matching and
49
+ expect functionality.
50
+ """
51
+
52
+ def __init__(
53
+ self,
54
+ command: Union[str, List[str]],
55
+ cwd: Optional[str] = None,
56
+ env: Optional[Dict[str, str]] = None,
57
+ shell: bool = True,
58
+ encoding: str = 'utf-8',
59
+ timeout: Optional[float] = None,
60
+ maxread: int = 2000,
61
+ searchwindowsize: Optional[int] = None,
62
+ **kwargs
63
+ ):
64
+ """
65
+ Initialize interactive pexpect process.
66
+
67
+ Args:
68
+ command: Command to execute
69
+ cwd: Working directory
70
+ env: Environment variables
71
+ shell: Whether to use shell
72
+ encoding: Text encoding
73
+ timeout: Default timeout for expect operations
74
+ maxread: Maximum bytes to read at once
75
+ searchwindowsize: Size of search window for pattern matching
76
+ **kwargs: Additional pexpect arguments
77
+ """
78
+ self.command = command
79
+ self.cwd = cwd
80
+ self.env = env
81
+ self.encoding = encoding
82
+ self.shell = shell
83
+ self.timeout = timeout
84
+ self.maxread = maxread
85
+ self.searchwindowsize = searchwindowsize
86
+ self.pexpect_kwargs = kwargs
87
+
88
+ # Check availability
89
+ if not PEXPECT_AVAILABLE:
90
+ raise CommandExecutionError("pexpect not available on this platform")
91
+
92
+ # State management
93
+ self.child: Optional[pexpect.spawn] = None
94
+ self.logfile_read = None
95
+ self.logfile_send = None
96
+
97
+ # Threading
98
+ self.output_queue: queue.Queue = queue.Queue()
99
+ self.error_queue: queue.Queue = queue.Queue()
100
+ self.io_thread: Optional[threading.Thread] = None
101
+ self.alive_event = threading.Event()
102
+ self.started_event = threading.Event()
103
+
104
+ # Monitoring
105
+ self.start_time: Optional[float] = None
106
+ self.end_time: Optional[float] = None
107
+ self.bytes_written = 0
108
+ self.bytes_read = 0
109
+
110
+ # Buffer for continuous reading
111
+ self._output_buffer = ""
112
+ self._read_lock = threading.Lock()
113
+
114
+ logger.debug(f"InteractivePexpectProcess initialized: platform={PLATFORM}")
115
+
116
+ def start(self) -> None:
117
+ """Start the interactive pexpect process."""
118
+ if self.is_alive():
119
+ raise CommandExecutionError("Process is already running")
120
+
121
+ self.start_time = time.time()
122
+ self.alive_event.set()
123
+
124
+ try:
125
+ # Prepare command
126
+ if isinstance(self.command, list):
127
+ if self.shell:
128
+ # Join command parts for shell execution
129
+ cmd = ' '.join(self.command)
130
+ else:
131
+ # Use first element as command, rest as args
132
+ cmd = self.command[0]
133
+ args = self.command[1:] if len(self.command) > 1 else []
134
+ else:
135
+ cmd = self.command
136
+ args = []
137
+
138
+ # Create pexpect spawn
139
+ if PLATFORM == "Windows":
140
+ # Use popen_spawn for Windows
141
+ self.child = pexpect.popen_spawn.PopenSpawn(
142
+ cmd,
143
+ timeout=self.timeout,
144
+ maxread=self.maxread,
145
+ searchwindowsize=self.searchwindowsize,
146
+ encoding=self.encoding,
147
+ cwd=self.cwd,
148
+ env=self.env,
149
+ **self.pexpect_kwargs
150
+ )
151
+ else:
152
+ # Use regular spawn for Unix-like systems
153
+ if self.shell:
154
+ # Use shell to execute command
155
+ shell_cmd = os.environ.get("SHELL", "/bin/sh")
156
+ self.child = pexpect.spawn(
157
+ shell_cmd,
158
+ args=["-c", cmd],
159
+ timeout=self.timeout,
160
+ maxread=self.maxread,
161
+ searchwindowsize=self.searchwindowsize,
162
+ encoding=self.encoding,
163
+ cwd=self.cwd,
164
+ env=self.env,
165
+ **self.pexpect_kwargs
166
+ )
167
+ else:
168
+ # Direct command execution
169
+ self.child = pexpect.spawn(
170
+ cmd,
171
+ args=args,
172
+ timeout=self.timeout,
173
+ maxread=self.maxread,
174
+ searchwindowsize=self.searchwindowsize,
175
+ encoding=self.encoding,
176
+ cwd=self.cwd,
177
+ env=self.env,
178
+ **self.pexpect_kwargs
179
+ )
180
+
181
+ # Configure logging if needed
182
+ if hasattr(self, 'logfile_read') and self.logfile_read:
183
+ self.child.logfile_read = self.logfile_read
184
+ if hasattr(self, 'logfile_send') and self.logfile_send:
185
+ self.child.logfile_send = self.logfile_send
186
+
187
+ # Start I/O thread for continuous reading
188
+ self.io_thread = threading.Thread(target=self._io_worker, daemon=True)
189
+ self.io_thread.start()
190
+
191
+ # Give process a moment to start
192
+ time.sleep(0.1)
193
+
194
+ # Check if process is alive
195
+ if not self.is_alive():
196
+ self._cleanup()
197
+ raise CommandExecutionError("Pexpect process failed to start")
198
+
199
+ self.started_event.set()
200
+ logger.info(f"Interactive pexpect process started: PID {self.pid}")
201
+
202
+ except Exception as e:
203
+ self.alive_event.clear()
204
+ self._cleanup()
205
+ raise CommandExecutionError(f"Failed to start pexpect process: {e}")
206
+
207
+ def _io_worker(self) -> None:
208
+ """I/O worker thread for continuous reading."""
209
+ try:
210
+ while self.alive_event.is_set() and self.child and self.child.isalive():
211
+ try:
212
+ # Read data with timeout
213
+ data = self.child.read_nonblocking(size=1024, timeout=0.1)
214
+ if data:
215
+ with self._read_lock:
216
+ self._output_buffer += data
217
+ self.bytes_read += len(data.encode(self.encoding))
218
+ self.output_queue.put(data)
219
+
220
+ except pexpect.TIMEOUT:
221
+ # No data available, continue
222
+ continue
223
+ except pexpect.EOF:
224
+ # Process terminated
225
+ self.alive_event.clear()
226
+ break
227
+ except Exception as e:
228
+ logger.debug(f"I/O worker error: {e}")
229
+ break
230
+
231
+ except Exception as e:
232
+ logger.error(f"I/O worker fatal error: {e}")
233
+ finally:
234
+ self.alive_event.clear()
235
+
236
+ def write(self, data: str) -> None:
237
+ """
238
+ Write data to process stdin.
239
+
240
+ Args:
241
+ data: Data to write
242
+
243
+ Raises:
244
+ CommandExecutionError: If process is not running or write fails
245
+ """
246
+ if not self.is_alive():
247
+ raise CommandExecutionError("Process is not running")
248
+
249
+ if not self.started_event.is_set():
250
+ raise CommandExecutionError("Process has not started yet")
251
+
252
+ try:
253
+ if self.child:
254
+ self.child.send(data)
255
+ self.bytes_written += len(data.encode(self.encoding))
256
+ else:
257
+ raise CommandExecutionError("No pexpect child process available")
258
+
259
+ except Exception as e:
260
+ raise CommandExecutionError(f"Failed to write to process: {e}")
261
+
262
+ def sendline(self, line: str = "") -> None:
263
+ """
264
+ Send a line to the process (adds newline).
265
+
266
+ Args:
267
+ line: Line to send
268
+ """
269
+ if self.child:
270
+ self.child.sendline(line)
271
+ self.bytes_written += len(line.encode(self.encoding)) + 1 # +1 for newline
272
+
273
+ def sendcontrol(self, char: str) -> None:
274
+ """
275
+ Send a control character to the process.
276
+
277
+ Args:
278
+ char: Control character (e.g., 'c' for Ctrl-C)
279
+ """
280
+ if self.child:
281
+ self.child.sendcontrol(char)
282
+ self.bytes_written += 1
283
+
284
+ def read_output(self, timeout: Optional[float] = None) -> Optional[str]:
285
+ """
286
+ Read output from process.
287
+
288
+ Args:
289
+ timeout: Timeout in seconds (None for non-blocking)
290
+
291
+ Returns:
292
+ Output string or None if no data available
293
+ """
294
+ try:
295
+ if timeout is None:
296
+ return self.output_queue.get_nowait()
297
+ else:
298
+ return self.output_queue.get(timeout=timeout)
299
+ except queue.Empty:
300
+ return None
301
+
302
+ def read_error(self, timeout: Optional[float] = None) -> Optional[str]:
303
+ """
304
+ Read error output from process.
305
+
306
+ Args:
307
+ timeout: Timeout in seconds (None for non-blocking)
308
+
309
+ Returns:
310
+ Error string or None if no data available
311
+ """
312
+ try:
313
+ if timeout is None:
314
+ return self.error_queue.get_nowait()
315
+ else:
316
+ return self.error_queue.get(timeout=timeout)
317
+ except queue.Empty:
318
+ return None
319
+
320
+ def expect(self, pattern: Union[str, List[str]], timeout: Optional[float] = None) -> int:
321
+ """
322
+ Wait for a pattern to appear in the output.
323
+
324
+ Args:
325
+ pattern: Pattern(s) to match
326
+ timeout: Timeout in seconds
327
+
328
+ Returns:
329
+ Index of matched pattern (0 if single pattern)
330
+
331
+ Raises:
332
+ CommandExecutionError: If expect fails
333
+ """
334
+ if not self.child:
335
+ raise CommandExecutionError("No pexpect child process available")
336
+
337
+ try:
338
+ if timeout is None:
339
+ timeout = self.timeout
340
+
341
+ result = self.child.expect(pattern, timeout=timeout)
342
+
343
+ # Add matched text to output queue
344
+ if self.child.after:
345
+ self.output_queue.put(self.child.after)
346
+
347
+ return result
348
+
349
+ except pexpect.TIMEOUT as e:
350
+ raise CommandExecutionError(f"Expect timeout: {e}")
351
+ except pexpect.EOF as e:
352
+ raise CommandExecutionError(f"Expect EOF: {e}")
353
+ except Exception as e:
354
+ raise CommandExecutionError(f"Expect error: {e}")
355
+
356
+ def expect_exact(self, pattern: Union[str, List[str]], timeout: Optional[float] = None) -> int:
357
+ """
358
+ Wait for exact string(s) to appear in the output.
359
+
360
+ Args:
361
+ pattern: Exact string(s) to match
362
+ timeout: Timeout in seconds
363
+
364
+ Returns:
365
+ Index of matched pattern (0 if single pattern)
366
+ """
367
+ if not self.child:
368
+ raise CommandExecutionError("No pexpect child process available")
369
+
370
+ try:
371
+ if timeout is None:
372
+ timeout = self.timeout
373
+
374
+ result = self.child.expect_exact(pattern, timeout=timeout)
375
+
376
+ # Add matched text to output queue
377
+ if self.child.after:
378
+ self.output_queue.put(self.child.after)
379
+
380
+ return result
381
+
382
+ except pexpect.TIMEOUT as e:
383
+ raise CommandExecutionError(f"Expect exact timeout: {e}")
384
+ except pexpect.EOF as e:
385
+ raise CommandExecutionError(f"Expect exact EOF: {e}")
386
+ except Exception as e:
387
+ raise CommandExecutionError(f"Expect exact error: {e}")
388
+
389
+ def read_lines(self, timeout: Optional[float] = 1.0) -> Generator[str, None, None]:
390
+ """
391
+ Generator that yields output lines.
392
+
393
+ Args:
394
+ timeout: Timeout for each read operation
395
+
396
+ Yields:
397
+ Output lines
398
+ """
399
+ buffer = ""
400
+
401
+ while self.is_alive():
402
+ try:
403
+ data = self.read_output(timeout=timeout)
404
+ if data:
405
+ buffer += data
406
+
407
+ # Yield complete lines
408
+ while '\n' in buffer:
409
+ line, buffer = buffer.split('\n', 1)
410
+ yield line + '\n'
411
+ else:
412
+ # No data available, check if process is still alive
413
+ if not self.is_alive():
414
+ break
415
+
416
+ except Exception as e:
417
+ logger.debug(f"Error reading lines: {e}")
418
+ break
419
+
420
+ # Yield any remaining buffer content
421
+ if buffer:
422
+ yield buffer
423
+
424
+ def interact(self, escape_character: str = chr(29), input_filter=None, output_filter=None) -> None:
425
+ """
426
+ Give control of the child process to the user.
427
+
428
+ Args:
429
+ escape_character: Character to exit interaction
430
+ input_filter: Filter for input
431
+ output_filter: Filter for output
432
+ """
433
+ if not self.child:
434
+ raise CommandExecutionError("No pexpect child process available")
435
+
436
+ try:
437
+ self.child.interact(
438
+ escape_character=escape_character,
439
+ input_filter=input_filter,
440
+ output_filter=output_filter
441
+ )
442
+ except Exception as e:
443
+ raise CommandExecutionError(f"Interaction error: {e}")
444
+
445
+ def send_signal(self, sig: int) -> None:
446
+ """
447
+ Send signal to process.
448
+
449
+ Args:
450
+ sig: Signal number
451
+ """
452
+ if not self.is_alive():
453
+ return
454
+
455
+ try:
456
+ if self.child:
457
+ if PLATFORM == "Windows":
458
+ # Windows signal handling
459
+ if sig == signal.SIGINT:
460
+ self.child.sendcontrol('c')
461
+ else:
462
+ self.child.terminate()
463
+ else:
464
+ # Unix signal handling
465
+ self.child.kill(sig)
466
+
467
+ except Exception as e:
468
+ logger.debug(f"Error sending signal {sig}: {e}")
469
+
470
+ def terminate(self, grace_timeout: float = 5.0) -> bool:
471
+ """
472
+ Terminate the process gracefully.
473
+
474
+ Args:
475
+ grace_timeout: Time to wait for graceful termination
476
+
477
+ Returns:
478
+ True if terminated successfully
479
+ """
480
+ if not self.is_alive():
481
+ return True
482
+
483
+ logger.debug(f"Terminating pexpect process PID {self.pid}")
484
+
485
+ try:
486
+ # Send SIGTERM (or equivalent)
487
+ if self.child:
488
+ self.child.terminate()
489
+
490
+ # Wait for graceful termination
491
+ start_time = time.time()
492
+ while time.time() - start_time < grace_timeout:
493
+ if not self.is_alive():
494
+ break
495
+ time.sleep(0.1)
496
+
497
+ # Force kill if still alive
498
+ if self.is_alive() and self.child:
499
+ logger.debug(f"Force killing pexpect process PID {self.pid}")
500
+ self.child.kill(signal.SIGKILL)
501
+
502
+ # Wait for I/O thread to finish
503
+ self.alive_event.clear()
504
+ if self.io_thread and self.io_thread.is_alive():
505
+ self.io_thread.join(timeout=2.0)
506
+
507
+ self._cleanup()
508
+ self.end_time = time.time()
509
+
510
+ return not self.is_alive()
511
+
512
+ except Exception as e:
513
+ logger.error(f"Error terminating pexpect process: {e}")
514
+ return False
515
+
516
+ def _cleanup(self) -> None:
517
+ """Clean up resources."""
518
+ try:
519
+ if self.child:
520
+ try:
521
+ if self.child.isalive():
522
+ self.child.terminate(force=True)
523
+ except:
524
+ pass
525
+
526
+ # Close file descriptors
527
+ try:
528
+ self.child.close()
529
+ except:
530
+ pass
531
+
532
+ self.child = None
533
+
534
+ except Exception as e:
535
+ logger.debug(f"Cleanup error: {e}")
536
+
537
+ def is_alive(self) -> bool:
538
+ """Check if process is alive."""
539
+ if self.child:
540
+ return self.child.isalive()
541
+ return False
542
+
543
+ @property
544
+ def pid(self) -> Optional[int]:
545
+ """Get process PID."""
546
+ if self.child:
547
+ return self.child.pid
548
+ return None
549
+
550
+ @property
551
+ def exit_code(self) -> Optional[int]:
552
+ """Get process exit code."""
553
+ if self.child:
554
+ return self.child.exitstatus
555
+ return None
556
+
557
+ @property
558
+ def signal_status(self) -> Optional[int]:
559
+ """Get process signal status."""
560
+ if self.child:
561
+ return self.child.signalstatus
562
+ return None
563
+
564
+ @property
565
+ def duration(self) -> Optional[float]:
566
+ """Get process duration."""
567
+ if self.start_time is None:
568
+ return None
569
+
570
+ end_time = self.end_time or time.time()
571
+ return end_time - self.start_time
572
+
573
+ @property
574
+ def before(self) -> Optional[str]:
575
+ """Get text before the last match."""
576
+ if self.child:
577
+ return self.child.before
578
+ return None
579
+
580
+ @property
581
+ def after(self) -> Optional[str]:
582
+ """Get text after the last match."""
583
+ if self.child:
584
+ return self.child.after
585
+ return None
586
+
587
+ @property
588
+ def match(self) -> Optional[str]:
589
+ """Get the last match object."""
590
+ if self.child:
591
+ return self.child.match
592
+ return None
593
+
594
+ def get_stats(self) -> Dict[str, Any]:
595
+ """Get process statistics."""
596
+ return {
597
+ 'pid': self.pid,
598
+ 'exit_code': self.exit_code,
599
+ 'signal_status': self.signal_status,
600
+ 'duration': self.duration,
601
+ 'bytes_written': self.bytes_written,
602
+ 'bytes_read': self.bytes_read,
603
+ 'is_alive': self.is_alive(),
604
+ 'platform': PLATFORM,
605
+ 'pexpect_available': PEXPECT_AVAILABLE
606
+ }
607
+
608
+ def __enter__(self) -> 'InteractivePexpectProcess':
609
+ """Context manager entry."""
610
+ self.start()
611
+ return self
612
+
613
+ def __exit__(self, exc_type, exc_val, exc_tb) -> None:
614
+ """Context manager exit."""
615
+ self.terminate()
616
+
617
+ def __del__(self) -> None:
618
+ """Destructor - cleanup resources."""
619
+ try:
620
+ if self.is_alive():
621
+ self.terminate(grace_timeout=1.0)
622
+ except Exception:
623
+ pass