auto-coder 1.0.0__py3-none-any.whl → 2.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of auto-coder might be problematic. Click here for more details.
- auto_coder-2.0.1.dist-info/LICENSE +158 -0
- auto_coder-2.0.1.dist-info/METADATA +558 -0
- auto_coder-2.0.1.dist-info/RECORD +795 -0
- {auto_coder-1.0.0.dist-info → auto_coder-2.0.1.dist-info}/WHEEL +1 -1
- {auto_coder-1.0.0.dist-info → auto_coder-2.0.1.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 +77 -73
- autocoder/auto_coder.py +31 -40
- autocoder/auto_coder_rag.py +11 -1084
- autocoder/auto_coder_runner.py +962 -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 +409 -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 +316 -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 +356 -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 +1094 -0
- autocoder/default_project/__init__.py +501 -0
- autocoder/dispacher/__init__.py +4 -12
- autocoder/dispacher/actions/action.py +400 -129
- autocoder/dispacher/actions/plugins/action_regex_project.py +2 -2
- autocoder/index/entry.py +117 -125
- 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 +923 -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 +665 -0
- autocoder/workflow_agents/loader.py +749 -0
- autocoder/workflow_agents/runner.py +267 -0
- autocoder/workflow_agents/types.py +173 -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.1.dist-info}/top_level.txt +0 -0
- /autocoder/{sdk/example.py → common/agent_query_queue/__init__.py} +0 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
"""Tests for paste_handler functionality."""
|
|
2
|
+
|
|
3
|
+
import unittest
|
|
4
|
+
from unittest.mock import Mock, patch, MagicMock
|
|
5
|
+
from autocoder.common.terminal_paste.paste_handler import (
|
|
6
|
+
register_paste_handler,
|
|
7
|
+
resolve_paste_placeholders,
|
|
8
|
+
get_paste_manager,
|
|
9
|
+
PLACEHOLDER_PATTERN
|
|
10
|
+
)
|
|
11
|
+
from prompt_toolkit.key_binding import KeyBindings
|
|
12
|
+
from prompt_toolkit.clipboard import ClipboardData
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class TestPasteHandler(unittest.TestCase):
|
|
16
|
+
"""Test cases for paste handler functionality."""
|
|
17
|
+
|
|
18
|
+
def setUp(self):
|
|
19
|
+
"""Set up test environment."""
|
|
20
|
+
# Reset global paste manager
|
|
21
|
+
import autocoder.common.terminal_paste.paste_handler
|
|
22
|
+
autocoder.common.terminal_paste.paste_handler._paste_manager = None
|
|
23
|
+
|
|
24
|
+
def test_register_paste_handler_no_error(self):
|
|
25
|
+
"""Test that register_paste_handler runs without error."""
|
|
26
|
+
kb = KeyBindings()
|
|
27
|
+
# This should not raise any exception
|
|
28
|
+
register_paste_handler(kb)
|
|
29
|
+
|
|
30
|
+
# Verify that a key binding was registered
|
|
31
|
+
self.assertTrue(len(kb.bindings) > 0)
|
|
32
|
+
|
|
33
|
+
# Check that the binding is for 'c-p'
|
|
34
|
+
binding_found = False
|
|
35
|
+
for binding in kb.bindings:
|
|
36
|
+
if binding.keys == ('c-p',):
|
|
37
|
+
binding_found = True
|
|
38
|
+
break
|
|
39
|
+
self.assertTrue(binding_found, "Ctrl+P binding not found")
|
|
40
|
+
|
|
41
|
+
def test_paste_handler_single_line(self):
|
|
42
|
+
"""Test paste handler with single-line content."""
|
|
43
|
+
kb = KeyBindings()
|
|
44
|
+
register_paste_handler(kb)
|
|
45
|
+
|
|
46
|
+
# Create mock event
|
|
47
|
+
mock_event = Mock()
|
|
48
|
+
mock_app = Mock()
|
|
49
|
+
mock_buffer = Mock()
|
|
50
|
+
mock_clipboard_data = Mock()
|
|
51
|
+
mock_clipboard_data.text = "single line text"
|
|
52
|
+
|
|
53
|
+
mock_event.app = mock_app
|
|
54
|
+
mock_event.current_buffer = mock_buffer
|
|
55
|
+
mock_app.clipboard.get_data.return_value = mock_clipboard_data
|
|
56
|
+
|
|
57
|
+
# Find and execute the paste handler
|
|
58
|
+
paste_handler = None
|
|
59
|
+
for binding in kb.bindings:
|
|
60
|
+
if binding.keys == ('c-p',):
|
|
61
|
+
paste_handler = binding.handler
|
|
62
|
+
break
|
|
63
|
+
|
|
64
|
+
self.assertIsNotNone(paste_handler)
|
|
65
|
+
|
|
66
|
+
# Execute the handler (we know it's not None due to assertion above)
|
|
67
|
+
if paste_handler:
|
|
68
|
+
paste_handler(mock_event)
|
|
69
|
+
|
|
70
|
+
# Verify single line was pasted normally
|
|
71
|
+
mock_buffer.insert_text.assert_called_once_with("single line text")
|
|
72
|
+
|
|
73
|
+
def test_paste_handler_multi_line(self):
|
|
74
|
+
"""Test paste handler with multi-line content."""
|
|
75
|
+
kb = KeyBindings()
|
|
76
|
+
register_paste_handler(kb)
|
|
77
|
+
|
|
78
|
+
# Create mock event
|
|
79
|
+
mock_event = Mock()
|
|
80
|
+
mock_app = Mock()
|
|
81
|
+
mock_buffer = Mock()
|
|
82
|
+
mock_clipboard_data = Mock()
|
|
83
|
+
mock_clipboard_data.text = "line 1\nline 2\nline 3"
|
|
84
|
+
|
|
85
|
+
mock_event.app = mock_app
|
|
86
|
+
mock_event.current_buffer = mock_buffer
|
|
87
|
+
mock_app.clipboard.get_data.return_value = mock_clipboard_data
|
|
88
|
+
|
|
89
|
+
# Mock the paste manager
|
|
90
|
+
with patch('autocoder.common.terminal_paste.paste_handler.get_paste_manager') as mock_get_paste_manager:
|
|
91
|
+
mock_paste_manager = Mock()
|
|
92
|
+
mock_paste_manager.save_paste.return_value = "pasted-abc123def45678901234567890123456"
|
|
93
|
+
mock_get_paste_manager.return_value = mock_paste_manager
|
|
94
|
+
|
|
95
|
+
# Find and execute the paste handler
|
|
96
|
+
paste_handler = None
|
|
97
|
+
for binding in kb.bindings:
|
|
98
|
+
if binding.keys == ('c-p',):
|
|
99
|
+
paste_handler = binding.handler
|
|
100
|
+
break
|
|
101
|
+
|
|
102
|
+
self.assertIsNotNone(paste_handler)
|
|
103
|
+
|
|
104
|
+
# Execute the handler (we know it's not None due to assertion above)
|
|
105
|
+
if paste_handler:
|
|
106
|
+
paste_handler(mock_event)
|
|
107
|
+
|
|
108
|
+
# Verify multi-line content was saved and placeholder inserted
|
|
109
|
+
mock_paste_manager.save_paste.assert_called_once_with("line 1\nline 2\nline 3")
|
|
110
|
+
mock_buffer.insert_text.assert_called_once_with("[pasted-abc123def45678901234567890123456]")
|
|
111
|
+
|
|
112
|
+
def test_get_paste_manager(self):
|
|
113
|
+
"""Test that get_paste_manager returns a PasteManager instance."""
|
|
114
|
+
manager = get_paste_manager()
|
|
115
|
+
self.assertIsNotNone(manager)
|
|
116
|
+
|
|
117
|
+
# Test that it returns the same instance on subsequent calls
|
|
118
|
+
manager2 = get_paste_manager()
|
|
119
|
+
self.assertIs(manager, manager2)
|
|
120
|
+
|
|
121
|
+
def test_resolve_paste_placeholders_no_placeholders(self):
|
|
122
|
+
"""Test resolving text without placeholders."""
|
|
123
|
+
text = "This is normal text without placeholders"
|
|
124
|
+
result = resolve_paste_placeholders(text)
|
|
125
|
+
self.assertEqual(result, text)
|
|
126
|
+
|
|
127
|
+
def test_resolve_paste_placeholders_with_placeholder(self):
|
|
128
|
+
"""Test resolving text with placeholders."""
|
|
129
|
+
with patch('autocoder.common.terminal_paste.paste_handler.get_paste_manager') as mock_get_paste_manager:
|
|
130
|
+
mock_paste_manager = Mock()
|
|
131
|
+
mock_paste_manager.read_paste.return_value = "Hello World"
|
|
132
|
+
mock_get_paste_manager.return_value = mock_paste_manager
|
|
133
|
+
|
|
134
|
+
text_with_placeholder = "Say [pasted-abc123def45678901234567890123456]"
|
|
135
|
+
result = resolve_paste_placeholders(text_with_placeholder)
|
|
136
|
+
|
|
137
|
+
expected = "Say Hello World"
|
|
138
|
+
self.assertEqual(result, expected)
|
|
139
|
+
mock_paste_manager.read_paste.assert_called_once_with("pasted-abc123def45678901234567890123456")
|
|
140
|
+
|
|
141
|
+
def test_resolve_multiple_placeholders(self):
|
|
142
|
+
"""Test resolving multiple placeholders in one text."""
|
|
143
|
+
with patch('autocoder.common.terminal_paste.paste_handler.get_paste_manager') as mock_get_paste_manager:
|
|
144
|
+
mock_paste_manager = Mock()
|
|
145
|
+
# The resolve function calls read_paste with "pasted-" + file_id
|
|
146
|
+
mock_paste_manager.read_paste.side_effect = lambda file_id: {
|
|
147
|
+
"pasted-abc123def45678901234567890123456": "Hello",
|
|
148
|
+
"pasted-def456abc78901234567890123456abc": "World"
|
|
149
|
+
}.get(file_id, "Not found")
|
|
150
|
+
mock_get_paste_manager.return_value = mock_paste_manager
|
|
151
|
+
|
|
152
|
+
# Test with multiple placeholders (both 32 chars)
|
|
153
|
+
text_with_placeholders = "Say [pasted-abc123def45678901234567890123456] [pasted-def456abc78901234567890123456abc]!"
|
|
154
|
+
result = resolve_paste_placeholders(text_with_placeholders)
|
|
155
|
+
|
|
156
|
+
expected = "Say Hello World!"
|
|
157
|
+
self.assertEqual(result, expected)
|
|
158
|
+
|
|
159
|
+
def test_placeholder_pattern_regex(self):
|
|
160
|
+
"""Test that the placeholder pattern matches correctly."""
|
|
161
|
+
# Test valid placeholder
|
|
162
|
+
valid_placeholder = "[pasted-abc123def45678901234567890123456]"
|
|
163
|
+
match = PLACEHOLDER_PATTERN.search(valid_placeholder)
|
|
164
|
+
self.assertIsNotNone(match)
|
|
165
|
+
if match: # Fix linter error by checking match is not None
|
|
166
|
+
self.assertEqual(match.group(1), "abc123def45678901234567890123456")
|
|
167
|
+
|
|
168
|
+
# Test invalid placeholders
|
|
169
|
+
invalid_placeholders = [
|
|
170
|
+
"[pasted-short]", # Too short
|
|
171
|
+
"[pasted-abc123def45678901234567890123456extra]", # Too long
|
|
172
|
+
"[pasted-abc123def45678901234567890123456X]", # Contains invalid character
|
|
173
|
+
"pasted-abc123def45678901234567890123456", # Missing brackets
|
|
174
|
+
]
|
|
175
|
+
|
|
176
|
+
for invalid in invalid_placeholders:
|
|
177
|
+
match = PLACEHOLDER_PATTERN.search(invalid)
|
|
178
|
+
self.assertIsNone(match, f"Pattern should not match: {invalid}")
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
if __name__ == '__main__':
|
|
182
|
+
unittest.main()
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"""Tests for PasteManager."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import tempfile
|
|
5
|
+
import shutil
|
|
6
|
+
import unittest
|
|
7
|
+
from unittest.mock import patch
|
|
8
|
+
from autocoder.common.terminal_paste.paste_manager import PasteManager
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class TestPasteManager(unittest.TestCase):
|
|
12
|
+
"""Test cases for PasteManager."""
|
|
13
|
+
|
|
14
|
+
def setUp(self):
|
|
15
|
+
"""Set up test environment."""
|
|
16
|
+
self.temp_dir = tempfile.mkdtemp()
|
|
17
|
+
self.paste_manager = PasteManager(self.temp_dir)
|
|
18
|
+
|
|
19
|
+
def tearDown(self):
|
|
20
|
+
"""Clean up test environment."""
|
|
21
|
+
shutil.rmtree(self.temp_dir)
|
|
22
|
+
|
|
23
|
+
def test_initialization(self):
|
|
24
|
+
"""Test PasteManager initialization."""
|
|
25
|
+
# Test with custom directory
|
|
26
|
+
manager = PasteManager(self.temp_dir)
|
|
27
|
+
expected_paste_dir = os.path.join(self.temp_dir, ".auto-coder", "pastes")
|
|
28
|
+
self.assertEqual(manager.paste_dir, expected_paste_dir)
|
|
29
|
+
self.assertTrue(os.path.exists(expected_paste_dir))
|
|
30
|
+
|
|
31
|
+
# Test with default directory (current working directory)
|
|
32
|
+
with patch('os.getcwd', return_value=self.temp_dir):
|
|
33
|
+
manager = PasteManager()
|
|
34
|
+
self.assertEqual(manager.paste_dir, expected_paste_dir)
|
|
35
|
+
|
|
36
|
+
def test_save_paste(self):
|
|
37
|
+
"""Test saving paste content."""
|
|
38
|
+
content = "Hello, World!\nThis is a test paste."
|
|
39
|
+
file_id = self.paste_manager.save_paste(content)
|
|
40
|
+
|
|
41
|
+
# Check file ID format
|
|
42
|
+
self.assertTrue(file_id.startswith("pasted-"))
|
|
43
|
+
self.assertEqual(len(file_id), 39) # "pasted-" + 32 hex chars
|
|
44
|
+
|
|
45
|
+
# Check file exists and content is correct
|
|
46
|
+
file_path = os.path.join(self.paste_manager.paste_dir, file_id)
|
|
47
|
+
self.assertTrue(os.path.exists(file_path))
|
|
48
|
+
|
|
49
|
+
with open(file_path, "r", encoding="utf-8") as f:
|
|
50
|
+
saved_content = f.read()
|
|
51
|
+
self.assertEqual(saved_content, content)
|
|
52
|
+
|
|
53
|
+
def test_read_paste(self):
|
|
54
|
+
"""Test reading paste content."""
|
|
55
|
+
content = "Test content for reading"
|
|
56
|
+
file_id = self.paste_manager.save_paste(content)
|
|
57
|
+
|
|
58
|
+
# Test reading with full file ID
|
|
59
|
+
read_content = self.paste_manager.read_paste(file_id)
|
|
60
|
+
self.assertEqual(read_content, content)
|
|
61
|
+
|
|
62
|
+
# Test reading with UUID only (without "pasted-" prefix)
|
|
63
|
+
uuid_only = file_id[7:] # Remove "pasted-" prefix
|
|
64
|
+
read_content = self.paste_manager.read_paste(uuid_only)
|
|
65
|
+
self.assertEqual(read_content, content)
|
|
66
|
+
|
|
67
|
+
# Test reading non-existent file
|
|
68
|
+
non_existent = self.paste_manager.read_paste("pasted-nonexistent")
|
|
69
|
+
self.assertIsNone(non_existent)
|
|
70
|
+
|
|
71
|
+
def test_list_pastes(self):
|
|
72
|
+
"""Test listing paste files."""
|
|
73
|
+
# Initially empty
|
|
74
|
+
pastes = self.paste_manager.list_pastes()
|
|
75
|
+
self.assertEqual(len(pastes), 0)
|
|
76
|
+
|
|
77
|
+
# Add some pastes
|
|
78
|
+
content1 = "First paste"
|
|
79
|
+
content2 = "Second paste"
|
|
80
|
+
file_id1 = self.paste_manager.save_paste(content1)
|
|
81
|
+
file_id2 = self.paste_manager.save_paste(content2)
|
|
82
|
+
|
|
83
|
+
pastes = self.paste_manager.list_pastes()
|
|
84
|
+
self.assertEqual(len(pastes), 2)
|
|
85
|
+
self.assertIn(file_id1, pastes)
|
|
86
|
+
self.assertIn(file_id2, pastes)
|
|
87
|
+
|
|
88
|
+
# Check sorting
|
|
89
|
+
self.assertEqual(pastes, sorted(pastes))
|
|
90
|
+
|
|
91
|
+
def test_cleanup_old_pastes(self):
|
|
92
|
+
"""Test cleaning up old paste files."""
|
|
93
|
+
# Create some paste files
|
|
94
|
+
content = "Test content"
|
|
95
|
+
file_id1 = self.paste_manager.save_paste(content)
|
|
96
|
+
file_id2 = self.paste_manager.save_paste(content)
|
|
97
|
+
|
|
98
|
+
# Initially no cleanup (files are new)
|
|
99
|
+
cleaned = self.paste_manager.cleanup_old_pastes(max_age_hours=24)
|
|
100
|
+
self.assertEqual(cleaned, 0)
|
|
101
|
+
|
|
102
|
+
# Mock old files by setting max_age_hours to 0
|
|
103
|
+
cleaned = self.paste_manager.cleanup_old_pastes(max_age_hours=0)
|
|
104
|
+
self.assertEqual(cleaned, 2)
|
|
105
|
+
|
|
106
|
+
# Verify files are gone
|
|
107
|
+
pastes = self.paste_manager.list_pastes()
|
|
108
|
+
self.assertEqual(len(pastes), 0)
|
|
109
|
+
|
|
110
|
+
def test_error_handling(self):
|
|
111
|
+
"""Test error handling in PasteManager."""
|
|
112
|
+
# Test save_paste with invalid directory
|
|
113
|
+
with patch('builtins.open', side_effect=PermissionError("Permission denied")):
|
|
114
|
+
with self.assertRaises(RuntimeError) as context:
|
|
115
|
+
self.paste_manager.save_paste("test")
|
|
116
|
+
self.assertIn("Failed to save paste content", str(context.exception))
|
|
117
|
+
|
|
118
|
+
# Test read_paste with invalid file
|
|
119
|
+
with patch('builtins.open', side_effect=PermissionError("Permission denied")):
|
|
120
|
+
with self.assertRaises(RuntimeError) as context:
|
|
121
|
+
self.paste_manager.read_paste("pasted-test")
|
|
122
|
+
self.assertIn("Failed to read paste file", str(context.exception))
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
if __name__ == "__main__":
|
|
126
|
+
unittest.main()
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"""Utility functions for terminal paste module."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import re
|
|
5
|
+
from typing import Optional, Tuple
|
|
6
|
+
from datetime import datetime, timedelta
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def is_valid_paste_id(paste_id: str) -> bool:
|
|
10
|
+
"""Check if a paste ID is valid.
|
|
11
|
+
|
|
12
|
+
Args:
|
|
13
|
+
paste_id: Paste ID to validate
|
|
14
|
+
|
|
15
|
+
Returns:
|
|
16
|
+
True if valid, False otherwise
|
|
17
|
+
"""
|
|
18
|
+
if not paste_id:
|
|
19
|
+
return False
|
|
20
|
+
|
|
21
|
+
# Handle both "pasted-<uuid>" and just "<uuid>" formats
|
|
22
|
+
if paste_id.startswith("pasted-"):
|
|
23
|
+
uuid_part = paste_id[7:] # Remove "pasted-" prefix
|
|
24
|
+
else:
|
|
25
|
+
uuid_part = paste_id
|
|
26
|
+
|
|
27
|
+
# Check if it's a valid 32-character hex string (UUID without dashes)
|
|
28
|
+
return bool(re.match(r"^[0-9a-f]{32}$", uuid_part))
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def format_paste_info(paste_id: str, paste_dir: str) -> Optional[dict]:
|
|
32
|
+
"""Get formatted information about a paste file.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
paste_id: Paste file ID
|
|
36
|
+
paste_dir: Directory containing paste files
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
Dictionary with paste information or None if file not found
|
|
40
|
+
"""
|
|
41
|
+
if not is_valid_paste_id(paste_id):
|
|
42
|
+
return None
|
|
43
|
+
|
|
44
|
+
# Ensure paste_id has proper format
|
|
45
|
+
if not paste_id.startswith("pasted-"):
|
|
46
|
+
paste_id = f"pasted-{paste_id}"
|
|
47
|
+
|
|
48
|
+
file_path = os.path.join(paste_dir, paste_id)
|
|
49
|
+
|
|
50
|
+
if not os.path.exists(file_path):
|
|
51
|
+
return None
|
|
52
|
+
|
|
53
|
+
try:
|
|
54
|
+
stat = os.stat(file_path)
|
|
55
|
+
created_time = datetime.fromtimestamp(stat.st_ctime)
|
|
56
|
+
modified_time = datetime.fromtimestamp(stat.st_mtime)
|
|
57
|
+
file_size = stat.st_size
|
|
58
|
+
|
|
59
|
+
# Read first few lines for preview
|
|
60
|
+
with open(file_path, "r", encoding="utf-8") as f:
|
|
61
|
+
content = f.read()
|
|
62
|
+
lines = content.splitlines()
|
|
63
|
+
preview = "\n".join(lines[:3])
|
|
64
|
+
if len(lines) > 3:
|
|
65
|
+
preview += f"\n... ({len(lines) - 3} more lines)"
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
"id": paste_id,
|
|
69
|
+
"path": file_path,
|
|
70
|
+
"size": file_size,
|
|
71
|
+
"created": created_time,
|
|
72
|
+
"modified": modified_time,
|
|
73
|
+
"line_count": len(lines),
|
|
74
|
+
"preview": preview[:200] + "..." if len(preview) > 200 else preview
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
except Exception:
|
|
78
|
+
return None
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def format_file_size(size_bytes: int) -> str:
|
|
82
|
+
"""Format file size in human-readable format.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
size_bytes: Size in bytes
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
Formatted size string
|
|
89
|
+
"""
|
|
90
|
+
if size_bytes < 1024:
|
|
91
|
+
return f"{size_bytes} B"
|
|
92
|
+
elif size_bytes < 1024 * 1024:
|
|
93
|
+
return f"{size_bytes / 1024:.1f} KB"
|
|
94
|
+
elif size_bytes < 1024 * 1024 * 1024:
|
|
95
|
+
return f"{size_bytes / (1024 * 1024):.1f} MB"
|
|
96
|
+
else:
|
|
97
|
+
return f"{size_bytes / (1024 * 1024 * 1024):.1f} GB"
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def format_time_ago(timestamp: datetime) -> str:
|
|
101
|
+
"""Format timestamp as time ago string.
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
timestamp: Timestamp to format
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
Human-readable time ago string
|
|
108
|
+
"""
|
|
109
|
+
now = datetime.now()
|
|
110
|
+
diff = now - timestamp
|
|
111
|
+
|
|
112
|
+
if diff.days > 0:
|
|
113
|
+
return f"{diff.days} day{'s' if diff.days > 1 else ''} ago"
|
|
114
|
+
elif diff.seconds > 3600:
|
|
115
|
+
hours = diff.seconds // 3600
|
|
116
|
+
return f"{hours} hour{'s' if hours > 1 else ''} ago"
|
|
117
|
+
elif diff.seconds > 60:
|
|
118
|
+
minutes = diff.seconds // 60
|
|
119
|
+
return f"{minutes} minute{'s' if minutes > 1 else ''} ago"
|
|
120
|
+
else:
|
|
121
|
+
return "just now"
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def extract_placeholder_ids(text: str) -> list[str]:
|
|
125
|
+
"""Extract all paste placeholder IDs from text.
|
|
126
|
+
|
|
127
|
+
Args:
|
|
128
|
+
text: Text to search for placeholders
|
|
129
|
+
|
|
130
|
+
Returns:
|
|
131
|
+
List of paste IDs found in text
|
|
132
|
+
"""
|
|
133
|
+
if not text:
|
|
134
|
+
return []
|
|
135
|
+
|
|
136
|
+
pattern = re.compile(r"\[pasted-([0-9a-f]{32})\]")
|
|
137
|
+
matches = pattern.findall(text)
|
|
138
|
+
return [f"pasted-{match}" for match in matches]
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def validate_paste_directory(paste_dir: str) -> Tuple[bool, str]:
|
|
142
|
+
"""Validate paste directory and return status.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
paste_dir: Directory path to validate
|
|
146
|
+
|
|
147
|
+
Returns:
|
|
148
|
+
Tuple of (is_valid, message)
|
|
149
|
+
"""
|
|
150
|
+
try:
|
|
151
|
+
if not os.path.exists(paste_dir):
|
|
152
|
+
return False, f"Directory does not exist: {paste_dir}"
|
|
153
|
+
|
|
154
|
+
if not os.path.isdir(paste_dir):
|
|
155
|
+
return False, f"Path is not a directory: {paste_dir}"
|
|
156
|
+
|
|
157
|
+
if not os.access(paste_dir, os.R_OK | os.W_OK):
|
|
158
|
+
return False, f"Directory is not readable/writable: {paste_dir}"
|
|
159
|
+
|
|
160
|
+
return True, "Directory is valid"
|
|
161
|
+
|
|
162
|
+
except Exception as e:
|
|
163
|
+
return False, f"Error validating directory: {e}"
|