drydock-cli 2.7.15__tar.gz → 2.7.17__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.7.17/.auto_release.lock +1 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/PKG-INFO +1 -1
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/admiral/detectors.py +20 -10
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/agent_loop.py +30 -4
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/llm/format.py +45 -3
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/builtins/bash.py +12 -1
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/builtins/search_replace.py +59 -11
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/pyproject.toml +1 -1
- drydock_cli-2.7.17/tests/core/test_circuit_breaker_readonly_threshold.py +93 -0
- drydock_cli-2.7.17/tests/test_admiral_struggle_dedup.py +68 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_truncated_arg_path_hint.py +30 -0
- drydock_cli-2.7.17/tests/tools/test_search_replace_dir_path.py +91 -0
- drydock_cli-2.7.17/tests/tools/test_search_replace_hard_stop.py +136 -0
- drydock_cli-2.7.17/tests/tools/test_write_file_missing_path_hint.py +78 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/trip_log.md +175 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/uv.lock +1 -1
- drydock_cli-2.7.15/.auto_release.lock +0 -1
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/.claude/scheduled_tasks.lock +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/.github/CODEOWNERS +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/.github/DISCUSSION_TEMPLATE/ideas.yml +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/.github/workflows/build-and-upload.yml +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/.github/workflows/ci.yml +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/.github/workflows/issue-labeler.yml +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/.github/workflows/release.yml +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/.gitignore +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/.pre-commit-config.yaml +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/.python-version +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/.typos.toml +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/.vscode/extensions.json +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/.vscode/launch.json +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/.vscode/settings.json +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/AGENTS.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/Admiral.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/BASELINE_412.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/CHANGELOG.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/CLAUDE.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/CONTRIBUTING.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/DEPLOYMENT.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/Drydock_rebrand.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/LICENSE +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/MODEL_SHORTCOMINGS.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/NOTICE +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/OVERNIGHT_PROGRESS.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/OVERNIGHT_REPORT_2026_04_13.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/PRD.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/README.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/action.yml +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/baseline_history/README.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/baseline_history/results1.tsv +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/baseline_history/results13.tsv +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/baseline_history/results14.tsv +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/baseline_history/results15.tsv +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/baseline_history/results16.tsv +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/baseline_history/results17.tsv +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/baseline_history/results18.tsv +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/baseline_history/results19.tsv +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/baseline_history/results2.tsv +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/baseline_history/results20.tsv +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/baseline_history/results3.tsv +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/baseline_history/results4.tsv +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/baseline_history/results5.tsv +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/baseline_history/results6.tsv +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/baseline_history/results7.tsv +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/baseline_history/results8.tsv +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/baseline_history/results9.tsv +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/baseline_history/results_evolved_v1.tsv +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/distribution/zed/LICENSE +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/distribution/zed/extension.toml +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/distribution/zed/icons/mistral_vibe.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/docs/README.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/docs/acp-setup.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/docs/proxy-setup.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/__init__.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/acp/__init__.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/acp/acp_agent_loop.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/acp/acp_logger.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/acp/entrypoint.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/acp/tools/__init__.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/acp/tools/base.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/acp/tools/builtins/bash.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/acp/tools/builtins/read_file.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/acp/tools/builtins/search_replace.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/acp/tools/builtins/todo.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/acp/tools/builtins/write_file.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/acp/tools/session_update.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/acp/utils.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/admiral/__init__.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/admiral/detectors_proposed.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/admiral/history.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/admiral/interventions.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/admiral/llm_analyzer.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/admiral/metrics.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/admiral/opus_escalator.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/admiral/persistence.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/admiral/policy.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/admiral/proposer.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/admiral/stager.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/admiral/task_classifier.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/admiral/tuning.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/admiral/validator.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/admiral/worker.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/__init__.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/autocompletion/__init__.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/autocompletion/base.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/autocompletion/path_completion.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/autocompletion/slash_command.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/cli.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/clipboard.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/commands.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/entrypoint.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/history_manager.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/plan_offer/adapters/http_whoami_gateway.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/plan_offer/decide_plan_offer.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/plan_offer/ports/whoami_gateway.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/terminal_setup.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/__init__.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/ansi_markdown.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/app.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/app.tcss +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/external_editor.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/handlers/__init__.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/handlers/event_handler.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/notifications/__init__.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/notifications/adapters/__init__.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/notifications/adapters/textual_notification_adapter.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/notifications/ports/__init__.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/notifications/ports/notification_port.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/widgets/__init__.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/widgets/approval_app.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/widgets/banner/banner.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/widgets/banner/petit_chat.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/widgets/braille_renderer.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/widgets/chat_input/__init__.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/widgets/chat_input/body.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/widgets/chat_input/completion_manager.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/widgets/chat_input/completion_popup.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/widgets/chat_input/container.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/widgets/chat_input/text_area.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/widgets/checkpoint_picker.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/widgets/compact.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/widgets/config_app.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/widgets/context_progress.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/widgets/load_more.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/widgets/loading.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/widgets/messages.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/widgets/no_markup_static.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/widgets/path_display.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/widgets/proxy_setup_app.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/widgets/question_app.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/widgets/session_picker.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/widgets/spinner.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/widgets/status_message.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/widgets/teleport_message.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/widgets/tool_widgets.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/widgets/tools.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/widgets/vscode_compat.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/windowing/__init__.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/windowing/history.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/windowing/history_windowing.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/textual_ui/windowing/state.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/update_notifier/__init__.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/update_notifier/adapters/filesystem_update_cache_repository.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/update_notifier/adapters/github_update_gateway.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/update_notifier/adapters/pypi_update_gateway.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/update_notifier/ports/update_cache_repository.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/update_notifier/ports/update_gateway.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/update_notifier/update.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/cli/update_notifier/whats_new.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/__init__.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/agents/__init__.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/agents/manager.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/agents/models.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/auth/__init__.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/auth/crypto.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/auth/github.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/autocompletion/__init__.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/autocompletion/completers.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/autocompletion/file_indexer/__init__.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/autocompletion/file_indexer/ignore_rules.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/autocompletion/file_indexer/indexer.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/autocompletion/file_indexer/store.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/autocompletion/file_indexer/watcher.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/autocompletion/fuzzy.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/autocompletion/path_prompt.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/autocompletion/path_prompt_adapter.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/build_orchestrator.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/checkpoint.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/config/__init__.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/config/_settings.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/config/doctor.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/config/harness_files/__init__.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/config/harness_files/_harness_manager.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/config/harness_files/_paths.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/consultant.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/drydock_states.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/hooks.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/llm/__init__.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/llm/backend/anthropic.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/llm/backend/base.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/llm/backend/factory.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/llm/backend/generic.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/llm/backend/mistral.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/llm/backend/reasoning_adapter.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/llm/backend/vertex.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/llm/exceptions.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/llm/message_utils.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/llm/types.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/logger.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/middleware.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/output_formatters.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/paths/__init__.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/paths/_drydock_home.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/paths/_local_config_walk.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/paths/conventions.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/plan_session.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/plugins.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/programmatic.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/prompts/__init__.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/prompts/builder.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/prompts/cli.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/prompts/compact.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/prompts/dangerous_directory.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/prompts/diagnostic.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/prompts/explore.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/prompts/gemma4.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/prompts/planner.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/prompts/project_context.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/prompts/tests.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/proxy_setup.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/session/agent_memory.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/session/checkpoints.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/session/session_loader.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/session/session_logger.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/session/session_migration.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/session/state_file.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/session_checker.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/skills/__init__.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/skills/manager.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/skills/models.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/skills/parser.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/slug.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/system_prompt.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/telemetry/__init__.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/telemetry/send.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/teleport/errors.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/teleport/git.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/teleport/nuage.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/teleport/teleport.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/teleport/types.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/base.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/builtins/_task_manager.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/builtins/ask_user_question.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/builtins/cron.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/builtins/exit_plan_mode.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/builtins/glob_tool.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/builtins/grep.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/builtins/invoke_skill.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/builtins/lsp.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/builtins/mcp_resources.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/builtins/notebook_edit.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/builtins/powershell.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/builtins/prompts/__init__.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/builtins/prompts/ask_user_question.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/builtins/prompts/bash.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/builtins/prompts/cron.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/builtins/prompts/glob.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/builtins/prompts/grep.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/builtins/prompts/invoke_skill.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/builtins/prompts/lsp.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/builtins/prompts/mcp_resources.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/builtins/prompts/notebook_edit.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/builtins/prompts/powershell.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/builtins/prompts/read_file.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/builtins/prompts/search_replace.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/builtins/prompts/swe_bench.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/builtins/prompts/task.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/builtins/prompts/task_manager.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/builtins/prompts/todo.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/builtins/prompts/tool_search.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/builtins/prompts/webfetch.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/builtins/prompts/websearch.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/builtins/prompts/worktree.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/builtins/prompts/write_file.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/builtins/read_file.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/builtins/task.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/builtins/todo.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/builtins/tool_search.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/builtins/webfetch.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/builtins/websearch.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/builtins/worktree.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/builtins/write_file.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/injection_guard.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/manager.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/mcp/__init__.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/mcp/registry.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/mcp/tools.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/mcp_sampling.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/ui.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/tools/utils.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/trusted_folders.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/types.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/core/utils.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/setup/onboarding/__init__.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/setup/onboarding/base.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/setup/onboarding/onboarding.tcss +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/setup/onboarding/screens/__init__.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/setup/onboarding/screens/api_key.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/setup/onboarding/screens/choice.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/setup/onboarding/screens/local_model.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/setup/onboarding/screens/welcome.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/setup/trusted_folders/trust_folder_dialog.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/setup/trusted_folders/trust_folder_dialog.tcss +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/skills/__init__.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/skills/api-design/SKILL.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/skills/audit-tests/SKILL.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/skills/batch/SKILL.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/skills/commit-code/SKILL.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/skills/context-summary/SKILL.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/skills/create-presentation/SKILL.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/skills/deep-research/SKILL.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/skills/deploy/SKILL.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/skills/diff-review/SKILL.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/skills/doc-gen/SKILL.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/skills/explain-code/SKILL.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/skills/explore-code/SKILL.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/skills/fix-issue/SKILL.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/skills/git-ops/SKILL.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/skills/init-project/SKILL.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/skills/investigate/SKILL.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/skills/loop/SKILL.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/skills/migrate/SKILL.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/skills/perf-analyze/SKILL.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/skills/plan-impl/SKILL.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/skills/pr-review/SKILL.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/skills/refactor/SKILL.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/skills/regex-help/SKILL.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/skills/review/SKILL.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/skills/security-review/SKILL.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/skills/ship/SKILL.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/skills/simplify/SKILL.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/skills/strong-tests/SKILL.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/skills/test-verify/SKILL.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock/whats_new.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock-acp.spec +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/drydock_terms.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/flake.lock +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/flake.nix +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/nohup.out +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/research/README.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/research/config_base.toml +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/research/config_best.toml +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/research/domain_spec.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/research/experimenter.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/research/kernel.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/research/mini_prd.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/research/mini_prompts.txt +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/research/proposer.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/research/results.tsv +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/resume.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/README.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/admiral_probe.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/audit_sampler.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/auto_generate_tests.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/auto_release.sh +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/auto_test_loop.sh +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/autonomous_review.sh +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/autonomous_review_prompt.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/backup.sh +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/bump_version.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/comprehensive_loop.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/deploy_to_github.sh +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/discover_cli_tools.sh +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/evolve_tests.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/gen_2000_prompts.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/install.sh +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/llm_balancer.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/mega_loop.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/meta_ralph_loop.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/monitor_swebench.sh +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/monitor_test_battery.sh +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/notify_release.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/oss_task_harness.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/overnight_agents_test.sh +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/poll_issues.sh +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/port_task.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/prepare_release.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/publish_to_pypi.sh +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/ralph_loop.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/research_babysitter.sh +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/session_loop_audit.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/shakedown.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/shakedown_interactive.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/shakedown_regression.sh +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/shakedown_suite.sh +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/shakedown_variance.sh +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/stress_babysitter.sh +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/stress_prompts_50.txt +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/stress_prompts_realuser.txt +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/stress_prompts_tool_agent.txt +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/stress_prompts_tool_agent_2000.txt +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/stress_shakedown.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/stress_telegram_status.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/stress_watcher.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/telegram_bot.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/test_bank.sh +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/test_full.sh +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/test_smoke.sh +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/test_tui_path.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/tui_test.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/scripts/vllm_failover.sh +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/test/project/dummy +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/__init__.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/acp/conftest.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/acp/test_acp.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/acp/test_agent_thought.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/acp/test_bash.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/acp/test_compact_session_updates.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/acp/test_content.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/acp/test_initialize.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/acp/test_list_sessions.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/acp/test_load_session.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/acp/test_multi_session.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/acp/test_new_session.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/acp/test_proxy_setup_acp.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/acp/test_read_file.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/acp/test_search_replace.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/acp/test_set_config_option.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/acp/test_set_mode.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/acp/test_set_model.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/acp/test_tool_call_session_update.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/acp/test_utils.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/acp/test_write_file.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/autocompletion/test_file_indexer.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/autocompletion/test_fuzzy.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/autocompletion/test_path_completer_fuzzy.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/autocompletion/test_path_completer_recursive.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/autocompletion/test_path_completion_controller.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/autocompletion/test_path_prompt_transformer.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/autocompletion/test_slash_command_controller.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/autocompletion/test_ui_chat_autocompletion.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/backend/__init__.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/backend/data/__init__.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/backend/data/fireworks.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/backend/data/mistral.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/backend/test_anthropic_adapter.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/backend/test_backend.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/backend/test_generic_adapter_sanitize.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/backend/test_reasoning_adapter.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/backend/test_vertex_anthropic_adapter.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/cli/plan_offer/adapters/fake_whoami_gateway.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/cli/plan_offer/test_decide_plan_offer.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/cli/plan_offer/test_http_whoami_gateway.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/cli/test_bell_notifications.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/cli/test_braille_renderer.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/cli/test_clipboard.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/cli/test_commands.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/cli/test_copy_shortcuts.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/cli/test_external_editor.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/cli/test_no_markup_static.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/cli/test_question_app.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/cli/test_spinner.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/cli/test_switching_mode.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/cli/test_ui_clipboard_notifications.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/cli/test_ui_session_incremental_renderer.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/cli/test_ui_session_resume.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/cli/test_ui_skill_dispatch.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/cli/textual_ui/__init__.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/cli/textual_ui/test_session_picker.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/conftest.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/core/test_agents.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/core/test_auth_crypto.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/core/test_auth_github.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/core/test_config_load_dotenv.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/core/test_config_paths.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/core/test_config_resolution.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/core/test_file_logging.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/core/test_plan_session.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/core/test_proxy_setup.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/core/test_slug.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/core/test_telemetry_send.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/core/test_teleport_git.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/core/test_teleport_nuage.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/core/test_teleport_service.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/core/test_trusted_folders.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/core/test_utils.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/e2e/common.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/e2e/conftest.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/e2e/mock_server.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/e2e/test_cli_tui_onboarding.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/e2e/test_cli_tui_streaming.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/e2e/test_cli_tui_tool_approval.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/fixtures/doc_qa_system_prd.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/mock/__init__.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/mock/mock_backend_factory.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/mock/mock_entrypoint.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/mock/utils.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/onboarding/test_run_onboarding.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/onboarding/test_ui_onboarding.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/session/test_session_loader.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/session/test_session_logger.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/session/test_session_migration.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/skills/conftest.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/skills/test_manager.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/skills/test_models.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/skills/test_parser.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_ask_user_question/test_snapshot_ask_user_question_collapsed.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_ask_user_question/test_snapshot_ask_user_question_expanded.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_basic_conversation/test_snapshot_shows_basic_conversation.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/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.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_empty_assistant_before_reasoning/test_snapshot_empty_assistant_removed_when_reasoning_starts.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_cycle_to_accept_edits_mode.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_cycle_to_auto_approve_mode.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_cycle_to_plan_mode.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_cycle_wraps_to_default.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_default_mode.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_parallel_tool_calls/test_snapshot_parallel_tool_calls_pending.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_parallel_tool_calls/test_snapshot_parallel_tool_calls_resolved.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_cancel_discards_changes.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_edit_existing_values.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_initial_empty.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_initial_with_values.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_save_error.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_save_new_values.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_answer_first_advance.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_first_answered_checkmark.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_initial.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_navigate_left_wraps.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_navigate_right.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_tab_to_second.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_initial.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_mixed_selection.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_navigate_to_submit.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_other_with_text.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_toggle_first.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_toggle_multiple.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_untoggle.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_initial.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_navigate_down.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_navigate_to_other.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_navigate_to_third_option.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_navigate_up_wraps.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_other_typing.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_reasoning_content/test_snapshot_buffered_reasoning_yields_before_content.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_reasoning_content/test_snapshot_shows_interleaved_reasoning.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_reasoning_content/test_snapshot_shows_reasoning_content.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_reasoning_content/test_snapshot_shows_reasoning_content_expanded.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_release_update_notification/test_snapshot_shows_release_update_notification.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_session_resume/test_snapshot_shows_resumed_session_messages.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_streaming_tool_call/test_snapshot_tool_call_partial.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_streaming_tool_call/test_snapshot_tool_call_updated.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_push_confirmation_cancel_selected.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_push_confirmation_multiple_commits.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_push_confirmation_single_commit.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_auth_complete.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_auth_required.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_checking_git.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_complete.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_error.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_pushing.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_sending_token.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_starting_workflow.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_whats_new/test_snapshot_shows_no_plan_message.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_whats_new/test_snapshot_shows_switch_message.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_whats_new/test_snapshot_shows_upgrade_message.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/__snapshots__/test_ui_snapshot_whats_new/test_snapshot_shows_whats_new_message.svg +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/base_snapshot_test_app.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/conftest.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/snap_compare.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/test_ui_snapshot_ask_user_question.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/test_ui_snapshot_basic_conversation.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/test_ui_snapshot_code_block_horizontal_scrolling.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/test_ui_snapshot_empty_assistant_before_reasoning.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/test_ui_snapshot_modes.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/test_ui_snapshot_parallel_tool_calls.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/test_ui_snapshot_proxy_setup.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/test_ui_snapshot_question_app.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/test_ui_snapshot_reasoning_content.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/test_ui_snapshot_release_update_notification.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/test_ui_snapshot_session_resume.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/test_ui_snapshot_streaming_tool_call.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/test_ui_snapshot_teleport.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/snapshots/test_ui_snapshot_whats_new.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/stubs/fake_backend.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/stubs/fake_client.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/stubs/fake_tool.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_admiral.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_admiral_phase3.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_admiral_proposed.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_agent_auto_compact.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_agent_backend.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_agent_observer_streaming.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_agent_stats.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_agent_tasks.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_agent_tool_call.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_agents.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_bank_build.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_bank_debug.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_bank_multiagent.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_bank_prd.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_bank_prd_extended.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_bank_tools.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_bank_update.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_build_projects.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_checkpoint.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_cli_programmatic_preload.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_current_bugs.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_drydock_regression.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_drydock_tasks.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_fake_tool_call_paren_syntax.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_full_regression.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_history_manager.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_integration.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_issue_fixes.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_loop_detection.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_message_id.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_message_merging.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_middleware.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_multi_agent.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_read_file_not_found_listing.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_real_failures.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_real_issues.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_real_workflow.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_reasoning_content.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_smoke.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_system_prompt.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_tagged_text.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_tool_args.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_truncate_args_valid_json.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_ui_external_editor.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_ui_input_history.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_user_issues.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_wall_of_text_rescue.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/test_workloads.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/testbank_helpers.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/tools/test_ask_user_question.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/tools/test_bash.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/tools/test_exit_plan_mode.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/tools/test_grep.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/tools/test_invoke_context.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/tools/test_manager_gemma_derived_models.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/tools/test_manager_get_tool_config.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/tools/test_mcp.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/tools/test_mcp_sampling.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/tools/test_read_file_directory.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/tools/test_search_replace_append_fallback.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/tools/test_search_replace_no_op_loop_breaker.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/tools/test_search_replace_refused_loop_breaker.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/tools/test_task.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/tools/test_ui_bash_execution.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/tools/test_webfetch.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/tools/test_websearch.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/tools/test_write_file_dedup_missing_imports.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/update_notifier/adapters/fake_update_cache_repository.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/update_notifier/adapters/fake_update_gateway.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/update_notifier/test_do_update.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/update_notifier/test_filesystem_update_cache_repository.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/update_notifier/test_github_update_gateway.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/update_notifier/test_pypi_update_gateway.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/update_notifier/test_ui_update_notification.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/update_notifier/test_update_use_case.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/tests/update_notifier/test_whats_new.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/worked_examples/README.md +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/worked_examples/cli_subcommand_dispatch.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/worked_examples/lookup.json +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/worked_examples/sql_parser.py +0 -0
- {drydock_cli-2.7.15 → drydock_cli-2.7.17}/worked_examples/tree_walking_interpreter.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
291967
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: drydock-cli
|
|
3
|
-
Version: 2.7.
|
|
3
|
+
Version: 2.7.17
|
|
4
4
|
Summary: Local-first CLI coding agent — tested with Gemma 4 26B via vLLM
|
|
5
5
|
Project-URL: Homepage, https://github.com/fbobe321/drydock
|
|
6
6
|
Project-URL: Repository, https://github.com/fbobe321/drydock
|
|
@@ -80,18 +80,28 @@ def detect_struggle(messages: Sequence[LLMMessage], threshold: int = 20) -> Find
|
|
|
80
80
|
calls_since_write += 1
|
|
81
81
|
if calls_since_write < threshold:
|
|
82
82
|
return None
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
83
|
+
# Stable code (no count) so DEDUP_WINDOW_SEC suppresses repeated firings.
|
|
84
|
+
# Previously included the count, which caused 33 identical interventions
|
|
85
|
+
# in a single session (each with a unique key that bypassed dedup).
|
|
86
|
+
code = f"struggle:{last_write_tool or 'none'}"
|
|
87
|
+
if calls_since_write >= 30:
|
|
88
|
+
directive = (
|
|
89
|
+
f"Admiral: you have made {calls_since_write} tool calls without "
|
|
90
|
+
f"writing any file — search_replace is clearly not finding the text. "
|
|
91
|
+
f"STOP retrying. Call `write_file` with `overwrite=True` to rewrite "
|
|
92
|
+
f"the target file from scratch right now."
|
|
93
|
+
)
|
|
94
|
+
else:
|
|
95
|
+
hint = (
|
|
96
|
+
"Either (a) you already have enough context — commit to a plan and "
|
|
97
|
+
"start writing code now, or (b) you're genuinely stuck — stop and "
|
|
98
|
+
"report what's blocking you to the user."
|
|
99
|
+
)
|
|
100
|
+
directive = (
|
|
91
101
|
f"Admiral: you have made {calls_since_write} tool calls without "
|
|
92
102
|
f"writing or editing any file. {hint}"
|
|
93
|
-
)
|
|
94
|
-
)
|
|
103
|
+
)
|
|
104
|
+
return Finding(code=code, directive=directive)
|
|
95
105
|
|
|
96
106
|
|
|
97
107
|
def run_all(messages: Sequence[LLMMessage]) -> list[Finding]:
|
|
@@ -1131,10 +1131,12 @@ class AgentLoop:
|
|
|
1131
1131
|
token-level sampling bumps don't help when the model picks
|
|
1132
1132
|
the SAME serialized args every time.
|
|
1133
1133
|
|
|
1134
|
-
|
|
1135
|
-
|
|
1134
|
+
Thresholds tuned for 45-prompt session windows (stress sessions
|
|
1135
|
+
reset every 45 prompts — a threshold of 12 never fires in practice
|
|
1136
|
+
because the model loops 4-8 times then moves on; admiral advisories
|
|
1137
|
+
fire at 3 but the model ignores them):
|
|
1136
1138
|
search_replace, write_file, bash: after 8 identical calls
|
|
1137
|
-
read_file, grep, glob, ls: after
|
|
1139
|
+
read_file, grep, glob, ls: after 5 identical calls
|
|
1138
1140
|
"""
|
|
1139
1141
|
args_str = json.dumps(tool_call.args_dict, sort_keys=True, default=str)
|
|
1140
1142
|
sig = hashlib.sha256(
|
|
@@ -1143,7 +1145,7 @@ class AgentLoop:
|
|
|
1143
1145
|
count, last_result = self._tool_call_history.get(sig, (0, ""))
|
|
1144
1146
|
tool_name = tool_call.tool_name
|
|
1145
1147
|
is_readonly = tool_name in ("grep", "read_file", "glob", "ls")
|
|
1146
|
-
threshold =
|
|
1148
|
+
threshold = 5 if is_readonly else 8
|
|
1147
1149
|
if count < threshold:
|
|
1148
1150
|
return None
|
|
1149
1151
|
return (
|
|
@@ -2379,6 +2381,30 @@ class AgentLoop:
|
|
|
2379
2381
|
if len(recent_sr) >= 2 and recent_sr[0] == recent_sr[1]:
|
|
2380
2382
|
return "WARNING|search_replace"
|
|
2381
2383
|
|
|
2384
|
+
# Early check: write_file with _truncated args twice in a row for the
|
|
2385
|
+
# same path. format.py already embeds the file content in the error,
|
|
2386
|
+
# but Gemma 4 ignores the advisory and retries identically. Mute
|
|
2387
|
+
# write_file for 1 turn so the model must use read_file or
|
|
2388
|
+
# search_replace instead — same pattern as the search_replace check.
|
|
2389
|
+
recent_wf_truncated: list[str] = []
|
|
2390
|
+
for msg in reversed(self.messages[-20:]):
|
|
2391
|
+
if msg.role == Role.assistant and msg.tool_calls:
|
|
2392
|
+
for tc in msg.tool_calls:
|
|
2393
|
+
if tc.function and tc.function.name == "write_file":
|
|
2394
|
+
try:
|
|
2395
|
+
args = json.loads(tc.function.arguments or "{}")
|
|
2396
|
+
if args.get("_truncated"):
|
|
2397
|
+
p = (args.get("file_path") or args.get("path") or "")
|
|
2398
|
+
recent_wf_truncated.append(p)
|
|
2399
|
+
except (json.JSONDecodeError, AttributeError):
|
|
2400
|
+
pass
|
|
2401
|
+
if len(recent_wf_truncated) >= 2:
|
|
2402
|
+
break
|
|
2403
|
+
if (len(recent_wf_truncated) >= 2
|
|
2404
|
+
and recent_wf_truncated[0] == recent_wf_truncated[1]):
|
|
2405
|
+
self._hot_tool_path = ("write_file", recent_wf_truncated[0])
|
|
2406
|
+
return "FORCE_STOP"
|
|
2407
|
+
|
|
2382
2408
|
sigs: list[str] = []
|
|
2383
2409
|
tool_names: list[str] = []
|
|
2384
2410
|
lookback = 0
|
|
@@ -3,6 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
import json
|
|
4
4
|
import logging
|
|
5
5
|
import re as _re
|
|
6
|
+
from pathlib import Path
|
|
6
7
|
from typing import TYPE_CHECKING, Any
|
|
7
8
|
|
|
8
9
|
from pydantic import BaseModel, ConfigDict, Field, ValidationError
|
|
@@ -378,7 +379,34 @@ class APIToolFormatHandler:
|
|
|
378
379
|
path_hint = (parsed_call.raw_args.get("path")
|
|
379
380
|
or parsed_call.raw_args.get("file_path")
|
|
380
381
|
or "")
|
|
381
|
-
|
|
382
|
+
# Auto-embed the current file content so the model can
|
|
383
|
+
# rewrite immediately without an extra read_file round-trip.
|
|
384
|
+
file_embed = ""
|
|
385
|
+
if path_hint:
|
|
386
|
+
try:
|
|
387
|
+
p = Path(path_hint)
|
|
388
|
+
if p.exists() and p.is_file():
|
|
389
|
+
raw = p.read_text(errors="replace")
|
|
390
|
+
lines = raw.splitlines()
|
|
391
|
+
max_lines = 120
|
|
392
|
+
if len(lines) <= max_lines:
|
|
393
|
+
file_embed = (
|
|
394
|
+
f"\n\nCurrent file content of `{path_hint}`:\n"
|
|
395
|
+
f"```\n{raw}\n```\n"
|
|
396
|
+
f"Rewrite it now using write_file with the correct content."
|
|
397
|
+
)
|
|
398
|
+
else:
|
|
399
|
+
snippet = "\n".join(lines[:max_lines])
|
|
400
|
+
file_embed = (
|
|
401
|
+
f"\n\nCurrent file content of `{path_hint}` "
|
|
402
|
+
f"(first {max_lines} of {len(lines)} lines):\n"
|
|
403
|
+
f"```\n{snippet}\n```\n"
|
|
404
|
+
f"Use read_file to see the rest, then rewrite with write_file."
|
|
405
|
+
)
|
|
406
|
+
except Exception:
|
|
407
|
+
pass
|
|
408
|
+
if not file_embed and path_hint:
|
|
409
|
+
file_embed = f" Re-read `{path_hint}` with read_file first."
|
|
382
410
|
failed_calls.append(
|
|
383
411
|
FailedToolCall(
|
|
384
412
|
tool_name=parsed_call.tool_name,
|
|
@@ -387,7 +415,7 @@ class APIToolFormatHandler:
|
|
|
387
415
|
f"{parsed_call.tool_name}: your call used a "
|
|
388
416
|
f"truncated history entry as a template (it contained "
|
|
389
417
|
f"'_truncated'/'_original_bytes' instead of real "
|
|
390
|
-
f"arguments).{
|
|
418
|
+
f"arguments).{file_embed} Provide the full required arguments."
|
|
391
419
|
),
|
|
392
420
|
)
|
|
393
421
|
)
|
|
@@ -404,11 +432,25 @@ class APIToolFormatHandler:
|
|
|
404
432
|
)
|
|
405
433
|
)
|
|
406
434
|
except ValidationError as e:
|
|
435
|
+
error_str = str(e)
|
|
436
|
+
if (
|
|
437
|
+
parsed_call.tool_name == "write_file"
|
|
438
|
+
and "path" in error_str
|
|
439
|
+
and "Field required" in error_str
|
|
440
|
+
):
|
|
441
|
+
error_msg = (
|
|
442
|
+
"write_file: missing required `path` parameter. "
|
|
443
|
+
"You must pass BOTH `path` AND `content` as separate arguments. "
|
|
444
|
+
'Fix: write_file(path="your/file.py", content="..."). '
|
|
445
|
+
"Do NOT omit `path`."
|
|
446
|
+
)
|
|
447
|
+
else:
|
|
448
|
+
error_msg = f"Invalid arguments: {e}"
|
|
407
449
|
failed_calls.append(
|
|
408
450
|
FailedToolCall(
|
|
409
451
|
tool_name=parsed_call.tool_name,
|
|
410
452
|
call_id=parsed_call.call_id,
|
|
411
|
-
error=
|
|
453
|
+
error=error_msg,
|
|
412
454
|
)
|
|
413
455
|
)
|
|
414
456
|
|
|
@@ -412,7 +412,18 @@ class Bash(
|
|
|
412
412
|
# the model can reason about what happened.
|
|
413
413
|
# See feedback_no_tool_errors_for_loop_detection.md.
|
|
414
414
|
annotation = f"[Exit code {returncode}]"
|
|
415
|
-
if
|
|
415
|
+
if returncode < 0:
|
|
416
|
+
# Negative returncode means killed by a Unix signal.
|
|
417
|
+
try:
|
|
418
|
+
sig_name = signal.Signals(-returncode).name
|
|
419
|
+
except ValueError:
|
|
420
|
+
sig_name = f"signal {-returncode}"
|
|
421
|
+
annotation += (
|
|
422
|
+
f" — process killed by {sig_name}."
|
|
423
|
+
" If this command starts a server or long-running process,"
|
|
424
|
+
" background it with `command &` and verify ports with `ss -tlnp`."
|
|
425
|
+
)
|
|
426
|
+
elif not stdout and not stderr:
|
|
416
427
|
annotation += " (no output)"
|
|
417
428
|
if returncode == 1:
|
|
418
429
|
annotation += (
|
|
@@ -131,6 +131,34 @@ class SearchReplace(
|
|
|
131
131
|
file_path, search_replace_blocks = self._prepare_and_validate_args(args)
|
|
132
132
|
except ToolError as e:
|
|
133
133
|
err_msg = str(e)
|
|
134
|
+
if err_msg.startswith("Path is not a file:"):
|
|
135
|
+
# Model passed a directory instead of a file path.
|
|
136
|
+
# Return a result (not raise) so the model corrects the call
|
|
137
|
+
# rather than retrying the same directory path in a loop.
|
|
138
|
+
dir_path_str = args.file_path.strip()
|
|
139
|
+
dir_path = Path(dir_path_str).expanduser()
|
|
140
|
+
if not dir_path.is_absolute():
|
|
141
|
+
dir_path = Path.cwd() / dir_path
|
|
142
|
+
dir_path = dir_path.resolve()
|
|
143
|
+
if dir_path.is_dir():
|
|
144
|
+
try:
|
|
145
|
+
files = sorted(p.name for p in dir_path.iterdir() if p.is_file())
|
|
146
|
+
except OSError:
|
|
147
|
+
files = []
|
|
148
|
+
files_list = "\n".join(f" {f}" for f in files[:20]) or " (empty directory)"
|
|
149
|
+
yield SearchReplaceResult(
|
|
150
|
+
file=str(dir_path),
|
|
151
|
+
blocks_applied=0,
|
|
152
|
+
lines_changed=0,
|
|
153
|
+
content=(
|
|
154
|
+
f"PATH ERROR: '{dir_path}' is a directory, not a file. "
|
|
155
|
+
f"search_replace requires a path to a specific file.\n"
|
|
156
|
+
f"Files in that directory:\n{files_list}\n"
|
|
157
|
+
f"Specify the full path including the filename, e.g. "
|
|
158
|
+
f"'{dir_path}/<filename.py>'"
|
|
159
|
+
),
|
|
160
|
+
)
|
|
161
|
+
return
|
|
134
162
|
if err_msg.startswith("NO_BLOCKS:"):
|
|
135
163
|
# Gemma 4 sent raw code without SEARCH/REPLACE markers.
|
|
136
164
|
# CAREFULLY fall back to full file overwrite — but refuse if
|
|
@@ -383,18 +411,38 @@ class SearchReplace(
|
|
|
383
411
|
state[fail_key] = entry
|
|
384
412
|
if entry["count"] >= 2:
|
|
385
413
|
try:
|
|
386
|
-
head = original_content[:2000]
|
|
387
414
|
line_count = original_content.count("\n")
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
415
|
+
count = entry["count"]
|
|
416
|
+
if count >= 3:
|
|
417
|
+
# Show full file (up to 4000 chars) and prohibit retry.
|
|
418
|
+
body = original_content[:4000]
|
|
419
|
+
tail = (
|
|
420
|
+
f"\n...[truncated, {line_count} lines total]"
|
|
421
|
+
if len(original_content) > 4000 else ""
|
|
422
|
+
)
|
|
423
|
+
error_message += (
|
|
424
|
+
f"\n\n[HARD-STOP: this is the #{count} consecutive "
|
|
425
|
+
f"search_replace failure on {file_path.name}. "
|
|
426
|
+
f"Your search text was NOT found in the file. "
|
|
427
|
+
f"DO NOT retry search_replace with the same or similar text. "
|
|
428
|
+
f"REQUIRED action: call write_file with overwrite=True "
|
|
429
|
+
f"and provide the complete new file content. "
|
|
430
|
+
f"Full file content below — use this as the basis "
|
|
431
|
+
f"for your write_file call:\n"
|
|
432
|
+
f"-----FILE START-----\n{body}{tail}\n-----FILE END-----]"
|
|
433
|
+
)
|
|
434
|
+
else:
|
|
435
|
+
head = original_content[:2000]
|
|
436
|
+
error_message += (
|
|
437
|
+
f"\n\n[LOOP-BREAKER: this is the #{count} "
|
|
438
|
+
f"consecutive search_replace failure on "
|
|
439
|
+
f"{file_path.name}. Stop retrying the same search. "
|
|
440
|
+
f"Actual file content (first 2000 chars of "
|
|
441
|
+
f"{line_count} lines):\n"
|
|
442
|
+
f"-----FILE START-----\n{head}\n-----FILE END-----\n"
|
|
443
|
+
f"Use THIS exact text as your search target, OR "
|
|
444
|
+
f"abandon this edit and try write_file.]"
|
|
445
|
+
)
|
|
398
446
|
except Exception:
|
|
399
447
|
pass
|
|
400
448
|
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""Regression test: read_file circuit breaker fires at threshold 5, not 12.
|
|
2
|
+
|
|
3
|
+
Stress sessions reset every 45 prompts. With threshold=12, the model could
|
|
4
|
+
loop 11× on the same read_file call before being blocked — admiral advisories
|
|
5
|
+
fire at 3× but are ignored. Threshold=5 actually engages the block before
|
|
6
|
+
the session's budget is exhausted.
|
|
7
|
+
"""
|
|
8
|
+
import hashlib
|
|
9
|
+
import json
|
|
10
|
+
import unittest
|
|
11
|
+
from unittest.mock import MagicMock
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _make_circuit_breaker_check():
|
|
15
|
+
"""Import and bind just the circuit breaker logic for unit testing."""
|
|
16
|
+
from drydock.core.agent_loop import AgentLoop
|
|
17
|
+
|
|
18
|
+
loop = AgentLoop.__new__(AgentLoop)
|
|
19
|
+
loop._tool_call_history = {}
|
|
20
|
+
loop._get_attempted_summary = lambda: ""
|
|
21
|
+
return loop
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class TestCircuitBreakerReadonlyThreshold(unittest.TestCase):
|
|
25
|
+
def _make_tool_call(self, name, args):
|
|
26
|
+
tc = MagicMock()
|
|
27
|
+
tc.tool_name = name
|
|
28
|
+
tc.args_dict = args
|
|
29
|
+
tc.call_id = "test-id"
|
|
30
|
+
return tc
|
|
31
|
+
|
|
32
|
+
def _record(self, loop, tool_call, result="some content"):
|
|
33
|
+
from drydock.core.agent_loop import AgentLoop
|
|
34
|
+
AgentLoop._circuit_breaker_record(loop, tool_call, result)
|
|
35
|
+
|
|
36
|
+
def test_read_file_blocks_at_5(self):
|
|
37
|
+
"""Circuit breaker fires on the 6th identical call (threshold=5 means count>=5 blocks)."""
|
|
38
|
+
loop = _make_circuit_breaker_check()
|
|
39
|
+
tc = self._make_tool_call("read_file", {"path": "foo.py", "offset": 150, "limit": 100})
|
|
40
|
+
|
|
41
|
+
# First 5 calls: should not block
|
|
42
|
+
for i in range(5):
|
|
43
|
+
result = loop._circuit_breaker_check(tc)
|
|
44
|
+
self.assertIsNone(result, f"Expected no block on call {i+1}, got: {result}")
|
|
45
|
+
self._record(loop, tc)
|
|
46
|
+
|
|
47
|
+
# 6th call: should block (count=5 >= threshold=5)
|
|
48
|
+
result = loop._circuit_breaker_check(tc)
|
|
49
|
+
self.assertIsNotNone(result, "Expected circuit breaker to fire on 6th identical read_file")
|
|
50
|
+
self.assertIn("read_file", result)
|
|
51
|
+
|
|
52
|
+
def test_bash_still_blocks_at_8(self):
|
|
53
|
+
"""bash threshold=8, so blocks on 9th call (count=8 >= threshold=8)."""
|
|
54
|
+
loop = _make_circuit_breaker_check()
|
|
55
|
+
tc = self._make_tool_call("bash", {"command": "ls -la"})
|
|
56
|
+
|
|
57
|
+
for i in range(8):
|
|
58
|
+
result = loop._circuit_breaker_check(tc)
|
|
59
|
+
self.assertIsNone(result, f"Expected no block on bash call {i+1}")
|
|
60
|
+
self._record(loop, tc)
|
|
61
|
+
|
|
62
|
+
result = loop._circuit_breaker_check(tc)
|
|
63
|
+
self.assertIsNotNone(result, "Expected circuit breaker to fire on 9th identical bash")
|
|
64
|
+
|
|
65
|
+
def test_grep_blocks_at_5(self):
|
|
66
|
+
loop = _make_circuit_breaker_check()
|
|
67
|
+
tc = self._make_tool_call("grep", {"pattern": "def foo", "path": "bar.py"})
|
|
68
|
+
|
|
69
|
+
for i in range(5):
|
|
70
|
+
result = loop._circuit_breaker_check(tc)
|
|
71
|
+
self.assertIsNone(result)
|
|
72
|
+
self._record(loop, tc)
|
|
73
|
+
|
|
74
|
+
# 6th call blocks (count=5 >= threshold=5)
|
|
75
|
+
result = loop._circuit_breaker_check(tc)
|
|
76
|
+
self.assertIsNotNone(result, "Expected circuit breaker to fire on 6th identical grep")
|
|
77
|
+
|
|
78
|
+
def test_different_args_not_blocked(self):
|
|
79
|
+
loop = _make_circuit_breaker_check()
|
|
80
|
+
|
|
81
|
+
# 5 reads of foo.py at offset 150
|
|
82
|
+
tc1 = self._make_tool_call("read_file", {"path": "foo.py", "offset": 150})
|
|
83
|
+
for _ in range(5):
|
|
84
|
+
self._record(loop, tc1)
|
|
85
|
+
|
|
86
|
+
# Different offset should not be blocked
|
|
87
|
+
tc2 = self._make_tool_call("read_file", {"path": "foo.py", "offset": 200})
|
|
88
|
+
result = loop._circuit_breaker_check(tc2)
|
|
89
|
+
self.assertIsNone(result, "Different args should not be blocked")
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
if __name__ == "__main__":
|
|
93
|
+
unittest.main()
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""Regression tests for struggle detector dedup fix.
|
|
2
|
+
|
|
3
|
+
Before the fix, the finding code was f"struggle:{count}:{tool}" — each count
|
|
4
|
+
was a unique key, bypassing DEDUP_WINDOW_SEC and producing 33 identical
|
|
5
|
+
interventions in one session that the model ignored.
|
|
6
|
+
|
|
7
|
+
After the fix, the code is stable (f"struggle:{tool}") so a single entry
|
|
8
|
+
in recent_findings suppresses repeat firings within the 60-second window.
|
|
9
|
+
"""
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from drydock.admiral.detectors import detect_struggle
|
|
13
|
+
from drydock.core.types import FunctionCall, LLMMessage, Role, ToolCall
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _assistant(tool: str, args: str = "{}") -> LLMMessage:
|
|
17
|
+
return LLMMessage(
|
|
18
|
+
role=Role.assistant,
|
|
19
|
+
content="",
|
|
20
|
+
tool_calls=[ToolCall(function=FunctionCall(name=tool, arguments=args))],
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _make_msgs(write_tool: str, non_write_count: int) -> list[LLMMessage]:
|
|
25
|
+
msgs: list[LLMMessage] = [LLMMessage(role=Role.user, content="build it")]
|
|
26
|
+
msgs.append(_assistant(write_tool, '{"path":"x.py","content":"x"}'))
|
|
27
|
+
msgs.append(LLMMessage(role=Role.tool, content="ok"))
|
|
28
|
+
for i in range(non_write_count):
|
|
29
|
+
msgs.append(_assistant("read_file", f'{{"path":"f{i}.py"}}'))
|
|
30
|
+
msgs.append(LLMMessage(role=Role.tool, content="content"))
|
|
31
|
+
return msgs
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def test_struggle_code_is_stable_no_count() -> None:
|
|
35
|
+
"""Finding code must NOT include the count so dedup works across counts."""
|
|
36
|
+
msgs20 = _make_msgs("search_replace", 20)
|
|
37
|
+
msgs33 = _make_msgs("search_replace", 33)
|
|
38
|
+
f20 = detect_struggle(msgs20)
|
|
39
|
+
f33 = detect_struggle(msgs33)
|
|
40
|
+
assert f20 is not None
|
|
41
|
+
assert f33 is not None
|
|
42
|
+
# Same stable code regardless of count
|
|
43
|
+
assert f20.code == f33.code
|
|
44
|
+
assert "20" not in f20.code
|
|
45
|
+
assert "33" not in f33.code
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def test_struggle_escalated_directive_at_30() -> None:
|
|
49
|
+
"""At 30+ non-write calls, directive must mention write_file overwrite."""
|
|
50
|
+
msgs = _make_msgs("search_replace", 30)
|
|
51
|
+
f = detect_struggle(msgs)
|
|
52
|
+
assert f is not None
|
|
53
|
+
assert "write_file" in f.directive
|
|
54
|
+
assert "overwrite" in f.directive
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def test_struggle_gentle_directive_below_30() -> None:
|
|
58
|
+
"""Below 30, directive is the gentle nudge (no overwrite mention)."""
|
|
59
|
+
msgs = _make_msgs("search_replace", 22)
|
|
60
|
+
f = detect_struggle(msgs)
|
|
61
|
+
assert f is not None
|
|
62
|
+
assert "overwrite" not in f.directive
|
|
63
|
+
assert "commit to a plan" in f.directive
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def test_struggle_no_fire_below_threshold() -> None:
|
|
67
|
+
msgs = _make_msgs("write_file", 5)
|
|
68
|
+
assert detect_struggle(msgs) is None
|
|
@@ -92,3 +92,33 @@ class TestTruncatedArgPathHint:
|
|
|
92
92
|
assert len(result.failed_calls) == 1
|
|
93
93
|
assert "Re-read" not in result.failed_calls[0].error
|
|
94
94
|
assert "_truncated" in result.failed_calls[0].error or "truncated" in result.failed_calls[0].error
|
|
95
|
+
|
|
96
|
+
def test_existing_file_content_embedded(self, tmp_path):
|
|
97
|
+
"""When the target file exists, its content is embedded in the error
|
|
98
|
+
so the model can rewrite without an extra read_file round-trip."""
|
|
99
|
+
target = tmp_path / "utils.py"
|
|
100
|
+
target.write_text("def hello():\n return 42\n")
|
|
101
|
+
|
|
102
|
+
handler = APIToolFormatHandler()
|
|
103
|
+
parsed = ParsedMessage(
|
|
104
|
+
tool_calls=[
|
|
105
|
+
ParsedToolCall(
|
|
106
|
+
tool_name="write_file",
|
|
107
|
+
call_id="tc4",
|
|
108
|
+
raw_args={
|
|
109
|
+
"_truncated": True,
|
|
110
|
+
"_original_bytes": 4096,
|
|
111
|
+
"file_path": str(target),
|
|
112
|
+
},
|
|
113
|
+
)
|
|
114
|
+
]
|
|
115
|
+
)
|
|
116
|
+
tm = _make_tool_manager_with("write_file", _make_write_file_class())
|
|
117
|
+
result = handler.resolve_tool_calls(parsed, tm)
|
|
118
|
+
assert len(result.failed_calls) == 1
|
|
119
|
+
err = result.failed_calls[0].error
|
|
120
|
+
# Content should be embedded, not just a Re-read directive
|
|
121
|
+
assert "def hello():" in err
|
|
122
|
+
assert "return 42" in err
|
|
123
|
+
# Re-read advisory should NOT appear when content is embedded
|
|
124
|
+
assert "Re-read" not in err
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"""Regression test: search_replace returns actionable result when passed a directory.
|
|
2
|
+
|
|
3
|
+
Admiral logs (2026-04-28) showed 38 instances of retry_after_error:search_replace
|
|
4
|
+
with error head 'file: /data3/.../tool_agent' — the model was passing the package
|
|
5
|
+
directory path instead of a specific file path. The old code raised ToolError
|
|
6
|
+
("Path is not a file") which the framework turned into a tool error, and the model
|
|
7
|
+
retried the same bad path in a loop.
|
|
8
|
+
|
|
9
|
+
Fix: catch the directory-path case in run() and yield a SearchReplaceResult listing
|
|
10
|
+
the files in the directory. The model can then correct the path instead of looping.
|
|
11
|
+
"""
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import os
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
import pytest
|
|
18
|
+
|
|
19
|
+
from drydock.core.tools.base import BaseToolState, InvokeContext
|
|
20
|
+
from drydock.core.tools.builtins.search_replace import (
|
|
21
|
+
SearchReplace,
|
|
22
|
+
SearchReplaceArgs,
|
|
23
|
+
SearchReplaceConfig,
|
|
24
|
+
SearchReplaceResult,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
async def _collect(gen):
|
|
29
|
+
results = []
|
|
30
|
+
async for item in gen:
|
|
31
|
+
results.append(item)
|
|
32
|
+
return results
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@pytest.fixture
|
|
36
|
+
def tool():
|
|
37
|
+
return SearchReplace(SearchReplaceConfig(), BaseToolState())
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@pytest.fixture
|
|
41
|
+
def ctx() -> InvokeContext:
|
|
42
|
+
return InvokeContext(tool_call_id="tc_1", read_file_state={})
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@pytest.mark.asyncio
|
|
46
|
+
async def test_directory_path_returns_result_not_error(tool, ctx, tmp_path):
|
|
47
|
+
"""Passing a directory path should yield a SearchReplaceResult with the file list."""
|
|
48
|
+
# Create some files in the temp dir
|
|
49
|
+
(tmp_path / "cli.py").write_text("print('cli')\n")
|
|
50
|
+
(tmp_path / "tools.py").write_text("def run(): pass\n")
|
|
51
|
+
|
|
52
|
+
args = SearchReplaceArgs(
|
|
53
|
+
file_path=str(tmp_path),
|
|
54
|
+
content="<<<<<<< SEARCH\nold\n=======\nnew\n>>>>>>> REPLACE",
|
|
55
|
+
)
|
|
56
|
+
results = await _collect(tool.run(args, ctx))
|
|
57
|
+
assert results, "expected at least one result"
|
|
58
|
+
result = results[-1]
|
|
59
|
+
assert isinstance(result, SearchReplaceResult)
|
|
60
|
+
assert result.blocks_applied == 0
|
|
61
|
+
assert "PATH ERROR" in result.content
|
|
62
|
+
assert "cli.py" in result.content
|
|
63
|
+
assert "tools.py" in result.content
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@pytest.mark.asyncio
|
|
67
|
+
async def test_directory_path_does_not_raise(tool, ctx, tmp_path):
|
|
68
|
+
"""Verify no exception propagates when a directory path is given."""
|
|
69
|
+
args = SearchReplaceArgs(
|
|
70
|
+
file_path=str(tmp_path),
|
|
71
|
+
content="<<<<<<< SEARCH\nold\n=======\nnew\n>>>>>>> REPLACE",
|
|
72
|
+
)
|
|
73
|
+
# Should not raise
|
|
74
|
+
results = await _collect(tool.run(args, ctx))
|
|
75
|
+
assert any(isinstance(r, SearchReplaceResult) for r in results)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@pytest.mark.asyncio
|
|
79
|
+
async def test_directory_path_repeated_call_still_returns_result(tool, ctx, tmp_path):
|
|
80
|
+
"""Second call with the same directory path still returns a result (not an error)."""
|
|
81
|
+
(tmp_path / "main.py").write_text("x = 1\n")
|
|
82
|
+
args = SearchReplaceArgs(
|
|
83
|
+
file_path=str(tmp_path),
|
|
84
|
+
content="<<<<<<< SEARCH\nold\n=======\nnew\n>>>>>>> REPLACE",
|
|
85
|
+
)
|
|
86
|
+
for _ in range(3):
|
|
87
|
+
results = await _collect(tool.run(args, ctx))
|
|
88
|
+
result = results[-1]
|
|
89
|
+
assert isinstance(result, SearchReplaceResult)
|
|
90
|
+
assert result.blocks_applied == 0
|
|
91
|
+
assert "PATH ERROR" in result.content
|