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.
- auto_coder-2.0.0.dist-info/LICENSE +158 -0
- auto_coder-2.0.0.dist-info/METADATA +558 -0
- auto_coder-2.0.0.dist-info/RECORD +795 -0
- {auto_coder-1.0.0.dist-info → auto_coder-2.0.0.dist-info}/WHEEL +1 -1
- {auto_coder-1.0.0.dist-info → auto_coder-2.0.0.dist-info}/entry_points.txt +3 -3
- autocoder/__init__.py +31 -0
- autocoder/agent/auto_filegroup.py +32 -13
- autocoder/agent/auto_learn_from_commit.py +9 -1
- autocoder/agent/base_agentic/__init__.py +3 -0
- autocoder/agent/base_agentic/agent_hub.py +1 -1
- autocoder/agent/base_agentic/base_agent.py +235 -136
- autocoder/agent/base_agentic/default_tools.py +119 -118
- autocoder/agent/base_agentic/test_base_agent.py +1 -1
- autocoder/agent/base_agentic/tool_registry.py +32 -20
- autocoder/agent/base_agentic/tools/read_file_tool_resolver.py +24 -3
- autocoder/agent/base_agentic/tools/write_to_file_tool_resolver.py +24 -11
- autocoder/agent/base_agentic/types.py +42 -0
- autocoder/agent/entry_command_agent/chat.py +73 -59
- autocoder/auto_coder.py +31 -40
- autocoder/auto_coder_rag.py +11 -1084
- autocoder/auto_coder_runner.py +970 -2345
- autocoder/auto_coder_terminal.py +26 -0
- autocoder/auto_coder_terminal_v3.py +190 -0
- autocoder/chat/conf_command.py +224 -124
- autocoder/chat/models_command.py +361 -299
- autocoder/chat/rules_command.py +79 -31
- autocoder/chat_auto_coder.py +988 -398
- autocoder/chat_auto_coder_lang.py +23 -732
- autocoder/commands/auto_command.py +25 -8
- autocoder/commands/auto_web.py +1 -1
- autocoder/commands/tools.py +44 -44
- autocoder/common/__init__.py +150 -128
- autocoder/common/ac_style_command_parser/__init__.py +39 -2
- autocoder/common/ac_style_command_parser/config.py +422 -0
- autocoder/common/ac_style_command_parser/parser.py +292 -78
- autocoder/common/ac_style_command_parser/test_parser.py +241 -16
- autocoder/common/ac_style_command_parser/test_typed_parser.py +342 -0
- autocoder/common/ac_style_command_parser/typed_parser.py +653 -0
- autocoder/common/action_yml_file_manager.py +25 -13
- autocoder/common/agent_events/__init__.py +52 -0
- autocoder/common/agent_events/agent_event_emitter.py +193 -0
- autocoder/common/agent_events/event_factory.py +177 -0
- autocoder/common/agent_events/examples.py +307 -0
- autocoder/common/agent_events/types.py +113 -0
- autocoder/common/agent_events/utils.py +68 -0
- autocoder/common/agent_hooks/__init__.py +44 -0
- autocoder/common/agent_hooks/examples.py +582 -0
- autocoder/common/agent_hooks/hook_executor.py +217 -0
- autocoder/common/agent_hooks/hook_manager.py +288 -0
- autocoder/common/agent_hooks/types.py +133 -0
- autocoder/common/agent_hooks/utils.py +99 -0
- autocoder/common/agent_query_queue/queue_executor.py +324 -0
- autocoder/common/agent_query_queue/queue_manager.py +325 -0
- autocoder/common/agents/__init__.py +11 -0
- autocoder/common/agents/agent_manager.py +323 -0
- autocoder/common/agents/agent_parser.py +189 -0
- autocoder/common/agents/example_usage.py +344 -0
- autocoder/common/agents/integration_example.py +330 -0
- autocoder/common/agents/test_agent_parser.py +545 -0
- autocoder/common/async_utils.py +101 -0
- autocoder/common/auto_coder_lang.py +23 -972
- autocoder/common/autocoderargs_parser/__init__.py +14 -0
- autocoder/common/autocoderargs_parser/parser.py +184 -0
- autocoder/common/autocoderargs_parser/tests/__init__.py +1 -0
- autocoder/common/autocoderargs_parser/tests/test_args_parser.py +235 -0
- autocoder/common/autocoderargs_parser/tests/test_token_parser.py +195 -0
- autocoder/common/autocoderargs_parser/token_parser.py +290 -0
- autocoder/common/buildin_tokenizer.py +2 -4
- autocoder/common/code_auto_generate.py +149 -74
- autocoder/common/code_auto_generate_diff.py +163 -70
- autocoder/common/code_auto_generate_editblock.py +179 -89
- autocoder/common/code_auto_generate_strict_diff.py +167 -72
- autocoder/common/code_auto_merge_editblock.py +13 -6
- autocoder/common/code_modification_ranker.py +1 -1
- autocoder/common/command_completer.py +3 -3
- autocoder/common/command_file_manager/manager.py +183 -47
- autocoder/common/command_file_manager/test_command_file_manager.py +507 -0
- autocoder/common/command_templates.py +1 -1
- autocoder/common/conf_utils.py +2 -4
- autocoder/common/conversations/config.py +11 -3
- autocoder/common/conversations/get_conversation_manager.py +100 -2
- autocoder/common/conversations/llm_stats_models.py +264 -0
- autocoder/common/conversations/manager.py +112 -28
- autocoder/common/conversations/models.py +16 -2
- autocoder/common/conversations/storage/index_manager.py +134 -10
- autocoder/common/core_config/__init__.py +63 -0
- autocoder/common/core_config/agentic_mode_manager.py +109 -0
- autocoder/common/core_config/base_manager.py +123 -0
- autocoder/common/core_config/compatibility.py +151 -0
- autocoder/common/core_config/config_manager.py +156 -0
- autocoder/common/core_config/conversation_manager.py +31 -0
- autocoder/common/core_config/exclude_manager.py +72 -0
- autocoder/common/core_config/file_manager.py +177 -0
- autocoder/common/core_config/human_as_model_manager.py +129 -0
- autocoder/common/core_config/lib_manager.py +54 -0
- autocoder/common/core_config/main_manager.py +81 -0
- autocoder/common/core_config/mode_manager.py +126 -0
- autocoder/common/core_config/models.py +70 -0
- autocoder/common/core_config/test_memory_manager.py +1056 -0
- autocoder/common/env_manager.py +282 -0
- autocoder/common/env_manager_usage_example.py +211 -0
- autocoder/common/file_checkpoint/conversation_checkpoint.py +19 -19
- autocoder/common/file_checkpoint/manager.py +264 -48
- autocoder/common/file_checkpoint/test_backup.py +1 -18
- autocoder/common/file_checkpoint/test_manager.py +270 -1
- autocoder/common/file_checkpoint/test_store.py +1 -17
- autocoder/common/file_handler/__init__.py +23 -0
- autocoder/common/file_handler/active_context_handler.py +159 -0
- autocoder/common/file_handler/add_files_handler.py +409 -0
- autocoder/common/file_handler/chat_handler.py +180 -0
- autocoder/common/file_handler/coding_handler.py +401 -0
- autocoder/common/file_handler/commit_handler.py +200 -0
- autocoder/common/file_handler/lib_handler.py +156 -0
- autocoder/common/file_handler/list_files_handler.py +111 -0
- autocoder/common/file_handler/mcp_handler.py +268 -0
- autocoder/common/file_handler/models_handler.py +493 -0
- autocoder/common/file_handler/remove_files_handler.py +172 -0
- autocoder/common/git_utils.py +44 -8
- autocoder/common/global_cancel.py +15 -6
- autocoder/common/ignorefiles/test_ignore_file_utils.py +1 -1
- autocoder/common/international/__init__.py +31 -0
- autocoder/common/international/demo_international.py +92 -0
- autocoder/common/international/message_manager.py +157 -0
- autocoder/common/international/messages/__init__.py +56 -0
- autocoder/common/international/messages/async_command_messages.py +507 -0
- autocoder/common/international/messages/auto_coder_messages.py +2208 -0
- autocoder/common/international/messages/chat_auto_coder_messages.py +1547 -0
- autocoder/common/international/messages/command_help_messages.py +986 -0
- autocoder/common/international/messages/conversation_command_messages.py +191 -0
- autocoder/common/international/messages/git_helper_plugin_messages.py +159 -0
- autocoder/common/international/messages/queue_command_messages.py +751 -0
- autocoder/common/international/messages/rules_command_messages.py +77 -0
- autocoder/common/international/messages/sdk_messages.py +1707 -0
- autocoder/common/international/messages/token_helper_plugin_messages.py +361 -0
- autocoder/common/international/messages/tool_display_messages.py +1212 -0
- autocoder/common/international/messages/workflow_exception_messages.py +473 -0
- autocoder/common/international/test_international.py +612 -0
- autocoder/common/linter_core/__init__.py +28 -0
- autocoder/common/linter_core/base_linter.py +61 -0
- autocoder/common/linter_core/config_loader.py +271 -0
- autocoder/common/linter_core/formatters/__init__.py +0 -0
- autocoder/common/linter_core/formatters/base_formatter.py +38 -0
- autocoder/common/linter_core/formatters/raw_formatter.py +17 -0
- autocoder/common/linter_core/linter.py +166 -0
- autocoder/common/linter_core/linter_factory.py +216 -0
- autocoder/common/linter_core/linter_manager.py +333 -0
- autocoder/common/linter_core/linters/__init__.py +9 -0
- autocoder/common/linter_core/linters/java_linter.py +342 -0
- autocoder/common/linter_core/linters/python_linter.py +115 -0
- autocoder/common/linter_core/linters/typescript_linter.py +119 -0
- autocoder/common/linter_core/models/__init__.py +7 -0
- autocoder/common/linter_core/models/lint_result.py +91 -0
- autocoder/common/linter_core/models.py +33 -0
- autocoder/common/linter_core/tests/__init__.py +3 -0
- autocoder/common/linter_core/tests/test_config_loader.py +323 -0
- autocoder/common/linter_core/tests/test_config_loading.py +308 -0
- autocoder/common/linter_core/tests/test_factory_manager.py +234 -0
- autocoder/common/linter_core/tests/test_formatters.py +147 -0
- autocoder/common/linter_core/tests/test_integration.py +317 -0
- autocoder/common/linter_core/tests/test_java_linter.py +496 -0
- autocoder/common/linter_core/tests/test_linters.py +265 -0
- autocoder/common/linter_core/tests/test_models.py +81 -0
- autocoder/common/linter_core/tests/verify_config_loading.py +296 -0
- autocoder/common/linter_core/tests/verify_fixes.py +183 -0
- autocoder/common/llm_friendly_package/__init__.py +31 -0
- autocoder/common/llm_friendly_package/base_manager.py +102 -0
- autocoder/common/llm_friendly_package/docs_manager.py +121 -0
- autocoder/common/llm_friendly_package/library_manager.py +171 -0
- autocoder/common/{llm_friendly_package.py → llm_friendly_package/main_manager.py} +204 -231
- autocoder/common/llm_friendly_package/models.py +40 -0
- autocoder/common/llm_friendly_package/test_llm_friendly_package.py +536 -0
- autocoder/common/llms/__init__.py +15 -0
- autocoder/common/llms/demo_error_handling.py +85 -0
- autocoder/common/llms/factory.py +142 -0
- autocoder/common/llms/manager.py +264 -0
- autocoder/common/llms/pricing.py +121 -0
- autocoder/common/llms/registry.py +288 -0
- autocoder/common/llms/schema.py +77 -0
- autocoder/common/llms/simple_demo.py +45 -0
- autocoder/common/llms/test_quick_model.py +116 -0
- autocoder/common/llms/test_remove_functionality.py +182 -0
- autocoder/common/llms/tests/__init__.py +1 -0
- autocoder/common/llms/tests/test_manager.py +330 -0
- autocoder/common/llms/tests/test_registry.py +364 -0
- autocoder/common/mcp_tools/__init__.py +62 -0
- autocoder/common/{mcp_tools.py → mcp_tools/executor.py} +49 -40
- autocoder/common/{mcp_hub.py → mcp_tools/hub.py} +42 -68
- autocoder/common/{mcp_server_install.py → mcp_tools/installer.py} +16 -28
- autocoder/common/{mcp_server.py → mcp_tools/server.py} +176 -48
- autocoder/common/mcp_tools/test_keyboard_interrupt.py +93 -0
- autocoder/common/mcp_tools/test_mcp_tools.py +391 -0
- autocoder/common/{mcp_server_types.py → mcp_tools/types.py} +121 -48
- autocoder/common/mcp_tools/verify_functionality.py +202 -0
- autocoder/common/model_speed_tester.py +32 -26
- autocoder/common/priority_directory_finder/__init__.py +142 -0
- autocoder/common/priority_directory_finder/examples.py +230 -0
- autocoder/common/priority_directory_finder/finder.py +283 -0
- autocoder/common/priority_directory_finder/models.py +236 -0
- autocoder/common/priority_directory_finder/test_priority_directory_finder.py +431 -0
- autocoder/common/project_scanner/__init__.py +18 -0
- autocoder/common/project_scanner/compat.py +77 -0
- autocoder/common/project_scanner/scanner.py +436 -0
- autocoder/common/project_tracker/__init__.py +27 -0
- autocoder/common/project_tracker/api.py +228 -0
- autocoder/common/project_tracker/demo.py +272 -0
- autocoder/common/project_tracker/tracker.py +487 -0
- autocoder/common/project_tracker/types.py +53 -0
- autocoder/common/pruner/__init__.py +67 -0
- autocoder/common/pruner/agentic_conversation_pruner.py +651 -102
- autocoder/common/pruner/conversation_message_ids_api.py +386 -0
- autocoder/common/pruner/conversation_message_ids_manager.py +347 -0
- autocoder/common/pruner/conversation_message_ids_pruner.py +473 -0
- autocoder/common/pruner/conversation_normalizer.py +347 -0
- autocoder/common/pruner/conversation_pruner.py +26 -6
- autocoder/common/pruner/test_agentic_conversation_pruner.py +554 -112
- autocoder/common/pruner/test_conversation_normalizer.py +502 -0
- autocoder/common/pruner/test_tool_content_detector.py +324 -0
- autocoder/common/pruner/tool_content_detector.py +227 -0
- autocoder/common/pruner/tools/__init__.py +18 -0
- autocoder/common/pruner/tools/query_message_ids.py +264 -0
- autocoder/common/pruner/tools/test_agentic_pruning_logic.py +432 -0
- autocoder/common/pruner/tools/test_message_ids_pruning_only.py +192 -0
- autocoder/common/pull_requests/__init__.py +9 -1
- autocoder/common/pull_requests/utils.py +122 -1
- autocoder/common/rag_manager/rag_manager.py +36 -40
- autocoder/common/rulefiles/__init__.py +53 -1
- autocoder/common/rulefiles/api.py +250 -0
- autocoder/common/rulefiles/core/__init__.py +14 -0
- autocoder/common/rulefiles/core/manager.py +241 -0
- autocoder/common/rulefiles/core/selector.py +805 -0
- autocoder/common/rulefiles/models/__init__.py +20 -0
- autocoder/common/rulefiles/models/index.py +16 -0
- autocoder/common/rulefiles/models/init_rule.py +18 -0
- autocoder/common/rulefiles/models/rule_file.py +18 -0
- autocoder/common/rulefiles/models/rule_relevance.py +14 -0
- autocoder/common/rulefiles/models/summary.py +16 -0
- autocoder/common/rulefiles/test_rulefiles.py +776 -0
- autocoder/common/rulefiles/utils/__init__.py +34 -0
- autocoder/common/rulefiles/utils/monitor.py +86 -0
- autocoder/common/rulefiles/utils/parser.py +230 -0
- autocoder/common/save_formatted_log.py +67 -10
- autocoder/common/search_replace.py +8 -1
- autocoder/common/search_replace_patch/__init__.py +24 -0
- autocoder/common/search_replace_patch/base.py +115 -0
- autocoder/common/search_replace_patch/manager.py +248 -0
- autocoder/common/search_replace_patch/patch_replacer.py +304 -0
- autocoder/common/search_replace_patch/similarity_replacer.py +306 -0
- autocoder/common/search_replace_patch/string_replacer.py +181 -0
- autocoder/common/search_replace_patch/tests/__init__.py +3 -0
- autocoder/common/search_replace_patch/tests/run_tests.py +126 -0
- autocoder/common/search_replace_patch/tests/test_base.py +188 -0
- autocoder/common/search_replace_patch/tests/test_empty_line_insert.py +233 -0
- autocoder/common/search_replace_patch/tests/test_integration.py +389 -0
- autocoder/common/search_replace_patch/tests/test_manager.py +351 -0
- autocoder/common/search_replace_patch/tests/test_patch_replacer.py +316 -0
- autocoder/common/search_replace_patch/tests/test_regex_replacer.py +306 -0
- autocoder/common/search_replace_patch/tests/test_similarity_replacer.py +384 -0
- autocoder/common/shell_commands/__init__.py +197 -0
- autocoder/common/shell_commands/background_process_notifier.py +346 -0
- autocoder/common/shell_commands/command_executor.py +1127 -0
- autocoder/common/shell_commands/error_recovery.py +541 -0
- autocoder/common/shell_commands/exceptions.py +120 -0
- autocoder/common/shell_commands/interactive_executor.py +476 -0
- autocoder/common/shell_commands/interactive_pexpect_process.py +623 -0
- autocoder/common/shell_commands/interactive_process.py +744 -0
- autocoder/common/shell_commands/interactive_session_manager.py +1014 -0
- autocoder/common/shell_commands/monitoring.py +529 -0
- autocoder/common/shell_commands/process_cleanup.py +386 -0
- autocoder/common/shell_commands/process_manager.py +606 -0
- autocoder/common/shell_commands/test_interactive_pexpect_process.py +281 -0
- autocoder/common/shell_commands/tests/__init__.py +6 -0
- autocoder/common/shell_commands/tests/conftest.py +118 -0
- autocoder/common/shell_commands/tests/test_background_process_notifier.py +703 -0
- autocoder/common/shell_commands/tests/test_command_executor.py +448 -0
- autocoder/common/shell_commands/tests/test_error_recovery.py +305 -0
- autocoder/common/shell_commands/tests/test_exceptions.py +299 -0
- autocoder/common/shell_commands/tests/test_execute_batch.py +588 -0
- autocoder/common/shell_commands/tests/test_indented_batch_commands.py +244 -0
- autocoder/common/shell_commands/tests/test_integration.py +664 -0
- autocoder/common/shell_commands/tests/test_monitoring.py +546 -0
- autocoder/common/shell_commands/tests/test_performance.py +632 -0
- autocoder/common/shell_commands/tests/test_process_cleanup.py +397 -0
- autocoder/common/shell_commands/tests/test_process_manager.py +606 -0
- autocoder/common/shell_commands/tests/test_timeout_config.py +343 -0
- autocoder/common/shell_commands/tests/test_timeout_manager.py +520 -0
- autocoder/common/shell_commands/timeout_config.py +315 -0
- autocoder/common/shell_commands/timeout_manager.py +352 -0
- autocoder/common/terminal_paste/__init__.py +14 -0
- autocoder/common/terminal_paste/demo.py +145 -0
- autocoder/common/terminal_paste/demo_paste_functionality.py +95 -0
- autocoder/common/terminal_paste/paste_handler.py +200 -0
- autocoder/common/terminal_paste/paste_manager.py +118 -0
- autocoder/common/terminal_paste/tests/__init__.py +1 -0
- autocoder/common/terminal_paste/tests/test_paste_handler.py +182 -0
- autocoder/common/terminal_paste/tests/test_paste_manager.py +126 -0
- autocoder/common/terminal_paste/utils.py +163 -0
- autocoder/common/test_autocoder_args.py +232 -0
- autocoder/common/test_env_manager.py +173 -0
- autocoder/common/test_env_manager_integration.py +159 -0
- autocoder/common/text_similarity/__init__.py +9 -0
- autocoder/common/text_similarity/demo.py +216 -0
- autocoder/common/text_similarity/examples.py +266 -0
- autocoder/common/text_similarity/test_text_similarity.py +306 -0
- autocoder/common/text_similarity/text_similarity.py +194 -0
- autocoder/common/text_similarity/utils.py +125 -0
- autocoder/common/todos/__init__.py +61 -0
- autocoder/common/todos/cache/__init__.py +16 -0
- autocoder/common/todos/cache/base_cache.py +89 -0
- autocoder/common/todos/cache/cache_manager.py +228 -0
- autocoder/common/todos/cache/memory_cache.py +225 -0
- autocoder/common/todos/config.py +155 -0
- autocoder/common/todos/exceptions.py +35 -0
- autocoder/common/todos/get_todo_manager.py +161 -0
- autocoder/common/todos/manager.py +537 -0
- autocoder/common/todos/models.py +239 -0
- autocoder/common/todos/storage/__init__.py +14 -0
- autocoder/common/todos/storage/base_storage.py +76 -0
- autocoder/common/todos/storage/file_storage.py +278 -0
- autocoder/common/tokens/counter.py +24 -2
- autocoder/common/tools_manager/__init__.py +17 -0
- autocoder/common/tools_manager/examples.py +162 -0
- autocoder/common/tools_manager/manager.py +385 -0
- autocoder/common/tools_manager/models.py +39 -0
- autocoder/common/tools_manager/test_tools_manager.py +303 -0
- autocoder/common/tools_manager/utils.py +191 -0
- autocoder/common/v2/agent/agentic_callbacks.py +270 -0
- autocoder/common/v2/agent/agentic_edit.py +2699 -1856
- autocoder/common/v2/agent/agentic_edit_change_manager.py +474 -0
- autocoder/common/v2/agent/agentic_edit_tools/__init__.py +35 -1
- autocoder/common/v2/agent/agentic_edit_tools/ac_mod_list_tool_resolver.py +279 -0
- autocoder/common/v2/agent/agentic_edit_tools/ac_mod_write_tool_resolver.py +10 -1
- autocoder/common/v2/agent/agentic_edit_tools/background_task_tool_resolver.py +1167 -0
- autocoder/common/v2/agent/agentic_edit_tools/base_tool_resolver.py +2 -2
- autocoder/common/v2/agent/agentic_edit_tools/conversation_message_ids_read_tool_resolver.py +214 -0
- autocoder/common/v2/agent/agentic_edit_tools/conversation_message_ids_write_tool_resolver.py +299 -0
- autocoder/common/v2/agent/agentic_edit_tools/count_tokens_tool_resolver.py +290 -0
- autocoder/common/v2/agent/agentic_edit_tools/execute_command_tool_resolver.py +564 -29
- autocoder/common/v2/agent/agentic_edit_tools/execute_workflow_tool_resolver.py +485 -0
- autocoder/common/v2/agent/agentic_edit_tools/extract_to_text_tool_resolver.py +225 -0
- autocoder/common/v2/agent/agentic_edit_tools/lint_report.py +79 -0
- autocoder/common/v2/agent/agentic_edit_tools/linter_config_models.py +343 -0
- autocoder/common/v2/agent/agentic_edit_tools/linter_enabled_tool_resolver.py +189 -0
- autocoder/common/v2/agent/agentic_edit_tools/list_files_tool_resolver.py +169 -101
- autocoder/common/v2/agent/agentic_edit_tools/load_extra_document_tool_resolver.py +349 -0
- autocoder/common/v2/agent/agentic_edit_tools/read_file_tool_resolver.py +243 -50
- autocoder/common/v2/agent/agentic_edit_tools/replace_in_file_tool_resolver.py +667 -147
- autocoder/common/v2/agent/agentic_edit_tools/run_named_subagents_tool_resolver.py +691 -0
- autocoder/common/v2/agent/agentic_edit_tools/search_files_tool_resolver.py +410 -86
- autocoder/common/v2/agent/agentic_edit_tools/session_interactive_tool_resolver.py +115 -0
- autocoder/common/v2/agent/agentic_edit_tools/session_start_tool_resolver.py +190 -0
- autocoder/common/v2/agent/agentic_edit_tools/session_stop_tool_resolver.py +76 -0
- autocoder/common/v2/agent/agentic_edit_tools/test_write_to_file_tool_resolver.py +207 -192
- autocoder/common/v2/agent/agentic_edit_tools/todo_read_tool_resolver.py +80 -63
- autocoder/common/v2/agent/agentic_edit_tools/todo_write_tool_resolver.py +237 -233
- autocoder/common/v2/agent/agentic_edit_tools/use_mcp_tool_resolver.py +2 -2
- autocoder/common/v2/agent/agentic_edit_tools/web_crawl_tool_resolver.py +557 -0
- autocoder/common/v2/agent/agentic_edit_tools/web_search_tool_resolver.py +600 -0
- autocoder/common/v2/agent/agentic_edit_tools/write_to_file_tool_resolver.py +56 -121
- autocoder/common/v2/agent/agentic_edit_types.py +343 -9
- autocoder/common/v2/agent/runner/__init__.py +3 -3
- autocoder/common/v2/agent/runner/base_runner.py +12 -26
- autocoder/common/v2/agent/runner/{event_runner.py → file_based_event_runner.py} +3 -2
- autocoder/common/v2/agent/runner/sdk_runner.py +150 -8
- autocoder/common/v2/agent/runner/terminal_runner.py +170 -57
- autocoder/common/v2/agent/runner/tool_display.py +557 -159
- autocoder/common/v2/agent/test_agentic_callbacks.py +265 -0
- autocoder/common/v2/agent/test_agentic_edit.py +194 -0
- autocoder/common/v2/agent/tool_caller/__init__.py +24 -0
- autocoder/common/v2/agent/tool_caller/default_tool_resolver_map.py +135 -0
- autocoder/common/v2/agent/tool_caller/integration_test.py +172 -0
- autocoder/common/v2/agent/tool_caller/plugins/__init__.py +14 -0
- autocoder/common/v2/agent/tool_caller/plugins/base_plugin.py +126 -0
- autocoder/common/v2/agent/tool_caller/plugins/examples/__init__.py +13 -0
- autocoder/common/v2/agent/tool_caller/plugins/examples/logging_plugin.py +164 -0
- autocoder/common/v2/agent/tool_caller/plugins/examples/security_filter_plugin.py +198 -0
- autocoder/common/v2/agent/tool_caller/plugins/plugin_interface.py +141 -0
- autocoder/common/v2/agent/tool_caller/test_tool_caller.py +278 -0
- autocoder/common/v2/agent/tool_caller/tool_call_plugin_manager.py +331 -0
- autocoder/common/v2/agent/tool_caller/tool_caller.py +337 -0
- autocoder/common/v2/agent/tool_caller/usage_example.py +193 -0
- autocoder/common/v2/code_agentic_editblock_manager.py +4 -4
- autocoder/common/v2/code_auto_generate.py +136 -78
- autocoder/common/v2/code_auto_generate_diff.py +135 -79
- autocoder/common/v2/code_auto_generate_editblock.py +174 -99
- autocoder/common/v2/code_auto_generate_strict_diff.py +151 -71
- autocoder/common/v2/code_auto_merge.py +1 -1
- autocoder/common/v2/code_auto_merge_editblock.py +13 -1
- autocoder/common/v2/code_diff_manager.py +3 -3
- autocoder/common/v2/code_editblock_manager.py +4 -14
- autocoder/common/v2/code_manager.py +1 -1
- autocoder/common/v2/code_strict_diff_manager.py +2 -2
- autocoder/common/wrap_llm_hint/__init__.py +10 -0
- autocoder/common/wrap_llm_hint/test_wrap_llm_hint.py +1067 -0
- autocoder/common/wrap_llm_hint/utils.py +432 -0
- autocoder/common/wrap_llm_hint/wrap_llm_hint.py +323 -0
- autocoder/completer/__init__.py +8 -0
- autocoder/completer/command_completer_v2.py +1051 -0
- autocoder/default_project/__init__.py +501 -0
- autocoder/dispacher/__init__.py +4 -12
- autocoder/dispacher/actions/action.py +165 -7
- autocoder/dispacher/actions/plugins/action_regex_project.py +2 -2
- autocoder/index/entry.py +116 -124
- autocoder/{agent → index/filter}/agentic_filter.py +322 -333
- autocoder/index/filter/normal_filter.py +5 -11
- autocoder/index/filter/quick_filter.py +1 -1
- autocoder/index/index.py +36 -9
- autocoder/index/tests/__init__.py +1 -0
- autocoder/index/tests/run_tests.py +195 -0
- autocoder/index/tests/test_entry.py +303 -0
- autocoder/index/tests/test_index_manager.py +314 -0
- autocoder/index/tests/test_module_integration.py +300 -0
- autocoder/index/tests/test_symbols_utils.py +183 -0
- autocoder/inner/__init__.py +4 -0
- autocoder/inner/agentic.py +932 -0
- autocoder/inner/async_command_handler.py +992 -0
- autocoder/inner/conversation_command_handlers.py +623 -0
- autocoder/inner/merge_command_handler.py +213 -0
- autocoder/inner/queue_command_handler.py +684 -0
- autocoder/models.py +95 -266
- autocoder/plugins/git_helper_plugin.py +31 -29
- autocoder/plugins/token_helper_plugin.py +65 -46
- autocoder/pyproject/__init__.py +32 -29
- autocoder/rag/agentic_rag.py +215 -75
- autocoder/rag/cache/simple_cache.py +1 -2
- autocoder/rag/loaders/image_loader.py +1 -1
- autocoder/rag/long_context_rag.py +42 -26
- autocoder/rag/qa_conversation_strategy.py +1 -1
- autocoder/rag/terminal/__init__.py +17 -0
- autocoder/rag/terminal/args.py +581 -0
- autocoder/rag/terminal/bootstrap.py +61 -0
- autocoder/rag/terminal/command_handlers.py +653 -0
- autocoder/rag/terminal/formatters/__init__.py +20 -0
- autocoder/rag/terminal/formatters/base.py +70 -0
- autocoder/rag/terminal/formatters/json_format.py +66 -0
- autocoder/rag/terminal/formatters/stream_json.py +95 -0
- autocoder/rag/terminal/formatters/text.py +28 -0
- autocoder/rag/terminal/init.py +120 -0
- autocoder/rag/terminal/utils.py +106 -0
- autocoder/rag/test_agentic_rag.py +389 -0
- autocoder/rag/test_doc_filter.py +3 -3
- autocoder/rag/test_long_context_rag.py +1 -1
- autocoder/rag/test_token_limiter.py +517 -10
- autocoder/rag/token_counter.py +3 -0
- autocoder/rag/token_limiter.py +19 -15
- autocoder/rag/tools/__init__.py +26 -2
- autocoder/rag/tools/bochaai_example.py +343 -0
- autocoder/rag/tools/bochaai_sdk.py +541 -0
- autocoder/rag/tools/metaso_example.py +268 -0
- autocoder/rag/tools/metaso_sdk.py +417 -0
- autocoder/rag/tools/recall_tool.py +28 -7
- autocoder/rag/tools/run_integration_tests.py +204 -0
- autocoder/rag/tools/test_all_providers.py +318 -0
- autocoder/rag/tools/test_bochaai_integration.py +482 -0
- autocoder/rag/tools/test_final_integration.py +215 -0
- autocoder/rag/tools/test_metaso_integration.py +424 -0
- autocoder/rag/tools/test_metaso_real.py +171 -0
- autocoder/rag/tools/test_web_crawl_tool.py +639 -0
- autocoder/rag/tools/test_web_search_tool.py +509 -0
- autocoder/rag/tools/todo_read_tool.py +202 -0
- autocoder/rag/tools/todo_write_tool.py +412 -0
- autocoder/rag/tools/web_crawl_tool.py +634 -0
- autocoder/rag/tools/web_search_tool.py +558 -0
- autocoder/rag/tools/web_tools_example.py +119 -0
- autocoder/rag/types.py +16 -0
- autocoder/rag/variable_holder.py +4 -2
- autocoder/rags.py +86 -79
- autocoder/regexproject/__init__.py +23 -21
- autocoder/sdk/__init__.py +46 -190
- autocoder/sdk/api.py +370 -0
- autocoder/sdk/async_runner/__init__.py +26 -0
- autocoder/sdk/async_runner/async_executor.py +650 -0
- autocoder/sdk/async_runner/async_handler.py +356 -0
- autocoder/sdk/async_runner/markdown_processor.py +595 -0
- autocoder/sdk/async_runner/task_metadata.py +284 -0
- autocoder/sdk/async_runner/worktree_manager.py +438 -0
- autocoder/sdk/cli/__init__.py +2 -5
- autocoder/sdk/cli/formatters.py +28 -204
- autocoder/sdk/cli/handlers.py +77 -44
- autocoder/sdk/cli/main.py +154 -171
- autocoder/sdk/cli/options.py +95 -22
- autocoder/sdk/constants.py +139 -51
- autocoder/sdk/core/auto_coder_core.py +484 -109
- autocoder/sdk/core/bridge.py +297 -115
- autocoder/sdk/exceptions.py +18 -12
- autocoder/sdk/formatters/__init__.py +19 -0
- autocoder/sdk/formatters/input.py +64 -0
- autocoder/sdk/formatters/output.py +247 -0
- autocoder/sdk/formatters/stream.py +54 -0
- autocoder/sdk/models/__init__.py +6 -5
- autocoder/sdk/models/options.py +55 -18
- autocoder/sdk/utils/formatters.py +27 -195
- autocoder/suffixproject/__init__.py +28 -25
- autocoder/terminal/__init__.py +14 -0
- autocoder/terminal/app.py +454 -0
- autocoder/terminal/args.py +32 -0
- autocoder/terminal/bootstrap.py +178 -0
- autocoder/terminal/command_processor.py +521 -0
- autocoder/terminal/command_registry.py +57 -0
- autocoder/terminal/help.py +97 -0
- autocoder/terminal/tasks/__init__.py +5 -0
- autocoder/terminal/tasks/background.py +77 -0
- autocoder/terminal/tasks/task_event.py +70 -0
- autocoder/terminal/ui/__init__.py +13 -0
- autocoder/terminal/ui/completer.py +268 -0
- autocoder/terminal/ui/keybindings.py +75 -0
- autocoder/terminal/ui/session.py +41 -0
- autocoder/terminal/ui/toolbar.py +64 -0
- autocoder/terminal/utils/__init__.py +13 -0
- autocoder/terminal/utils/errors.py +18 -0
- autocoder/terminal/utils/paths.py +19 -0
- autocoder/terminal/utils/shell.py +43 -0
- autocoder/terminal_v3/__init__.py +10 -0
- autocoder/terminal_v3/app.py +201 -0
- autocoder/terminal_v3/handlers/__init__.py +5 -0
- autocoder/terminal_v3/handlers/command_handler.py +131 -0
- autocoder/terminal_v3/models/__init__.py +6 -0
- autocoder/terminal_v3/models/conversation_buffer.py +214 -0
- autocoder/terminal_v3/models/message.py +50 -0
- autocoder/terminal_v3/models/tool_display.py +247 -0
- autocoder/terminal_v3/ui/__init__.py +7 -0
- autocoder/terminal_v3/ui/keybindings.py +56 -0
- autocoder/terminal_v3/ui/layout.py +141 -0
- autocoder/terminal_v3/ui/styles.py +43 -0
- autocoder/tsproject/__init__.py +23 -23
- autocoder/utils/auto_coder_utils/chat_stream_out.py +1 -1
- autocoder/utils/llms.py +88 -80
- autocoder/utils/math_utils.py +101 -0
- autocoder/utils/model_provider_selector.py +16 -4
- autocoder/utils/operate_config_api.py +33 -5
- autocoder/utils/thread_utils.py +2 -2
- autocoder/version.py +4 -2
- autocoder/workflow_agents/__init__.py +84 -0
- autocoder/workflow_agents/agent.py +143 -0
- autocoder/workflow_agents/exceptions.py +573 -0
- autocoder/workflow_agents/executor.py +489 -0
- autocoder/workflow_agents/loader.py +737 -0
- autocoder/workflow_agents/runner.py +267 -0
- autocoder/workflow_agents/types.py +172 -0
- autocoder/workflow_agents/utils.py +434 -0
- autocoder/workflow_agents/workflow_manager.py +211 -0
- auto_coder-1.0.0.dist-info/METADATA +0 -396
- auto_coder-1.0.0.dist-info/RECORD +0 -442
- auto_coder-1.0.0.dist-info/licenses/LICENSE +0 -201
- autocoder/auto_coder_server.py +0 -672
- autocoder/benchmark.py +0 -138
- autocoder/common/ac_style_command_parser/example.py +0 -7
- autocoder/common/cleaner.py +0 -31
- autocoder/common/command_completer_v2.py +0 -615
- autocoder/common/context_pruner.py +0 -477
- autocoder/common/conversation_pruner.py +0 -132
- autocoder/common/directory_cache/__init__.py +0 -1
- autocoder/common/directory_cache/cache.py +0 -192
- autocoder/common/directory_cache/test_cache.py +0 -190
- autocoder/common/file_checkpoint/examples.py +0 -217
- autocoder/common/llm_friendly_package_example.py +0 -138
- autocoder/common/llm_friendly_package_test.py +0 -63
- autocoder/common/pull_requests/test_module.py +0 -1
- autocoder/common/rulefiles/autocoderrules_utils.py +0 -484
- autocoder/common/text.py +0 -30
- autocoder/common/v2/agent/agentic_edit_tools/list_package_info_tool_resolver.py +0 -42
- autocoder/common/v2/agent/agentic_edit_tools/test_execute_command_tool_resolver.py +0 -70
- autocoder/common/v2/agent/agentic_edit_tools/test_search_files_tool_resolver.py +0 -163
- autocoder/common/v2/agent/agentic_tool_display.py +0 -183
- autocoder/plugins/dynamic_completion_example.py +0 -148
- autocoder/plugins/sample_plugin.py +0 -160
- autocoder/sdk/cli/__main__.py +0 -26
- autocoder/sdk/cli/completion_wrapper.py +0 -38
- autocoder/sdk/cli/install_completion.py +0 -301
- autocoder/sdk/models/messages.py +0 -209
- autocoder/sdk/session/__init__.py +0 -32
- autocoder/sdk/session/session.py +0 -106
- autocoder/sdk/session/session_manager.py +0 -56
- {auto_coder-1.0.0.dist-info → auto_coder-2.0.0.dist-info}/top_level.txt +0 -0
- /autocoder/{sdk/example.py → common/agent_query_queue/__init__.py} +0 -0
|
@@ -0,0 +1,664 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Integration tests for Shell Commands module.
|
|
3
|
+
|
|
4
|
+
This module provides comprehensive integration tests that verify
|
|
5
|
+
the interaction between different components of the shell commands
|
|
6
|
+
system including command execution, process management, timeout
|
|
7
|
+
handling, background processing, and interactive sessions.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import unittest
|
|
11
|
+
import pytest
|
|
12
|
+
import time
|
|
13
|
+
import tempfile
|
|
14
|
+
import os
|
|
15
|
+
import platform
|
|
16
|
+
import threading
|
|
17
|
+
from unittest.mock import patch
|
|
18
|
+
from typing import List, Dict, Any
|
|
19
|
+
|
|
20
|
+
from autocoder.common.shell_commands import (
|
|
21
|
+
CommandExecutor,
|
|
22
|
+
TimeoutConfig,
|
|
23
|
+
execute_command,
|
|
24
|
+
execute_command_background,
|
|
25
|
+
execute_commands,
|
|
26
|
+
get_background_processes,
|
|
27
|
+
get_background_process_info,
|
|
28
|
+
cleanup_background_process,
|
|
29
|
+
InteractiveCommandExecutor,
|
|
30
|
+
execute_interactive,
|
|
31
|
+
create_interactive_shell,
|
|
32
|
+
get_session_manager,
|
|
33
|
+
get_background_process_notifier,
|
|
34
|
+
CommandTimeoutError,
|
|
35
|
+
CommandExecutionError
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class TestBasicIntegration(unittest.TestCase):
|
|
40
|
+
"""Test basic integration between core components."""
|
|
41
|
+
|
|
42
|
+
def setUp(self):
|
|
43
|
+
"""Set up integration test environment."""
|
|
44
|
+
self.temp_dir = tempfile.mkdtemp()
|
|
45
|
+
|
|
46
|
+
def tearDown(self):
|
|
47
|
+
"""Clean up integration test environment."""
|
|
48
|
+
import shutil
|
|
49
|
+
try:
|
|
50
|
+
shutil.rmtree(self.temp_dir)
|
|
51
|
+
except:
|
|
52
|
+
pass
|
|
53
|
+
|
|
54
|
+
def test_command_executor_with_timeout_config(self):
|
|
55
|
+
"""Test CommandExecutor integration with TimeoutConfig."""
|
|
56
|
+
# Create custom timeout configuration
|
|
57
|
+
config = TimeoutConfig(
|
|
58
|
+
default_timeout=5.0,
|
|
59
|
+
cleanup_timeout=2.0,
|
|
60
|
+
grace_period=1.0
|
|
61
|
+
)
|
|
62
|
+
config.set_command_timeout("echo*", 10.0)
|
|
63
|
+
|
|
64
|
+
# Create executor with custom config
|
|
65
|
+
executor = CommandExecutor(config=config, verbose=True)
|
|
66
|
+
|
|
67
|
+
try:
|
|
68
|
+
# Test normal command execution
|
|
69
|
+
exit_code, output = executor.execute("echo 'Hello Integration'")
|
|
70
|
+
self.assertEqual(exit_code, 0)
|
|
71
|
+
self.assertIn("Hello Integration", output)
|
|
72
|
+
|
|
73
|
+
# Test command with specific timeout
|
|
74
|
+
start_time = time.time()
|
|
75
|
+
exit_code, output = executor.execute("echo 'Specific timeout'")
|
|
76
|
+
duration = time.time() - start_time
|
|
77
|
+
|
|
78
|
+
self.assertEqual(exit_code, 0)
|
|
79
|
+
self.assertLess(duration, 10.0) # Should complete quickly
|
|
80
|
+
|
|
81
|
+
finally:
|
|
82
|
+
executor.cleanup()
|
|
83
|
+
|
|
84
|
+
def test_command_executor_with_working_directory(self):
|
|
85
|
+
"""Test CommandExecutor with custom working directory."""
|
|
86
|
+
config = TimeoutConfig(default_timeout=10.0)
|
|
87
|
+
executor = CommandExecutor(config=config)
|
|
88
|
+
|
|
89
|
+
try:
|
|
90
|
+
# Test command in custom directory
|
|
91
|
+
if platform.system() == "Windows":
|
|
92
|
+
exit_code, output = executor.execute("dir", cwd=self.temp_dir)
|
|
93
|
+
else:
|
|
94
|
+
exit_code, output = executor.execute("pwd", cwd=self.temp_dir)
|
|
95
|
+
|
|
96
|
+
self.assertEqual(exit_code, 0)
|
|
97
|
+
if platform.system() != "Windows":
|
|
98
|
+
self.assertIn(self.temp_dir, output)
|
|
99
|
+
|
|
100
|
+
finally:
|
|
101
|
+
executor.cleanup()
|
|
102
|
+
|
|
103
|
+
def test_timeout_integration(self):
|
|
104
|
+
"""Test timeout integration across components."""
|
|
105
|
+
config = TimeoutConfig(default_timeout=2.0)
|
|
106
|
+
executor = CommandExecutor(config=config)
|
|
107
|
+
|
|
108
|
+
try:
|
|
109
|
+
# Test timeout with cleanup
|
|
110
|
+
with self.assertRaises(CommandTimeoutError):
|
|
111
|
+
executor.execute("sleep 5") # Should timeout after 2 seconds
|
|
112
|
+
|
|
113
|
+
finally:
|
|
114
|
+
executor.cleanup()
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class TestBackgroundProcessIntegration(unittest.TestCase):
|
|
118
|
+
"""Test background process integration."""
|
|
119
|
+
|
|
120
|
+
def setUp(self):
|
|
121
|
+
"""Set up background process tests."""
|
|
122
|
+
self.temp_dir = tempfile.mkdtemp()
|
|
123
|
+
|
|
124
|
+
def tearDown(self):
|
|
125
|
+
"""Clean up background process tests."""
|
|
126
|
+
# Clean up any remaining background processes
|
|
127
|
+
try:
|
|
128
|
+
bg_processes = get_background_processes()
|
|
129
|
+
for pid in bg_processes.keys():
|
|
130
|
+
cleanup_background_process(pid)
|
|
131
|
+
except:
|
|
132
|
+
pass
|
|
133
|
+
|
|
134
|
+
import shutil
|
|
135
|
+
try:
|
|
136
|
+
shutil.rmtree(self.temp_dir)
|
|
137
|
+
except:
|
|
138
|
+
pass
|
|
139
|
+
|
|
140
|
+
@pytest.mark.integration
|
|
141
|
+
def test_background_execution_lifecycle(self):
|
|
142
|
+
"""Test complete background execution lifecycle."""
|
|
143
|
+
# Start background process
|
|
144
|
+
info = execute_command_background(
|
|
145
|
+
"python -c \"import time; print('start'); time.sleep(1); print('end')\"",
|
|
146
|
+
cwd=self.temp_dir
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
try:
|
|
150
|
+
self.assertIn("pid", info)
|
|
151
|
+
self.assertIn("command", info)
|
|
152
|
+
pid = info["pid"]
|
|
153
|
+
|
|
154
|
+
# Verify process is tracked
|
|
155
|
+
bg_processes = get_background_processes()
|
|
156
|
+
self.assertIn(pid, bg_processes)
|
|
157
|
+
|
|
158
|
+
# Get process info
|
|
159
|
+
process_info = get_background_process_info(pid)
|
|
160
|
+
self.assertIsNotNone(process_info)
|
|
161
|
+
self.assertEqual(process_info["command"], info["command"])
|
|
162
|
+
|
|
163
|
+
# Wait for completion
|
|
164
|
+
start_time = time.time()
|
|
165
|
+
while time.time() - start_time < 10: # 10 second timeout
|
|
166
|
+
process_info = get_background_process_info(pid)
|
|
167
|
+
if process_info and process_info.get("status") == "completed":
|
|
168
|
+
break
|
|
169
|
+
time.sleep(0.1)
|
|
170
|
+
|
|
171
|
+
# Verify completion
|
|
172
|
+
final_info = get_background_process_info(pid)
|
|
173
|
+
self.assertEqual(final_info["status"], "completed")
|
|
174
|
+
self.assertEqual(final_info["exit_code"], 0)
|
|
175
|
+
|
|
176
|
+
finally:
|
|
177
|
+
# Clean up
|
|
178
|
+
cleanup_background_process(pid)
|
|
179
|
+
|
|
180
|
+
@pytest.mark.integration
|
|
181
|
+
def test_background_process_with_notifier(self):
|
|
182
|
+
"""Test background process integration with notifier."""
|
|
183
|
+
import uuid
|
|
184
|
+
|
|
185
|
+
conv_id = f"test-{uuid.uuid4()}"
|
|
186
|
+
notifier = get_background_process_notifier()
|
|
187
|
+
|
|
188
|
+
try:
|
|
189
|
+
# Start background process
|
|
190
|
+
info = execute_command_background(
|
|
191
|
+
"python -c \"print('notification test')\"",
|
|
192
|
+
cwd=self.temp_dir
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
# Register with notifier
|
|
196
|
+
task_id = notifier.register_process(
|
|
197
|
+
conversation_id=conv_id,
|
|
198
|
+
pid=info["pid"],
|
|
199
|
+
tool_name="test_tool",
|
|
200
|
+
command=info["command"],
|
|
201
|
+
cwd=self.temp_dir
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
# Wait for completion notification
|
|
205
|
+
deadline = time.time() + 10.0
|
|
206
|
+
while time.time() < deadline:
|
|
207
|
+
if notifier.has_messages(conv_id):
|
|
208
|
+
break
|
|
209
|
+
time.sleep(0.1)
|
|
210
|
+
|
|
211
|
+
# Check for messages
|
|
212
|
+
messages = notifier.poll_messages(conv_id)
|
|
213
|
+
self.assertGreater(len(messages), 0)
|
|
214
|
+
|
|
215
|
+
message = messages[0]
|
|
216
|
+
self.assertEqual(message.task_id, task_id)
|
|
217
|
+
self.assertEqual(message.conversation_id, conv_id)
|
|
218
|
+
self.assertIn(message.status, ["completed", "failed"])
|
|
219
|
+
|
|
220
|
+
finally:
|
|
221
|
+
# Clean up
|
|
222
|
+
if 'info' in locals():
|
|
223
|
+
cleanup_background_process(info["pid"])
|
|
224
|
+
|
|
225
|
+
@pytest.mark.integration
|
|
226
|
+
def test_concurrent_background_processes(self):
|
|
227
|
+
"""Test multiple concurrent background processes."""
|
|
228
|
+
processes = []
|
|
229
|
+
|
|
230
|
+
try:
|
|
231
|
+
# Start multiple background processes
|
|
232
|
+
for i in range(3):
|
|
233
|
+
info = execute_command_background(
|
|
234
|
+
f"python -c \"import time; print('process {i}'); time.sleep(0.5)\"",
|
|
235
|
+
cwd=self.temp_dir
|
|
236
|
+
)
|
|
237
|
+
processes.append(info)
|
|
238
|
+
|
|
239
|
+
# Verify all processes are tracked
|
|
240
|
+
bg_processes = get_background_processes()
|
|
241
|
+
for info in processes:
|
|
242
|
+
self.assertIn(info["pid"], bg_processes)
|
|
243
|
+
|
|
244
|
+
# Wait for all to complete
|
|
245
|
+
deadline = time.time() + 15.0
|
|
246
|
+
while time.time() < deadline:
|
|
247
|
+
all_completed = True
|
|
248
|
+
for info in processes:
|
|
249
|
+
process_info = get_background_process_info(info["pid"])
|
|
250
|
+
if not process_info or process_info.get("status") != "completed":
|
|
251
|
+
all_completed = False
|
|
252
|
+
break
|
|
253
|
+
|
|
254
|
+
if all_completed:
|
|
255
|
+
break
|
|
256
|
+
time.sleep(0.1)
|
|
257
|
+
|
|
258
|
+
# Verify all completed successfully
|
|
259
|
+
for info in processes:
|
|
260
|
+
process_info = get_background_process_info(info["pid"])
|
|
261
|
+
self.assertEqual(process_info["status"], "completed")
|
|
262
|
+
self.assertEqual(process_info["exit_code"], 0)
|
|
263
|
+
|
|
264
|
+
finally:
|
|
265
|
+
# Clean up all processes
|
|
266
|
+
for info in processes:
|
|
267
|
+
cleanup_background_process(info["pid"])
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
class TestInteractiveSessionIntegration(unittest.TestCase):
|
|
271
|
+
"""Test interactive session integration."""
|
|
272
|
+
|
|
273
|
+
def setUp(self):
|
|
274
|
+
"""Set up interactive session tests."""
|
|
275
|
+
self.temp_dir = tempfile.mkdtemp()
|
|
276
|
+
|
|
277
|
+
def tearDown(self):
|
|
278
|
+
"""Clean up interactive session tests."""
|
|
279
|
+
# Clean up any remaining sessions
|
|
280
|
+
try:
|
|
281
|
+
manager = get_session_manager()
|
|
282
|
+
manager.cleanup_all()
|
|
283
|
+
except:
|
|
284
|
+
pass
|
|
285
|
+
|
|
286
|
+
import shutil
|
|
287
|
+
try:
|
|
288
|
+
shutil.rmtree(self.temp_dir)
|
|
289
|
+
except:
|
|
290
|
+
pass
|
|
291
|
+
|
|
292
|
+
@pytest.mark.integration
|
|
293
|
+
def test_interactive_session_creation_and_communication(self):
|
|
294
|
+
"""Test creating interactive session and communication."""
|
|
295
|
+
manager = get_session_manager()
|
|
296
|
+
|
|
297
|
+
# Create session
|
|
298
|
+
result = manager.create_session(
|
|
299
|
+
"python -c \"import sys; print('Ready'); sys.stdout.flush(); exec(input())\"",
|
|
300
|
+
cwd=self.temp_dir,
|
|
301
|
+
timeout=30,
|
|
302
|
+
use_pexpect=False
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
try:
|
|
306
|
+
self.assertTrue(result.success, f"Session creation failed: {result.message}")
|
|
307
|
+
session_id = result.content["session_id"]
|
|
308
|
+
|
|
309
|
+
# Send input
|
|
310
|
+
input_result = manager.send_input(session_id, "print('Hello from session')\n")
|
|
311
|
+
self.assertTrue(input_result.success)
|
|
312
|
+
|
|
313
|
+
# Read output
|
|
314
|
+
time.sleep(0.5) # Give time for command to execute
|
|
315
|
+
output_result = manager.read_output(session_id)
|
|
316
|
+
# Output reading might not always succeed depending on timing
|
|
317
|
+
if not output_result.success:
|
|
318
|
+
print(f"Output read failed: {output_result.message}")
|
|
319
|
+
# Don't assert success as it may depend on timing
|
|
320
|
+
|
|
321
|
+
finally:
|
|
322
|
+
if result.success:
|
|
323
|
+
manager.terminate_session(result.content["session_id"])
|
|
324
|
+
|
|
325
|
+
@pytest.mark.integration
|
|
326
|
+
@pytest.mark.skipif(platform.system() == "Windows", reason="Shell behavior different on Windows")
|
|
327
|
+
def test_interactive_shell_integration(self):
|
|
328
|
+
"""Test interactive shell integration."""
|
|
329
|
+
session = create_interactive_shell(timeout=30)
|
|
330
|
+
|
|
331
|
+
try:
|
|
332
|
+
self.assertIsNotNone(session)
|
|
333
|
+
self.assertTrue(session.process.is_alive())
|
|
334
|
+
|
|
335
|
+
# Send command
|
|
336
|
+
session.process.write("echo 'shell test'\n")
|
|
337
|
+
|
|
338
|
+
# Read output
|
|
339
|
+
time.sleep(0.5)
|
|
340
|
+
output = session.process.read_output(timeout=2.0)
|
|
341
|
+
|
|
342
|
+
# Output might contain shell control characters
|
|
343
|
+
if output:
|
|
344
|
+
# Clean the output and check for our test string
|
|
345
|
+
clean_output = output.replace('\x1b', '').replace('\r', '').replace('%', '')
|
|
346
|
+
if "shell test" not in clean_output:
|
|
347
|
+
print(f"Unexpected output: {repr(output)}")
|
|
348
|
+
# Don't fail the test as shell output can vary
|
|
349
|
+
|
|
350
|
+
finally:
|
|
351
|
+
session.terminate()
|
|
352
|
+
|
|
353
|
+
@pytest.mark.integration
|
|
354
|
+
def test_multiple_interactive_sessions(self):
|
|
355
|
+
"""Test managing multiple interactive sessions."""
|
|
356
|
+
executor = InteractiveCommandExecutor()
|
|
357
|
+
sessions = []
|
|
358
|
+
|
|
359
|
+
try:
|
|
360
|
+
# Create multiple sessions
|
|
361
|
+
for i in range(3):
|
|
362
|
+
session = executor.execute_interactive(
|
|
363
|
+
f"python -c \"print('session {i}'); import time; time.sleep(1)\"",
|
|
364
|
+
timeout=10
|
|
365
|
+
)
|
|
366
|
+
sessions.append(session)
|
|
367
|
+
|
|
368
|
+
# Verify all sessions are active
|
|
369
|
+
session_list = executor.list_sessions()
|
|
370
|
+
self.assertEqual(len(session_list), 3)
|
|
371
|
+
|
|
372
|
+
# Verify each session has unique ID
|
|
373
|
+
session_ids = [s["session_id"] for s in session_list]
|
|
374
|
+
self.assertEqual(len(session_ids), len(set(session_ids)))
|
|
375
|
+
|
|
376
|
+
finally:
|
|
377
|
+
# Clean up all sessions
|
|
378
|
+
executor.cleanup()
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
class TestBatchExecutionIntegration(unittest.TestCase):
|
|
382
|
+
"""Test batch execution integration."""
|
|
383
|
+
|
|
384
|
+
def setUp(self):
|
|
385
|
+
"""Set up batch execution tests."""
|
|
386
|
+
self.temp_dir = tempfile.mkdtemp()
|
|
387
|
+
|
|
388
|
+
def tearDown(self):
|
|
389
|
+
"""Clean up batch execution tests."""
|
|
390
|
+
import shutil
|
|
391
|
+
try:
|
|
392
|
+
shutil.rmtree(self.temp_dir)
|
|
393
|
+
except:
|
|
394
|
+
pass
|
|
395
|
+
|
|
396
|
+
@pytest.mark.integration
|
|
397
|
+
def test_batch_parallel_execution(self):
|
|
398
|
+
"""Test parallel batch execution."""
|
|
399
|
+
commands = [
|
|
400
|
+
"echo 'Task 1'",
|
|
401
|
+
"echo 'Task 2'",
|
|
402
|
+
"echo 'Task 3'"
|
|
403
|
+
]
|
|
404
|
+
|
|
405
|
+
start_time = time.time()
|
|
406
|
+
results = execute_commands(commands, parallel=True, timeout=10.0)
|
|
407
|
+
duration = time.time() - start_time
|
|
408
|
+
|
|
409
|
+
# Verify results
|
|
410
|
+
self.assertEqual(len(results), 3)
|
|
411
|
+
|
|
412
|
+
for i, result in enumerate(results):
|
|
413
|
+
self.assertEqual(result["index"], i)
|
|
414
|
+
self.assertEqual(result["exit_code"], 0)
|
|
415
|
+
self.assertIn(f"Task {i+1}", result["output"])
|
|
416
|
+
self.assertFalse(result["timed_out"])
|
|
417
|
+
|
|
418
|
+
# Parallel execution should be faster than serial
|
|
419
|
+
self.assertLess(duration, 5.0)
|
|
420
|
+
|
|
421
|
+
@pytest.mark.integration
|
|
422
|
+
def test_batch_serial_execution(self):
|
|
423
|
+
"""Test serial batch execution."""
|
|
424
|
+
commands = [
|
|
425
|
+
"echo 'Step 1'",
|
|
426
|
+
"echo 'Step 2'",
|
|
427
|
+
"echo 'Step 3'"
|
|
428
|
+
]
|
|
429
|
+
|
|
430
|
+
results = execute_commands(commands, parallel=False, timeout=10.0)
|
|
431
|
+
|
|
432
|
+
# Verify results are in order
|
|
433
|
+
self.assertEqual(len(results), 3)
|
|
434
|
+
|
|
435
|
+
for i, result in enumerate(results):
|
|
436
|
+
self.assertEqual(result["index"], i)
|
|
437
|
+
self.assertEqual(result["exit_code"], 0)
|
|
438
|
+
self.assertIn(f"Step {i+1}", result["output"])
|
|
439
|
+
|
|
440
|
+
@pytest.mark.integration
|
|
441
|
+
def test_batch_with_failures(self):
|
|
442
|
+
"""Test batch execution with some failures."""
|
|
443
|
+
commands = [
|
|
444
|
+
"echo 'Success'",
|
|
445
|
+
"python -c \"import sys; sys.exit(1)\"", # This will fail
|
|
446
|
+
"echo 'Another success'"
|
|
447
|
+
]
|
|
448
|
+
|
|
449
|
+
results = execute_commands(commands, parallel=True, timeout=10.0)
|
|
450
|
+
|
|
451
|
+
# Verify mixed results
|
|
452
|
+
self.assertEqual(len(results), 3)
|
|
453
|
+
self.assertEqual(results[0]["exit_code"], 0) # Success
|
|
454
|
+
self.assertEqual(results[1]["exit_code"], 1) # Failure
|
|
455
|
+
self.assertEqual(results[2]["exit_code"], 0) # Success
|
|
456
|
+
|
|
457
|
+
@pytest.mark.integration
|
|
458
|
+
def test_batch_with_timeout(self):
|
|
459
|
+
"""Test batch execution with timeouts."""
|
|
460
|
+
commands = [
|
|
461
|
+
"echo 'Quick task'",
|
|
462
|
+
"python -c \"import time; time.sleep(5)\"", # This will timeout
|
|
463
|
+
"echo 'Another quick task'"
|
|
464
|
+
]
|
|
465
|
+
|
|
466
|
+
results = execute_commands(
|
|
467
|
+
commands,
|
|
468
|
+
parallel=True,
|
|
469
|
+
per_command_timeout=1.0, # Short timeout
|
|
470
|
+
timeout=10.0
|
|
471
|
+
)
|
|
472
|
+
|
|
473
|
+
# Verify timeout behavior
|
|
474
|
+
self.assertEqual(len(results), 3)
|
|
475
|
+
self.assertEqual(results[0]["exit_code"], 0) # Should succeed
|
|
476
|
+
self.assertTrue(results[1]["timed_out"]) # Should timeout
|
|
477
|
+
self.assertEqual(results[2]["exit_code"], 0) # Should succeed
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
class TestErrorHandlingIntegration(unittest.TestCase):
|
|
481
|
+
"""Test error handling integration across components."""
|
|
482
|
+
|
|
483
|
+
def setUp(self):
|
|
484
|
+
"""Set up error handling tests."""
|
|
485
|
+
self.temp_dir = tempfile.mkdtemp()
|
|
486
|
+
|
|
487
|
+
def tearDown(self):
|
|
488
|
+
"""Clean up error handling tests."""
|
|
489
|
+
import shutil
|
|
490
|
+
try:
|
|
491
|
+
shutil.rmtree(self.temp_dir)
|
|
492
|
+
except:
|
|
493
|
+
pass
|
|
494
|
+
|
|
495
|
+
def test_timeout_error_propagation(self):
|
|
496
|
+
"""Test timeout error propagation through components."""
|
|
497
|
+
config = TimeoutConfig(default_timeout=1.0)
|
|
498
|
+
executor = CommandExecutor(config=config)
|
|
499
|
+
|
|
500
|
+
try:
|
|
501
|
+
with self.assertRaises(CommandTimeoutError) as cm:
|
|
502
|
+
executor.execute("python -c \"import time; time.sleep(5)\"")
|
|
503
|
+
|
|
504
|
+
# Verify error details
|
|
505
|
+
error = cm.exception
|
|
506
|
+
self.assertIn("python", error.command)
|
|
507
|
+
self.assertEqual(error.timeout, 1.0)
|
|
508
|
+
self.assertIsNotNone(error.pid)
|
|
509
|
+
|
|
510
|
+
finally:
|
|
511
|
+
executor.cleanup()
|
|
512
|
+
|
|
513
|
+
def test_invalid_command_error_handling(self):
|
|
514
|
+
"""Test handling of invalid commands."""
|
|
515
|
+
executor = CommandExecutor()
|
|
516
|
+
|
|
517
|
+
try:
|
|
518
|
+
# On macOS, invalid commands may not always raise exceptions
|
|
519
|
+
# They might return with exit code 127 instead
|
|
520
|
+
exit_code, output = executor.execute("/nonexistent/command/that/does/not/exist")
|
|
521
|
+
# If no exception is raised, check that exit code indicates failure
|
|
522
|
+
self.assertNotEqual(exit_code, 0, "Invalid command should not succeed")
|
|
523
|
+
|
|
524
|
+
finally:
|
|
525
|
+
executor.cleanup()
|
|
526
|
+
|
|
527
|
+
def test_background_process_error_handling(self):
|
|
528
|
+
"""Test error handling in background processes."""
|
|
529
|
+
# Start a background process that will fail
|
|
530
|
+
info = execute_command_background(
|
|
531
|
+
"python -c \"import sys; sys.exit(42)\"", # Exit with code 42
|
|
532
|
+
cwd=self.temp_dir
|
|
533
|
+
)
|
|
534
|
+
|
|
535
|
+
try:
|
|
536
|
+
pid = info["pid"]
|
|
537
|
+
|
|
538
|
+
# Wait for completion
|
|
539
|
+
deadline = time.time() + 10.0
|
|
540
|
+
while time.time() < deadline:
|
|
541
|
+
process_info = get_background_process_info(pid)
|
|
542
|
+
if process_info and process_info.get("status") == "completed":
|
|
543
|
+
break
|
|
544
|
+
time.sleep(0.1)
|
|
545
|
+
|
|
546
|
+
# Verify error is captured
|
|
547
|
+
final_info = get_background_process_info(pid)
|
|
548
|
+
self.assertEqual(final_info["status"], "completed")
|
|
549
|
+
self.assertEqual(final_info["exit_code"], 42)
|
|
550
|
+
|
|
551
|
+
finally:
|
|
552
|
+
cleanup_background_process(pid)
|
|
553
|
+
|
|
554
|
+
|
|
555
|
+
class TestConcurrencyIntegration(unittest.TestCase):
|
|
556
|
+
"""Test concurrency integration across components."""
|
|
557
|
+
|
|
558
|
+
def setUp(self):
|
|
559
|
+
"""Set up concurrency tests."""
|
|
560
|
+
self.temp_dir = tempfile.mkdtemp()
|
|
561
|
+
|
|
562
|
+
def tearDown(self):
|
|
563
|
+
"""Clean up concurrency tests."""
|
|
564
|
+
import shutil
|
|
565
|
+
try:
|
|
566
|
+
shutil.rmtree(self.temp_dir)
|
|
567
|
+
except:
|
|
568
|
+
pass
|
|
569
|
+
|
|
570
|
+
@pytest.mark.integration
|
|
571
|
+
def test_concurrent_command_execution(self):
|
|
572
|
+
"""Test concurrent command execution."""
|
|
573
|
+
config = TimeoutConfig(default_timeout=10.0)
|
|
574
|
+
results = []
|
|
575
|
+
threads = []
|
|
576
|
+
|
|
577
|
+
def execute_command_thread(index):
|
|
578
|
+
try:
|
|
579
|
+
executor = CommandExecutor(config=config)
|
|
580
|
+
exit_code, output = executor.execute(f"echo 'Thread {index}'")
|
|
581
|
+
results.append((index, exit_code, output))
|
|
582
|
+
executor.cleanup()
|
|
583
|
+
except Exception as e:
|
|
584
|
+
results.append((index, -1, str(e)))
|
|
585
|
+
|
|
586
|
+
# Start multiple concurrent executions
|
|
587
|
+
for i in range(5):
|
|
588
|
+
thread = threading.Thread(target=execute_command_thread, args=(i,))
|
|
589
|
+
threads.append(thread)
|
|
590
|
+
thread.start()
|
|
591
|
+
|
|
592
|
+
# Wait for all threads
|
|
593
|
+
for thread in threads:
|
|
594
|
+
thread.join(timeout=15.0)
|
|
595
|
+
|
|
596
|
+
# Verify all completed successfully
|
|
597
|
+
self.assertEqual(len(results), 5)
|
|
598
|
+
for index, exit_code, output in results:
|
|
599
|
+
self.assertEqual(exit_code, 0)
|
|
600
|
+
self.assertIn(f"Thread {index}", output)
|
|
601
|
+
|
|
602
|
+
@pytest.mark.integration
|
|
603
|
+
def test_concurrent_background_processes(self):
|
|
604
|
+
"""Test concurrent background process management."""
|
|
605
|
+
processes = []
|
|
606
|
+
threads = []
|
|
607
|
+
|
|
608
|
+
def start_background_process(index):
|
|
609
|
+
try:
|
|
610
|
+
info = execute_command_background(
|
|
611
|
+
f"python -c \"import time; print('BG {index}'); time.sleep(0.5)\"",
|
|
612
|
+
cwd=self.temp_dir
|
|
613
|
+
)
|
|
614
|
+
processes.append(info)
|
|
615
|
+
except Exception as e:
|
|
616
|
+
processes.append({"error": str(e), "index": index})
|
|
617
|
+
|
|
618
|
+
# Start multiple background processes concurrently
|
|
619
|
+
for i in range(3):
|
|
620
|
+
thread = threading.Thread(target=start_background_process, args=(i,))
|
|
621
|
+
threads.append(thread)
|
|
622
|
+
thread.start()
|
|
623
|
+
|
|
624
|
+
# Wait for all threads
|
|
625
|
+
for thread in threads:
|
|
626
|
+
thread.join(timeout=10.0)
|
|
627
|
+
|
|
628
|
+
try:
|
|
629
|
+
# Verify all processes started
|
|
630
|
+
self.assertEqual(len(processes), 3)
|
|
631
|
+
for info in processes:
|
|
632
|
+
self.assertNotIn("error", info)
|
|
633
|
+
self.assertIn("pid", info)
|
|
634
|
+
|
|
635
|
+
# Wait for all to complete
|
|
636
|
+
deadline = time.time() + 15.0
|
|
637
|
+
while time.time() < deadline:
|
|
638
|
+
all_completed = True
|
|
639
|
+
for info in processes:
|
|
640
|
+
if "pid" in info:
|
|
641
|
+
process_info = get_background_process_info(info["pid"])
|
|
642
|
+
if not process_info or process_info.get("status") != "completed":
|
|
643
|
+
all_completed = False
|
|
644
|
+
break
|
|
645
|
+
|
|
646
|
+
if all_completed:
|
|
647
|
+
break
|
|
648
|
+
time.sleep(0.1)
|
|
649
|
+
|
|
650
|
+
# Verify all completed
|
|
651
|
+
for info in processes:
|
|
652
|
+
if "pid" in info:
|
|
653
|
+
process_info = get_background_process_info(info["pid"])
|
|
654
|
+
self.assertEqual(process_info["status"], "completed")
|
|
655
|
+
|
|
656
|
+
finally:
|
|
657
|
+
# Clean up
|
|
658
|
+
for info in processes:
|
|
659
|
+
if "pid" in info:
|
|
660
|
+
cleanup_background_process(info["pid"])
|
|
661
|
+
|
|
662
|
+
|
|
663
|
+
if __name__ == "__main__":
|
|
664
|
+
unittest.main()
|