drydock-cli 2.1.3__tar.gz → 2.2.0__tar.gz
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.
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/PKG-INFO +1 -1
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/PRD.md +42 -5
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/textual_ui/app.py +2 -1
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/agent_loop.py +51 -43
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/pyproject.toml +1 -1
- drydock_cli-2.2.0/scripts/overnight_agents_test.sh +219 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/test_drydock_tasks.py +8 -8
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/test_loop_detection.py +18 -20
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/test_user_issues.py +15 -18
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/.github/CODEOWNERS +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/.github/DISCUSSION_TEMPLATE/ideas.yml +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/.github/workflows/build-and-upload.yml +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/.github/workflows/ci.yml +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/.github/workflows/issue-labeler.yml +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/.github/workflows/release.yml +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/.gitignore +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/.pre-commit-config.yaml +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/.python-version +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/.typos.toml +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/.vscode/extensions.json +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/.vscode/launch.json +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/.vscode/settings.json +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/AGENTS.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/CHANGELOG.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/CLAUDE.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/CONTRIBUTING.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/Drydock_rebrand.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/LICENSE +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/NOTICE +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/README.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/action.yml +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/distribution/zed/LICENSE +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/distribution/zed/extension.toml +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/distribution/zed/icons/mistral_vibe.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/docs/README.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/docs/acp-setup.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/docs/proxy-setup.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/__init__.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/acp/__init__.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/acp/acp_agent_loop.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/acp/acp_logger.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/acp/entrypoint.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/acp/tools/__init__.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/acp/tools/base.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/acp/tools/builtins/bash.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/acp/tools/builtins/read_file.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/acp/tools/builtins/search_replace.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/acp/tools/builtins/todo.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/acp/tools/builtins/write_file.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/acp/tools/session_update.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/acp/utils.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/__init__.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/autocompletion/__init__.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/autocompletion/base.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/autocompletion/path_completion.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/autocompletion/slash_command.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/cli.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/clipboard.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/commands.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/entrypoint.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/history_manager.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/plan_offer/adapters/http_whoami_gateway.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/plan_offer/decide_plan_offer.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/plan_offer/ports/whoami_gateway.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/terminal_setup.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/textual_ui/__init__.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/textual_ui/ansi_markdown.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/textual_ui/app.tcss +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/textual_ui/external_editor.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/textual_ui/handlers/__init__.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/textual_ui/handlers/event_handler.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/textual_ui/notifications/__init__.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/textual_ui/notifications/adapters/__init__.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/textual_ui/notifications/adapters/textual_notification_adapter.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/textual_ui/notifications/ports/__init__.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/textual_ui/notifications/ports/notification_port.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/textual_ui/widgets/__init__.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/textual_ui/widgets/approval_app.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/textual_ui/widgets/banner/banner.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/textual_ui/widgets/banner/petit_chat.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/textual_ui/widgets/braille_renderer.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/textual_ui/widgets/chat_input/__init__.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/textual_ui/widgets/chat_input/body.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/textual_ui/widgets/chat_input/completion_manager.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/textual_ui/widgets/chat_input/completion_popup.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/textual_ui/widgets/chat_input/container.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/textual_ui/widgets/chat_input/text_area.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/textual_ui/widgets/compact.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/textual_ui/widgets/config_app.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/textual_ui/widgets/context_progress.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/textual_ui/widgets/load_more.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/textual_ui/widgets/loading.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/textual_ui/widgets/messages.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/textual_ui/widgets/no_markup_static.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/textual_ui/widgets/path_display.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/textual_ui/widgets/proxy_setup_app.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/textual_ui/widgets/question_app.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/textual_ui/widgets/session_picker.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/textual_ui/widgets/spinner.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/textual_ui/widgets/status_message.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/textual_ui/widgets/teleport_message.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/textual_ui/widgets/tool_widgets.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/textual_ui/widgets/tools.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/textual_ui/widgets/vscode_compat.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/textual_ui/windowing/__init__.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/textual_ui/windowing/history.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/textual_ui/windowing/history_windowing.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/textual_ui/windowing/state.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/update_notifier/__init__.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/update_notifier/adapters/filesystem_update_cache_repository.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/update_notifier/adapters/github_update_gateway.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/update_notifier/adapters/pypi_update_gateway.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/update_notifier/ports/update_cache_repository.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/update_notifier/ports/update_gateway.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/update_notifier/update.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/cli/update_notifier/whats_new.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/__init__.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/agents/__init__.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/agents/manager.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/agents/models.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/auth/__init__.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/auth/crypto.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/auth/github.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/autocompletion/__init__.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/autocompletion/completers.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/autocompletion/file_indexer/__init__.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/autocompletion/file_indexer/ignore_rules.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/autocompletion/file_indexer/indexer.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/autocompletion/file_indexer/store.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/autocompletion/file_indexer/watcher.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/autocompletion/fuzzy.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/autocompletion/path_prompt.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/autocompletion/path_prompt_adapter.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/build_orchestrator.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/config/__init__.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/config/_settings.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/config/harness_files/__init__.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/config/harness_files/_harness_manager.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/config/harness_files/_paths.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/consultant.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/drydock_states.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/hooks.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/llm/__init__.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/llm/backend/anthropic.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/llm/backend/base.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/llm/backend/factory.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/llm/backend/generic.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/llm/backend/mistral.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/llm/backend/reasoning_adapter.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/llm/backend/vertex.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/llm/exceptions.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/llm/format.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/llm/message_utils.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/llm/types.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/logger.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/middleware.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/output_formatters.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/paths/__init__.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/paths/_local_config_walk.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/paths/_vibe_home.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/paths/conventions.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/plan_session.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/plugins.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/programmatic.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/prompts/__init__.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/prompts/builder.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/prompts/cli.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/prompts/compact.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/prompts/dangerous_directory.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/prompts/diagnostic.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/prompts/explore.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/prompts/planner.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/prompts/project_context.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/prompts/tests.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/proxy_setup.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/session/agent_memory.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/session/checkpoints.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/session/session_loader.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/session/session_logger.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/session/session_migration.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/session/state_file.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/skills/__init__.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/skills/manager.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/skills/models.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/skills/parser.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/slug.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/system_prompt.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/telemetry/__init__.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/telemetry/send.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/teleport/errors.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/teleport/git.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/teleport/nuage.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/teleport/teleport.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/teleport/types.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/base.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/builtins/ask_user_question.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/builtins/bash.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/builtins/cron.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/builtins/exit_plan_mode.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/builtins/glob_tool.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/builtins/grep.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/builtins/invoke_skill.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/builtins/lsp.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/builtins/mcp_resources.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/builtins/notebook_edit.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/builtins/powershell.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/builtins/prompts/__init__.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/builtins/prompts/ask_user_question.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/builtins/prompts/bash.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/builtins/prompts/cron.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/builtins/prompts/glob.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/builtins/prompts/grep.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/builtins/prompts/invoke_skill.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/builtins/prompts/lsp.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/builtins/prompts/mcp_resources.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/builtins/prompts/notebook_edit.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/builtins/prompts/powershell.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/builtins/prompts/read_file.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/builtins/prompts/search_replace.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/builtins/prompts/swe_bench.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/builtins/prompts/task.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/builtins/prompts/task_manager.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/builtins/prompts/todo.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/builtins/prompts/tool_search.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/builtins/prompts/webfetch.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/builtins/prompts/websearch.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/builtins/prompts/worktree.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/builtins/prompts/write_file.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/builtins/read_file.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/builtins/search_replace.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/builtins/task.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/builtins/task_manager.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/builtins/todo.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/builtins/tool_search.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/builtins/webfetch.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/builtins/websearch.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/builtins/worktree.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/builtins/write_file.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/injection_guard.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/manager.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/mcp/__init__.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/mcp/registry.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/mcp/tools.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/mcp_sampling.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/ui.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/tools/utils.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/trusted_folders.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/types.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/core/utils.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/setup/onboarding/__init__.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/setup/onboarding/base.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/setup/onboarding/onboarding.tcss +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/setup/onboarding/screens/__init__.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/setup/onboarding/screens/api_key.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/setup/onboarding/screens/welcome.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/setup/trusted_folders/trust_folder_dialog.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/setup/trusted_folders/trust_folder_dialog.tcss +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/skills/__init__.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/skills/batch/SKILL.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/skills/create-presentation/SKILL.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/skills/deep-research/SKILL.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/skills/investigate/SKILL.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/skills/review/SKILL.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/skills/ship/SKILL.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/skills/simplify/SKILL.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock/whats_new.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock-acp.spec +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/drydock_terms.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/flake.lock +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/flake.nix +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/scripts/README.md +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/scripts/auto_test_loop.sh +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/scripts/backup.sh +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/scripts/bump_version.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/scripts/deploy_to_github.sh +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/scripts/install.sh +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/scripts/monitor_test_battery.sh +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/scripts/notify_release.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/scripts/prepare_release.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/scripts/publish_to_pypi.sh +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/scripts/test_bank.sh +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/scripts/test_full.sh +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/scripts/test_smoke.sh +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/__init__.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/acp/conftest.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/acp/test_acp.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/acp/test_agent_thought.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/acp/test_bash.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/acp/test_compact_session_updates.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/acp/test_content.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/acp/test_initialize.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/acp/test_list_sessions.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/acp/test_load_session.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/acp/test_multi_session.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/acp/test_new_session.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/acp/test_proxy_setup_acp.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/acp/test_read_file.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/acp/test_search_replace.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/acp/test_set_config_option.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/acp/test_set_mode.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/acp/test_set_model.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/acp/test_tool_call_session_update.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/acp/test_utils.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/acp/test_write_file.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/autocompletion/test_file_indexer.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/autocompletion/test_fuzzy.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/autocompletion/test_path_completer_fuzzy.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/autocompletion/test_path_completer_recursive.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/autocompletion/test_path_completion_controller.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/autocompletion/test_path_prompt_transformer.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/autocompletion/test_slash_command_controller.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/autocompletion/test_ui_chat_autocompletion.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/backend/__init__.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/backend/data/__init__.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/backend/data/fireworks.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/backend/data/mistral.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/backend/test_anthropic_adapter.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/backend/test_backend.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/backend/test_reasoning_adapter.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/backend/test_vertex_anthropic_adapter.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/cli/plan_offer/adapters/fake_whoami_gateway.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/cli/plan_offer/test_decide_plan_offer.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/cli/plan_offer/test_http_whoami_gateway.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/cli/test_bell_notifications.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/cli/test_braille_renderer.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/cli/test_clipboard.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/cli/test_commands.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/cli/test_copy_shortcuts.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/cli/test_external_editor.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/cli/test_no_markup_static.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/cli/test_question_app.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/cli/test_spinner.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/cli/test_switching_mode.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/cli/test_ui_clipboard_notifications.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/cli/test_ui_session_incremental_renderer.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/cli/test_ui_session_resume.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/cli/test_ui_skill_dispatch.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/cli/textual_ui/__init__.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/cli/textual_ui/test_session_picker.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/conftest.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/core/test_agents.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/core/test_auth_crypto.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/core/test_auth_github.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/core/test_config_load_dotenv.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/core/test_config_paths.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/core/test_config_resolution.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/core/test_file_logging.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/core/test_plan_session.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/core/test_proxy_setup.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/core/test_slug.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/core/test_telemetry_send.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/core/test_teleport_git.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/core/test_teleport_nuage.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/core/test_teleport_service.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/core/test_trusted_folders.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/core/test_utils.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/e2e/common.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/e2e/conftest.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/e2e/mock_server.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/e2e/test_cli_tui_onboarding.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/e2e/test_cli_tui_streaming.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/e2e/test_cli_tui_tool_approval.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/mock/__init__.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/mock/mock_backend_factory.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/mock/mock_entrypoint.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/mock/utils.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/onboarding/test_run_onboarding.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/onboarding/test_ui_onboarding.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/session/test_session_loader.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/session/test_session_logger.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/session/test_session_migration.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/skills/conftest.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/skills/test_manager.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/skills/test_models.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/skills/test_parser.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_ask_user_question/test_snapshot_ask_user_question_collapsed.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_ask_user_question/test_snapshot_ask_user_question_expanded.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_basic_conversation/test_snapshot_shows_basic_conversation.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_code_block_horizontal_scrolling/test_snapshot_allows_horizontal_scrolling_for_long_code_blocks.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_empty_assistant_before_reasoning/test_snapshot_empty_assistant_removed_when_reasoning_starts.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_cycle_to_accept_edits_mode.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_cycle_to_auto_approve_mode.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_cycle_to_plan_mode.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_cycle_wraps_to_default.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_default_mode.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_parallel_tool_calls/test_snapshot_parallel_tool_calls_pending.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_parallel_tool_calls/test_snapshot_parallel_tool_calls_resolved.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_cancel_discards_changes.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_edit_existing_values.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_initial_empty.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_initial_with_values.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_save_error.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_save_new_values.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_answer_first_advance.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_first_answered_checkmark.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_initial.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_navigate_left_wraps.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_navigate_right.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_tab_to_second.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_initial.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_mixed_selection.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_navigate_to_submit.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_other_with_text.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_toggle_first.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_toggle_multiple.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_untoggle.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_initial.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_navigate_down.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_navigate_to_other.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_navigate_to_third_option.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_navigate_up_wraps.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_other_typing.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_reasoning_content/test_snapshot_buffered_reasoning_yields_before_content.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_reasoning_content/test_snapshot_shows_interleaved_reasoning.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_reasoning_content/test_snapshot_shows_reasoning_content.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_reasoning_content/test_snapshot_shows_reasoning_content_expanded.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_release_update_notification/test_snapshot_shows_release_update_notification.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_session_resume/test_snapshot_shows_resumed_session_messages.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_streaming_tool_call/test_snapshot_tool_call_partial.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_streaming_tool_call/test_snapshot_tool_call_updated.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_push_confirmation_cancel_selected.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_push_confirmation_multiple_commits.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_push_confirmation_single_commit.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_auth_complete.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_auth_required.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_checking_git.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_complete.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_error.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_pushing.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_sending_token.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_starting_workflow.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_whats_new/test_snapshot_shows_no_plan_message.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_whats_new/test_snapshot_shows_switch_message.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_whats_new/test_snapshot_shows_upgrade_message.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/__snapshots__/test_ui_snapshot_whats_new/test_snapshot_shows_whats_new_message.svg +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/base_snapshot_test_app.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/conftest.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/snap_compare.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/test_ui_snapshot_ask_user_question.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/test_ui_snapshot_basic_conversation.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/test_ui_snapshot_code_block_horizontal_scrolling.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/test_ui_snapshot_empty_assistant_before_reasoning.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/test_ui_snapshot_modes.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/test_ui_snapshot_parallel_tool_calls.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/test_ui_snapshot_proxy_setup.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/test_ui_snapshot_question_app.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/test_ui_snapshot_reasoning_content.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/test_ui_snapshot_release_update_notification.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/test_ui_snapshot_session_resume.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/test_ui_snapshot_streaming_tool_call.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/test_ui_snapshot_teleport.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/snapshots/test_ui_snapshot_whats_new.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/stubs/fake_backend.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/stubs/fake_client.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/stubs/fake_tool.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/test_agent_auto_compact.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/test_agent_backend.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/test_agent_observer_streaming.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/test_agent_stats.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/test_agent_tasks.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/test_agent_tool_call.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/test_agents.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/test_bank_build.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/test_bank_debug.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/test_bank_multiagent.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/test_bank_prd.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/test_bank_prd_extended.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/test_bank_tools.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/test_bank_update.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/test_build_projects.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/test_cli_programmatic_preload.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/test_current_bugs.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/test_drydock_regression.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/test_full_regression.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/test_history_manager.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/test_integration.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/test_message_id.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/test_message_merging.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/test_middleware.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/test_multi_agent.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/test_real_failures.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/test_real_issues.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/test_real_workflow.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/test_reasoning_content.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/test_smoke.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/test_system_prompt.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/test_tagged_text.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/test_ui_external_editor.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/test_ui_input_history.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/test_workloads.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/testbank_helpers.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/tools/test_ask_user_question.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/tools/test_bash.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/tools/test_exit_plan_mode.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/tools/test_grep.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/tools/test_invoke_context.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/tools/test_manager_get_tool_config.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/tools/test_mcp.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/tools/test_mcp_sampling.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/tools/test_task.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/tools/test_ui_bash_execution.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/tools/test_webfetch.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/tools/test_websearch.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/update_notifier/adapters/fake_update_cache_repository.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/update_notifier/adapters/fake_update_gateway.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/update_notifier/test_do_update.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/update_notifier/test_filesystem_update_cache_repository.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/update_notifier/test_github_update_gateway.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/update_notifier/test_pypi_update_gateway.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/update_notifier/test_ui_update_notification.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/update_notifier/test_update_use_case.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/tests/update_notifier/test_whats_new.py +0 -0
- {drydock_cli-2.1.3 → drydock_cli-2.2.0}/uv.lock +0 -0
|
@@ -547,11 +547,48 @@ Evidence: removing this one line improved `task(agent="explore")` usage from 1/5
|
|
|
547
547
|
- Telegram release notifications
|
|
548
548
|
- `whats_new.md` updated
|
|
549
549
|
|
|
550
|
+
### Phase 15 (Mar 31): Meta-Harness Framework + SWE-bench Push
|
|
551
|
+
|
|
552
|
+
**Paper:** "Meta-Harness: End-to-End Optimization of Model Harnesses" (arXiv:2603.28052)
|
|
553
|
+
**Key insight:** Optimize the harness around the model, not the model itself. A harness change gave +18pp on TerminalBench-2.
|
|
554
|
+
|
|
555
|
+
**What we implemented from Meta-Harness:**
|
|
556
|
+
|
|
557
|
+
1. **Environment bootstrapping** — Single compound shell command before first LLM call gathers:
|
|
558
|
+
- Repo structure (`find . -name "*.py" | head -30`)
|
|
559
|
+
- Python version, test framework
|
|
560
|
+
- Top-level directories, recent commits
|
|
561
|
+
- Injected as `[Environment Snapshot]` in the prompt
|
|
562
|
+
- Eliminates 2-4 wasted exploratory turns
|
|
563
|
+
|
|
564
|
+
2. **AGENTS.md per SWE-bench task** — Auto-created in each worktree with bug-fix workflow instructions
|
|
565
|
+
|
|
566
|
+
3. **Additive-only changes** — Paper proved that modifying control flow regresses. Only ADD context before the agent loop. This validates our decision to disable the orchestrator and circuit breaker.
|
|
567
|
+
|
|
568
|
+
**SWE-bench status:**
|
|
569
|
+
- Baseline (v2.1.3 + AGENTS.md): 4/10 file matches (40%)
|
|
570
|
+
- 50-task eval running with env bootstrapping
|
|
571
|
+
- Previous "39-42% pass rate" was file-match only — actual test pass rate was 0%
|
|
572
|
+
- Target: 68% (devstral-small-2 24B, per Mistral's published results)
|
|
573
|
+
- Mistral achieved 68% with Vibe CLI + Cline harness
|
|
574
|
+
|
|
575
|
+
**Meta-Harness techniques still to implement:**
|
|
576
|
+
- Double-confirmation before completion (verify checklist)
|
|
577
|
+
- Execution trace logging for systematic failure diagnosis
|
|
578
|
+
- Repo-specific routing (different strategies per SWE-bench repo)
|
|
579
|
+
- Draft-then-verify for patches
|
|
580
|
+
- Contrastive examples for decision boundaries
|
|
581
|
+
|
|
582
|
+
**Reference:** https://github.com/stanford-iris-lab/meta-harness-tbench2-artifact
|
|
583
|
+
|
|
550
584
|
### Lessons Learned (Updated)
|
|
551
585
|
|
|
552
586
|
1. **One prompt line can block an entire feature.** "Restate the goal" prevented tool calling for months.
|
|
553
|
-
2. **
|
|
554
|
-
3. **
|
|
555
|
-
4. **
|
|
556
|
-
5. **
|
|
557
|
-
6. **
|
|
587
|
+
2. **AGENTS.md is essential for devstral.** Without per-project instructions file, model loops on ls/bash. Auto-created on first session.
|
|
588
|
+
3. **Additive-only harness changes work best.** Every control flow modification (circuit breaker, orchestrator, nudges) caused regressions. Just inject better context.
|
|
589
|
+
4. **The harness matters as much as the model.** Meta-Harness paper shows 6x performance gap from harness changes alone.
|
|
590
|
+
5. **Environment bootstrapping saves turns.** Pre-gathering repo structure/versions eliminates 2-4 wasted exploration turns.
|
|
591
|
+
6. **Plan→Edit workflow is Mistral's design.** Use plan mode first, then switch to accept-edits. Don't try to do everything in one agent shot.
|
|
592
|
+
7. **Same-process API calls can fail.** httpx from inside DryDock got 404 from vLLM. Use the existing backend connection.
|
|
593
|
+
8. **Test the installed package, not source.** Different Python envs (miniconda3 vs miniforge3) have different behavior.
|
|
594
|
+
9. **Explicit Python paths everywhere.** Cron doesn't inherit PATH. Every script must use the full path.
|
|
@@ -398,7 +398,8 @@ class VibeApp(App): # noqa: PLR0904
|
|
|
398
398
|
if not hasattr(self, "_pending_messages"):
|
|
399
399
|
self._pending_messages: list[str] = []
|
|
400
400
|
self._pending_messages.append(value)
|
|
401
|
-
|
|
401
|
+
preview = value[:60] + "..." if len(value) > 60 else value
|
|
402
|
+
self.notify(f"Queued: \"{preview}\" ({len(self._pending_messages)} pending)")
|
|
402
403
|
return
|
|
403
404
|
|
|
404
405
|
if value.startswith("!"):
|
|
@@ -299,7 +299,8 @@ class AgentLoop:
|
|
|
299
299
|
# Auto-create AGENTS.md if no project instructions exist.
|
|
300
300
|
# devstral needs per-project AGENTS.md to anchor its behavior —
|
|
301
301
|
# without it the model loops on ls/bash instead of using subagents.
|
|
302
|
-
self.
|
|
302
|
+
if self.stats.steps <= 1:
|
|
303
|
+
self._ensure_agents_md()
|
|
303
304
|
|
|
304
305
|
# Load project state for cross-session context
|
|
305
306
|
try:
|
|
@@ -541,11 +542,14 @@ class AgentLoop:
|
|
|
541
542
|
except (RuntimeError, AgentLoopLLMResponseError) as e:
|
|
542
543
|
api_error_count += 1
|
|
543
544
|
if api_error_count > MAX_API_ERRORS:
|
|
545
|
+
# Don't stop — reset and let the user know
|
|
546
|
+
import asyncio as _aio
|
|
544
547
|
yield AssistantEvent(
|
|
545
|
-
content=f"\n\n[
|
|
546
|
-
stopped_by_middleware=True,
|
|
548
|
+
content=f"\n\n[{api_error_count} consecutive API errors. Waiting 10s then retrying. Last error: {str(e)[:200]}]\n",
|
|
547
549
|
)
|
|
548
|
-
|
|
550
|
+
await _aio.sleep(10)
|
|
551
|
+
api_error_count = 0 # Reset — give it another chance
|
|
552
|
+
continue
|
|
549
553
|
# Check if the error is about invalid function/tool name
|
|
550
554
|
error_str = str(e)
|
|
551
555
|
if "Function name" in error_str or "function" in error_str.lower() and "must be" in error_str.lower():
|
|
@@ -696,11 +700,14 @@ class AgentLoop:
|
|
|
696
700
|
"search_replace to edit one. Do NOT run any more bash commands."
|
|
697
701
|
)
|
|
698
702
|
elif bash_count >= 10:
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
703
|
+
# Redirect, don't stop — prune bash calls and guide
|
|
704
|
+
self._prune_repeated_tool_calls()
|
|
705
|
+
self._inject_system_note(
|
|
706
|
+
"You have run 10+ bash commands without creating files. "
|
|
707
|
+
"Use write_file or search_replace NOW. If you need help, "
|
|
708
|
+
"ask the user what to do."
|
|
702
709
|
)
|
|
703
|
-
|
|
710
|
+
bash_count = 6 # Reset partially so it doesn't re-trigger immediately
|
|
704
711
|
|
|
705
712
|
# 3-Strike Rule: search_replace keeps failing
|
|
706
713
|
if search_replace_failures >= 3:
|
|
@@ -817,55 +824,56 @@ class AgentLoop:
|
|
|
817
824
|
if nudge_text:
|
|
818
825
|
self._inject_system_note(nudge_text)
|
|
819
826
|
|
|
820
|
-
# Check for repeated tool calls (loop
|
|
827
|
+
# Check for repeated tool calls (loop guidance — never stops, only redirects)
|
|
821
828
|
if not should_break_loop:
|
|
822
829
|
rep = self._check_tool_call_repetition()
|
|
823
830
|
if rep == "FORCE_STOP":
|
|
824
831
|
repeat_warnings += 1
|
|
825
|
-
logger.warning("
|
|
826
|
-
|
|
827
|
-
# Stop after 5 redirects — model is not recovering
|
|
828
|
-
yield AssistantEvent(
|
|
829
|
-
content="\n\n[Stopping: exhausted all retry attempts.]\n",
|
|
830
|
-
stopped_by_middleware=True,
|
|
831
|
-
)
|
|
832
|
-
return
|
|
833
|
-
# Redirect instead of kill — force an edit attempt
|
|
834
|
-
self._inject_system_note(
|
|
835
|
-
"CRITICAL: You are in an infinite loop. STOP all searching/reading. "
|
|
836
|
-
"Based on what you have already seen, use search_replace RIGHT NOW to make "
|
|
837
|
-
"your best fix attempt. If you don't know the exact text, use read_file ONE MORE TIME "
|
|
838
|
-
"on the specific function, then search_replace immediately.",
|
|
839
|
-
replace_last_tool=True,
|
|
840
|
-
)
|
|
832
|
+
logger.warning("Loop detected: same call %d+ times (redirect %d)", REPEAT_FORCE_STOP_THRESHOLD, repeat_warnings)
|
|
833
|
+
# Prune repeated calls and redirect — NEVER stop
|
|
841
834
|
self._prune_repeated_tool_calls()
|
|
835
|
+
if repeat_warnings <= 3:
|
|
836
|
+
self._inject_system_note(
|
|
837
|
+
"You are repeating the same action. Try a DIFFERENT approach:\n"
|
|
838
|
+
"- If searching: pick a different search term or file\n"
|
|
839
|
+
"- If testing: read the error and fix the code first\n"
|
|
840
|
+
"- If stuck: use task(agent='explore') to get a fresh perspective",
|
|
841
|
+
replace_last_tool=True,
|
|
842
|
+
)
|
|
843
|
+
else:
|
|
844
|
+
# After 3+ redirects, ask the user what to do
|
|
845
|
+
self._inject_system_note(
|
|
846
|
+
"You have been redirected multiple times for repeating actions. "
|
|
847
|
+
"Ask the user for clarification on what to do next.",
|
|
848
|
+
replace_last_tool=True,
|
|
849
|
+
)
|
|
842
850
|
elif rep and rep.startswith("WARNING"):
|
|
843
|
-
# During investigation (no edit yet), soft-count warnings from
|
|
844
|
-
# investigation tools — they need room to explore.
|
|
845
851
|
stuck_tool = ""
|
|
846
852
|
if "|" in rep:
|
|
847
853
|
stuck_tool = rep.split("|", 1)[1]
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
)
|
|
852
|
-
if is_investigation_warning:
|
|
853
|
-
repeat_warnings += 0.3 # Count less — investigation needs room
|
|
854
|
+
is_investigation = not has_made_edit and stuck_tool in ("grep", "read_file")
|
|
855
|
+
if is_investigation:
|
|
856
|
+
repeat_warnings += 0.3
|
|
854
857
|
else:
|
|
855
858
|
repeat_warnings += 1
|
|
856
|
-
logger.warning("
|
|
857
|
-
if repeat_warnings >= 6:
|
|
858
|
-
yield AssistantEvent(
|
|
859
|
-
content="\n\n[Stopping: too many repeated actions despite warnings.]\n",
|
|
860
|
-
stopped_by_middleware=True,
|
|
861
|
-
)
|
|
862
|
-
return
|
|
859
|
+
logger.warning("Repeated tool calls (warning %.1f, investigation=%s)", repeat_warnings, is_investigation)
|
|
863
860
|
|
|
864
|
-
#
|
|
865
|
-
|
|
866
|
-
if repeat_warnings == 3:
|
|
861
|
+
# Prune on 3rd warning
|
|
862
|
+
if repeat_warnings >= 3 and int(repeat_warnings) % 3 == 0:
|
|
867
863
|
self._prune_repeated_tool_calls()
|
|
868
864
|
|
|
865
|
+
# Tool-specific guidance
|
|
866
|
+
nudge = ""
|
|
867
|
+
if stuck_tool in ("read_file",):
|
|
868
|
+
nudge = " You already read this file. Make your edit with search_replace now."
|
|
869
|
+
elif stuck_tool in ("grep",):
|
|
870
|
+
nudge = " Try a different search term, or read the file you found."
|
|
871
|
+
elif stuck_tool in ("bash", "run_command"):
|
|
872
|
+
nudge = " Read the error output and fix the code with search_replace."
|
|
873
|
+
self._inject_system_note(
|
|
874
|
+
f"You are repeating the same tool call.{nudge} Try something different."
|
|
875
|
+
)
|
|
876
|
+
|
|
869
877
|
# Extract tool-specific nudge
|
|
870
878
|
nudge = ""
|
|
871
879
|
if stuck_tool in ("read_file",):
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Overnight test: Try different AGENTS.md versions with plan→build workflow
|
|
3
|
+
# Tests DryDock's ability to build the log analyzer from PRD
|
|
4
|
+
# Runs for up to 20 hours, logs all results
|
|
5
|
+
|
|
6
|
+
set -uo pipefail
|
|
7
|
+
export PATH="/home/bobef/miniconda3/bin:$PATH"
|
|
8
|
+
PYTHON="/home/bobef/miniconda3/bin/python3"
|
|
9
|
+
DRYDOCK="/data3/drydock"
|
|
10
|
+
RESULTS="$DRYDOCK/test_bank_results/agents_md_test"
|
|
11
|
+
PRD="/data3/test_drydock/PRD.md"
|
|
12
|
+
MAX_HOURS=20
|
|
13
|
+
START=$(date +%s)
|
|
14
|
+
|
|
15
|
+
mkdir -p "$RESULTS"
|
|
16
|
+
|
|
17
|
+
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$RESULTS/run.log"; }
|
|
18
|
+
|
|
19
|
+
check_time() {
|
|
20
|
+
NOW=$(date +%s)
|
|
21
|
+
ELAPSED=$(( (NOW - START) / 3600 ))
|
|
22
|
+
if [ "$ELAPSED" -ge "$MAX_HOURS" ]; then
|
|
23
|
+
log "Time limit reached ($ELAPSED hours). Stopping."
|
|
24
|
+
$PYTHON "$DRYDOCK/scripts/notify_release.py" "test" "Overnight AGENTS.md test complete. $PASS passes, $FAIL fails. Check results."
|
|
25
|
+
exit 0
|
|
26
|
+
fi
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
# Test a single AGENTS.md variant
|
|
30
|
+
run_test() {
|
|
31
|
+
local variant_name="$1"
|
|
32
|
+
local agents_md_content="$2"
|
|
33
|
+
local test_dir="/tmp/drydock_agentsmd_test_$$"
|
|
34
|
+
local result_file="$RESULTS/${variant_name}_$(date +%H%M%S).txt"
|
|
35
|
+
|
|
36
|
+
log "=== Testing variant: $variant_name ==="
|
|
37
|
+
|
|
38
|
+
rm -rf "$test_dir"
|
|
39
|
+
mkdir -p "$test_dir"
|
|
40
|
+
cp "$PRD" "$test_dir/PRD.md"
|
|
41
|
+
echo "$agents_md_content" > "$test_dir/AGENTS.md"
|
|
42
|
+
|
|
43
|
+
cd "$test_dir"
|
|
44
|
+
|
|
45
|
+
# Run DryDock programmatically: simulate plan→build
|
|
46
|
+
timeout 600 $PYTHON -c "
|
|
47
|
+
import asyncio, os, sys, subprocess
|
|
48
|
+
from pathlib import Path
|
|
49
|
+
sys.path.insert(0, '$DRYDOCK')
|
|
50
|
+
sys.path.insert(0, '$DRYDOCK/tests')
|
|
51
|
+
os.chdir('$test_dir')
|
|
52
|
+
from drydock.core.config.harness_files import init_harness_files_manager
|
|
53
|
+
try: init_harness_files_manager('u','p')
|
|
54
|
+
except: pass
|
|
55
|
+
from testbank_helpers import make_agent, run_workload, count_python_files, check_syntax_all
|
|
56
|
+
|
|
57
|
+
async def test():
|
|
58
|
+
agent = make_agent(Path('$test_dir'), max_turns=40)
|
|
59
|
+
r = await run_workload(agent, max_events=400, prompt='review the PRD and build the log analyzer. Test it.')
|
|
60
|
+
n = count_python_files(Path('$test_dir'))
|
|
61
|
+
errs = check_syntax_all(Path('$test_dir'))
|
|
62
|
+
print(f'RESULT: files={n} syntax_errors={len(errs)} tools={r.total_tool_calls} stops={r.force_stops}')
|
|
63
|
+
print(f'TOOLS: {r.summary()}')
|
|
64
|
+
# Check subagent usage
|
|
65
|
+
task_calls = r.tool_counts.get('task', 0)
|
|
66
|
+
print(f'SUBAGENT_CALLS: {task_calls}')
|
|
67
|
+
# Try to run
|
|
68
|
+
for d in Path('$test_dir').iterdir():
|
|
69
|
+
if d.is_dir() and (d / '__init__.py').exists():
|
|
70
|
+
result = subprocess.run(f'python3 -m {d.name} --help', shell=True, capture_output=True, text=True, timeout=10)
|
|
71
|
+
print(f'HELP: rc={result.returncode}')
|
|
72
|
+
if result.returncode == 0:
|
|
73
|
+
print(f'HELP_OUT: {result.stdout[:200]}')
|
|
74
|
+
# Try analyze
|
|
75
|
+
Path('$test_dir/test.log').write_text('2026-03-01 10:01:22 ERROR DBConnection failed: timeout\n2026-03-01 10:01:23 WARN Retrying\n2026-03-01 10:02:00 INFO Recovered\n')
|
|
76
|
+
result2 = subprocess.run(f'python3 -m {d.name} analyze test.log', shell=True, capture_output=True, text=True, timeout=10)
|
|
77
|
+
print(f'ANALYZE: rc={result2.returncode}')
|
|
78
|
+
if result2.returncode == 0:
|
|
79
|
+
print(f'ANALYZE_OUT: {result2.stdout[:300]}')
|
|
80
|
+
break
|
|
81
|
+
else:
|
|
82
|
+
print('HELP: no_package')
|
|
83
|
+
|
|
84
|
+
asyncio.run(test())
|
|
85
|
+
" > "$result_file" 2>&1
|
|
86
|
+
|
|
87
|
+
local rc=$?
|
|
88
|
+
|
|
89
|
+
# Parse results
|
|
90
|
+
local files=$(grep "RESULT:" "$result_file" 2>/dev/null | grep -o "files=[0-9]*" | cut -d= -f2)
|
|
91
|
+
local help_rc=$(grep "HELP:" "$result_file" 2>/dev/null | grep -o "rc=[0-9]*" | cut -d= -f2)
|
|
92
|
+
local analyze_rc=$(grep "ANALYZE:" "$result_file" 2>/dev/null | grep -o "rc=[0-9]*" | cut -d= -f2)
|
|
93
|
+
local subagent=$(grep "SUBAGENT_CALLS:" "$result_file" 2>/dev/null | grep -o "[0-9]*")
|
|
94
|
+
|
|
95
|
+
if [ "${analyze_rc:-1}" = "0" ]; then
|
|
96
|
+
log " FULL PASS: $files files, analyze works, subagents=$subagent"
|
|
97
|
+
echo "FULL_PASS" > "$result_file.status"
|
|
98
|
+
return 0
|
|
99
|
+
elif [ "${help_rc:-1}" = "0" ]; then
|
|
100
|
+
log " HELP PASS: $files files, --help works, subagents=$subagent"
|
|
101
|
+
echo "HELP_PASS" > "$result_file.status"
|
|
102
|
+
return 1
|
|
103
|
+
elif [ "${files:-0}" -gt "3" ]; then
|
|
104
|
+
log " PARTIAL: $files files, subagents=$subagent"
|
|
105
|
+
echo "PARTIAL" > "$result_file.status"
|
|
106
|
+
return 1
|
|
107
|
+
else
|
|
108
|
+
log " FAIL: ${files:-0} files, subagents=${subagent:-0}"
|
|
109
|
+
echo "FAIL" > "$result_file.status"
|
|
110
|
+
return 1
|
|
111
|
+
fi
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
# ============================================================================
|
|
115
|
+
# AGENTS.md Variants
|
|
116
|
+
# ============================================================================
|
|
117
|
+
|
|
118
|
+
VARIANT_A='# Project Instructions
|
|
119
|
+
|
|
120
|
+
## Workflow
|
|
121
|
+
When building a project:
|
|
122
|
+
1. Use `task(agent="planner")` to create an implementation plan first
|
|
123
|
+
2. Use `task(agent="explore")` to understand existing code
|
|
124
|
+
3. Create files using `write_file` with absolute imports
|
|
125
|
+
4. Always create `__main__.py` so `python3 -m package_name` works
|
|
126
|
+
5. Test with `bash` after creating files
|
|
127
|
+
|
|
128
|
+
## Rules
|
|
129
|
+
- Use absolute imports: `from package.module import X`, NOT `from .module import X`
|
|
130
|
+
- Always create `__init__.py` and `__main__.py` for packages
|
|
131
|
+
- Create sample test data before testing
|
|
132
|
+
- Use `python3 -m package_name` to run, NOT `python3 package/file.py`'
|
|
133
|
+
|
|
134
|
+
VARIANT_B='# Project Instructions
|
|
135
|
+
|
|
136
|
+
## Build Workflow
|
|
137
|
+
1. Read the PRD with `read_file`
|
|
138
|
+
2. Plan: use `task(agent="planner")` to create an implementation plan
|
|
139
|
+
3. Create each file with `write_file` using absolute imports
|
|
140
|
+
4. Create `__init__.py` and `__main__.py` for every package
|
|
141
|
+
5. Create sample data and test with `bash`
|
|
142
|
+
|
|
143
|
+
## Import Rules
|
|
144
|
+
- ALWAYS: `from package.module import X`
|
|
145
|
+
- NEVER: `from .module import X`
|
|
146
|
+
- Run with: `python3 -m package_name`'
|
|
147
|
+
|
|
148
|
+
VARIANT_C='# Instructions for AI Agent
|
|
149
|
+
|
|
150
|
+
When asked to build a project:
|
|
151
|
+
- Start by reading any PRD or requirements files
|
|
152
|
+
- Use task(agent="planner") to plan the implementation
|
|
153
|
+
- Create files one at a time with write_file
|
|
154
|
+
- Use absolute imports (from pkg.mod import X, not from .mod import X)
|
|
155
|
+
- Create __init__.py and __main__.py for packages
|
|
156
|
+
- Test with python3 -m package_name after building'
|
|
157
|
+
|
|
158
|
+
VARIANT_D='# Build Rules
|
|
159
|
+
|
|
160
|
+
1. Read requirements (PRD.md)
|
|
161
|
+
2. Plan with task(agent="planner")
|
|
162
|
+
3. Explore existing code with task(agent="explore")
|
|
163
|
+
4. Create files with write_file
|
|
164
|
+
5. Use absolute imports only
|
|
165
|
+
6. Always create __init__.py and __main__.py
|
|
166
|
+
7. Test with python3 -m package_name
|
|
167
|
+
8. Fix errors with search_replace'
|
|
168
|
+
|
|
169
|
+
VARIANT_E='# Project Configuration
|
|
170
|
+
|
|
171
|
+
## Agent Workflow
|
|
172
|
+
- For new projects: task(agent="planner") → write_file → bash test
|
|
173
|
+
- For existing projects: task(agent="explore") → read_file → search_replace
|
|
174
|
+
- For reviews: task(agent="explore") → invoke_skill(skill_name="review")
|
|
175
|
+
|
|
176
|
+
## Package Rules
|
|
177
|
+
- Absolute imports: from package.module import X
|
|
178
|
+
- Always: __init__.py + __main__.py
|
|
179
|
+
- Test: python3 -m package_name
|
|
180
|
+
- Never: from .module import X'
|
|
181
|
+
|
|
182
|
+
# ============================================================================
|
|
183
|
+
# Main Loop
|
|
184
|
+
# ============================================================================
|
|
185
|
+
|
|
186
|
+
log "Starting overnight AGENTS.md test (max $MAX_HOURS hours)"
|
|
187
|
+
log "Variants: A B C D E"
|
|
188
|
+
|
|
189
|
+
PASS=0
|
|
190
|
+
FAIL=0
|
|
191
|
+
ROUND=0
|
|
192
|
+
|
|
193
|
+
while true; do
|
|
194
|
+
check_time
|
|
195
|
+
ROUND=$((ROUND + 1))
|
|
196
|
+
log ""
|
|
197
|
+
log "========== ROUND $ROUND =========="
|
|
198
|
+
|
|
199
|
+
for variant in A B C D E; do
|
|
200
|
+
check_time
|
|
201
|
+
eval "content=\$VARIANT_$variant"
|
|
202
|
+
if run_test "variant_$variant" "$content"; then
|
|
203
|
+
PASS=$((PASS + 1))
|
|
204
|
+
else
|
|
205
|
+
FAIL=$((FAIL + 1))
|
|
206
|
+
fi
|
|
207
|
+
done
|
|
208
|
+
|
|
209
|
+
TOTAL=$((PASS + FAIL))
|
|
210
|
+
PASS_RATE=$((PASS * 100 / TOTAL))
|
|
211
|
+
log "Round $ROUND: $PASS/$TOTAL pass ($PASS_RATE%)"
|
|
212
|
+
|
|
213
|
+
# Send Telegram update every 5 rounds
|
|
214
|
+
if [ $((ROUND % 5)) -eq 0 ]; then
|
|
215
|
+
$PYTHON "$DRYDOCK/scripts/notify_release.py" "test-r$ROUND" "AGENTS.md test round $ROUND: $PASS/$TOTAL pass ($PASS_RATE%). Best variant TBD."
|
|
216
|
+
fi
|
|
217
|
+
|
|
218
|
+
sleep 30
|
|
219
|
+
done
|
|
@@ -408,8 +408,8 @@ class TestCircuitBreaker:
|
|
|
408
408
|
|
|
409
409
|
assert al._circuit_breaker_check(tc) is None
|
|
410
410
|
|
|
411
|
-
def
|
|
412
|
-
"""
|
|
411
|
+
def test_circuit_breaker_disabled_for_failed_commands(self):
|
|
412
|
+
"""Circuit breaker is disabled — even failed commands are not blocked."""
|
|
413
413
|
from drydock.core.agent_loop import AgentLoop
|
|
414
414
|
from drydock.core.types import MessageList
|
|
415
415
|
from types import SimpleNamespace
|
|
@@ -426,12 +426,11 @@ class TestCircuitBreaker:
|
|
|
426
426
|
assert al._circuit_breaker_check(tc) is None
|
|
427
427
|
al._circuit_breaker_record(tc, "FAILED: command not found")
|
|
428
428
|
|
|
429
|
-
|
|
430
|
-
assert
|
|
431
|
-
assert "failed" in result
|
|
429
|
+
# CB is disabled — always returns None
|
|
430
|
+
assert al._circuit_breaker_check(tc) is None
|
|
432
431
|
|
|
433
|
-
def
|
|
434
|
-
"""
|
|
432
|
+
def test_circuit_breaker_disabled_for_all_args(self):
|
|
433
|
+
"""Circuit breaker is disabled — no arguments are ever blocked."""
|
|
435
434
|
from drydock.core.agent_loop import AgentLoop
|
|
436
435
|
from drydock.core.types import MessageList
|
|
437
436
|
from types import SimpleNamespace
|
|
@@ -445,7 +444,8 @@ class TestCircuitBreaker:
|
|
|
445
444
|
|
|
446
445
|
for _ in range(3):
|
|
447
446
|
al._circuit_breaker_record(tc1, "FAILED: command not found")
|
|
448
|
-
|
|
447
|
+
# CB is disabled — both return None
|
|
448
|
+
assert al._circuit_breaker_check(tc1) is None
|
|
449
449
|
assert al._circuit_breaker_check(tc2) is None
|
|
450
450
|
|
|
451
451
|
|
|
@@ -55,7 +55,7 @@ def _add_tool_call(al: AgentLoop, tool_name: str, arguments: str = "{}") -> None
|
|
|
55
55
|
# ============================================================================
|
|
56
56
|
|
|
57
57
|
class TestCircuitBreaker:
|
|
58
|
-
"""Circuit breaker
|
|
58
|
+
"""Circuit breaker is fully disabled — always returns None."""
|
|
59
59
|
|
|
60
60
|
def test_first_call_allowed(self):
|
|
61
61
|
al = _make_agent()
|
|
@@ -68,18 +68,16 @@ class TestCircuitBreaker:
|
|
|
68
68
|
al._circuit_breaker_record(tc, "file1.py\nfile2.py")
|
|
69
69
|
assert al._circuit_breaker_check(tc) is None
|
|
70
70
|
|
|
71
|
-
def
|
|
72
|
-
"""
|
|
71
|
+
def test_disabled_for_failed_after_3(self):
|
|
72
|
+
"""CB disabled — failed commands are NOT blocked even after 3 repeats."""
|
|
73
73
|
al = _make_agent()
|
|
74
74
|
tc = SimpleNamespace(tool_name="bash", args_dict={"command":"bad_cmd"})
|
|
75
75
|
for _ in range(3):
|
|
76
76
|
al._circuit_breaker_record(tc, "FAILED: command not found")
|
|
77
|
-
|
|
78
|
-
assert result is not None
|
|
79
|
-
assert "failed" in result
|
|
77
|
+
assert al._circuit_breaker_check(tc) is None
|
|
80
78
|
|
|
81
79
|
def test_failed_2_not_blocked(self):
|
|
82
|
-
"""Failed commands with only 2 repeats are not blocked
|
|
80
|
+
"""Failed commands with only 2 repeats are not blocked."""
|
|
83
81
|
al = _make_agent()
|
|
84
82
|
tc = SimpleNamespace(tool_name="bash", args_dict={"command":"bad_cmd"})
|
|
85
83
|
al._circuit_breaker_record(tc, "FAILED: command not found")
|
|
@@ -102,39 +100,40 @@ class TestCircuitBreaker:
|
|
|
102
100
|
al._circuit_breaker_record(tc, "match.py:10:foo")
|
|
103
101
|
assert al._circuit_breaker_check(tc) is None
|
|
104
102
|
|
|
105
|
-
def
|
|
103
|
+
def test_disabled_returns_none_even_for_failed(self):
|
|
104
|
+
"""CB disabled — returns None even for commands that would have been blocked."""
|
|
106
105
|
al = _make_agent()
|
|
107
106
|
tc = SimpleNamespace(tool_name="bash", args_dict={"command":"python3 run.py"})
|
|
108
107
|
for _ in range(3):
|
|
109
108
|
al._circuit_breaker_record(tc, "FAILED: module not found")
|
|
110
|
-
|
|
111
|
-
assert result is not None
|
|
112
|
-
assert "DIFFERENT" in result or "different" in result
|
|
109
|
+
assert al._circuit_breaker_check(tc) is None
|
|
113
110
|
|
|
114
|
-
def
|
|
111
|
+
def test_disabled_returns_none_for_repeated_failures(self):
|
|
112
|
+
"""CB disabled — returns None regardless of failure count."""
|
|
115
113
|
al = _make_agent()
|
|
116
114
|
tc = SimpleNamespace(tool_name="bash", args_dict={"command":"python3 run.py"})
|
|
117
115
|
for _ in range(3):
|
|
118
116
|
al._circuit_breaker_record(tc, "FAILED: error")
|
|
119
|
-
|
|
120
|
-
assert "3" in result
|
|
117
|
+
assert al._circuit_breaker_check(tc) is None
|
|
121
118
|
|
|
122
|
-
def
|
|
119
|
+
def test_disabled_for_all_args(self):
|
|
120
|
+
"""CB disabled — no args are blocked, even after repeated failures."""
|
|
123
121
|
al = _make_agent()
|
|
124
122
|
tc1 = SimpleNamespace(tool_name="bash", args_dict={"command":"bad_cmd"})
|
|
125
123
|
tc2 = SimpleNamespace(tool_name="bash", args_dict={"command":"ls -la"})
|
|
126
124
|
for _ in range(3):
|
|
127
125
|
al._circuit_breaker_record(tc1, "FAILED: not found")
|
|
128
|
-
assert al._circuit_breaker_check(tc1) is
|
|
129
|
-
assert al._circuit_breaker_check(tc2) is None
|
|
126
|
+
assert al._circuit_breaker_check(tc1) is None
|
|
127
|
+
assert al._circuit_breaker_check(tc2) is None
|
|
130
128
|
|
|
131
|
-
def
|
|
129
|
+
def test_disabled_for_all_tools(self):
|
|
130
|
+
"""CB disabled — no tools are blocked, even after repeated failures."""
|
|
132
131
|
al = _make_agent()
|
|
133
132
|
tc1 = SimpleNamespace(tool_name="bash", args_dict={"command":"bad_cmd"})
|
|
134
133
|
tc2 = SimpleNamespace(tool_name="grep", args_dict={"pattern":"foo"})
|
|
135
134
|
for _ in range(3):
|
|
136
135
|
al._circuit_breaker_record(tc1, "FAILED: not found")
|
|
137
|
-
assert al._circuit_breaker_check(tc1) is
|
|
136
|
+
assert al._circuit_breaker_check(tc1) is None
|
|
138
137
|
assert al._circuit_breaker_check(tc2) is None
|
|
139
138
|
|
|
140
139
|
def test_failed_then_success_not_blocked(self):
|
|
@@ -143,7 +142,6 @@ class TestCircuitBreaker:
|
|
|
143
142
|
tc = SimpleNamespace(tool_name="bash", args_dict={"command":"python3 run.py"})
|
|
144
143
|
al._circuit_breaker_record(tc, "FAILED: error")
|
|
145
144
|
al._circuit_breaker_record(tc, "FAILED: error")
|
|
146
|
-
# Now it succeeds — last_result no longer starts with FAILED:
|
|
147
145
|
al._circuit_breaker_record(tc, "output ok")
|
|
148
146
|
assert al._circuit_breaker_check(tc) is None
|
|
149
147
|
|