drydock-cli 2.7.8__tar.gz → 2.7.22__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.22/.auto_release.lock +1 -0
- drydock_cli-2.7.22/.claude/scheduled_tasks.lock +1 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/PKG-INFO +1 -1
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/admiral/detectors.py +28 -10
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/admiral/detectors_proposed.py +9 -2
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/agent_loop.py +62 -9
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/llm/format.py +185 -4
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/bash.py +65 -8
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/read_file.py +74 -15
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/search_replace.py +212 -42
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/write_file.py +30 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/pyproject.toml +1 -1
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/resume.md +13 -2
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/auto_release.sh +26 -6
- drydock_cli-2.7.22/scripts/autonomous_review.sh +97 -0
- drydock_cli-2.7.22/scripts/autonomous_review_prompt.md +101 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/llm_balancer.py +5 -1
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/stress_babysitter.sh +1 -2
- drydock_cli-2.7.22/tests/core/test_circuit_breaker_count_escalation.py +93 -0
- drydock_cli-2.7.22/tests/core/test_circuit_breaker_readonly_threshold.py +93 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_admiral_proposed.py +19 -0
- drydock_cli-2.7.22/tests/test_admiral_struggle_dedup.py +99 -0
- drydock_cli-2.7.22/tests/test_hallucinated_tool_suppression.py +87 -0
- drydock_cli-2.7.22/tests/test_read_file_not_found_listing.py +70 -0
- drydock_cli-2.7.22/tests/test_truncated_arg_path_hint.py +124 -0
- drydock_cli-2.7.22/tests/test_truncated_search_replace_escalation.py +76 -0
- drydock_cli-2.7.22/tests/test_truncated_write_escalation.py +104 -0
- drydock_cli-2.7.22/tests/test_write_file_missing_path.py +75 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/tools/test_bash.py +42 -10
- drydock_cli-2.7.22/tests/tools/test_read_file_dedup_reembed.py +136 -0
- drydock_cli-2.7.22/tests/tools/test_read_file_directory.py +65 -0
- drydock_cli-2.7.22/tests/tools/test_read_file_limit_truncation.py +76 -0
- drydock_cli-2.7.22/tests/tools/test_search_replace_dir_path.py +114 -0
- drydock_cli-2.7.22/tests/tools/test_search_replace_empty_content.py +90 -0
- drydock_cli-2.7.22/tests/tools/test_search_replace_hard_stop.py +136 -0
- drydock_cli-2.7.22/tests/tools/test_search_replace_no_op_loop_breaker.py +139 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/tools/test_search_replace_refused_loop_breaker.py +34 -33
- drydock_cli-2.7.22/tests/tools/test_write_file_dedup_missing_imports.py +103 -0
- drydock_cli-2.7.22/tests/tools/test_write_file_missing_path_hint.py +78 -0
- drydock_cli-2.7.22/trip_log.md +772 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/uv.lock +1 -1
- drydock_cli-2.7.8/.auto_release.lock +0 -1
- drydock_cli-2.7.8/.claude/scheduled_tasks.lock +0 -1
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/.github/CODEOWNERS +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/.github/DISCUSSION_TEMPLATE/ideas.yml +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/.github/workflows/build-and-upload.yml +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/.github/workflows/ci.yml +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/.github/workflows/issue-labeler.yml +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/.github/workflows/release.yml +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/.gitignore +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/.pre-commit-config.yaml +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/.python-version +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/.typos.toml +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/.vscode/extensions.json +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/.vscode/launch.json +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/.vscode/settings.json +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/AGENTS.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/Admiral.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/BASELINE_412.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/CHANGELOG.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/CLAUDE.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/CONTRIBUTING.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/DEPLOYMENT.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/Drydock_rebrand.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/LICENSE +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/MODEL_SHORTCOMINGS.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/NOTICE +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/OVERNIGHT_PROGRESS.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/OVERNIGHT_REPORT_2026_04_13.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/PRD.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/README.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/action.yml +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/baseline_history/README.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/baseline_history/results1.tsv +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/baseline_history/results13.tsv +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/baseline_history/results14.tsv +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/baseline_history/results15.tsv +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/baseline_history/results16.tsv +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/baseline_history/results17.tsv +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/baseline_history/results18.tsv +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/baseline_history/results19.tsv +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/baseline_history/results2.tsv +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/baseline_history/results20.tsv +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/baseline_history/results3.tsv +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/baseline_history/results4.tsv +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/baseline_history/results5.tsv +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/baseline_history/results6.tsv +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/baseline_history/results7.tsv +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/baseline_history/results8.tsv +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/baseline_history/results9.tsv +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/baseline_history/results_evolved_v1.tsv +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/distribution/zed/LICENSE +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/distribution/zed/extension.toml +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/distribution/zed/icons/mistral_vibe.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/docs/README.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/docs/acp-setup.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/docs/proxy-setup.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/__init__.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/acp/__init__.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/acp/acp_agent_loop.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/acp/acp_logger.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/acp/entrypoint.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/acp/tools/__init__.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/acp/tools/base.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/acp/tools/builtins/bash.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/acp/tools/builtins/read_file.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/acp/tools/builtins/search_replace.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/acp/tools/builtins/todo.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/acp/tools/builtins/write_file.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/acp/tools/session_update.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/acp/utils.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/admiral/__init__.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/admiral/history.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/admiral/interventions.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/admiral/llm_analyzer.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/admiral/metrics.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/admiral/opus_escalator.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/admiral/persistence.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/admiral/policy.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/admiral/proposer.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/admiral/stager.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/admiral/task_classifier.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/admiral/tuning.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/admiral/validator.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/admiral/worker.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/__init__.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/autocompletion/__init__.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/autocompletion/base.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/autocompletion/path_completion.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/autocompletion/slash_command.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/cli.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/clipboard.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/commands.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/entrypoint.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/history_manager.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/plan_offer/adapters/http_whoami_gateway.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/plan_offer/decide_plan_offer.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/plan_offer/ports/whoami_gateway.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/terminal_setup.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/__init__.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/ansi_markdown.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/app.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/app.tcss +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/external_editor.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/handlers/__init__.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/handlers/event_handler.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/notifications/__init__.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/notifications/adapters/__init__.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/notifications/adapters/textual_notification_adapter.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/notifications/ports/__init__.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/notifications/ports/notification_port.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/__init__.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/approval_app.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/banner/banner.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/banner/petit_chat.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/braille_renderer.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/chat_input/__init__.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/chat_input/body.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/chat_input/completion_manager.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/chat_input/completion_popup.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/chat_input/container.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/chat_input/text_area.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/checkpoint_picker.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/compact.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/config_app.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/context_progress.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/load_more.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/loading.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/messages.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/no_markup_static.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/path_display.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/proxy_setup_app.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/question_app.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/session_picker.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/spinner.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/status_message.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/teleport_message.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/tool_widgets.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/tools.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/vscode_compat.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/windowing/__init__.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/windowing/history.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/windowing/history_windowing.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/windowing/state.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/update_notifier/__init__.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/update_notifier/adapters/filesystem_update_cache_repository.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/update_notifier/adapters/github_update_gateway.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/update_notifier/adapters/pypi_update_gateway.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/update_notifier/ports/update_cache_repository.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/update_notifier/ports/update_gateway.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/update_notifier/update.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/update_notifier/whats_new.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/__init__.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/agents/__init__.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/agents/manager.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/agents/models.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/auth/__init__.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/auth/crypto.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/auth/github.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/autocompletion/__init__.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/autocompletion/completers.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/autocompletion/file_indexer/__init__.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/autocompletion/file_indexer/ignore_rules.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/autocompletion/file_indexer/indexer.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/autocompletion/file_indexer/store.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/autocompletion/file_indexer/watcher.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/autocompletion/fuzzy.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/autocompletion/path_prompt.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/autocompletion/path_prompt_adapter.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/build_orchestrator.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/checkpoint.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/config/__init__.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/config/_settings.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/config/doctor.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/config/harness_files/__init__.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/config/harness_files/_harness_manager.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/config/harness_files/_paths.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/consultant.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/drydock_states.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/hooks.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/llm/__init__.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/llm/backend/anthropic.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/llm/backend/base.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/llm/backend/factory.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/llm/backend/generic.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/llm/backend/mistral.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/llm/backend/reasoning_adapter.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/llm/backend/vertex.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/llm/exceptions.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/llm/message_utils.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/llm/types.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/logger.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/middleware.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/output_formatters.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/paths/__init__.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/paths/_drydock_home.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/paths/_local_config_walk.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/paths/conventions.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/plan_session.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/plugins.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/programmatic.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/prompts/__init__.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/prompts/builder.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/prompts/cli.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/prompts/compact.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/prompts/dangerous_directory.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/prompts/diagnostic.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/prompts/explore.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/prompts/gemma4.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/prompts/planner.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/prompts/project_context.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/prompts/tests.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/proxy_setup.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/session/agent_memory.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/session/checkpoints.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/session/session_loader.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/session/session_logger.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/session/session_migration.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/session/state_file.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/session_checker.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/skills/__init__.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/skills/manager.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/skills/models.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/skills/parser.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/slug.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/system_prompt.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/telemetry/__init__.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/telemetry/send.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/teleport/errors.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/teleport/git.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/teleport/nuage.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/teleport/teleport.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/teleport/types.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/base.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/_task_manager.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/ask_user_question.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/cron.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/exit_plan_mode.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/glob_tool.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/grep.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/invoke_skill.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/lsp.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/mcp_resources.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/notebook_edit.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/powershell.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/prompts/__init__.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/prompts/ask_user_question.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/prompts/bash.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/prompts/cron.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/prompts/glob.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/prompts/grep.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/prompts/invoke_skill.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/prompts/lsp.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/prompts/mcp_resources.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/prompts/notebook_edit.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/prompts/powershell.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/prompts/read_file.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/prompts/search_replace.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/prompts/swe_bench.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/prompts/task.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/prompts/task_manager.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/prompts/todo.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/prompts/tool_search.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/prompts/webfetch.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/prompts/websearch.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/prompts/worktree.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/prompts/write_file.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/task.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/todo.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/tool_search.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/webfetch.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/websearch.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/worktree.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/injection_guard.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/manager.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/mcp/__init__.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/mcp/registry.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/mcp/tools.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/mcp_sampling.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/ui.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/utils.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/trusted_folders.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/types.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/utils.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/setup/onboarding/__init__.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/setup/onboarding/base.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/setup/onboarding/onboarding.tcss +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/setup/onboarding/screens/__init__.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/setup/onboarding/screens/api_key.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/setup/onboarding/screens/choice.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/setup/onboarding/screens/local_model.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/setup/onboarding/screens/welcome.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/setup/trusted_folders/trust_folder_dialog.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/setup/trusted_folders/trust_folder_dialog.tcss +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/__init__.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/api-design/SKILL.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/audit-tests/SKILL.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/batch/SKILL.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/commit-code/SKILL.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/context-summary/SKILL.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/create-presentation/SKILL.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/deep-research/SKILL.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/deploy/SKILL.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/diff-review/SKILL.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/doc-gen/SKILL.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/explain-code/SKILL.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/explore-code/SKILL.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/fix-issue/SKILL.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/git-ops/SKILL.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/init-project/SKILL.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/investigate/SKILL.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/loop/SKILL.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/migrate/SKILL.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/perf-analyze/SKILL.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/plan-impl/SKILL.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/pr-review/SKILL.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/refactor/SKILL.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/regex-help/SKILL.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/review/SKILL.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/security-review/SKILL.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/ship/SKILL.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/simplify/SKILL.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/strong-tests/SKILL.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/test-verify/SKILL.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/whats_new.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock-acp.spec +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock_terms.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/flake.lock +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/flake.nix +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/nohup.out +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/research/README.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/research/config_base.toml +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/research/config_best.toml +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/research/domain_spec.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/research/experimenter.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/research/kernel.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/research/mini_prd.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/research/mini_prompts.txt +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/research/proposer.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/research/results.tsv +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/README.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/admiral_probe.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/audit_sampler.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/auto_generate_tests.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/auto_test_loop.sh +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/backup.sh +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/bump_version.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/comprehensive_loop.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/deploy_to_github.sh +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/discover_cli_tools.sh +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/evolve_tests.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/gen_2000_prompts.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/install.sh +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/mega_loop.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/meta_ralph_loop.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/monitor_swebench.sh +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/monitor_test_battery.sh +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/notify_release.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/oss_task_harness.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/overnight_agents_test.sh +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/poll_issues.sh +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/port_task.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/prepare_release.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/publish_to_pypi.sh +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/ralph_loop.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/research_babysitter.sh +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/session_loop_audit.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/shakedown.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/shakedown_interactive.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/shakedown_regression.sh +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/shakedown_suite.sh +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/shakedown_variance.sh +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/stress_prompts_50.txt +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/stress_prompts_realuser.txt +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/stress_prompts_tool_agent.txt +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/stress_prompts_tool_agent_2000.txt +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/stress_shakedown.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/stress_telegram_status.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/stress_watcher.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/telegram_bot.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/test_bank.sh +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/test_full.sh +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/test_smoke.sh +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/test_tui_path.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/tui_test.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/vllm_failover.sh +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/test/project/dummy +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/__init__.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/acp/conftest.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/acp/test_acp.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/acp/test_agent_thought.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/acp/test_bash.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/acp/test_compact_session_updates.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/acp/test_content.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/acp/test_initialize.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/acp/test_list_sessions.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/acp/test_load_session.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/acp/test_multi_session.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/acp/test_new_session.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/acp/test_proxy_setup_acp.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/acp/test_read_file.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/acp/test_search_replace.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/acp/test_set_config_option.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/acp/test_set_mode.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/acp/test_set_model.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/acp/test_tool_call_session_update.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/acp/test_utils.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/acp/test_write_file.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/autocompletion/test_file_indexer.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/autocompletion/test_fuzzy.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/autocompletion/test_path_completer_fuzzy.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/autocompletion/test_path_completer_recursive.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/autocompletion/test_path_completion_controller.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/autocompletion/test_path_prompt_transformer.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/autocompletion/test_slash_command_controller.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/autocompletion/test_ui_chat_autocompletion.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/backend/__init__.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/backend/data/__init__.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/backend/data/fireworks.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/backend/data/mistral.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/backend/test_anthropic_adapter.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/backend/test_backend.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/backend/test_generic_adapter_sanitize.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/backend/test_reasoning_adapter.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/backend/test_vertex_anthropic_adapter.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/cli/plan_offer/adapters/fake_whoami_gateway.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/cli/plan_offer/test_decide_plan_offer.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/cli/plan_offer/test_http_whoami_gateway.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/cli/test_bell_notifications.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/cli/test_braille_renderer.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/cli/test_clipboard.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/cli/test_commands.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/cli/test_copy_shortcuts.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/cli/test_external_editor.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/cli/test_no_markup_static.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/cli/test_question_app.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/cli/test_spinner.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/cli/test_switching_mode.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/cli/test_ui_clipboard_notifications.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/cli/test_ui_session_incremental_renderer.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/cli/test_ui_session_resume.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/cli/test_ui_skill_dispatch.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/cli/textual_ui/__init__.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/cli/textual_ui/test_session_picker.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/conftest.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/core/test_agents.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/core/test_auth_crypto.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/core/test_auth_github.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/core/test_config_load_dotenv.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/core/test_config_paths.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/core/test_config_resolution.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/core/test_file_logging.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/core/test_plan_session.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/core/test_proxy_setup.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/core/test_slug.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/core/test_telemetry_send.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/core/test_teleport_git.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/core/test_teleport_nuage.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/core/test_teleport_service.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/core/test_trusted_folders.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/core/test_utils.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/e2e/common.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/e2e/conftest.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/e2e/mock_server.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/e2e/test_cli_tui_onboarding.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/e2e/test_cli_tui_streaming.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/e2e/test_cli_tui_tool_approval.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/fixtures/doc_qa_system_prd.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/mock/__init__.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/mock/mock_backend_factory.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/mock/mock_entrypoint.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/mock/utils.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/onboarding/test_run_onboarding.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/onboarding/test_ui_onboarding.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/session/test_session_loader.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/session/test_session_logger.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/session/test_session_migration.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/skills/conftest.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/skills/test_manager.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/skills/test_models.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/skills/test_parser.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_ask_user_question/test_snapshot_ask_user_question_collapsed.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_ask_user_question/test_snapshot_ask_user_question_expanded.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_basic_conversation/test_snapshot_shows_basic_conversation.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/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.8 → drydock_cli-2.7.22}/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.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_cycle_to_accept_edits_mode.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_cycle_to_auto_approve_mode.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_cycle_to_plan_mode.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_cycle_wraps_to_default.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_default_mode.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_parallel_tool_calls/test_snapshot_parallel_tool_calls_pending.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_parallel_tool_calls/test_snapshot_parallel_tool_calls_resolved.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_cancel_discards_changes.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_edit_existing_values.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_initial_empty.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_initial_with_values.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_save_error.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_save_new_values.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_answer_first_advance.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_first_answered_checkmark.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_initial.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_navigate_left_wraps.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_navigate_right.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_tab_to_second.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_initial.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_mixed_selection.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_navigate_to_submit.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_other_with_text.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_toggle_first.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_toggle_multiple.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_untoggle.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_initial.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_navigate_down.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_navigate_to_other.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_navigate_to_third_option.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_navigate_up_wraps.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_other_typing.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_reasoning_content/test_snapshot_buffered_reasoning_yields_before_content.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_reasoning_content/test_snapshot_shows_interleaved_reasoning.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_reasoning_content/test_snapshot_shows_reasoning_content.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_reasoning_content/test_snapshot_shows_reasoning_content_expanded.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_release_update_notification/test_snapshot_shows_release_update_notification.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_session_resume/test_snapshot_shows_resumed_session_messages.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_streaming_tool_call/test_snapshot_tool_call_partial.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_streaming_tool_call/test_snapshot_tool_call_updated.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_push_confirmation_cancel_selected.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_push_confirmation_multiple_commits.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_push_confirmation_single_commit.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_auth_complete.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_auth_required.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_checking_git.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_complete.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_error.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_pushing.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_sending_token.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_starting_workflow.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_whats_new/test_snapshot_shows_no_plan_message.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_whats_new/test_snapshot_shows_switch_message.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_whats_new/test_snapshot_shows_upgrade_message.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_whats_new/test_snapshot_shows_whats_new_message.svg +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/base_snapshot_test_app.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/conftest.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/snap_compare.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/test_ui_snapshot_ask_user_question.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/test_ui_snapshot_basic_conversation.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/test_ui_snapshot_code_block_horizontal_scrolling.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/test_ui_snapshot_empty_assistant_before_reasoning.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/test_ui_snapshot_modes.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/test_ui_snapshot_parallel_tool_calls.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/test_ui_snapshot_proxy_setup.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/test_ui_snapshot_question_app.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/test_ui_snapshot_reasoning_content.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/test_ui_snapshot_release_update_notification.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/test_ui_snapshot_session_resume.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/test_ui_snapshot_streaming_tool_call.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/test_ui_snapshot_teleport.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/test_ui_snapshot_whats_new.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/stubs/fake_backend.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/stubs/fake_client.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/stubs/fake_tool.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_admiral.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_admiral_phase3.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_agent_auto_compact.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_agent_backend.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_agent_observer_streaming.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_agent_stats.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_agent_tasks.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_agent_tool_call.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_agents.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_bank_build.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_bank_debug.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_bank_multiagent.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_bank_prd.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_bank_prd_extended.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_bank_tools.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_bank_update.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_build_projects.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_checkpoint.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_cli_programmatic_preload.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_current_bugs.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_drydock_regression.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_drydock_tasks.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_fake_tool_call_paren_syntax.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_full_regression.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_history_manager.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_integration.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_issue_fixes.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_loop_detection.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_message_id.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_message_merging.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_middleware.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_multi_agent.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_real_failures.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_real_issues.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_real_workflow.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_reasoning_content.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_smoke.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_system_prompt.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_tagged_text.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_tool_args.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_truncate_args_valid_json.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_ui_external_editor.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_ui_input_history.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_user_issues.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_wall_of_text_rescue.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_workloads.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/testbank_helpers.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/tools/test_ask_user_question.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/tools/test_exit_plan_mode.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/tools/test_grep.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/tools/test_invoke_context.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/tools/test_manager_gemma_derived_models.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/tools/test_manager_get_tool_config.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/tools/test_mcp.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/tools/test_mcp_sampling.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/tools/test_search_replace_append_fallback.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/tools/test_task.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/tools/test_ui_bash_execution.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/tools/test_webfetch.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/tools/test_websearch.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/update_notifier/adapters/fake_update_cache_repository.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/update_notifier/adapters/fake_update_gateway.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/update_notifier/test_do_update.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/update_notifier/test_filesystem_update_cache_repository.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/update_notifier/test_github_update_gateway.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/update_notifier/test_pypi_update_gateway.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/update_notifier/test_ui_update_notification.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/update_notifier/test_update_use_case.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/update_notifier/test_whats_new.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/worked_examples/README.md +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/worked_examples/cli_subcommand_dispatch.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/worked_examples/lookup.json +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/worked_examples/sql_parser.py +0 -0
- {drydock_cli-2.7.8 → drydock_cli-2.7.22}/worked_examples/tree_walking_interpreter.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
522842
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"sessionId":"facd51cc-fa47-4911-afc8-14485ae9caf3","pid":711220,"acquiredAt":1775966390914}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: drydock-cli
|
|
3
|
-
Version: 2.7.
|
|
3
|
+
Version: 2.7.22
|
|
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,36 @@ 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
|
+
if last_write_tool is None:
|
|
89
|
+
directive = (
|
|
90
|
+
f"Admiral: you have made {calls_since_write} tool calls without "
|
|
91
|
+
f"writing a single file. You have enough context. STOP exploring "
|
|
92
|
+
f"and start writing code NOW. Call `write_file` to create your "
|
|
93
|
+
f"first file immediately."
|
|
94
|
+
)
|
|
95
|
+
else:
|
|
96
|
+
directive = (
|
|
97
|
+
f"Admiral: you have made {calls_since_write} tool calls without "
|
|
98
|
+
f"writing any file — search_replace is clearly not finding the text. "
|
|
99
|
+
f"STOP retrying. Call `write_file` with `overwrite=True` to rewrite "
|
|
100
|
+
f"the target file from scratch right now."
|
|
101
|
+
)
|
|
102
|
+
else:
|
|
103
|
+
hint = (
|
|
104
|
+
"Either (a) you already have enough context — commit to a plan and "
|
|
105
|
+
"start writing code now, or (b) you're genuinely stuck — stop and "
|
|
106
|
+
"report what's blocking you to the user."
|
|
107
|
+
)
|
|
108
|
+
directive = (
|
|
91
109
|
f"Admiral: you have made {calls_since_write} tool calls without "
|
|
92
110
|
f"writing or editing any file. {hint}"
|
|
93
|
-
)
|
|
94
|
-
)
|
|
111
|
+
)
|
|
112
|
+
return Finding(code=code, directive=directive)
|
|
95
113
|
|
|
96
114
|
|
|
97
115
|
def run_all(messages: Sequence[LLMMessage]) -> list[Finding]:
|
|
@@ -43,11 +43,18 @@ def _tool_result_errored(m: LLMMessage) -> bool:
|
|
|
43
43
|
"""Heuristic: does this tool-role message look like a failure?
|
|
44
44
|
|
|
45
45
|
Conservative — we only want high-precision firing on actual errors.
|
|
46
|
-
Scanned the first
|
|
46
|
+
Scanned the first 200 chars of the result content (tightened from 800
|
|
47
|
+
to avoid false positives when matched file content contains words like
|
|
48
|
+
"error" or "failed" — grep results starting with "matches:" are always
|
|
49
|
+
successful).
|
|
47
50
|
"""
|
|
48
51
|
if m.role is not Role.tool:
|
|
49
52
|
return False
|
|
50
|
-
|
|
53
|
+
raw = str(getattr(m, "content", "") or "")
|
|
54
|
+
# Successful grep results start with "matches:" — never treat as error.
|
|
55
|
+
if raw.lstrip().startswith("matches:"):
|
|
56
|
+
return False
|
|
57
|
+
content = raw[:200].lower()
|
|
51
58
|
return any(marker in content for marker in _TOOL_ERROR_MARKERS)
|
|
52
59
|
|
|
53
60
|
|
|
@@ -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,9 +1145,13 @@ 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
|
|
1151
|
+
# Increment so the count escalates on every repeated fire, giving the
|
|
1152
|
+
# model a growing signal that nothing has changed. Preserve last_result
|
|
1153
|
+
# so the message always shows the real bash/tool output, not a prior NOTE.
|
|
1154
|
+
self._tool_call_history[sig] = (count + 1, last_result)
|
|
1149
1155
|
return (
|
|
1150
1156
|
f"NOTE: this exact call to `{tool_name}` has been made "
|
|
1151
1157
|
f"{count} times this session with identical arguments. "
|
|
@@ -1505,9 +1511,23 @@ class AgentLoop:
|
|
|
1505
1511
|
self.stats.tool_calls_failed += 1
|
|
1506
1512
|
self._handle_tool_response(tool_call, error_msg, "failure", decision)
|
|
1507
1513
|
|
|
1514
|
+
def _silence_suppressed_failures(self, suppressed: list) -> None:
|
|
1515
|
+
"""Add tool result messages for hallucinated tools without TUI events.
|
|
1516
|
+
|
|
1517
|
+
Keeps message history well-formed (assistant tool_call → tool result)
|
|
1518
|
+
while hiding the error from the TUI to avoid confusing the user.
|
|
1519
|
+
"""
|
|
1520
|
+
for failed in suppressed:
|
|
1521
|
+
error_msg = f"<{TOOL_ERROR_TAG}>{failed.tool_name}: {failed.error}</{TOOL_ERROR_TAG}>"
|
|
1522
|
+
self.messages.append(
|
|
1523
|
+
self.format_handler.create_failed_tool_response_message(failed, error_msg)
|
|
1524
|
+
)
|
|
1525
|
+
self.stats.tool_calls_failed += 1
|
|
1526
|
+
|
|
1508
1527
|
async def _handle_tool_calls(
|
|
1509
1528
|
self, resolved: ResolvedMessage
|
|
1510
1529
|
) -> AsyncGenerator[ToolCallEvent | ToolResultEvent | ToolStreamEvent | AssistantEvent]:
|
|
1530
|
+
self._silence_suppressed_failures(resolved.suppressed_failures)
|
|
1511
1531
|
async for event in self._emit_failed_tool_events(resolved.failed_calls):
|
|
1512
1532
|
yield event
|
|
1513
1533
|
for tool_call in resolved.tool_calls:
|
|
@@ -1703,10 +1723,10 @@ class AgentLoop:
|
|
|
1703
1723
|
Runs every turn but is a no-op when nothing exceeds the caps.
|
|
1704
1724
|
Truncation is in-place and idempotent.
|
|
1705
1725
|
"""
|
|
1706
|
-
KEEP_RECENT =
|
|
1707
|
-
SOFT_CAP_BYTES =
|
|
1708
|
-
HEAD_BYTES =
|
|
1709
|
-
TAIL_BYTES =
|
|
1726
|
+
KEEP_RECENT = 4 # last N tool messages stay full
|
|
1727
|
+
SOFT_CAP_BYTES = 500 # tool result longer than this gets shrunk
|
|
1728
|
+
HEAD_BYTES = 200 # bytes kept from the head
|
|
1729
|
+
TAIL_BYTES = 60 # bytes kept from the tail
|
|
1710
1730
|
|
|
1711
1731
|
if len(self.messages) < KEEP_RECENT + 4:
|
|
1712
1732
|
return
|
|
@@ -2334,7 +2354,16 @@ class AgentLoop:
|
|
|
2334
2354
|
if replace_last_tool:
|
|
2335
2355
|
msg.content = f"[SYSTEM: {text}]"
|
|
2336
2356
|
else:
|
|
2337
|
-
|
|
2357
|
+
content = msg.content or ""
|
|
2358
|
+
# Cap at 2 accumulated system notes per message; replace the
|
|
2359
|
+
# last one when the limit is exceeded so repeated admiral
|
|
2360
|
+
# interventions don't unboundedly bloat the context.
|
|
2361
|
+
_SYS_PREFIX = "\n\n[SYSTEM: "
|
|
2362
|
+
if content.count(_SYS_PREFIX) >= 2:
|
|
2363
|
+
last_idx = content.rfind(_SYS_PREFIX)
|
|
2364
|
+
msg.content = content[:last_idx] + _SYS_PREFIX + text + "]"
|
|
2365
|
+
else:
|
|
2366
|
+
msg.content = content + _SYS_PREFIX + text + "]"
|
|
2338
2367
|
return
|
|
2339
2368
|
|
|
2340
2369
|
# Second try: append to last user message
|
|
@@ -2370,6 +2399,30 @@ class AgentLoop:
|
|
|
2370
2399
|
if len(recent_sr) >= 2 and recent_sr[0] == recent_sr[1]:
|
|
2371
2400
|
return "WARNING|search_replace"
|
|
2372
2401
|
|
|
2402
|
+
# Early check: write_file with _truncated args twice in a row for the
|
|
2403
|
+
# same path. format.py already embeds the file content in the error,
|
|
2404
|
+
# but Gemma 4 ignores the advisory and retries identically. Mute
|
|
2405
|
+
# write_file for 1 turn so the model must use read_file or
|
|
2406
|
+
# search_replace instead — same pattern as the search_replace check.
|
|
2407
|
+
recent_wf_truncated: list[str] = []
|
|
2408
|
+
for msg in reversed(self.messages[-20:]):
|
|
2409
|
+
if msg.role == Role.assistant and msg.tool_calls:
|
|
2410
|
+
for tc in msg.tool_calls:
|
|
2411
|
+
if tc.function and tc.function.name == "write_file":
|
|
2412
|
+
try:
|
|
2413
|
+
args = json.loads(tc.function.arguments or "{}")
|
|
2414
|
+
if args.get("_truncated"):
|
|
2415
|
+
p = (args.get("file_path") or args.get("path") or "")
|
|
2416
|
+
recent_wf_truncated.append(p)
|
|
2417
|
+
except (json.JSONDecodeError, AttributeError):
|
|
2418
|
+
pass
|
|
2419
|
+
if len(recent_wf_truncated) >= 2:
|
|
2420
|
+
break
|
|
2421
|
+
if (len(recent_wf_truncated) >= 2
|
|
2422
|
+
and recent_wf_truncated[0] == recent_wf_truncated[1]):
|
|
2423
|
+
self._hot_tool_path = ("write_file", recent_wf_truncated[0])
|
|
2424
|
+
return "FORCE_STOP"
|
|
2425
|
+
|
|
2373
2426
|
sigs: list[str] = []
|
|
2374
2427
|
tool_names: list[str] = []
|
|
2375
2428
|
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
|
|
@@ -165,9 +166,17 @@ class ResolvedMessage(BaseModel):
|
|
|
165
166
|
model_config = ConfigDict(frozen=True)
|
|
166
167
|
tool_calls: list[ResolvedToolCall]
|
|
167
168
|
failed_calls: list[FailedToolCall] = Field(default_factory=list)
|
|
169
|
+
# Hallucinated tools: need a tool result in message history (to keep the
|
|
170
|
+
# conversation well-formed) but should NOT be shown as errors in the TUI.
|
|
171
|
+
suppressed_failures: list[FailedToolCall] = Field(default_factory=list)
|
|
168
172
|
|
|
169
173
|
|
|
170
174
|
class APIToolFormatHandler:
|
|
175
|
+
def __init__(self) -> None:
|
|
176
|
+
# Track per-path truncated-history write_file retries so we can
|
|
177
|
+
# escalate on 2nd+ identical failures (model ignores advisory-only msgs).
|
|
178
|
+
self._truncated_hit_count: dict[str, int] = {}
|
|
179
|
+
|
|
171
180
|
@property
|
|
172
181
|
def name(self) -> str:
|
|
173
182
|
return "api"
|
|
@@ -346,12 +355,25 @@ class APIToolFormatHandler:
|
|
|
346
355
|
"list_mcp_resources", "list_resources", "search_resources",
|
|
347
356
|
}
|
|
348
357
|
|
|
358
|
+
suppressed_failures = []
|
|
349
359
|
for parsed_call in parsed.tool_calls:
|
|
350
360
|
tool_class = active_tools.get(parsed_call.tool_name)
|
|
351
361
|
if not tool_class:
|
|
352
|
-
#
|
|
353
|
-
#
|
|
362
|
+
# Hallucinated tools: add a tool result to keep the message
|
|
363
|
+
# history well-formed (prevents empty_after_tool loops) but
|
|
364
|
+
# route to suppressed_failures so the TUI doesn't show an error.
|
|
354
365
|
if parsed_call.tool_name in _IGNORE_TOOLS:
|
|
366
|
+
suppressed_failures.append(
|
|
367
|
+
FailedToolCall(
|
|
368
|
+
tool_name=parsed_call.tool_name,
|
|
369
|
+
call_id=parsed_call.call_id,
|
|
370
|
+
error=(
|
|
371
|
+
f"'{parsed_call.tool_name}' is not available. "
|
|
372
|
+
f"Use only tools from your tool list: "
|
|
373
|
+
f"{', '.join(sorted(active_tools.keys())[:8])}."
|
|
374
|
+
),
|
|
375
|
+
)
|
|
376
|
+
)
|
|
355
377
|
continue
|
|
356
378
|
failed_calls.append(
|
|
357
379
|
FailedToolCall(
|
|
@@ -367,6 +389,102 @@ class APIToolFormatHandler:
|
|
|
367
389
|
continue
|
|
368
390
|
|
|
369
391
|
args_model, _ = tool_class._get_tool_args_results()
|
|
392
|
+
|
|
393
|
+
# Detect when model copied truncated-history args (our truncation
|
|
394
|
+
# code replaces large tool-call args with {_truncated, _original_bytes,
|
|
395
|
+
# path}). Return a clear advisory instead of a pydantic traceback so
|
|
396
|
+
# the model re-does the call with real arguments rather than retrying
|
|
397
|
+
# the truncated form.
|
|
398
|
+
if (isinstance(parsed_call.raw_args, dict)
|
|
399
|
+
and parsed_call.raw_args.get("_truncated")):
|
|
400
|
+
path_hint = (parsed_call.raw_args.get("path")
|
|
401
|
+
or parsed_call.raw_args.get("file_path")
|
|
402
|
+
or "")
|
|
403
|
+
# Track retry count per path to escalate on 2nd+ offense.
|
|
404
|
+
hit_key = path_hint or "<unknown>"
|
|
405
|
+
hit_count = self._truncated_hit_count.get(hit_key, 0) + 1
|
|
406
|
+
self._truncated_hit_count[hit_key] = hit_count
|
|
407
|
+
escalate = hit_count >= 2
|
|
408
|
+
|
|
409
|
+
# Auto-embed the current file content so the model can
|
|
410
|
+
# rewrite immediately without an extra read_file round-trip.
|
|
411
|
+
file_embed = ""
|
|
412
|
+
if path_hint:
|
|
413
|
+
try:
|
|
414
|
+
p = Path(path_hint)
|
|
415
|
+
if p.exists() and p.is_file():
|
|
416
|
+
raw = p.read_text(errors="replace")
|
|
417
|
+
lines = raw.splitlines()
|
|
418
|
+
max_lines = 120
|
|
419
|
+
if len(lines) <= max_lines:
|
|
420
|
+
file_embed = (
|
|
421
|
+
f"\n\nCurrent file content of `{path_hint}`:\n"
|
|
422
|
+
f"```\n{raw}\n```\n"
|
|
423
|
+
f"Rewrite it now using write_file with the correct content."
|
|
424
|
+
)
|
|
425
|
+
else:
|
|
426
|
+
snippet = "\n".join(lines[:max_lines])
|
|
427
|
+
file_embed = (
|
|
428
|
+
f"\n\nCurrent file content of `{path_hint}` "
|
|
429
|
+
f"(first {max_lines} of {len(lines)} lines):\n"
|
|
430
|
+
f"```\n{snippet}\n```\n"
|
|
431
|
+
f"Use read_file to see the rest, then rewrite with write_file."
|
|
432
|
+
)
|
|
433
|
+
except Exception:
|
|
434
|
+
pass
|
|
435
|
+
if not file_embed and path_hint:
|
|
436
|
+
file_embed = f" Re-read `{path_hint}` with read_file first."
|
|
437
|
+
|
|
438
|
+
if escalate:
|
|
439
|
+
# Model is stuck in a truncated-template retry loop.
|
|
440
|
+
# Show project files and give a concrete directive.
|
|
441
|
+
try:
|
|
442
|
+
py_files = sorted(
|
|
443
|
+
str(p2.relative_to(Path.cwd()))
|
|
444
|
+
for p2 in Path.cwd().rglob("*.py")
|
|
445
|
+
if "__pycache__" not in str(p2) and ".git" not in str(p2)
|
|
446
|
+
)[:20]
|
|
447
|
+
dir_listing = "\n".join(f" {f}" for f in py_files)
|
|
448
|
+
except Exception:
|
|
449
|
+
dir_listing = " (could not list files)"
|
|
450
|
+
tool_name_hint = parsed_call.tool_name
|
|
451
|
+
if tool_name_hint == "search_replace":
|
|
452
|
+
recovery_hint = (
|
|
453
|
+
f"Use read_file on '{path_hint}' to see its current content, "
|
|
454
|
+
f"then call search_replace with fresh <<<<<<< SEARCH / ======= / "
|
|
455
|
+
f">>>>>>> REPLACE markers copied from the actual file text."
|
|
456
|
+
)
|
|
457
|
+
else:
|
|
458
|
+
recovery_hint = (
|
|
459
|
+
f"Use read_file on the target file, then call write_file "
|
|
460
|
+
f"with fully typed content, OR use search_replace to make "
|
|
461
|
+
f"targeted edits without rewriting the whole file."
|
|
462
|
+
)
|
|
463
|
+
escalation_suffix = (
|
|
464
|
+
f"\n\n[REPEATED FAILURE #{hit_count}: your {tool_name_hint} call "
|
|
465
|
+
f"keeps using a stale truncated template for '{path_hint}'. "
|
|
466
|
+
f"You MUST NOT copy args from history. "
|
|
467
|
+
f"Current .py files in project:\n{dir_listing}\n"
|
|
468
|
+
f"{recovery_hint}]"
|
|
469
|
+
)
|
|
470
|
+
else:
|
|
471
|
+
escalation_suffix = ""
|
|
472
|
+
|
|
473
|
+
failed_calls.append(
|
|
474
|
+
FailedToolCall(
|
|
475
|
+
tool_name=parsed_call.tool_name,
|
|
476
|
+
call_id=parsed_call.call_id,
|
|
477
|
+
error=(
|
|
478
|
+
f"your call used a "
|
|
479
|
+
f"truncated history entry as a template (it contained "
|
|
480
|
+
f"'_truncated'/'_original_bytes' instead of real "
|
|
481
|
+
f"arguments).{file_embed} Provide the full required "
|
|
482
|
+
f"arguments.{escalation_suffix}"
|
|
483
|
+
),
|
|
484
|
+
)
|
|
485
|
+
)
|
|
486
|
+
continue
|
|
487
|
+
|
|
370
488
|
try:
|
|
371
489
|
validated_args = args_model.model_validate(parsed_call.raw_args)
|
|
372
490
|
resolved_calls.append(
|
|
@@ -378,15 +496,78 @@ class APIToolFormatHandler:
|
|
|
378
496
|
)
|
|
379
497
|
)
|
|
380
498
|
except ValidationError as e:
|
|
499
|
+
error_str = str(e)
|
|
500
|
+
if (
|
|
501
|
+
parsed_call.tool_name == "write_file"
|
|
502
|
+
and "path" in error_str
|
|
503
|
+
and "Field required" in error_str
|
|
504
|
+
):
|
|
505
|
+
# Try to infer path from the first comment line of content.
|
|
506
|
+
# Gemma 4 frequently calls write_file(content="...") without path.
|
|
507
|
+
content_val = parsed_call.raw_args.get("content", "")
|
|
508
|
+
inferred_path: str | None = None
|
|
509
|
+
if content_val:
|
|
510
|
+
for _line in content_val.splitlines()[:5]:
|
|
511
|
+
_line = _line.strip()
|
|
512
|
+
_m = _re.match(
|
|
513
|
+
r'^#\s+([\w./+-]+\.(?:py|js|ts|json|yaml|yml|toml|md|txt|sh|cfg|ini))\s*$',
|
|
514
|
+
_line,
|
|
515
|
+
)
|
|
516
|
+
if _m:
|
|
517
|
+
inferred_path = _m.group(1)
|
|
518
|
+
break
|
|
519
|
+
if inferred_path:
|
|
520
|
+
try:
|
|
521
|
+
_new_args = dict(parsed_call.raw_args)
|
|
522
|
+
_new_args["path"] = inferred_path
|
|
523
|
+
validated_args = args_model.model_validate(_new_args)
|
|
524
|
+
resolved_calls.append(
|
|
525
|
+
ResolvedToolCall(
|
|
526
|
+
tool_name=parsed_call.tool_name,
|
|
527
|
+
tool_class=tool_class,
|
|
528
|
+
validated_args=validated_args,
|
|
529
|
+
call_id=parsed_call.call_id,
|
|
530
|
+
)
|
|
531
|
+
)
|
|
532
|
+
continue
|
|
533
|
+
except ValidationError:
|
|
534
|
+
pass
|
|
535
|
+
# List project .py files as hints so the model can pick the right one
|
|
536
|
+
_candidates: list[str] = []
|
|
537
|
+
try:
|
|
538
|
+
_candidates = [
|
|
539
|
+
str(p.relative_to(Path.cwd()))
|
|
540
|
+
for p in sorted(Path.cwd().rglob("*.py"))
|
|
541
|
+
if "__pycache__" not in str(p) and ".git" not in str(p)
|
|
542
|
+
][:12]
|
|
543
|
+
except Exception:
|
|
544
|
+
pass
|
|
545
|
+
_hint = (
|
|
546
|
+
f"Project .py files: {', '.join(_candidates)}"
|
|
547
|
+
if _candidates
|
|
548
|
+
else "Use read_file or glob to list available files."
|
|
549
|
+
)
|
|
550
|
+
error_msg = (
|
|
551
|
+
"missing required `path` parameter. "
|
|
552
|
+
"You must pass BOTH `path` AND `content` as separate arguments: "
|
|
553
|
+
'write_file(path="pkg/file.py", content="..."). '
|
|
554
|
+
f"Do NOT omit `path`. {_hint}"
|
|
555
|
+
)
|
|
556
|
+
else:
|
|
557
|
+
error_msg = f"Invalid arguments: {e}"
|
|
381
558
|
failed_calls.append(
|
|
382
559
|
FailedToolCall(
|
|
383
560
|
tool_name=parsed_call.tool_name,
|
|
384
561
|
call_id=parsed_call.call_id,
|
|
385
|
-
error=
|
|
562
|
+
error=error_msg,
|
|
386
563
|
)
|
|
387
564
|
)
|
|
388
565
|
|
|
389
|
-
return ResolvedMessage(
|
|
566
|
+
return ResolvedMessage(
|
|
567
|
+
tool_calls=resolved_calls,
|
|
568
|
+
failed_calls=failed_calls,
|
|
569
|
+
suppressed_failures=suppressed_failures,
|
|
570
|
+
)
|
|
390
571
|
|
|
391
572
|
def create_tool_response_message(
|
|
392
573
|
self, tool_call: ResolvedToolCall, result_text: str
|
|
@@ -404,13 +404,38 @@ class Bash(
|
|
|
404
404
|
self, *, command: str, stdout: str, stderr: str, returncode: int
|
|
405
405
|
) -> BashResult:
|
|
406
406
|
if returncode != 0:
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
if
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
407
|
+
# ADVISORY ONLY — never raise ToolError for non-zero exit codes.
|
|
408
|
+
# Raising blocks the model: it gets <tool_error> with no useful
|
|
409
|
+
# output, doesn't know if exit 1 means "no matches" (grep) or a
|
|
410
|
+
# real failure, and retries identically. Same pattern as the
|
|
411
|
+
# timeout handler above. Include a clear exit-code annotation so
|
|
412
|
+
# the model can reason about what happened.
|
|
413
|
+
# See feedback_no_tool_errors_for_loop_detection.md.
|
|
414
|
+
annotation = f"[Exit code {returncode}]"
|
|
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:
|
|
427
|
+
annotation += " (no output)"
|
|
428
|
+
if returncode == 1:
|
|
429
|
+
annotation += (
|
|
430
|
+
" — for grep/find, exit code 1 means no matches found"
|
|
431
|
+
)
|
|
432
|
+
annotated_stdout = (stdout + "\n" + annotation).strip() if stdout else annotation
|
|
433
|
+
return BashResult(
|
|
434
|
+
command=command,
|
|
435
|
+
stdout=annotated_stdout,
|
|
436
|
+
stderr=stderr,
|
|
437
|
+
returncode=returncode,
|
|
438
|
+
)
|
|
414
439
|
|
|
415
440
|
return BashResult(
|
|
416
441
|
command=command, stdout=stdout, stderr=stderr, returncode=returncode
|
|
@@ -445,7 +470,39 @@ class Bash(
|
|
|
445
470
|
)
|
|
446
471
|
except TimeoutError:
|
|
447
472
|
await _kill_process_tree(proc)
|
|
448
|
-
raise
|
|
473
|
+
# ADVISORY ONLY — never raise ToolError on timeout; raising
|
|
474
|
+
# causes the model to retry the exact same command (loop).
|
|
475
|
+
# Track repeat timeouts per command and escalate the hint.
|
|
476
|
+
# See feedback_no_tool_errors_for_loop_detection.md.
|
|
477
|
+
timeout_state = self.state.__dict__.setdefault(
|
|
478
|
+
"_bash_timeout_history", {}
|
|
479
|
+
)
|
|
480
|
+
count = timeout_state.get(args.command, 0) + 1
|
|
481
|
+
timeout_state[args.command] = count
|
|
482
|
+
if count == 1:
|
|
483
|
+
hint = (
|
|
484
|
+
"The command was killed. If it starts a server or "
|
|
485
|
+
"long-running process, background it with `command &` "
|
|
486
|
+
"instead of running it in the foreground."
|
|
487
|
+
)
|
|
488
|
+
else:
|
|
489
|
+
hint = (
|
|
490
|
+
f"[TIMEOUT #{count}] You have timed out {count}x on "
|
|
491
|
+
f"this exact command. Running it again will produce the "
|
|
492
|
+
f"same result. STOP retrying. Background servers with "
|
|
493
|
+
f"`&`, check existing listeners with `ss -tlnp`, or fix "
|
|
494
|
+
f"the underlying cause before re-running."
|
|
495
|
+
)
|
|
496
|
+
yield BashResult(
|
|
497
|
+
command=args.command,
|
|
498
|
+
stdout=(
|
|
499
|
+
f"Command timed out after {timeout}s: {args.command!r}\n"
|
|
500
|
+
f"{hint}"
|
|
501
|
+
),
|
|
502
|
+
stderr="",
|
|
503
|
+
returncode=124,
|
|
504
|
+
)
|
|
505
|
+
return
|
|
449
506
|
|
|
450
507
|
encoding = _get_subprocess_encoding()
|
|
451
508
|
stdout = (
|
|
@@ -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"))
|
|
@@ -237,12 +263,45 @@ class ReadFile(
|
|
|
237
263
|
f"Security error: Cannot read path '{file_path}' outside of the project directory '{Path.cwd()}'."
|
|
238
264
|
)
|
|
239
265
|
except FileNotFoundError:
|
|
240
|
-
raise ToolError(
|
|
266
|
+
raise ToolError(self._not_found_msg(file_path))
|
|
241
267
|
|
|
242
268
|
if not resolved_path.exists():
|
|
243
|
-
raise ToolError(
|
|
269
|
+
raise ToolError(self._not_found_msg(file_path))
|
|
244
270
|
if resolved_path.is_dir():
|
|
245
|
-
raise ToolError(
|
|
271
|
+
raise ToolError(self._is_dir_msg(file_path, resolved_path))
|
|
272
|
+
|
|
273
|
+
@staticmethod
|
|
274
|
+
def _not_found_msg(file_path: Path) -> str:
|
|
275
|
+
"""Return 'File not found' error with parent directory listing for context."""
|
|
276
|
+
parent = file_path.parent if file_path.parent != file_path else Path(".")
|
|
277
|
+
try:
|
|
278
|
+
entries = sorted(p.name for p in parent.iterdir())
|
|
279
|
+
if entries:
|
|
280
|
+
listing = "\n".join(f" {e}" for e in entries[:30])
|
|
281
|
+
suffix = f"\n ... ({len(entries) - 30} more)" if len(entries) > 30 else ""
|
|
282
|
+
return (
|
|
283
|
+
f"File not found at: {file_path}\n"
|
|
284
|
+
f"Contents of {parent}/:\n{listing}{suffix}"
|
|
285
|
+
)
|
|
286
|
+
except (PermissionError, OSError):
|
|
287
|
+
pass
|
|
288
|
+
return f"File not found at: {file_path}"
|
|
289
|
+
|
|
290
|
+
@staticmethod
|
|
291
|
+
def _is_dir_msg(file_path: Path, resolved_path: Path) -> str:
|
|
292
|
+
"""Return 'is a directory' error with directory listing so model can pick a file."""
|
|
293
|
+
try:
|
|
294
|
+
entries = sorted(p.name for p in resolved_path.iterdir())
|
|
295
|
+
if entries:
|
|
296
|
+
listing = "\n".join(f" {e}" for e in entries[:30])
|
|
297
|
+
suffix = f"\n ... ({len(entries) - 30} more)" if len(entries) > 30 else ""
|
|
298
|
+
return (
|
|
299
|
+
f"Path is a directory, not a file: {file_path}\n"
|
|
300
|
+
f"Contents of {file_path}/:\n{listing}{suffix}"
|
|
301
|
+
)
|
|
302
|
+
except (PermissionError, OSError):
|
|
303
|
+
pass
|
|
304
|
+
return f"Path is a directory, not a file: {file_path}"
|
|
246
305
|
|
|
247
306
|
@classmethod
|
|
248
307
|
def format_call_display(cls, args: ReadFileArgs) -> ToolCallDisplay:
|