drydock-cli 2.7.17__tar.gz → 2.7.19__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.19/.auto_release.lock +1 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/PKG-INFO +1 -1
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/llm/format.py +50 -5
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/builtins/read_file.py +38 -12
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/builtins/search_replace.py +40 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/builtins/write_file.py +13 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/pyproject.toml +1 -1
- drydock_cli-2.7.19/tests/test_write_file_missing_path.py +75 -0
- drydock_cli-2.7.19/tests/tools/test_read_file_dedup_reembed.py +136 -0
- drydock_cli-2.7.19/tests/tools/test_read_file_limit_truncation.py +76 -0
- drydock_cli-2.7.19/tests/tools/test_search_replace_empty_content.py +90 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/trip_log.md +111 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/uv.lock +1 -1
- drydock_cli-2.7.17/.auto_release.lock +0 -1
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/.claude/scheduled_tasks.lock +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/.github/CODEOWNERS +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/.github/DISCUSSION_TEMPLATE/ideas.yml +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/.github/workflows/build-and-upload.yml +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/.github/workflows/ci.yml +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/.github/workflows/issue-labeler.yml +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/.github/workflows/release.yml +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/.gitignore +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/.pre-commit-config.yaml +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/.python-version +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/.typos.toml +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/.vscode/extensions.json +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/.vscode/launch.json +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/.vscode/settings.json +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/AGENTS.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/Admiral.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/BASELINE_412.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/CHANGELOG.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/CLAUDE.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/CONTRIBUTING.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/DEPLOYMENT.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/Drydock_rebrand.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/LICENSE +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/MODEL_SHORTCOMINGS.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/NOTICE +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/OVERNIGHT_PROGRESS.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/OVERNIGHT_REPORT_2026_04_13.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/PRD.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/README.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/action.yml +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/baseline_history/README.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/baseline_history/results1.tsv +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/baseline_history/results13.tsv +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/baseline_history/results14.tsv +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/baseline_history/results15.tsv +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/baseline_history/results16.tsv +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/baseline_history/results17.tsv +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/baseline_history/results18.tsv +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/baseline_history/results19.tsv +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/baseline_history/results2.tsv +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/baseline_history/results20.tsv +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/baseline_history/results3.tsv +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/baseline_history/results4.tsv +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/baseline_history/results5.tsv +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/baseline_history/results6.tsv +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/baseline_history/results7.tsv +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/baseline_history/results8.tsv +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/baseline_history/results9.tsv +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/baseline_history/results_evolved_v1.tsv +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/distribution/zed/LICENSE +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/distribution/zed/extension.toml +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/distribution/zed/icons/mistral_vibe.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/docs/README.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/docs/acp-setup.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/docs/proxy-setup.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/__init__.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/acp/__init__.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/acp/acp_agent_loop.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/acp/acp_logger.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/acp/entrypoint.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/acp/tools/__init__.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/acp/tools/base.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/acp/tools/builtins/bash.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/acp/tools/builtins/read_file.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/acp/tools/builtins/search_replace.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/acp/tools/builtins/todo.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/acp/tools/builtins/write_file.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/acp/tools/session_update.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/acp/utils.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/admiral/__init__.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/admiral/detectors.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/admiral/detectors_proposed.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/admiral/history.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/admiral/interventions.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/admiral/llm_analyzer.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/admiral/metrics.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/admiral/opus_escalator.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/admiral/persistence.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/admiral/policy.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/admiral/proposer.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/admiral/stager.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/admiral/task_classifier.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/admiral/tuning.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/admiral/validator.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/admiral/worker.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/__init__.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/autocompletion/__init__.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/autocompletion/base.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/autocompletion/path_completion.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/autocompletion/slash_command.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/cli.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/clipboard.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/commands.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/entrypoint.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/history_manager.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/plan_offer/adapters/http_whoami_gateway.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/plan_offer/decide_plan_offer.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/plan_offer/ports/whoami_gateway.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/terminal_setup.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/__init__.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/ansi_markdown.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/app.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/app.tcss +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/external_editor.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/handlers/__init__.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/handlers/event_handler.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/notifications/__init__.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/notifications/adapters/__init__.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/notifications/adapters/textual_notification_adapter.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/notifications/ports/__init__.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/notifications/ports/notification_port.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/widgets/__init__.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/widgets/approval_app.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/widgets/banner/banner.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/widgets/banner/petit_chat.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/widgets/braille_renderer.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/widgets/chat_input/__init__.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/widgets/chat_input/body.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/widgets/chat_input/completion_manager.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/widgets/chat_input/completion_popup.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/widgets/chat_input/container.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/widgets/chat_input/text_area.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/widgets/checkpoint_picker.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/widgets/compact.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/widgets/config_app.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/widgets/context_progress.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/widgets/load_more.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/widgets/loading.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/widgets/messages.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/widgets/no_markup_static.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/widgets/path_display.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/widgets/proxy_setup_app.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/widgets/question_app.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/widgets/session_picker.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/widgets/spinner.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/widgets/status_message.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/widgets/teleport_message.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/widgets/tool_widgets.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/widgets/tools.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/widgets/vscode_compat.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/windowing/__init__.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/windowing/history.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/windowing/history_windowing.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/textual_ui/windowing/state.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/update_notifier/__init__.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/update_notifier/adapters/filesystem_update_cache_repository.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/update_notifier/adapters/github_update_gateway.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/update_notifier/adapters/pypi_update_gateway.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/update_notifier/ports/update_cache_repository.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/update_notifier/ports/update_gateway.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/update_notifier/update.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/cli/update_notifier/whats_new.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/__init__.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/agent_loop.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/agents/__init__.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/agents/manager.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/agents/models.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/auth/__init__.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/auth/crypto.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/auth/github.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/autocompletion/__init__.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/autocompletion/completers.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/autocompletion/file_indexer/__init__.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/autocompletion/file_indexer/ignore_rules.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/autocompletion/file_indexer/indexer.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/autocompletion/file_indexer/store.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/autocompletion/file_indexer/watcher.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/autocompletion/fuzzy.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/autocompletion/path_prompt.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/autocompletion/path_prompt_adapter.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/build_orchestrator.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/checkpoint.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/config/__init__.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/config/_settings.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/config/doctor.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/config/harness_files/__init__.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/config/harness_files/_harness_manager.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/config/harness_files/_paths.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/consultant.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/drydock_states.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/hooks.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/llm/__init__.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/llm/backend/anthropic.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/llm/backend/base.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/llm/backend/factory.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/llm/backend/generic.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/llm/backend/mistral.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/llm/backend/reasoning_adapter.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/llm/backend/vertex.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/llm/exceptions.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/llm/message_utils.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/llm/types.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/logger.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/middleware.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/output_formatters.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/paths/__init__.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/paths/_drydock_home.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/paths/_local_config_walk.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/paths/conventions.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/plan_session.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/plugins.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/programmatic.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/prompts/__init__.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/prompts/builder.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/prompts/cli.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/prompts/compact.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/prompts/dangerous_directory.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/prompts/diagnostic.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/prompts/explore.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/prompts/gemma4.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/prompts/planner.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/prompts/project_context.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/prompts/tests.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/proxy_setup.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/session/agent_memory.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/session/checkpoints.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/session/session_loader.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/session/session_logger.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/session/session_migration.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/session/state_file.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/session_checker.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/skills/__init__.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/skills/manager.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/skills/models.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/skills/parser.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/slug.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/system_prompt.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/telemetry/__init__.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/telemetry/send.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/teleport/errors.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/teleport/git.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/teleport/nuage.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/teleport/teleport.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/teleport/types.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/base.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/builtins/_task_manager.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/builtins/ask_user_question.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/builtins/bash.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/builtins/cron.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/builtins/exit_plan_mode.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/builtins/glob_tool.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/builtins/grep.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/builtins/invoke_skill.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/builtins/lsp.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/builtins/mcp_resources.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/builtins/notebook_edit.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/builtins/powershell.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/builtins/prompts/__init__.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/builtins/prompts/ask_user_question.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/builtins/prompts/bash.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/builtins/prompts/cron.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/builtins/prompts/glob.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/builtins/prompts/grep.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/builtins/prompts/invoke_skill.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/builtins/prompts/lsp.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/builtins/prompts/mcp_resources.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/builtins/prompts/notebook_edit.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/builtins/prompts/powershell.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/builtins/prompts/read_file.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/builtins/prompts/search_replace.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/builtins/prompts/swe_bench.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/builtins/prompts/task.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/builtins/prompts/task_manager.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/builtins/prompts/todo.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/builtins/prompts/tool_search.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/builtins/prompts/webfetch.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/builtins/prompts/websearch.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/builtins/prompts/worktree.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/builtins/prompts/write_file.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/builtins/task.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/builtins/todo.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/builtins/tool_search.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/builtins/webfetch.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/builtins/websearch.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/builtins/worktree.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/injection_guard.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/manager.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/mcp/__init__.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/mcp/registry.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/mcp/tools.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/mcp_sampling.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/ui.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/tools/utils.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/trusted_folders.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/types.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/core/utils.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/setup/onboarding/__init__.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/setup/onboarding/base.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/setup/onboarding/onboarding.tcss +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/setup/onboarding/screens/__init__.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/setup/onboarding/screens/api_key.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/setup/onboarding/screens/choice.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/setup/onboarding/screens/local_model.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/setup/onboarding/screens/welcome.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/setup/trusted_folders/trust_folder_dialog.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/setup/trusted_folders/trust_folder_dialog.tcss +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/skills/__init__.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/skills/api-design/SKILL.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/skills/audit-tests/SKILL.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/skills/batch/SKILL.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/skills/commit-code/SKILL.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/skills/context-summary/SKILL.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/skills/create-presentation/SKILL.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/skills/deep-research/SKILL.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/skills/deploy/SKILL.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/skills/diff-review/SKILL.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/skills/doc-gen/SKILL.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/skills/explain-code/SKILL.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/skills/explore-code/SKILL.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/skills/fix-issue/SKILL.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/skills/git-ops/SKILL.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/skills/init-project/SKILL.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/skills/investigate/SKILL.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/skills/loop/SKILL.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/skills/migrate/SKILL.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/skills/perf-analyze/SKILL.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/skills/plan-impl/SKILL.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/skills/pr-review/SKILL.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/skills/refactor/SKILL.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/skills/regex-help/SKILL.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/skills/review/SKILL.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/skills/security-review/SKILL.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/skills/ship/SKILL.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/skills/simplify/SKILL.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/skills/strong-tests/SKILL.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/skills/test-verify/SKILL.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock/whats_new.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock-acp.spec +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/drydock_terms.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/flake.lock +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/flake.nix +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/nohup.out +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/research/README.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/research/config_base.toml +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/research/config_best.toml +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/research/domain_spec.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/research/experimenter.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/research/kernel.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/research/mini_prd.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/research/mini_prompts.txt +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/research/proposer.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/research/results.tsv +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/resume.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/README.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/admiral_probe.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/audit_sampler.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/auto_generate_tests.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/auto_release.sh +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/auto_test_loop.sh +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/autonomous_review.sh +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/autonomous_review_prompt.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/backup.sh +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/bump_version.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/comprehensive_loop.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/deploy_to_github.sh +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/discover_cli_tools.sh +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/evolve_tests.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/gen_2000_prompts.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/install.sh +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/llm_balancer.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/mega_loop.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/meta_ralph_loop.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/monitor_swebench.sh +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/monitor_test_battery.sh +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/notify_release.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/oss_task_harness.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/overnight_agents_test.sh +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/poll_issues.sh +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/port_task.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/prepare_release.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/publish_to_pypi.sh +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/ralph_loop.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/research_babysitter.sh +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/session_loop_audit.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/shakedown.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/shakedown_interactive.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/shakedown_regression.sh +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/shakedown_suite.sh +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/shakedown_variance.sh +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/stress_babysitter.sh +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/stress_prompts_50.txt +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/stress_prompts_realuser.txt +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/stress_prompts_tool_agent.txt +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/stress_prompts_tool_agent_2000.txt +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/stress_shakedown.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/stress_telegram_status.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/stress_watcher.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/telegram_bot.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/test_bank.sh +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/test_full.sh +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/test_smoke.sh +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/test_tui_path.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/tui_test.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/scripts/vllm_failover.sh +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/test/project/dummy +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/__init__.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/acp/conftest.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/acp/test_acp.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/acp/test_agent_thought.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/acp/test_bash.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/acp/test_compact_session_updates.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/acp/test_content.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/acp/test_initialize.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/acp/test_list_sessions.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/acp/test_load_session.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/acp/test_multi_session.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/acp/test_new_session.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/acp/test_proxy_setup_acp.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/acp/test_read_file.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/acp/test_search_replace.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/acp/test_set_config_option.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/acp/test_set_mode.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/acp/test_set_model.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/acp/test_tool_call_session_update.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/acp/test_utils.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/acp/test_write_file.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/autocompletion/test_file_indexer.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/autocompletion/test_fuzzy.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/autocompletion/test_path_completer_fuzzy.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/autocompletion/test_path_completer_recursive.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/autocompletion/test_path_completion_controller.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/autocompletion/test_path_prompt_transformer.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/autocompletion/test_slash_command_controller.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/autocompletion/test_ui_chat_autocompletion.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/backend/__init__.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/backend/data/__init__.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/backend/data/fireworks.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/backend/data/mistral.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/backend/test_anthropic_adapter.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/backend/test_backend.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/backend/test_generic_adapter_sanitize.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/backend/test_reasoning_adapter.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/backend/test_vertex_anthropic_adapter.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/cli/plan_offer/adapters/fake_whoami_gateway.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/cli/plan_offer/test_decide_plan_offer.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/cli/plan_offer/test_http_whoami_gateway.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/cli/test_bell_notifications.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/cli/test_braille_renderer.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/cli/test_clipboard.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/cli/test_commands.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/cli/test_copy_shortcuts.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/cli/test_external_editor.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/cli/test_no_markup_static.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/cli/test_question_app.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/cli/test_spinner.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/cli/test_switching_mode.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/cli/test_ui_clipboard_notifications.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/cli/test_ui_session_incremental_renderer.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/cli/test_ui_session_resume.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/cli/test_ui_skill_dispatch.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/cli/textual_ui/__init__.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/cli/textual_ui/test_session_picker.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/conftest.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/core/test_agents.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/core/test_auth_crypto.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/core/test_auth_github.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/core/test_circuit_breaker_readonly_threshold.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/core/test_config_load_dotenv.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/core/test_config_paths.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/core/test_config_resolution.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/core/test_file_logging.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/core/test_plan_session.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/core/test_proxy_setup.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/core/test_slug.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/core/test_telemetry_send.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/core/test_teleport_git.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/core/test_teleport_nuage.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/core/test_teleport_service.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/core/test_trusted_folders.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/core/test_utils.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/e2e/common.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/e2e/conftest.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/e2e/mock_server.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/e2e/test_cli_tui_onboarding.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/e2e/test_cli_tui_streaming.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/e2e/test_cli_tui_tool_approval.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/fixtures/doc_qa_system_prd.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/mock/__init__.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/mock/mock_backend_factory.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/mock/mock_entrypoint.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/mock/utils.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/onboarding/test_run_onboarding.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/onboarding/test_ui_onboarding.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/session/test_session_loader.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/session/test_session_logger.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/session/test_session_migration.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/skills/conftest.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/skills/test_manager.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/skills/test_models.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/skills/test_parser.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_ask_user_question/test_snapshot_ask_user_question_collapsed.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_ask_user_question/test_snapshot_ask_user_question_expanded.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_basic_conversation/test_snapshot_shows_basic_conversation.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/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.17 → drydock_cli-2.7.19}/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.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_cycle_to_accept_edits_mode.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_cycle_to_auto_approve_mode.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_cycle_to_plan_mode.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_cycle_wraps_to_default.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_default_mode.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_parallel_tool_calls/test_snapshot_parallel_tool_calls_pending.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_parallel_tool_calls/test_snapshot_parallel_tool_calls_resolved.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_cancel_discards_changes.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_edit_existing_values.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_initial_empty.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_initial_with_values.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_save_error.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_save_new_values.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_answer_first_advance.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_first_answered_checkmark.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_initial.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_navigate_left_wraps.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_navigate_right.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_tab_to_second.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_initial.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_mixed_selection.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_navigate_to_submit.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_other_with_text.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_toggle_first.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_toggle_multiple.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_untoggle.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_initial.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_navigate_down.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_navigate_to_other.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_navigate_to_third_option.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_navigate_up_wraps.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_other_typing.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_reasoning_content/test_snapshot_buffered_reasoning_yields_before_content.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_reasoning_content/test_snapshot_shows_interleaved_reasoning.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_reasoning_content/test_snapshot_shows_reasoning_content.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_reasoning_content/test_snapshot_shows_reasoning_content_expanded.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_release_update_notification/test_snapshot_shows_release_update_notification.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_session_resume/test_snapshot_shows_resumed_session_messages.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_streaming_tool_call/test_snapshot_tool_call_partial.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_streaming_tool_call/test_snapshot_tool_call_updated.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_push_confirmation_cancel_selected.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_push_confirmation_multiple_commits.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_push_confirmation_single_commit.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_auth_complete.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_auth_required.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_checking_git.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_complete.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_error.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_pushing.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_sending_token.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_starting_workflow.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_whats_new/test_snapshot_shows_no_plan_message.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_whats_new/test_snapshot_shows_switch_message.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_whats_new/test_snapshot_shows_upgrade_message.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/__snapshots__/test_ui_snapshot_whats_new/test_snapshot_shows_whats_new_message.svg +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/base_snapshot_test_app.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/conftest.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/snap_compare.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/test_ui_snapshot_ask_user_question.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/test_ui_snapshot_basic_conversation.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/test_ui_snapshot_code_block_horizontal_scrolling.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/test_ui_snapshot_empty_assistant_before_reasoning.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/test_ui_snapshot_modes.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/test_ui_snapshot_parallel_tool_calls.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/test_ui_snapshot_proxy_setup.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/test_ui_snapshot_question_app.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/test_ui_snapshot_reasoning_content.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/test_ui_snapshot_release_update_notification.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/test_ui_snapshot_session_resume.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/test_ui_snapshot_streaming_tool_call.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/test_ui_snapshot_teleport.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/snapshots/test_ui_snapshot_whats_new.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/stubs/fake_backend.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/stubs/fake_client.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/stubs/fake_tool.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_admiral.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_admiral_phase3.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_admiral_proposed.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_admiral_struggle_dedup.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_agent_auto_compact.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_agent_backend.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_agent_observer_streaming.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_agent_stats.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_agent_tasks.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_agent_tool_call.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_agents.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_bank_build.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_bank_debug.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_bank_multiagent.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_bank_prd.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_bank_prd_extended.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_bank_tools.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_bank_update.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_build_projects.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_checkpoint.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_cli_programmatic_preload.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_current_bugs.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_drydock_regression.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_drydock_tasks.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_fake_tool_call_paren_syntax.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_full_regression.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_history_manager.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_integration.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_issue_fixes.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_loop_detection.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_message_id.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_message_merging.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_middleware.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_multi_agent.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_read_file_not_found_listing.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_real_failures.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_real_issues.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_real_workflow.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_reasoning_content.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_smoke.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_system_prompt.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_tagged_text.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_tool_args.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_truncate_args_valid_json.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_truncated_arg_path_hint.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_ui_external_editor.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_ui_input_history.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_user_issues.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_wall_of_text_rescue.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/test_workloads.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/testbank_helpers.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/tools/test_ask_user_question.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/tools/test_bash.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/tools/test_exit_plan_mode.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/tools/test_grep.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/tools/test_invoke_context.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/tools/test_manager_gemma_derived_models.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/tools/test_manager_get_tool_config.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/tools/test_mcp.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/tools/test_mcp_sampling.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/tools/test_read_file_directory.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/tools/test_search_replace_append_fallback.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/tools/test_search_replace_dir_path.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/tools/test_search_replace_hard_stop.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/tools/test_search_replace_no_op_loop_breaker.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/tools/test_search_replace_refused_loop_breaker.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/tools/test_task.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/tools/test_ui_bash_execution.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/tools/test_webfetch.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/tools/test_websearch.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/tools/test_write_file_dedup_missing_imports.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/tools/test_write_file_missing_path_hint.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/update_notifier/adapters/fake_update_cache_repository.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/update_notifier/adapters/fake_update_gateway.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/update_notifier/test_do_update.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/update_notifier/test_filesystem_update_cache_repository.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/update_notifier/test_github_update_gateway.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/update_notifier/test_pypi_update_gateway.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/update_notifier/test_ui_update_notification.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/update_notifier/test_update_use_case.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/tests/update_notifier/test_whats_new.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/worked_examples/README.md +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/worked_examples/cli_subcommand_dispatch.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/worked_examples/lookup.json +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/worked_examples/sql_parser.py +0 -0
- {drydock_cli-2.7.17 → drydock_cli-2.7.19}/worked_examples/tree_walking_interpreter.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
361748
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: drydock-cli
|
|
3
|
-
Version: 2.7.
|
|
3
|
+
Version: 2.7.19
|
|
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
|
|
@@ -412,7 +412,7 @@ class APIToolFormatHandler:
|
|
|
412
412
|
tool_name=parsed_call.tool_name,
|
|
413
413
|
call_id=parsed_call.call_id,
|
|
414
414
|
error=(
|
|
415
|
-
f"
|
|
415
|
+
f"your call used a "
|
|
416
416
|
f"truncated history entry as a template (it contained "
|
|
417
417
|
f"'_truncated'/'_original_bytes' instead of real "
|
|
418
418
|
f"arguments).{file_embed} Provide the full required arguments."
|
|
@@ -438,11 +438,56 @@ class APIToolFormatHandler:
|
|
|
438
438
|
and "path" in error_str
|
|
439
439
|
and "Field required" in error_str
|
|
440
440
|
):
|
|
441
|
+
# Try to infer path from the first comment line of content.
|
|
442
|
+
# Gemma 4 frequently calls write_file(content="...") without path.
|
|
443
|
+
content_val = parsed_call.raw_args.get("content", "")
|
|
444
|
+
inferred_path: str | None = None
|
|
445
|
+
if content_val:
|
|
446
|
+
for _line in content_val.splitlines()[:5]:
|
|
447
|
+
_line = _line.strip()
|
|
448
|
+
_m = _re.match(
|
|
449
|
+
r'^#\s+([\w./+-]+\.(?:py|js|ts|json|yaml|yml|toml|md|txt|sh|cfg|ini))\s*$',
|
|
450
|
+
_line,
|
|
451
|
+
)
|
|
452
|
+
if _m:
|
|
453
|
+
inferred_path = _m.group(1)
|
|
454
|
+
break
|
|
455
|
+
if inferred_path:
|
|
456
|
+
try:
|
|
457
|
+
_new_args = dict(parsed_call.raw_args)
|
|
458
|
+
_new_args["path"] = inferred_path
|
|
459
|
+
validated_args = args_model.model_validate(_new_args)
|
|
460
|
+
resolved_calls.append(
|
|
461
|
+
ResolvedToolCall(
|
|
462
|
+
tool_name=parsed_call.tool_name,
|
|
463
|
+
tool_class=tool_class,
|
|
464
|
+
validated_args=validated_args,
|
|
465
|
+
call_id=parsed_call.call_id,
|
|
466
|
+
)
|
|
467
|
+
)
|
|
468
|
+
continue
|
|
469
|
+
except ValidationError:
|
|
470
|
+
pass
|
|
471
|
+
# List project .py files as hints so the model can pick the right one
|
|
472
|
+
_candidates: list[str] = []
|
|
473
|
+
try:
|
|
474
|
+
_candidates = [
|
|
475
|
+
str(p.relative_to(Path.cwd()))
|
|
476
|
+
for p in sorted(Path.cwd().rglob("*.py"))
|
|
477
|
+
if "__pycache__" not in str(p) and ".git" not in str(p)
|
|
478
|
+
][:12]
|
|
479
|
+
except Exception:
|
|
480
|
+
pass
|
|
481
|
+
_hint = (
|
|
482
|
+
f"Project .py files: {', '.join(_candidates)}"
|
|
483
|
+
if _candidates
|
|
484
|
+
else "Use read_file or glob to list available files."
|
|
485
|
+
)
|
|
441
486
|
error_msg = (
|
|
442
|
-
"
|
|
443
|
-
"You must pass BOTH `path` AND `content` as separate arguments
|
|
444
|
-
'
|
|
445
|
-
"Do NOT omit `path`."
|
|
487
|
+
"missing required `path` parameter. "
|
|
488
|
+
"You must pass BOTH `path` AND `content` as separate arguments: "
|
|
489
|
+
'write_file(path="pkg/file.py", content="..."). '
|
|
490
|
+
f"Do NOT omit `path`. {_hint}"
|
|
446
491
|
)
|
|
447
492
|
else:
|
|
448
493
|
error_msg = f"Invalid arguments: {e}"
|
|
@@ -45,7 +45,7 @@ class ReadFileResult(BaseModel):
|
|
|
45
45
|
content: str
|
|
46
46
|
lines_read: int
|
|
47
47
|
was_truncated: bool = Field(
|
|
48
|
-
description="True if the reading was stopped due to the max_read_bytes limit."
|
|
48
|
+
description="True if the reading was stopped due to the line limit or max_read_bytes limit."
|
|
49
49
|
)
|
|
50
50
|
|
|
51
51
|
|
|
@@ -111,25 +111,48 @@ class ReadFile(
|
|
|
111
111
|
and prior.get("offset") == args.offset
|
|
112
112
|
and prior.get("limit") == args.limit
|
|
113
113
|
):
|
|
114
|
+
# Re-embed the cached content so the model has it even if the
|
|
115
|
+
# earlier tool_result was truncated by _truncate_old_tool_results.
|
|
116
|
+
# Pointing at a stale/truncated prior result causes re-read loops.
|
|
117
|
+
cached_content = prior.get("content", "")
|
|
118
|
+
prior_lines = prior.get("lines_read", 0)
|
|
119
|
+
dedup_count = prior.get("dedup_count", 0)
|
|
120
|
+
if dedup_count == 0:
|
|
121
|
+
header = "[Unchanged since last read — content re-embedded]\n"
|
|
122
|
+
else:
|
|
123
|
+
header = (
|
|
124
|
+
f"[REPEATED READ #{dedup_count + 1}: file has not changed across your last "
|
|
125
|
+
f"{dedup_count + 1} reads with these exact arguments. "
|
|
126
|
+
f"Reading again will produce this same result. "
|
|
127
|
+
f"To make progress: write or edit a file, use offset= to read a different section, "
|
|
128
|
+
f"or move on to the next task.]\n"
|
|
129
|
+
)
|
|
130
|
+
if read_state is not None:
|
|
131
|
+
read_state[path_key] = {**prior, "dedup_count": dedup_count + 1}
|
|
114
132
|
yield ReadFileResult(
|
|
115
133
|
path=path_key,
|
|
116
|
-
content=
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
f"({file_path.name}, mtime unchanged, same offset/limit). "
|
|
120
|
-
"Use the content from the earlier Read tool_result — "
|
|
121
|
-
"do NOT re-read. If you need to take action, call "
|
|
122
|
-
"search_replace or write_file on what you already have.\n"
|
|
123
|
-
"</system-reminder>"
|
|
124
|
-
),
|
|
125
|
-
lines_read=0,
|
|
126
|
-
was_truncated=True,
|
|
134
|
+
content=f"{header}{cached_content}",
|
|
135
|
+
lines_read=prior_lines,
|
|
136
|
+
was_truncated=prior.get("was_truncated", False),
|
|
127
137
|
)
|
|
128
138
|
return
|
|
129
139
|
|
|
130
140
|
read_result = await self._read_file(args, file_path)
|
|
131
141
|
content = "".join(read_result.lines)
|
|
132
142
|
|
|
143
|
+
# When stopped by the line limit (not byte limit), append a hint so
|
|
144
|
+
# the model knows to paginate with offset= instead of re-reading.
|
|
145
|
+
if (
|
|
146
|
+
read_result.was_truncated
|
|
147
|
+
and args.limit is not None
|
|
148
|
+
and len(read_result.lines) == args.limit
|
|
149
|
+
):
|
|
150
|
+
next_offset = args.offset + args.limit
|
|
151
|
+
content += (
|
|
152
|
+
f"\n[lines {args.offset + 1}–{next_offset} shown; "
|
|
153
|
+
f"use offset={next_offset} to read more]"
|
|
154
|
+
)
|
|
155
|
+
|
|
133
156
|
# Record read state so Write/Edit can enforce Read-before-Write
|
|
134
157
|
# and so future re-reads can dedup against this one.
|
|
135
158
|
if read_state is not None:
|
|
@@ -138,6 +161,8 @@ class ReadFile(
|
|
|
138
161
|
"timestamp": current_mtime,
|
|
139
162
|
"offset": args.offset,
|
|
140
163
|
"limit": args.limit,
|
|
164
|
+
"lines_read": len(read_result.lines),
|
|
165
|
+
"was_truncated": read_result.was_truncated,
|
|
141
166
|
}
|
|
142
167
|
|
|
143
168
|
yield ReadFileResult(
|
|
@@ -195,6 +220,7 @@ class ReadFile(
|
|
|
195
220
|
continue
|
|
196
221
|
|
|
197
222
|
if args.limit is not None and len(lines_to_return) >= args.limit:
|
|
223
|
+
was_truncated = True
|
|
198
224
|
break
|
|
199
225
|
|
|
200
226
|
line_bytes = len(line.encode("utf-8"))
|
|
@@ -131,6 +131,46 @@ 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("Empty content provided.") or err_msg.startswith("File path is required."):
|
|
135
|
+
# Model sent search_replace with missing content or file_path.
|
|
136
|
+
# Convert to a soft result so the model corrects — a ToolError
|
|
137
|
+
# causes panic-retry loops (feedback: never raise ToolError for
|
|
138
|
+
# loop detection). Track count to escalate on repeat offenses.
|
|
139
|
+
empty_state = self.state.__dict__.setdefault("_sr_empty_history", {})
|
|
140
|
+
key = args.file_path.strip() or "<no-path>"
|
|
141
|
+
entry = empty_state.get(key, {"count": 0})
|
|
142
|
+
entry["count"] += 1
|
|
143
|
+
empty_state[key] = entry
|
|
144
|
+
count = entry["count"]
|
|
145
|
+
escalate = count >= 2
|
|
146
|
+
extra = ""
|
|
147
|
+
if escalate:
|
|
148
|
+
# Show project files so model can recover context
|
|
149
|
+
try:
|
|
150
|
+
py_files = sorted(
|
|
151
|
+
str(p.relative_to(Path.cwd()))
|
|
152
|
+
for p in Path.cwd().rglob("*.py")
|
|
153
|
+
if "__pycache__" not in str(p) and ".git" not in str(p)
|
|
154
|
+
)[:20]
|
|
155
|
+
extra = (
|
|
156
|
+
f"\n[This is the #{count} empty search_replace on '{key}'. "
|
|
157
|
+
f"Stop retrying. Current .py files in project:\n"
|
|
158
|
+
+ "\n".join(f" {f}" for f in py_files)
|
|
159
|
+
+ "\nUse write_file to create a file, or read_file to "
|
|
160
|
+
f"see file contents before editing.]"
|
|
161
|
+
)
|
|
162
|
+
except Exception:
|
|
163
|
+
extra = (
|
|
164
|
+
f"\n[This is the #{count} empty search_replace on '{key}'. "
|
|
165
|
+
"Stop retrying. Use write_file or read the file first.]"
|
|
166
|
+
)
|
|
167
|
+
yield SearchReplaceResult(
|
|
168
|
+
file=key,
|
|
169
|
+
blocks_applied=0,
|
|
170
|
+
lines_changed=0,
|
|
171
|
+
content=err_msg + extra,
|
|
172
|
+
)
|
|
173
|
+
return
|
|
134
174
|
if err_msg.startswith("Path is not a file:"):
|
|
135
175
|
# Model passed a directory instead of a file path.
|
|
136
176
|
# Return a result (not raise) so the model corrects the call
|
|
@@ -735,6 +735,19 @@ class WriteFile(
|
|
|
735
735
|
file_path = Path.cwd() / file_path
|
|
736
736
|
file_path = file_path.resolve()
|
|
737
737
|
|
|
738
|
+
if file_path.is_dir():
|
|
739
|
+
try:
|
|
740
|
+
children = sorted(p.name for p in file_path.iterdir())[:20]
|
|
741
|
+
listing = ", ".join(children) if children else "(empty)"
|
|
742
|
+
except OSError:
|
|
743
|
+
listing = "(unreadable)"
|
|
744
|
+
raise ToolError(
|
|
745
|
+
f"'{file_path}' is a directory, not a file. "
|
|
746
|
+
f"Specify the exact file path inside it.\n"
|
|
747
|
+
f"Files in that directory: {listing}\n"
|
|
748
|
+
f"Example: {file_path}/{children[0] if children else 'yourfile.py'}"
|
|
749
|
+
)
|
|
750
|
+
|
|
738
751
|
file_existed = file_path.exists()
|
|
739
752
|
|
|
740
753
|
if file_existed and not args.overwrite:
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""Regression test: write_file missing-path loop fix.
|
|
2
|
+
|
|
3
|
+
Stress run 2026-04-28 showed Gemma 4 calling write_file(content="...")
|
|
4
|
+
without a path. format.py returned "write_file: missing required `path`..."
|
|
5
|
+
and agent_loop.py wrapped it as "<tool_error>write_file: write_file: ..."
|
|
6
|
+
producing a confusing double-prefix. Also, the error message placeholder
|
|
7
|
+
"your/file.py" gave the model no real hint.
|
|
8
|
+
|
|
9
|
+
Fixes in format.py:
|
|
10
|
+
1. Remove tool-name prefix from error msg (agent_loop adds it already).
|
|
11
|
+
2. When content first line is "# filename.py", infer path and succeed.
|
|
12
|
+
3. When path can't be inferred, include project .py file listing in error.
|
|
13
|
+
"""
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
from unittest.mock import MagicMock
|
|
17
|
+
|
|
18
|
+
import pytest
|
|
19
|
+
|
|
20
|
+
from drydock.core.llm.format import APIToolFormatHandler, ParsedMessage, ParsedToolCall
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _make_tool_manager():
|
|
24
|
+
tm = MagicMock()
|
|
25
|
+
from drydock.core.tools.builtins.write_file import WriteFile
|
|
26
|
+
tm.available_tools = {"write_file": WriteFile}
|
|
27
|
+
return tm
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class TestWriteFileMissingPath:
|
|
31
|
+
def _resolve(self, raw_args: dict) -> object:
|
|
32
|
+
handler = APIToolFormatHandler()
|
|
33
|
+
parsed = ParsedMessage(
|
|
34
|
+
tool_calls=[
|
|
35
|
+
ParsedToolCall(
|
|
36
|
+
tool_name="write_file",
|
|
37
|
+
call_id="tc1",
|
|
38
|
+
raw_args=raw_args,
|
|
39
|
+
)
|
|
40
|
+
],
|
|
41
|
+
text_content="",
|
|
42
|
+
)
|
|
43
|
+
return handler.resolve_tool_calls(parsed, _make_tool_manager())
|
|
44
|
+
|
|
45
|
+
def test_missing_path_no_double_prefix(self):
|
|
46
|
+
"""Error for missing path must NOT start with 'write_file:'."""
|
|
47
|
+
result = self._resolve({"content": "import os\nprint('hello')\n"})
|
|
48
|
+
assert result.failed_calls
|
|
49
|
+
err = result.failed_calls[0].error
|
|
50
|
+
# agent_loop.py will add "write_file: " prefix — the error itself must not
|
|
51
|
+
assert not err.startswith("write_file:"), f"Double prefix found: {err!r}"
|
|
52
|
+
|
|
53
|
+
def test_missing_path_error_has_useful_hint(self):
|
|
54
|
+
"""Error should mention path parameter and how to fix it."""
|
|
55
|
+
result = self._resolve({"content": "import os\nprint('hello')\n"})
|
|
56
|
+
err = result.failed_calls[0].error
|
|
57
|
+
assert "path" in err.lower()
|
|
58
|
+
# Must not contain the useless placeholder "your/file.py"
|
|
59
|
+
assert "your/file.py" not in err
|
|
60
|
+
|
|
61
|
+
def test_path_inferred_from_comment(self, tmp_path, monkeypatch):
|
|
62
|
+
"""When first line is '# mymodule.py', path is inferred and write succeeds."""
|
|
63
|
+
monkeypatch.chdir(tmp_path)
|
|
64
|
+
content = "# mymodule.py\nimport os\n\ndef hello():\n pass\n"
|
|
65
|
+
result = self._resolve({"content": content})
|
|
66
|
+
# Should resolve (no failed call), path inferred as mymodule.py
|
|
67
|
+
assert not result.failed_calls, f"Expected no failure, got: {result.failed_calls[0].error!r}"
|
|
68
|
+
assert result.tool_calls
|
|
69
|
+
assert result.tool_calls[0].validated_args.path == "mymodule.py"
|
|
70
|
+
|
|
71
|
+
def test_path_not_inferred_from_plain_import(self):
|
|
72
|
+
"""Content starting with bare import (no comment) must produce a failed call."""
|
|
73
|
+
result = self._resolve({"content": "import abc\nimport os\nimport datetime\n"})
|
|
74
|
+
assert result.failed_calls
|
|
75
|
+
assert not result.tool_calls
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"""Regression test: read_file dedup re-embeds cached content instead of pointing
|
|
2
|
+
at a possibly-truncated prior tool_result.
|
|
3
|
+
|
|
4
|
+
The model (Gemma 4) looped re-reading cli.py with limit=100 because:
|
|
5
|
+
1. First read: stored in read_state, returned truncated content.
|
|
6
|
+
2. _truncate_old_tool_results pruned that tool_result from message history.
|
|
7
|
+
3. Second read (same offset/limit/mtime): dedup fired with "use earlier result."
|
|
8
|
+
4. Model couldn't find the earlier result (truncated) and re-read again → loop.
|
|
9
|
+
|
|
10
|
+
Fix: when dedup fires, embed the cached content directly in the response
|
|
11
|
+
rather than pointing at the prior (possibly absent) tool_result.
|
|
12
|
+
"""
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import pytest
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
from unittest.mock import MagicMock
|
|
18
|
+
|
|
19
|
+
from drydock.core.tools.base import BaseToolState
|
|
20
|
+
from drydock.core.tools.builtins.read_file import ReadFile, ReadFileArgs, ReadFileResult, ReadFileToolConfig
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
async def _run_result(tool, args, ctx) -> ReadFileResult:
|
|
24
|
+
async for event in tool.run(args, ctx):
|
|
25
|
+
if isinstance(event, ReadFileResult):
|
|
26
|
+
return event
|
|
27
|
+
raise AssertionError("no ReadFileResult yielded")
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@pytest.mark.asyncio
|
|
31
|
+
async def test_dedup_reembeds_cached_content(tmp_path):
|
|
32
|
+
"""Second identical read returns cached content, not a pointer stub."""
|
|
33
|
+
f = tmp_path / "cli.py"
|
|
34
|
+
f.write_text("def main():\n pass\n")
|
|
35
|
+
|
|
36
|
+
tool = ReadFile(ReadFileToolConfig(), BaseToolState())
|
|
37
|
+
read_state: dict = {}
|
|
38
|
+
ctx = MagicMock()
|
|
39
|
+
ctx.read_file_state = read_state
|
|
40
|
+
|
|
41
|
+
args = ReadFileArgs(path=str(f), offset=0, limit=100)
|
|
42
|
+
|
|
43
|
+
# First read populates the cache.
|
|
44
|
+
result1 = await _run_result(tool, args, ctx)
|
|
45
|
+
assert "def main" in result1.content
|
|
46
|
+
|
|
47
|
+
# Second read with same args/mtime must return real content, not a pointer.
|
|
48
|
+
result2 = await _run_result(tool, args, ctx)
|
|
49
|
+
assert "def main" in result2.content, "dedup must re-embed content, not point at prior result"
|
|
50
|
+
assert "re-embedded" in result2.content
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@pytest.mark.asyncio
|
|
54
|
+
async def test_dedup_does_not_fire_after_file_changes(tmp_path):
|
|
55
|
+
"""Dedup must not fire if the file has been modified on disk."""
|
|
56
|
+
f = tmp_path / "cli.py"
|
|
57
|
+
f.write_text("version = 1\n")
|
|
58
|
+
|
|
59
|
+
tool = ReadFile(ReadFileToolConfig(), BaseToolState())
|
|
60
|
+
read_state: dict = {}
|
|
61
|
+
ctx = MagicMock()
|
|
62
|
+
ctx.read_file_state = read_state
|
|
63
|
+
|
|
64
|
+
args = ReadFileArgs(path=str(f), offset=0, limit=100)
|
|
65
|
+
|
|
66
|
+
result1 = await _run_result(tool, args, ctx)
|
|
67
|
+
assert "version = 1" in result1.content
|
|
68
|
+
|
|
69
|
+
# Modify the file (mtime changes).
|
|
70
|
+
import time; time.sleep(0.01)
|
|
71
|
+
f.write_text("version = 2\n")
|
|
72
|
+
|
|
73
|
+
result2 = await _run_result(tool, args, ctx)
|
|
74
|
+
assert "version = 2" in result2.content, "should read updated file, not cached content"
|
|
75
|
+
assert "re-embedded" not in result2.content
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@pytest.mark.asyncio
|
|
79
|
+
async def test_dedup_escalates_on_repeated_reads(tmp_path):
|
|
80
|
+
"""Third and later identical reads get an escalating REPEATED READ advisory."""
|
|
81
|
+
f = tmp_path / "cli.py"
|
|
82
|
+
f.write_text("def main():\n pass\n")
|
|
83
|
+
|
|
84
|
+
tool = ReadFile(ReadFileToolConfig(), BaseToolState())
|
|
85
|
+
read_state: dict = {}
|
|
86
|
+
ctx = MagicMock()
|
|
87
|
+
ctx.read_file_state = read_state
|
|
88
|
+
|
|
89
|
+
args = ReadFileArgs(path=str(f), offset=0, limit=100)
|
|
90
|
+
|
|
91
|
+
# First read: no dedup.
|
|
92
|
+
r1 = await _run_result(tool, args, ctx)
|
|
93
|
+
assert "re-embedded" not in r1.content
|
|
94
|
+
assert "REPEATED READ" not in r1.content
|
|
95
|
+
|
|
96
|
+
# Second read: first dedup hit — gentle re-embed message.
|
|
97
|
+
r2 = await _run_result(tool, args, ctx)
|
|
98
|
+
assert "re-embedded" in r2.content
|
|
99
|
+
assert "REPEATED READ" not in r2.content
|
|
100
|
+
assert read_state[str(f)]["dedup_count"] == 1
|
|
101
|
+
|
|
102
|
+
# Third read: second dedup hit — escalated advisory.
|
|
103
|
+
r3 = await _run_result(tool, args, ctx)
|
|
104
|
+
assert "REPEATED READ #2" in r3.content
|
|
105
|
+
assert "def main" in r3.content
|
|
106
|
+
assert read_state[str(f)]["dedup_count"] == 2
|
|
107
|
+
|
|
108
|
+
# Fourth read: third dedup hit — counter increments.
|
|
109
|
+
r4 = await _run_result(tool, args, ctx)
|
|
110
|
+
assert "REPEATED READ #3" in r4.content
|
|
111
|
+
assert read_state[str(f)]["dedup_count"] == 3
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
@pytest.mark.asyncio
|
|
115
|
+
async def test_dedup_stores_lines_read_and_was_truncated(tmp_path):
|
|
116
|
+
"""read_state must record lines_read and was_truncated for correct dedup re-embedding."""
|
|
117
|
+
f = tmp_path / "big.py"
|
|
118
|
+
f.write_text("\n".join(f"line{i}" for i in range(1, 201))) # 200 lines
|
|
119
|
+
|
|
120
|
+
tool = ReadFile(ReadFileToolConfig(), BaseToolState())
|
|
121
|
+
read_state: dict = {}
|
|
122
|
+
ctx = MagicMock()
|
|
123
|
+
ctx.read_file_state = read_state
|
|
124
|
+
|
|
125
|
+
args = ReadFileArgs(path=str(f), offset=0, limit=50)
|
|
126
|
+
await _run_result(tool, args, ctx)
|
|
127
|
+
|
|
128
|
+
path_key = str(f)
|
|
129
|
+
assert "lines_read" in read_state[path_key]
|
|
130
|
+
assert read_state[path_key]["lines_read"] == 50
|
|
131
|
+
assert read_state[path_key]["was_truncated"] is True
|
|
132
|
+
|
|
133
|
+
# Second read: dedup fires, re-embeds with correct metadata.
|
|
134
|
+
result2 = await _run_result(tool, args, ctx)
|
|
135
|
+
assert result2.lines_read == 50
|
|
136
|
+
assert result2.was_truncated is True
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"""Regression test: read_file with limit= sets was_truncated and appends pagination hint.
|
|
2
|
+
|
|
3
|
+
The model (Gemma 4) called read_file with limit=100 on large files, received
|
|
4
|
+
was_truncated=False and no hint, and then re-read the same file 10+ times
|
|
5
|
+
confused about why it was seeing partial content. Fix: set was_truncated=True
|
|
6
|
+
when the line limit stops reading, and append an "offset=N to read more" hint
|
|
7
|
+
so the model knows to paginate rather than re-read.
|
|
8
|
+
"""
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import pytest
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from unittest.mock import MagicMock
|
|
14
|
+
|
|
15
|
+
from drydock.core.tools.base import BaseToolState
|
|
16
|
+
from drydock.core.tools.builtins.read_file import ReadFile, ReadFileArgs, ReadFileResult, ReadFileToolConfig
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
async def _run_result(tool, args, ctx) -> ReadFileResult:
|
|
20
|
+
async for event in tool.run(args, ctx):
|
|
21
|
+
if isinstance(event, ReadFileResult):
|
|
22
|
+
return event
|
|
23
|
+
raise AssertionError("no ReadFileResult yielded")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@pytest.mark.asyncio
|
|
27
|
+
async def test_limit_sets_was_truncated_and_adds_hint(tmp_path):
|
|
28
|
+
"""was_truncated=True and pagination hint appended when limit stops the read."""
|
|
29
|
+
f = tmp_path / "big.py"
|
|
30
|
+
f.write_text("\n".join(f"line{i}" for i in range(1, 201))) # 200 lines
|
|
31
|
+
|
|
32
|
+
tool = ReadFile(ReadFileToolConfig(), BaseToolState())
|
|
33
|
+
args = ReadFileArgs(path=str(f), offset=0, limit=100)
|
|
34
|
+
ctx = MagicMock()
|
|
35
|
+
ctx.read_file_state = {}
|
|
36
|
+
|
|
37
|
+
result = await _run_result(tool, args, ctx)
|
|
38
|
+
|
|
39
|
+
assert result.was_truncated is True
|
|
40
|
+
assert result.lines_read == 100
|
|
41
|
+
assert "offset=100" in result.content
|
|
42
|
+
assert "read more" in result.content
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@pytest.mark.asyncio
|
|
46
|
+
async def test_no_truncation_when_file_fits_in_limit(tmp_path):
|
|
47
|
+
"""was_truncated=False when file has fewer lines than the limit."""
|
|
48
|
+
f = tmp_path / "small.py"
|
|
49
|
+
f.write_text("\n".join(f"line{i}" for i in range(1, 11))) # 10 lines
|
|
50
|
+
|
|
51
|
+
tool = ReadFile(ReadFileToolConfig(), BaseToolState())
|
|
52
|
+
args = ReadFileArgs(path=str(f), offset=0, limit=100)
|
|
53
|
+
ctx = MagicMock()
|
|
54
|
+
ctx.read_file_state = {}
|
|
55
|
+
|
|
56
|
+
result = await _run_result(tool, args, ctx)
|
|
57
|
+
|
|
58
|
+
assert result.was_truncated is False
|
|
59
|
+
assert "offset=" not in result.content
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@pytest.mark.asyncio
|
|
63
|
+
async def test_offset_pagination_hint_uses_correct_next_offset(tmp_path):
|
|
64
|
+
"""Hint shows the correct next offset when reading a middle chunk."""
|
|
65
|
+
f = tmp_path / "file.py"
|
|
66
|
+
f.write_text("\n".join(f"line{i}" for i in range(1, 301))) # 300 lines
|
|
67
|
+
|
|
68
|
+
tool = ReadFile(ReadFileToolConfig(), BaseToolState())
|
|
69
|
+
args = ReadFileArgs(path=str(f), offset=50, limit=100)
|
|
70
|
+
ctx = MagicMock()
|
|
71
|
+
ctx.read_file_state = {}
|
|
72
|
+
|
|
73
|
+
result = await _run_result(tool, args, ctx)
|
|
74
|
+
|
|
75
|
+
assert result.was_truncated is True
|
|
76
|
+
assert "offset=150" in result.content # 50 + 100
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"""Regression test: search_replace empty-content raises ToolError → retry loop.
|
|
2
|
+
|
|
3
|
+
Stress run 2026-04-28 showed Gemma 4 calling search_replace with empty
|
|
4
|
+
content (content="") 20+ times consecutively. The ToolError path caused
|
|
5
|
+
panic-retry loops (feedback: never raise ToolError for loop detection).
|
|
6
|
+
|
|
7
|
+
Fix: detect empty content/file_path in the ToolError handler in run()
|
|
8
|
+
and yield a soft SearchReplaceResult instead of re-raising. Track count
|
|
9
|
+
per call-target so the 2nd+ offense escalates with project file listing.
|
|
10
|
+
"""
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import asyncio
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
|
|
16
|
+
import pytest
|
|
17
|
+
|
|
18
|
+
from drydock.core.tools.base import BaseToolState, InvokeContext
|
|
19
|
+
from drydock.core.tools.builtins.search_replace import (
|
|
20
|
+
SearchReplace,
|
|
21
|
+
SearchReplaceArgs,
|
|
22
|
+
SearchReplaceConfig,
|
|
23
|
+
SearchReplaceResult,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _make_tool() -> SearchReplace:
|
|
28
|
+
config = SearchReplaceConfig()
|
|
29
|
+
state = BaseToolState()
|
|
30
|
+
return SearchReplace(config=config, state=state)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
async def _run(tool: SearchReplace, args: SearchReplaceArgs, tmp_path: Path) -> SearchReplaceResult:
|
|
34
|
+
ctx = InvokeContext(tool_call_id="test-1", read_file_state={})
|
|
35
|
+
results = []
|
|
36
|
+
async for item in tool.run(args, ctx):
|
|
37
|
+
if isinstance(item, SearchReplaceResult):
|
|
38
|
+
results.append(item)
|
|
39
|
+
assert results, "Expected at least one SearchReplaceResult"
|
|
40
|
+
return results[-1]
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@pytest.mark.asyncio
|
|
44
|
+
async def test_empty_content_returns_result_not_raises(tmp_path: Path) -> None:
|
|
45
|
+
"""Empty content must yield a result, never raise ToolError."""
|
|
46
|
+
tool = _make_tool()
|
|
47
|
+
result = await _run(
|
|
48
|
+
tool,
|
|
49
|
+
SearchReplaceArgs(file_path="foo.py", content=""),
|
|
50
|
+
tmp_path,
|
|
51
|
+
)
|
|
52
|
+
assert isinstance(result, SearchReplaceResult)
|
|
53
|
+
assert result.blocks_applied == 0
|
|
54
|
+
assert "Empty content" in result.content
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@pytest.mark.asyncio
|
|
58
|
+
async def test_empty_content_escalates_on_repeat(tmp_path: Path) -> None:
|
|
59
|
+
"""2nd consecutive empty-content call adds project file listing."""
|
|
60
|
+
tool = _make_tool()
|
|
61
|
+
# First call
|
|
62
|
+
result1 = await _run(
|
|
63
|
+
tool,
|
|
64
|
+
SearchReplaceArgs(file_path="foo.py", content=""),
|
|
65
|
+
tmp_path,
|
|
66
|
+
)
|
|
67
|
+
assert "Empty content" in result1.content
|
|
68
|
+
assert "#2" not in result1.content # no escalation yet
|
|
69
|
+
|
|
70
|
+
# Second call — same key, should escalate
|
|
71
|
+
result2 = await _run(
|
|
72
|
+
tool,
|
|
73
|
+
SearchReplaceArgs(file_path="foo.py", content=""),
|
|
74
|
+
tmp_path,
|
|
75
|
+
)
|
|
76
|
+
assert "#2" in result2.content
|
|
77
|
+
assert "Stop retrying" in result2.content
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
@pytest.mark.asyncio
|
|
81
|
+
async def test_missing_file_path_returns_result_not_raises(tmp_path: Path) -> None:
|
|
82
|
+
"""Missing file_path (can't infer) must also yield a result, not raise."""
|
|
83
|
+
tool = _make_tool()
|
|
84
|
+
result = await _run(
|
|
85
|
+
tool,
|
|
86
|
+
SearchReplaceArgs(file_path="", content=""),
|
|
87
|
+
tmp_path,
|
|
88
|
+
)
|
|
89
|
+
assert isinstance(result, SearchReplaceResult)
|
|
90
|
+
assert result.blocks_applied == 0
|