drydock-cli 0.5.2__tar.gz → 0.6.1__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-0.5.2 → drydock_cli-0.6.1}/PKG-INFO +1 -1
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/PRD.md +26 -4
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/entrypoint.py +25 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/loading.py +9 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/agent_loop.py +78 -0
- drydock_cli-0.6.1/drydock/core/consultant.py +141 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/bash.py +17 -3
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/pyproject.toml +1 -1
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/test_drydock_tasks.py +79 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/.github/CODEOWNERS +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/.github/DISCUSSION_TEMPLATE/ideas.yml +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/.github/workflows/build-and-upload.yml +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/.github/workflows/ci.yml +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/.github/workflows/issue-labeler.yml +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/.github/workflows/release.yml +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/.gitignore +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/.pre-commit-config.yaml +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/.python-version +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/.typos.toml +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/.vscode/extensions.json +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/.vscode/launch.json +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/.vscode/settings.json +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/AGENTS.md +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/CHANGELOG.md +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/CLAUDE.md +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/CONTRIBUTING.md +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/Drydock_rebrand.md +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/LICENSE +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/NOTICE +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/README.md +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/action.yml +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/distribution/zed/LICENSE +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/distribution/zed/extension.toml +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/distribution/zed/icons/mistral_vibe.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/docs/README.md +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/docs/acp-setup.md +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/docs/proxy-setup.md +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/__init__.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/acp/__init__.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/acp/acp_agent_loop.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/acp/acp_logger.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/acp/entrypoint.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/acp/tools/__init__.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/acp/tools/base.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/acp/tools/builtins/bash.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/acp/tools/builtins/read_file.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/acp/tools/builtins/search_replace.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/acp/tools/builtins/todo.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/acp/tools/builtins/write_file.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/acp/tools/session_update.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/acp/utils.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/__init__.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/autocompletion/__init__.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/autocompletion/base.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/autocompletion/path_completion.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/autocompletion/slash_command.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/cli.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/clipboard.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/commands.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/history_manager.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/plan_offer/adapters/http_whoami_gateway.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/plan_offer/decide_plan_offer.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/plan_offer/ports/whoami_gateway.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/terminal_setup.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/__init__.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/ansi_markdown.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/app.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/app.tcss +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/external_editor.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/handlers/__init__.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/handlers/event_handler.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/notifications/__init__.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/notifications/adapters/__init__.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/notifications/adapters/textual_notification_adapter.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/notifications/ports/__init__.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/notifications/ports/notification_port.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/__init__.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/approval_app.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/banner/banner.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/banner/petit_chat.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/braille_renderer.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/chat_input/__init__.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/chat_input/body.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/chat_input/completion_manager.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/chat_input/completion_popup.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/chat_input/container.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/chat_input/text_area.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/compact.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/config_app.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/context_progress.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/load_more.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/messages.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/no_markup_static.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/path_display.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/proxy_setup_app.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/question_app.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/session_picker.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/spinner.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/status_message.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/teleport_message.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/tool_widgets.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/tools.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/vscode_compat.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/windowing/__init__.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/windowing/history.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/windowing/history_windowing.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/windowing/state.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/update_notifier/__init__.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/update_notifier/adapters/filesystem_update_cache_repository.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/update_notifier/adapters/github_update_gateway.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/update_notifier/adapters/pypi_update_gateway.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/update_notifier/ports/update_cache_repository.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/update_notifier/ports/update_gateway.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/update_notifier/update.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/update_notifier/whats_new.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/__init__.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/agents/__init__.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/agents/manager.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/agents/models.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/auth/__init__.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/auth/crypto.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/auth/github.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/autocompletion/__init__.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/autocompletion/completers.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/autocompletion/file_indexer/__init__.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/autocompletion/file_indexer/ignore_rules.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/autocompletion/file_indexer/indexer.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/autocompletion/file_indexer/store.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/autocompletion/file_indexer/watcher.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/autocompletion/fuzzy.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/autocompletion/path_prompt.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/autocompletion/path_prompt_adapter.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/config/__init__.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/config/_settings.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/config/harness_files/__init__.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/config/harness_files/_harness_manager.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/config/harness_files/_paths.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/drydock_states.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/llm/__init__.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/llm/backend/anthropic.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/llm/backend/base.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/llm/backend/factory.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/llm/backend/generic.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/llm/backend/mistral.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/llm/backend/reasoning_adapter.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/llm/backend/vertex.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/llm/exceptions.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/llm/format.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/llm/message_utils.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/llm/types.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/logger.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/middleware.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/output_formatters.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/paths/__init__.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/paths/_local_config_walk.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/paths/_vibe_home.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/paths/conventions.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/plan_session.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/programmatic.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/prompts/__init__.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/prompts/cli.md +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/prompts/compact.md +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/prompts/dangerous_directory.md +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/prompts/diagnostic.md +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/prompts/explore.md +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/prompts/planner.md +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/prompts/project_context.md +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/prompts/tests.md +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/proxy_setup.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/session/session_loader.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/session/session_logger.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/session/session_migration.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/session/state_file.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/skills/__init__.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/skills/manager.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/skills/models.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/skills/parser.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/slug.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/system_prompt.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/telemetry/__init__.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/telemetry/send.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/teleport/errors.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/teleport/git.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/teleport/nuage.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/teleport/teleport.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/teleport/types.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/base.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/ask_user_question.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/exit_plan_mode.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/grep.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/prompts/__init__.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/prompts/ask_user_question.md +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/prompts/bash.md +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/prompts/grep.md +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/prompts/read_file.md +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/prompts/search_replace.md +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/prompts/swe_bench.md +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/prompts/task.md +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/prompts/todo.md +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/prompts/webfetch.md +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/prompts/websearch.md +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/prompts/write_file.md +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/read_file.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/search_replace.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/task.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/todo.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/webfetch.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/websearch.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/write_file.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/injection_guard.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/manager.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/mcp/__init__.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/mcp/registry.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/mcp/tools.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/mcp_sampling.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/ui.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/utils.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/trusted_folders.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/types.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/utils.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/setup/onboarding/__init__.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/setup/onboarding/base.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/setup/onboarding/onboarding.tcss +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/setup/onboarding/screens/__init__.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/setup/onboarding/screens/api_key.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/setup/onboarding/screens/welcome.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/setup/trusted_folders/trust_folder_dialog.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/setup/trusted_folders/trust_folder_dialog.tcss +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/skills/__init__.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/skills/create-presentation/SKILL.md +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/whats_new.md +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock-acp.spec +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock_terms.md +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/flake.lock +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/flake.nix +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/scripts/README.md +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/scripts/bump_version.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/scripts/deploy_to_github.sh +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/scripts/install.sh +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/scripts/prepare_release.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/scripts/publish_to_pypi.sh +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/__init__.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/acp/conftest.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/acp/test_acp.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/acp/test_agent_thought.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/acp/test_bash.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/acp/test_compact_session_updates.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/acp/test_content.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/acp/test_initialize.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/acp/test_list_sessions.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/acp/test_load_session.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/acp/test_multi_session.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/acp/test_new_session.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/acp/test_proxy_setup_acp.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/acp/test_read_file.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/acp/test_search_replace.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/acp/test_set_config_option.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/acp/test_set_mode.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/acp/test_set_model.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/acp/test_tool_call_session_update.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/acp/test_utils.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/acp/test_write_file.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/autocompletion/test_file_indexer.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/autocompletion/test_fuzzy.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/autocompletion/test_path_completer_fuzzy.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/autocompletion/test_path_completer_recursive.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/autocompletion/test_path_completion_controller.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/autocompletion/test_path_prompt_transformer.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/autocompletion/test_slash_command_controller.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/autocompletion/test_ui_chat_autocompletion.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/backend/__init__.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/backend/data/__init__.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/backend/data/fireworks.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/backend/data/mistral.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/backend/test_anthropic_adapter.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/backend/test_backend.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/backend/test_reasoning_adapter.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/backend/test_vertex_anthropic_adapter.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/cli/plan_offer/adapters/fake_whoami_gateway.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/cli/plan_offer/test_decide_plan_offer.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/cli/plan_offer/test_http_whoami_gateway.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/cli/test_bell_notifications.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/cli/test_braille_renderer.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/cli/test_clipboard.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/cli/test_commands.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/cli/test_copy_shortcuts.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/cli/test_external_editor.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/cli/test_no_markup_static.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/cli/test_question_app.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/cli/test_spinner.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/cli/test_switching_mode.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/cli/test_ui_clipboard_notifications.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/cli/test_ui_session_incremental_renderer.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/cli/test_ui_session_resume.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/cli/test_ui_skill_dispatch.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/cli/textual_ui/__init__.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/cli/textual_ui/test_session_picker.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/conftest.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/core/test_agents.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/core/test_auth_crypto.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/core/test_auth_github.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/core/test_config_load_dotenv.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/core/test_config_paths.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/core/test_config_resolution.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/core/test_file_logging.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/core/test_plan_session.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/core/test_proxy_setup.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/core/test_slug.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/core/test_telemetry_send.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/core/test_teleport_git.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/core/test_teleport_nuage.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/core/test_teleport_service.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/core/test_trusted_folders.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/core/test_utils.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/e2e/common.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/e2e/conftest.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/e2e/mock_server.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/e2e/test_cli_tui_onboarding.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/e2e/test_cli_tui_streaming.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/e2e/test_cli_tui_tool_approval.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/mock/__init__.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/mock/mock_backend_factory.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/mock/mock_entrypoint.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/mock/utils.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/onboarding/test_run_onboarding.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/onboarding/test_ui_onboarding.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/session/test_session_loader.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/session/test_session_logger.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/session/test_session_migration.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/skills/conftest.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/skills/test_manager.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/skills/test_models.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/skills/test_parser.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_ask_user_question/test_snapshot_ask_user_question_collapsed.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_ask_user_question/test_snapshot_ask_user_question_expanded.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_basic_conversation/test_snapshot_shows_basic_conversation.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_code_block_horizontal_scrolling/test_snapshot_allows_horizontal_scrolling_for_long_code_blocks.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_empty_assistant_before_reasoning/test_snapshot_empty_assistant_removed_when_reasoning_starts.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_cycle_to_accept_edits_mode.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_cycle_to_auto_approve_mode.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_cycle_to_plan_mode.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_cycle_wraps_to_default.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_default_mode.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_parallel_tool_calls/test_snapshot_parallel_tool_calls_pending.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_parallel_tool_calls/test_snapshot_parallel_tool_calls_resolved.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_cancel_discards_changes.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_edit_existing_values.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_initial_empty.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_initial_with_values.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_save_error.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_save_new_values.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_answer_first_advance.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_first_answered_checkmark.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_initial.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_navigate_left_wraps.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_navigate_right.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_tab_to_second.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_initial.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_mixed_selection.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_navigate_to_submit.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_other_with_text.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_toggle_first.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_toggle_multiple.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_untoggle.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_initial.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_navigate_down.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_navigate_to_other.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_navigate_to_third_option.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_navigate_up_wraps.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_other_typing.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_reasoning_content/test_snapshot_buffered_reasoning_yields_before_content.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_reasoning_content/test_snapshot_shows_interleaved_reasoning.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_reasoning_content/test_snapshot_shows_reasoning_content.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_reasoning_content/test_snapshot_shows_reasoning_content_expanded.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_release_update_notification/test_snapshot_shows_release_update_notification.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_session_resume/test_snapshot_shows_resumed_session_messages.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_streaming_tool_call/test_snapshot_tool_call_partial.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_streaming_tool_call/test_snapshot_tool_call_updated.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_push_confirmation_cancel_selected.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_push_confirmation_multiple_commits.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_push_confirmation_single_commit.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_auth_complete.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_auth_required.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_checking_git.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_complete.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_error.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_pushing.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_sending_token.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_starting_workflow.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_whats_new/test_snapshot_shows_no_plan_message.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_whats_new/test_snapshot_shows_switch_message.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_whats_new/test_snapshot_shows_upgrade_message.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_whats_new/test_snapshot_shows_whats_new_message.svg +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/base_snapshot_test_app.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/conftest.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/snap_compare.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/test_ui_snapshot_ask_user_question.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/test_ui_snapshot_basic_conversation.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/test_ui_snapshot_code_block_horizontal_scrolling.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/test_ui_snapshot_empty_assistant_before_reasoning.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/test_ui_snapshot_modes.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/test_ui_snapshot_parallel_tool_calls.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/test_ui_snapshot_proxy_setup.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/test_ui_snapshot_question_app.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/test_ui_snapshot_reasoning_content.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/test_ui_snapshot_release_update_notification.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/test_ui_snapshot_session_resume.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/test_ui_snapshot_streaming_tool_call.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/test_ui_snapshot_teleport.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/test_ui_snapshot_whats_new.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/stubs/fake_backend.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/stubs/fake_client.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/stubs/fake_tool.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/test_agent_auto_compact.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/test_agent_backend.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/test_agent_observer_streaming.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/test_agent_stats.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/test_agent_tool_call.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/test_agents.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/test_cli_programmatic_preload.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/test_drydock_regression.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/test_history_manager.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/test_message_id.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/test_message_merging.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/test_middleware.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/test_reasoning_content.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/test_system_prompt.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/test_tagged_text.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/test_ui_external_editor.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/test_ui_input_history.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/tools/test_ask_user_question.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/tools/test_bash.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/tools/test_exit_plan_mode.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/tools/test_grep.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/tools/test_invoke_context.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/tools/test_manager_get_tool_config.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/tools/test_mcp.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/tools/test_mcp_sampling.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/tools/test_task.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/tools/test_ui_bash_execution.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/tools/test_webfetch.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/tools/test_websearch.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/update_notifier/adapters/fake_update_cache_repository.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/update_notifier/adapters/fake_update_gateway.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/update_notifier/test_do_update.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/update_notifier/test_filesystem_update_cache_repository.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/update_notifier/test_github_update_gateway.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/update_notifier/test_pypi_update_gateway.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/update_notifier/test_ui_update_notification.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/update_notifier/test_update_use_case.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/update_notifier/test_whats_new.py +0 -0
- {drydock_cli-0.5.2 → drydock_cli-0.6.1}/uv.lock +0 -0
|
@@ -153,10 +153,32 @@ User-reported issues from real usage testing, all fixed:
|
|
|
153
153
|
|
|
154
154
|
### Phase 5b: Testing & CI (Mar 24)
|
|
155
155
|
|
|
156
|
-
- **
|
|
157
|
-
- **
|
|
158
|
-
- **
|
|
159
|
-
- **PyPI published** — drydock-cli v0.
|
|
156
|
+
- **76 regression tests** gating all deploys
|
|
157
|
+
- **Continuous SWE-bench loop** — 500/500 tasks tested, 49.0% pass rate (+9.4% from baseline)
|
|
158
|
+
- **vibe/ → drydock/** package rename (908 imports updated)
|
|
159
|
+
- **PyPI published** — drydock-cli v0.5.2
|
|
160
|
+
|
|
161
|
+
### Phase 6: GSD Integration & Performance (Mar 25)
|
|
162
|
+
|
|
163
|
+
GSD-inspired features (from [get-shit-done](https://github.com/gsd-build/get-shit-done)):
|
|
164
|
+
|
|
165
|
+
| Feature | Details |
|
|
166
|
+
|---------|---------|
|
|
167
|
+
| Tiered context warnings | 4 levels at 50/65/75/85% usage, debounced every 5 calls |
|
|
168
|
+
| Prompt injection guard | Detects role overrides, invisible Unicode, hidden instructions in file writes |
|
|
169
|
+
| Structured state file | `.drydock/state.md` persists task, files, decisions across sessions |
|
|
170
|
+
| Deviation handling rules | Auto-fix bugs/imports, ask user for architecture/scope decisions |
|
|
171
|
+
|
|
172
|
+
Performance and loop fixes:
|
|
173
|
+
|
|
174
|
+
| Fix | Details |
|
|
175
|
+
|-----|---------|
|
|
176
|
+
| Circuit breaker | Blocks exact same tool call after 2 attempts, returns cached result |
|
|
177
|
+
| Thinking flicker fix | Status words change every 4s, not every token |
|
|
178
|
+
| Conda env protection | Preserves user's active conda environment in subprocesses |
|
|
179
|
+
| `--insecure` / `-k` flag | Disables SSL verification for corporate proxy environments |
|
|
180
|
+
| `--consultant MODEL` flag | Allows calling a smarter model for single-turn advice when stuck |
|
|
181
|
+
| 81 regression tests | Circuit breaker, injection guard, state file, context tiers all tested |
|
|
160
182
|
|
|
161
183
|
---
|
|
162
184
|
|
|
@@ -90,6 +90,19 @@ def parse_arguments() -> argparse.Namespace:
|
|
|
90
90
|
help="Skip all tool permission checks. Equivalent to --agent auto-approve. "
|
|
91
91
|
"Use with caution — tools will execute without confirmation.",
|
|
92
92
|
)
|
|
93
|
+
parser.add_argument(
|
|
94
|
+
"-k", "--insecure",
|
|
95
|
+
action="store_true",
|
|
96
|
+
help="Disable SSL certificate verification for web searches and API calls. "
|
|
97
|
+
"Useful behind corporate proxies with self-signed certificates.",
|
|
98
|
+
)
|
|
99
|
+
parser.add_argument(
|
|
100
|
+
"--consultant",
|
|
101
|
+
metavar="MODEL",
|
|
102
|
+
help="Enable consultant mode: when the agent is uncertain or stuck in a loop, "
|
|
103
|
+
"it can call a more capable model (e.g., 'gemini-2.5-pro') for single-turn advice. "
|
|
104
|
+
"The consultant is NOT used for tool calls, only reasoning.",
|
|
105
|
+
)
|
|
93
106
|
|
|
94
107
|
# Feature flag for teleport, not exposed to the user yet
|
|
95
108
|
parser.add_argument("--teleport", action="store_true", help=argparse.SUPPRESS)
|
|
@@ -160,6 +173,18 @@ def main() -> None:
|
|
|
160
173
|
if args.dangerously_skip_permissions:
|
|
161
174
|
args.agent = BuiltinAgentName.AUTO_APPROVE
|
|
162
175
|
|
|
176
|
+
# --insecure → disable SSL verification globally
|
|
177
|
+
if args.insecure:
|
|
178
|
+
os.environ["DRYDOCK_INSECURE"] = "1"
|
|
179
|
+
os.environ["CURL_CA_BUNDLE"] = ""
|
|
180
|
+
os.environ["REQUESTS_CA_BUNDLE"] = ""
|
|
181
|
+
import ssl
|
|
182
|
+
ssl._create_default_https_context = ssl._create_unverified_context
|
|
183
|
+
|
|
184
|
+
# --consultant → store for agent loop to use
|
|
185
|
+
if args.consultant:
|
|
186
|
+
os.environ["DRYDOCK_CONSULTANT_MODEL"] = args.consultant
|
|
187
|
+
|
|
163
188
|
is_interactive = args.prompt is None
|
|
164
189
|
if is_interactive:
|
|
165
190
|
check_and_resolve_trusted_folder()
|
|
@@ -64,6 +64,9 @@ class LoadingWidget(SpinnerMixin, Static):
|
|
|
64
64
|
"Stocking the galley",
|
|
65
65
|
]
|
|
66
66
|
|
|
67
|
+
# Minimum seconds between status word changes (prevents flicker)
|
|
68
|
+
_STATUS_CHANGE_INTERVAL = 4.0
|
|
69
|
+
|
|
67
70
|
def __init__(self, status: str | None = None) -> None:
|
|
68
71
|
super().__init__(classes="loading-widget")
|
|
69
72
|
self.init_spinner()
|
|
@@ -77,6 +80,7 @@ class LoadingWidget(SpinnerMixin, Static):
|
|
|
77
80
|
self._last_elapsed: int = -1
|
|
78
81
|
self._paused_total: float = 0.0
|
|
79
82
|
self._pause_start: float | None = None
|
|
83
|
+
self._last_status_change: float = 0.0
|
|
80
84
|
|
|
81
85
|
def _get_easter_egg(self) -> str | None:
|
|
82
86
|
EASTER_EGG_PROBABILITY = 0.10
|
|
@@ -111,6 +115,11 @@ class LoadingWidget(SpinnerMixin, Static):
|
|
|
111
115
|
self._pause_start = None
|
|
112
116
|
|
|
113
117
|
def set_status(self, status: str) -> None:
|
|
118
|
+
# Throttle status word changes to prevent flicker
|
|
119
|
+
now = time()
|
|
120
|
+
if now - self._last_status_change < self._STATUS_CHANGE_INTERVAL:
|
|
121
|
+
return # Too soon — keep current word
|
|
122
|
+
self._last_status_change = now
|
|
114
123
|
self.status = self._apply_easter_egg(status)
|
|
115
124
|
self._update_animation()
|
|
116
125
|
|
|
@@ -188,6 +188,10 @@ class AgentLoop:
|
|
|
188
188
|
self.middleware_pipeline = MiddlewarePipeline()
|
|
189
189
|
self._setup_middleware()
|
|
190
190
|
|
|
191
|
+
# Circuit breaker: track tool call signatures to prevent exact repeats
|
|
192
|
+
# Key: hash(tool_name + args), Value: (count, last_result_snippet)
|
|
193
|
+
self._tool_call_history: dict[str, tuple[int, str]] = {}
|
|
194
|
+
|
|
191
195
|
system_prompt = get_universal_system_prompt(
|
|
192
196
|
self.tool_manager, self.config, self.skill_manager, self.agent_manager
|
|
193
197
|
)
|
|
@@ -831,9 +835,81 @@ class AgentLoop:
|
|
|
831
835
|
)
|
|
832
836
|
)
|
|
833
837
|
|
|
838
|
+
def _get_attempted_summary(self) -> str:
|
|
839
|
+
"""Build a summary of what the agent has already tried."""
|
|
840
|
+
if not self._tool_call_history:
|
|
841
|
+
return ""
|
|
842
|
+
attempts = []
|
|
843
|
+
for sig, (count, result) in self._tool_call_history.items():
|
|
844
|
+
if count >= 2:
|
|
845
|
+
attempts.append(f" - Ran {count}x, result: {result[:80]}")
|
|
846
|
+
if attempts:
|
|
847
|
+
return "ALREADY ATTEMPTED (do NOT repeat):\n" + "\n".join(attempts[:10])
|
|
848
|
+
return ""
|
|
849
|
+
|
|
850
|
+
async def _circuit_breaker_check(self, tool_call: ResolvedToolCall) -> str | None:
|
|
851
|
+
"""Block exact-duplicate tool calls. Returns cached result or None.
|
|
852
|
+
On 3rd attempt, auto-consults the smarter model if available."""
|
|
853
|
+
sig = hashlib.md5(
|
|
854
|
+
f"{tool_call.tool_name}:{tool_call.raw_arguments}".encode()
|
|
855
|
+
).hexdigest()
|
|
856
|
+
|
|
857
|
+
count, last_result = self._tool_call_history.get(sig, (0, ""))
|
|
858
|
+
if count >= 2:
|
|
859
|
+
attempted = self._get_attempted_summary()
|
|
860
|
+
msg = (
|
|
861
|
+
f"CIRCUIT BREAKER: You already ran `{tool_call.tool_name}` with these "
|
|
862
|
+
f"exact arguments {count} times and got the same result each time.\n\n"
|
|
863
|
+
f"Previous result: {last_result[:200]}\n\n"
|
|
864
|
+
f"{attempted}\n\n"
|
|
865
|
+
f"STOP repeating. You MUST try something DIFFERENT:\n"
|
|
866
|
+
f"- Different arguments or search terms\n"
|
|
867
|
+
f"- A completely different tool\n"
|
|
868
|
+
f"- Ask the user for clarification"
|
|
869
|
+
)
|
|
870
|
+
|
|
871
|
+
# Auto-consult smarter model if available
|
|
872
|
+
if count == 2:
|
|
873
|
+
try:
|
|
874
|
+
from drydock.core.consultant import is_consultant_available, ask_consultant
|
|
875
|
+
if is_consultant_available():
|
|
876
|
+
question = (
|
|
877
|
+
f"I'm stuck in a loop. I keep running `{tool_call.tool_name}` "
|
|
878
|
+
f"with args: {tool_call.raw_arguments[:100]} "
|
|
879
|
+
f"and getting: {last_result[:200]}. "
|
|
880
|
+
f"What should I do differently?"
|
|
881
|
+
)
|
|
882
|
+
advice = await ask_consultant(question)
|
|
883
|
+
if advice:
|
|
884
|
+
msg += f"\n\nCONSULTANT ADVICE: {advice}"
|
|
885
|
+
except Exception as e:
|
|
886
|
+
logger.debug("Consultant call failed: %s", e)
|
|
887
|
+
|
|
888
|
+
return msg
|
|
889
|
+
return None
|
|
890
|
+
|
|
891
|
+
def _circuit_breaker_record(self, tool_call: ResolvedToolCall, result_text: str) -> None:
|
|
892
|
+
"""Record a tool call execution for circuit breaker tracking."""
|
|
893
|
+
sig = hashlib.md5(
|
|
894
|
+
f"{tool_call.tool_name}:{tool_call.raw_arguments}".encode()
|
|
895
|
+
).hexdigest()
|
|
896
|
+
count, _ = self._tool_call_history.get(sig, (0, ""))
|
|
897
|
+
self._tool_call_history[sig] = (count + 1, result_text[:500])
|
|
898
|
+
|
|
834
899
|
async def _process_one_tool_call(
|
|
835
900
|
self, tool_call: ResolvedToolCall
|
|
836
901
|
) -> AsyncGenerator[ToolResultEvent | ToolStreamEvent]:
|
|
902
|
+
# Circuit breaker: block exact duplicate calls after 2 attempts
|
|
903
|
+
if blocked := await self._circuit_breaker_check(tool_call):
|
|
904
|
+
yield ToolResultEvent(
|
|
905
|
+
tool_name=tool_call.tool_name,
|
|
906
|
+
tool_class=tool_call.tool_class,
|
|
907
|
+
error=blocked,
|
|
908
|
+
tool_call_id=tool_call.call_id,
|
|
909
|
+
)
|
|
910
|
+
self._handle_tool_response(tool_call, blocked, "failure")
|
|
911
|
+
return
|
|
912
|
+
|
|
837
913
|
try:
|
|
838
914
|
tool_instance = self.tool_manager.get(tool_call.tool_name)
|
|
839
915
|
except Exception as exc:
|
|
@@ -902,6 +978,8 @@ class AgentLoop:
|
|
|
902
978
|
|
|
903
979
|
result_dict = result_model.model_dump()
|
|
904
980
|
text = "\n".join(f"{k}: {v}" for k, v in result_dict.items())
|
|
981
|
+
# Record for circuit breaker
|
|
982
|
+
self._circuit_breaker_record(tool_call, text)
|
|
905
983
|
self._handle_tool_response(
|
|
906
984
|
tool_call, text, "success", decision, result_dict
|
|
907
985
|
)
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"""Consultant agent — asks a smarter model for single-turn advice.
|
|
2
|
+
|
|
3
|
+
The consultant is a READ-ONLY advisor:
|
|
4
|
+
- The local model stays in control of ALL tool calls
|
|
5
|
+
- The consultant NEVER calls tools, writes files, or runs commands
|
|
6
|
+
- It only receives a question and returns reasoning/advice
|
|
7
|
+
- Used when the local model is stuck, uncertain, or looping
|
|
8
|
+
|
|
9
|
+
Usage from agent_loop:
|
|
10
|
+
advice = await ask_consultant("I found 3 files that match. Which one likely contains the bug?")
|
|
11
|
+
|
|
12
|
+
The consultant model is configured via:
|
|
13
|
+
- CLI: drydock --consultant gemini-2.5-pro
|
|
14
|
+
- Env: DRYDOCK_CONSULTANT_MODEL=gemini-2.5-pro
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import logging
|
|
20
|
+
import os
|
|
21
|
+
from typing import Any
|
|
22
|
+
|
|
23
|
+
import httpx
|
|
24
|
+
|
|
25
|
+
logger = logging.getLogger(__name__)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
async def ask_consultant(
|
|
29
|
+
question: str,
|
|
30
|
+
context: str = "",
|
|
31
|
+
model: str | None = None,
|
|
32
|
+
api_key: str | None = None,
|
|
33
|
+
api_base: str | None = None,
|
|
34
|
+
) -> str:
|
|
35
|
+
"""Ask the consultant model a question and get text advice back.
|
|
36
|
+
|
|
37
|
+
Parameters
|
|
38
|
+
----------
|
|
39
|
+
question : str
|
|
40
|
+
The specific question to ask.
|
|
41
|
+
context : str
|
|
42
|
+
Optional context (e.g., file contents, error messages).
|
|
43
|
+
model : str
|
|
44
|
+
Model name. Defaults to DRYDOCK_CONSULTANT_MODEL env var.
|
|
45
|
+
api_key : str
|
|
46
|
+
API key. Auto-detected from common env vars if not provided.
|
|
47
|
+
api_base : str
|
|
48
|
+
API base URL. Auto-detected based on model name if not provided.
|
|
49
|
+
|
|
50
|
+
Returns
|
|
51
|
+
-------
|
|
52
|
+
str
|
|
53
|
+
The consultant's advice text, or an error message.
|
|
54
|
+
"""
|
|
55
|
+
model = model or os.environ.get("DRYDOCK_CONSULTANT_MODEL", "")
|
|
56
|
+
if not model:
|
|
57
|
+
return ""
|
|
58
|
+
|
|
59
|
+
# Auto-detect API key and base URL from model name
|
|
60
|
+
api_key = api_key or _detect_api_key(model)
|
|
61
|
+
api_base = api_base or _detect_api_base(model)
|
|
62
|
+
|
|
63
|
+
if not api_key:
|
|
64
|
+
logger.warning("No API key found for consultant model '%s'", model)
|
|
65
|
+
return ""
|
|
66
|
+
|
|
67
|
+
prompt = f"""You are a senior software engineering consultant. A junior AI coding agent is asking for your advice.
|
|
68
|
+
Give concise, actionable guidance. Do NOT provide code — just tell them WHAT to do and WHERE to look.
|
|
69
|
+
|
|
70
|
+
QUESTION:
|
|
71
|
+
{question}
|
|
72
|
+
"""
|
|
73
|
+
if context:
|
|
74
|
+
prompt += f"\nCONTEXT:\n{context[:2000]}\n"
|
|
75
|
+
|
|
76
|
+
try:
|
|
77
|
+
# Use OpenAI-compatible API (works with Gemini, OpenAI, Mistral, local models)
|
|
78
|
+
verify_ssl = os.environ.get("DRYDOCK_INSECURE") != "1"
|
|
79
|
+
async with httpx.AsyncClient(verify=verify_ssl, timeout=30.0) as client:
|
|
80
|
+
response = await client.post(
|
|
81
|
+
f"{api_base}/chat/completions",
|
|
82
|
+
headers={
|
|
83
|
+
"Authorization": f"Bearer {api_key}",
|
|
84
|
+
"Content-Type": "application/json",
|
|
85
|
+
},
|
|
86
|
+
json={
|
|
87
|
+
"model": model,
|
|
88
|
+
"messages": [{"role": "user", "content": prompt}],
|
|
89
|
+
"max_tokens": 500,
|
|
90
|
+
"temperature": 0.3,
|
|
91
|
+
# NO tools — consultant is read-only
|
|
92
|
+
},
|
|
93
|
+
)
|
|
94
|
+
response.raise_for_status()
|
|
95
|
+
data = response.json()
|
|
96
|
+
advice = data["choices"][0]["message"]["content"]
|
|
97
|
+
logger.info("Consultant (%s) responded: %s", model, advice[:100])
|
|
98
|
+
return advice
|
|
99
|
+
|
|
100
|
+
except Exception as e:
|
|
101
|
+
logger.warning("Consultant call failed: %s", e)
|
|
102
|
+
return f"(Consultant unavailable: {e})"
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def _detect_api_key(model: str) -> str:
|
|
106
|
+
"""Auto-detect API key from environment based on model name."""
|
|
107
|
+
model_lower = model.lower()
|
|
108
|
+
|
|
109
|
+
if "gemini" in model_lower:
|
|
110
|
+
return os.environ.get("GEMINI_API_KEY", os.environ.get("GOOGLE_API_KEY", ""))
|
|
111
|
+
if "gpt" in model_lower or "o1" in model_lower or "o3" in model_lower:
|
|
112
|
+
return os.environ.get("OPENAI_API_KEY", "")
|
|
113
|
+
if "claude" in model_lower:
|
|
114
|
+
return os.environ.get("ANTHROPIC_API_KEY", "")
|
|
115
|
+
if "mistral" in model_lower or "devstral" in model_lower:
|
|
116
|
+
return os.environ.get("MISTRAL_API_KEY", "")
|
|
117
|
+
|
|
118
|
+
# Generic fallback
|
|
119
|
+
return os.environ.get("DRYDOCK_CONSULTANT_API_KEY", "")
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def _detect_api_base(model: str) -> str:
|
|
123
|
+
"""Auto-detect API base URL from model name."""
|
|
124
|
+
model_lower = model.lower()
|
|
125
|
+
|
|
126
|
+
if "gemini" in model_lower:
|
|
127
|
+
return "https://generativelanguage.googleapis.com/v1beta/openai"
|
|
128
|
+
if "gpt" in model_lower or "o1" in model_lower or "o3" in model_lower:
|
|
129
|
+
return "https://api.openai.com/v1"
|
|
130
|
+
if "claude" in model_lower:
|
|
131
|
+
return "https://api.anthropic.com/v1"
|
|
132
|
+
if "mistral" in model_lower or "devstral" in model_lower:
|
|
133
|
+
return os.environ.get("MISTRAL_API_BASE", "https://api.mistral.ai/v1")
|
|
134
|
+
|
|
135
|
+
# Try local vLLM
|
|
136
|
+
return os.environ.get("DRYDOCK_CONSULTANT_API_BASE", "http://localhost:8000/v1")
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def is_consultant_available() -> bool:
|
|
140
|
+
"""Check if a consultant model is configured."""
|
|
141
|
+
return bool(os.environ.get("DRYDOCK_CONSULTANT_MODEL"))
|
|
@@ -110,11 +110,25 @@ def _get_base_env() -> dict[str, str]:
|
|
|
110
110
|
|
|
111
111
|
# Enable conda in non-interactive shells by setting BASH_ENV
|
|
112
112
|
# to source conda's setup script. Without this, `conda activate`
|
|
113
|
-
# fails because it's a shell function defined in .bashrc
|
|
114
|
-
#
|
|
113
|
+
# fails because it's a shell function defined in .bashrc.
|
|
114
|
+
#
|
|
115
|
+
# IMPORTANT: We also preserve the user's active conda env to avoid
|
|
116
|
+
# interfering with other environments and losing their aliases.
|
|
115
117
|
conda_sh = _get_conda_setup_script()
|
|
116
118
|
if conda_sh:
|
|
117
|
-
|
|
119
|
+
# Create a wrapper that sources conda.sh then re-activates the user's env
|
|
120
|
+
active_env = os.environ.get("CONDA_DEFAULT_ENV", "")
|
|
121
|
+
if active_env and active_env != "base":
|
|
122
|
+
# Write a temp script that initializes conda AND activates the user's env
|
|
123
|
+
import tempfile
|
|
124
|
+
wrapper = tempfile.NamedTemporaryFile(
|
|
125
|
+
mode="w", suffix=".sh", delete=False, prefix="drydock_conda_"
|
|
126
|
+
)
|
|
127
|
+
wrapper.write(f'source "{conda_sh}"\nconda activate "{active_env}" 2>/dev/null\n')
|
|
128
|
+
wrapper.close()
|
|
129
|
+
base_env["BASH_ENV"] = wrapper.name
|
|
130
|
+
else:
|
|
131
|
+
base_env["BASH_ENV"] = conda_sh
|
|
118
132
|
|
|
119
133
|
return base_env
|
|
120
134
|
|
|
@@ -16,6 +16,7 @@ These catch the issues users find when actually using the application:
|
|
|
16
16
|
from __future__ import annotations
|
|
17
17
|
|
|
18
18
|
from pathlib import Path
|
|
19
|
+
from unittest.mock import patch
|
|
19
20
|
|
|
20
21
|
import pytest
|
|
21
22
|
|
|
@@ -382,6 +383,84 @@ class TestDeviationHandling:
|
|
|
382
383
|
assert "Auto-fix" in content or "Auto-resolve" in content
|
|
383
384
|
|
|
384
385
|
|
|
386
|
+
# ============================================================================
|
|
387
|
+
# Circuit Breaker
|
|
388
|
+
# ============================================================================
|
|
389
|
+
|
|
390
|
+
class TestCircuitBreaker:
|
|
391
|
+
"""Prevents exact duplicate tool calls."""
|
|
392
|
+
|
|
393
|
+
def test_circuit_breaker_blocks_after_2(self):
|
|
394
|
+
import asyncio
|
|
395
|
+
from drydock.core.agent_loop import AgentLoop
|
|
396
|
+
from drydock.core.types import MessageList
|
|
397
|
+
from types import SimpleNamespace
|
|
398
|
+
|
|
399
|
+
al = object.__new__(AgentLoop)
|
|
400
|
+
al.messages = MessageList()
|
|
401
|
+
al._tool_call_history = {}
|
|
402
|
+
|
|
403
|
+
tc = SimpleNamespace(tool_name="bash", raw_arguments='{"command": "ls -ltr"}')
|
|
404
|
+
|
|
405
|
+
assert asyncio.run(al._circuit_breaker_check(tc)) is None
|
|
406
|
+
al._circuit_breaker_record(tc, "file1.py\nfile2.py")
|
|
407
|
+
assert asyncio.run(al._circuit_breaker_check(tc)) is None
|
|
408
|
+
al._circuit_breaker_record(tc, "file1.py\nfile2.py")
|
|
409
|
+
|
|
410
|
+
result = asyncio.run(al._circuit_breaker_check(tc))
|
|
411
|
+
assert result is not None
|
|
412
|
+
assert "CIRCUIT BREAKER" in result
|
|
413
|
+
|
|
414
|
+
def test_different_args_not_blocked(self):
|
|
415
|
+
import asyncio
|
|
416
|
+
from drydock.core.agent_loop import AgentLoop
|
|
417
|
+
from drydock.core.types import MessageList
|
|
418
|
+
from types import SimpleNamespace
|
|
419
|
+
|
|
420
|
+
al = object.__new__(AgentLoop)
|
|
421
|
+
al.messages = MessageList()
|
|
422
|
+
al._tool_call_history = {}
|
|
423
|
+
|
|
424
|
+
tc1 = SimpleNamespace(tool_name="bash", raw_arguments='{"command": "ls -ltr"}')
|
|
425
|
+
tc2 = SimpleNamespace(tool_name="bash", raw_arguments='{"command": "ls -la"}')
|
|
426
|
+
|
|
427
|
+
al._circuit_breaker_record(tc1, "result1")
|
|
428
|
+
al._circuit_breaker_record(tc1, "result1")
|
|
429
|
+
assert asyncio.run(al._circuit_breaker_check(tc1)) is not None
|
|
430
|
+
assert asyncio.run(al._circuit_breaker_check(tc2)) is None
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
# ============================================================================
|
|
434
|
+
# Insecure Flag
|
|
435
|
+
# ============================================================================
|
|
436
|
+
|
|
437
|
+
class TestInsecureFlag:
|
|
438
|
+
def test_insecure_flag_exists(self):
|
|
439
|
+
from drydock.cli.entrypoint import parse_arguments
|
|
440
|
+
import sys
|
|
441
|
+
with patch.object(sys, "argv", ["drydock", "-k", "-p", "test"]):
|
|
442
|
+
args = parse_arguments()
|
|
443
|
+
assert args.insecure is True
|
|
444
|
+
|
|
445
|
+
def test_consultant_flag_exists(self):
|
|
446
|
+
from drydock.cli.entrypoint import parse_arguments
|
|
447
|
+
import sys
|
|
448
|
+
with patch.object(sys, "argv", ["drydock", "--consultant", "gemini-2.5-pro", "-p", "test"]):
|
|
449
|
+
args = parse_arguments()
|
|
450
|
+
assert args.consultant == "gemini-2.5-pro"
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
# ============================================================================
|
|
454
|
+
# Thinking Flicker Throttle
|
|
455
|
+
# ============================================================================
|
|
456
|
+
|
|
457
|
+
class TestThinkingThrottle:
|
|
458
|
+
def test_status_change_interval_exists(self):
|
|
459
|
+
from drydock.cli.textual_ui.widgets.loading import LoadingWidget
|
|
460
|
+
assert hasattr(LoadingWidget, "_STATUS_CHANGE_INTERVAL")
|
|
461
|
+
assert LoadingWidget._STATUS_CHANGE_INTERVAL >= 3.0
|
|
462
|
+
|
|
463
|
+
|
|
385
464
|
class TestEasterEggs:
|
|
386
465
|
"""Easter eggs are nautical, not French."""
|
|
387
466
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/plan_offer/adapters/http_whoami_gateway.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|