drydock-cli 2.7.16__tar.gz → 2.7.18__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.
Files changed (671) hide show
  1. drydock_cli-2.7.18/.auto_release.lock +1 -0
  2. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/PKG-INFO +1 -1
  3. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/admiral/detectors.py +20 -10
  4. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/agent_loop.py +30 -4
  5. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/llm/format.py +80 -7
  6. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/builtins/read_file.py +15 -1
  7. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/builtins/search_replace.py +99 -11
  8. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/builtins/write_file.py +13 -0
  9. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/pyproject.toml +1 -1
  10. drydock_cli-2.7.18/tests/core/test_circuit_breaker_readonly_threshold.py +93 -0
  11. drydock_cli-2.7.18/tests/test_admiral_struggle_dedup.py +68 -0
  12. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_truncated_arg_path_hint.py +30 -0
  13. drydock_cli-2.7.18/tests/test_write_file_missing_path.py +75 -0
  14. drydock_cli-2.7.18/tests/tools/test_read_file_limit_truncation.py +76 -0
  15. drydock_cli-2.7.18/tests/tools/test_search_replace_dir_path.py +91 -0
  16. drydock_cli-2.7.18/tests/tools/test_search_replace_empty_content.py +90 -0
  17. drydock_cli-2.7.18/tests/tools/test_search_replace_hard_stop.py +136 -0
  18. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/trip_log.md +145 -0
  19. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/uv.lock +1 -1
  20. drydock_cli-2.7.16/.auto_release.lock +0 -1
  21. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/.claude/scheduled_tasks.lock +0 -0
  22. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/.github/CODEOWNERS +0 -0
  23. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/.github/DISCUSSION_TEMPLATE/ideas.yml +0 -0
  24. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
  25. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  26. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/.github/workflows/build-and-upload.yml +0 -0
  27. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/.github/workflows/ci.yml +0 -0
  28. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/.github/workflows/issue-labeler.yml +0 -0
  29. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/.github/workflows/release.yml +0 -0
  30. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/.gitignore +0 -0
  31. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/.pre-commit-config.yaml +0 -0
  32. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/.python-version +0 -0
  33. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/.typos.toml +0 -0
  34. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/.vscode/extensions.json +0 -0
  35. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/.vscode/launch.json +0 -0
  36. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/.vscode/settings.json +0 -0
  37. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/AGENTS.md +0 -0
  38. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/Admiral.md +0 -0
  39. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/BASELINE_412.md +0 -0
  40. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/CHANGELOG.md +0 -0
  41. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/CLAUDE.md +0 -0
  42. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/CONTRIBUTING.md +0 -0
  43. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/DEPLOYMENT.md +0 -0
  44. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/Drydock_rebrand.md +0 -0
  45. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/LICENSE +0 -0
  46. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/MODEL_SHORTCOMINGS.md +0 -0
  47. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/NOTICE +0 -0
  48. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/OVERNIGHT_PROGRESS.md +0 -0
  49. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/OVERNIGHT_REPORT_2026_04_13.md +0 -0
  50. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/PRD.md +0 -0
  51. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/README.md +0 -0
  52. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/action.yml +0 -0
  53. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/baseline_history/README.md +0 -0
  54. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/baseline_history/results1.tsv +0 -0
  55. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/baseline_history/results13.tsv +0 -0
  56. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/baseline_history/results14.tsv +0 -0
  57. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/baseline_history/results15.tsv +0 -0
  58. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/baseline_history/results16.tsv +0 -0
  59. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/baseline_history/results17.tsv +0 -0
  60. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/baseline_history/results18.tsv +0 -0
  61. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/baseline_history/results19.tsv +0 -0
  62. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/baseline_history/results2.tsv +0 -0
  63. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/baseline_history/results20.tsv +0 -0
  64. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/baseline_history/results3.tsv +0 -0
  65. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/baseline_history/results4.tsv +0 -0
  66. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/baseline_history/results5.tsv +0 -0
  67. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/baseline_history/results6.tsv +0 -0
  68. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/baseline_history/results7.tsv +0 -0
  69. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/baseline_history/results8.tsv +0 -0
  70. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/baseline_history/results9.tsv +0 -0
  71. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/baseline_history/results_evolved_v1.tsv +0 -0
  72. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/distribution/zed/LICENSE +0 -0
  73. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/distribution/zed/extension.toml +0 -0
  74. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/distribution/zed/icons/mistral_vibe.svg +0 -0
  75. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/docs/README.md +0 -0
  76. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/docs/acp-setup.md +0 -0
  77. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/docs/proxy-setup.md +0 -0
  78. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/__init__.py +0 -0
  79. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/acp/__init__.py +0 -0
  80. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/acp/acp_agent_loop.py +0 -0
  81. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/acp/acp_logger.py +0 -0
  82. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/acp/entrypoint.py +0 -0
  83. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/acp/tools/__init__.py +0 -0
  84. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/acp/tools/base.py +0 -0
  85. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/acp/tools/builtins/bash.py +0 -0
  86. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/acp/tools/builtins/read_file.py +0 -0
  87. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/acp/tools/builtins/search_replace.py +0 -0
  88. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/acp/tools/builtins/todo.py +0 -0
  89. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/acp/tools/builtins/write_file.py +0 -0
  90. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/acp/tools/session_update.py +0 -0
  91. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/acp/utils.py +0 -0
  92. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/admiral/__init__.py +0 -0
  93. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/admiral/detectors_proposed.py +0 -0
  94. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/admiral/history.py +0 -0
  95. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/admiral/interventions.py +0 -0
  96. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/admiral/llm_analyzer.py +0 -0
  97. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/admiral/metrics.py +0 -0
  98. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/admiral/opus_escalator.py +0 -0
  99. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/admiral/persistence.py +0 -0
  100. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/admiral/policy.py +0 -0
  101. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/admiral/proposer.py +0 -0
  102. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/admiral/stager.py +0 -0
  103. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/admiral/task_classifier.py +0 -0
  104. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/admiral/tuning.py +0 -0
  105. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/admiral/validator.py +0 -0
  106. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/admiral/worker.py +0 -0
  107. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/__init__.py +0 -0
  108. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/autocompletion/__init__.py +0 -0
  109. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/autocompletion/base.py +0 -0
  110. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/autocompletion/path_completion.py +0 -0
  111. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/autocompletion/slash_command.py +0 -0
  112. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/cli.py +0 -0
  113. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/clipboard.py +0 -0
  114. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/commands.py +0 -0
  115. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/entrypoint.py +0 -0
  116. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/history_manager.py +0 -0
  117. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/plan_offer/adapters/http_whoami_gateway.py +0 -0
  118. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/plan_offer/decide_plan_offer.py +0 -0
  119. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/plan_offer/ports/whoami_gateway.py +0 -0
  120. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/terminal_setup.py +0 -0
  121. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/__init__.py +0 -0
  122. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/ansi_markdown.py +0 -0
  123. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/app.py +0 -0
  124. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/app.tcss +0 -0
  125. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/external_editor.py +0 -0
  126. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/handlers/__init__.py +0 -0
  127. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/handlers/event_handler.py +0 -0
  128. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/notifications/__init__.py +0 -0
  129. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/notifications/adapters/__init__.py +0 -0
  130. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/notifications/adapters/textual_notification_adapter.py +0 -0
  131. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/notifications/ports/__init__.py +0 -0
  132. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/notifications/ports/notification_port.py +0 -0
  133. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/widgets/__init__.py +0 -0
  134. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/widgets/approval_app.py +0 -0
  135. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/widgets/banner/banner.py +0 -0
  136. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/widgets/banner/petit_chat.py +0 -0
  137. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/widgets/braille_renderer.py +0 -0
  138. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/widgets/chat_input/__init__.py +0 -0
  139. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/widgets/chat_input/body.py +0 -0
  140. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/widgets/chat_input/completion_manager.py +0 -0
  141. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/widgets/chat_input/completion_popup.py +0 -0
  142. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/widgets/chat_input/container.py +0 -0
  143. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/widgets/chat_input/text_area.py +0 -0
  144. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/widgets/checkpoint_picker.py +0 -0
  145. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/widgets/compact.py +0 -0
  146. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/widgets/config_app.py +0 -0
  147. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/widgets/context_progress.py +0 -0
  148. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/widgets/load_more.py +0 -0
  149. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/widgets/loading.py +0 -0
  150. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/widgets/messages.py +0 -0
  151. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/widgets/no_markup_static.py +0 -0
  152. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/widgets/path_display.py +0 -0
  153. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/widgets/proxy_setup_app.py +0 -0
  154. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/widgets/question_app.py +0 -0
  155. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/widgets/session_picker.py +0 -0
  156. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/widgets/spinner.py +0 -0
  157. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/widgets/status_message.py +0 -0
  158. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/widgets/teleport_message.py +0 -0
  159. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/widgets/tool_widgets.py +0 -0
  160. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/widgets/tools.py +0 -0
  161. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/widgets/vscode_compat.py +0 -0
  162. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/windowing/__init__.py +0 -0
  163. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/windowing/history.py +0 -0
  164. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/windowing/history_windowing.py +0 -0
  165. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/textual_ui/windowing/state.py +0 -0
  166. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/update_notifier/__init__.py +0 -0
  167. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/update_notifier/adapters/filesystem_update_cache_repository.py +0 -0
  168. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/update_notifier/adapters/github_update_gateway.py +0 -0
  169. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/update_notifier/adapters/pypi_update_gateway.py +0 -0
  170. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/update_notifier/ports/update_cache_repository.py +0 -0
  171. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/update_notifier/ports/update_gateway.py +0 -0
  172. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/update_notifier/update.py +0 -0
  173. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/cli/update_notifier/whats_new.py +0 -0
  174. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/__init__.py +0 -0
  175. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/agents/__init__.py +0 -0
  176. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/agents/manager.py +0 -0
  177. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/agents/models.py +0 -0
  178. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/auth/__init__.py +0 -0
  179. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/auth/crypto.py +0 -0
  180. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/auth/github.py +0 -0
  181. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/autocompletion/__init__.py +0 -0
  182. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/autocompletion/completers.py +0 -0
  183. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/autocompletion/file_indexer/__init__.py +0 -0
  184. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/autocompletion/file_indexer/ignore_rules.py +0 -0
  185. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/autocompletion/file_indexer/indexer.py +0 -0
  186. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/autocompletion/file_indexer/store.py +0 -0
  187. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/autocompletion/file_indexer/watcher.py +0 -0
  188. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/autocompletion/fuzzy.py +0 -0
  189. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/autocompletion/path_prompt.py +0 -0
  190. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/autocompletion/path_prompt_adapter.py +0 -0
  191. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/build_orchestrator.py +0 -0
  192. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/checkpoint.py +0 -0
  193. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/config/__init__.py +0 -0
  194. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/config/_settings.py +0 -0
  195. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/config/doctor.py +0 -0
  196. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/config/harness_files/__init__.py +0 -0
  197. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/config/harness_files/_harness_manager.py +0 -0
  198. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/config/harness_files/_paths.py +0 -0
  199. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/consultant.py +0 -0
  200. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/drydock_states.py +0 -0
  201. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/hooks.py +0 -0
  202. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/llm/__init__.py +0 -0
  203. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/llm/backend/anthropic.py +0 -0
  204. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/llm/backend/base.py +0 -0
  205. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/llm/backend/factory.py +0 -0
  206. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/llm/backend/generic.py +0 -0
  207. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/llm/backend/mistral.py +0 -0
  208. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/llm/backend/reasoning_adapter.py +0 -0
  209. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/llm/backend/vertex.py +0 -0
  210. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/llm/exceptions.py +0 -0
  211. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/llm/message_utils.py +0 -0
  212. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/llm/types.py +0 -0
  213. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/logger.py +0 -0
  214. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/middleware.py +0 -0
  215. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/output_formatters.py +0 -0
  216. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/paths/__init__.py +0 -0
  217. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/paths/_drydock_home.py +0 -0
  218. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/paths/_local_config_walk.py +0 -0
  219. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/paths/conventions.py +0 -0
  220. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/plan_session.py +0 -0
  221. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/plugins.py +0 -0
  222. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/programmatic.py +0 -0
  223. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/prompts/__init__.py +0 -0
  224. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/prompts/builder.md +0 -0
  225. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/prompts/cli.md +0 -0
  226. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/prompts/compact.md +0 -0
  227. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/prompts/dangerous_directory.md +0 -0
  228. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/prompts/diagnostic.md +0 -0
  229. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/prompts/explore.md +0 -0
  230. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/prompts/gemma4.md +0 -0
  231. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/prompts/planner.md +0 -0
  232. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/prompts/project_context.md +0 -0
  233. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/prompts/tests.md +0 -0
  234. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/proxy_setup.py +0 -0
  235. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/session/agent_memory.py +0 -0
  236. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/session/checkpoints.py +0 -0
  237. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/session/session_loader.py +0 -0
  238. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/session/session_logger.py +0 -0
  239. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/session/session_migration.py +0 -0
  240. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/session/state_file.py +0 -0
  241. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/session_checker.py +0 -0
  242. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/skills/__init__.py +0 -0
  243. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/skills/manager.py +0 -0
  244. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/skills/models.py +0 -0
  245. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/skills/parser.py +0 -0
  246. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/slug.py +0 -0
  247. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/system_prompt.py +0 -0
  248. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/telemetry/__init__.py +0 -0
  249. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/telemetry/send.py +0 -0
  250. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/teleport/errors.py +0 -0
  251. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/teleport/git.py +0 -0
  252. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/teleport/nuage.py +0 -0
  253. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/teleport/teleport.py +0 -0
  254. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/teleport/types.py +0 -0
  255. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/base.py +0 -0
  256. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/builtins/_task_manager.py +0 -0
  257. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/builtins/ask_user_question.py +0 -0
  258. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/builtins/bash.py +0 -0
  259. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/builtins/cron.py +0 -0
  260. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/builtins/exit_plan_mode.py +0 -0
  261. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/builtins/glob_tool.py +0 -0
  262. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/builtins/grep.py +0 -0
  263. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/builtins/invoke_skill.py +0 -0
  264. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/builtins/lsp.py +0 -0
  265. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/builtins/mcp_resources.py +0 -0
  266. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/builtins/notebook_edit.py +0 -0
  267. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/builtins/powershell.py +0 -0
  268. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/builtins/prompts/__init__.py +0 -0
  269. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/builtins/prompts/ask_user_question.md +0 -0
  270. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/builtins/prompts/bash.md +0 -0
  271. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/builtins/prompts/cron.md +0 -0
  272. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/builtins/prompts/glob.md +0 -0
  273. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/builtins/prompts/grep.md +0 -0
  274. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/builtins/prompts/invoke_skill.md +0 -0
  275. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/builtins/prompts/lsp.md +0 -0
  276. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/builtins/prompts/mcp_resources.md +0 -0
  277. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/builtins/prompts/notebook_edit.md +0 -0
  278. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/builtins/prompts/powershell.md +0 -0
  279. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/builtins/prompts/read_file.md +0 -0
  280. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/builtins/prompts/search_replace.md +0 -0
  281. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/builtins/prompts/swe_bench.md +0 -0
  282. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/builtins/prompts/task.md +0 -0
  283. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/builtins/prompts/task_manager.md +0 -0
  284. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/builtins/prompts/todo.md +0 -0
  285. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/builtins/prompts/tool_search.md +0 -0
  286. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/builtins/prompts/webfetch.md +0 -0
  287. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/builtins/prompts/websearch.md +0 -0
  288. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/builtins/prompts/worktree.md +0 -0
  289. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/builtins/prompts/write_file.md +0 -0
  290. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/builtins/task.py +0 -0
  291. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/builtins/todo.py +0 -0
  292. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/builtins/tool_search.py +0 -0
  293. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/builtins/webfetch.py +0 -0
  294. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/builtins/websearch.py +0 -0
  295. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/builtins/worktree.py +0 -0
  296. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/injection_guard.py +0 -0
  297. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/manager.py +0 -0
  298. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/mcp/__init__.py +0 -0
  299. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/mcp/registry.py +0 -0
  300. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/mcp/tools.py +0 -0
  301. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/mcp_sampling.py +0 -0
  302. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/ui.py +0 -0
  303. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/tools/utils.py +0 -0
  304. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/trusted_folders.py +0 -0
  305. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/types.py +0 -0
  306. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/core/utils.py +0 -0
  307. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/setup/onboarding/__init__.py +0 -0
  308. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/setup/onboarding/base.py +0 -0
  309. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/setup/onboarding/onboarding.tcss +0 -0
  310. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/setup/onboarding/screens/__init__.py +0 -0
  311. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/setup/onboarding/screens/api_key.py +0 -0
  312. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/setup/onboarding/screens/choice.py +0 -0
  313. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/setup/onboarding/screens/local_model.py +0 -0
  314. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/setup/onboarding/screens/welcome.py +0 -0
  315. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/setup/trusted_folders/trust_folder_dialog.py +0 -0
  316. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/setup/trusted_folders/trust_folder_dialog.tcss +0 -0
  317. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/skills/__init__.py +0 -0
  318. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/skills/api-design/SKILL.md +0 -0
  319. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/skills/audit-tests/SKILL.md +0 -0
  320. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/skills/batch/SKILL.md +0 -0
  321. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/skills/commit-code/SKILL.md +0 -0
  322. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/skills/context-summary/SKILL.md +0 -0
  323. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/skills/create-presentation/SKILL.md +0 -0
  324. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/skills/deep-research/SKILL.md +0 -0
  325. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/skills/deploy/SKILL.md +0 -0
  326. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/skills/diff-review/SKILL.md +0 -0
  327. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/skills/doc-gen/SKILL.md +0 -0
  328. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/skills/explain-code/SKILL.md +0 -0
  329. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/skills/explore-code/SKILL.md +0 -0
  330. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/skills/fix-issue/SKILL.md +0 -0
  331. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/skills/git-ops/SKILL.md +0 -0
  332. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/skills/init-project/SKILL.md +0 -0
  333. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/skills/investigate/SKILL.md +0 -0
  334. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/skills/loop/SKILL.md +0 -0
  335. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/skills/migrate/SKILL.md +0 -0
  336. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/skills/perf-analyze/SKILL.md +0 -0
  337. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/skills/plan-impl/SKILL.md +0 -0
  338. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/skills/pr-review/SKILL.md +0 -0
  339. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/skills/refactor/SKILL.md +0 -0
  340. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/skills/regex-help/SKILL.md +0 -0
  341. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/skills/review/SKILL.md +0 -0
  342. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/skills/security-review/SKILL.md +0 -0
  343. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/skills/ship/SKILL.md +0 -0
  344. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/skills/simplify/SKILL.md +0 -0
  345. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/skills/strong-tests/SKILL.md +0 -0
  346. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/skills/test-verify/SKILL.md +0 -0
  347. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock/whats_new.md +0 -0
  348. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock-acp.spec +0 -0
  349. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/drydock_terms.md +0 -0
  350. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/flake.lock +0 -0
  351. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/flake.nix +0 -0
  352. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/nohup.out +0 -0
  353. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/research/README.md +0 -0
  354. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/research/config_base.toml +0 -0
  355. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/research/config_best.toml +0 -0
  356. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/research/domain_spec.md +0 -0
  357. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/research/experimenter.py +0 -0
  358. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/research/kernel.py +0 -0
  359. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/research/mini_prd.md +0 -0
  360. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/research/mini_prompts.txt +0 -0
  361. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/research/proposer.py +0 -0
  362. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/research/results.tsv +0 -0
  363. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/resume.md +0 -0
  364. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/README.md +0 -0
  365. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/admiral_probe.py +0 -0
  366. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/audit_sampler.py +0 -0
  367. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/auto_generate_tests.py +0 -0
  368. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/auto_release.sh +0 -0
  369. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/auto_test_loop.sh +0 -0
  370. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/autonomous_review.sh +0 -0
  371. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/autonomous_review_prompt.md +0 -0
  372. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/backup.sh +0 -0
  373. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/bump_version.py +0 -0
  374. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/comprehensive_loop.py +0 -0
  375. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/deploy_to_github.sh +0 -0
  376. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/discover_cli_tools.sh +0 -0
  377. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/evolve_tests.py +0 -0
  378. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/gen_2000_prompts.py +0 -0
  379. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/install.sh +0 -0
  380. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/llm_balancer.py +0 -0
  381. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/mega_loop.py +0 -0
  382. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/meta_ralph_loop.py +0 -0
  383. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/monitor_swebench.sh +0 -0
  384. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/monitor_test_battery.sh +0 -0
  385. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/notify_release.py +0 -0
  386. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/oss_task_harness.py +0 -0
  387. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/overnight_agents_test.sh +0 -0
  388. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/poll_issues.sh +0 -0
  389. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/port_task.py +0 -0
  390. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/prepare_release.py +0 -0
  391. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/publish_to_pypi.sh +0 -0
  392. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/ralph_loop.py +0 -0
  393. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/research_babysitter.sh +0 -0
  394. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/session_loop_audit.py +0 -0
  395. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/shakedown.py +0 -0
  396. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/shakedown_interactive.py +0 -0
  397. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/shakedown_regression.sh +0 -0
  398. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/shakedown_suite.sh +0 -0
  399. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/shakedown_variance.sh +0 -0
  400. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/stress_babysitter.sh +0 -0
  401. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/stress_prompts_50.txt +0 -0
  402. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/stress_prompts_realuser.txt +0 -0
  403. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/stress_prompts_tool_agent.txt +0 -0
  404. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/stress_prompts_tool_agent_2000.txt +0 -0
  405. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/stress_shakedown.py +0 -0
  406. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/stress_telegram_status.py +0 -0
  407. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/stress_watcher.py +0 -0
  408. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/telegram_bot.py +0 -0
  409. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/test_bank.sh +0 -0
  410. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/test_full.sh +0 -0
  411. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/test_smoke.sh +0 -0
  412. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/test_tui_path.py +0 -0
  413. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/tui_test.py +0 -0
  414. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/scripts/vllm_failover.sh +0 -0
  415. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/test/project/dummy +0 -0
  416. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/__init__.py +0 -0
  417. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/acp/conftest.py +0 -0
  418. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/acp/test_acp.py +0 -0
  419. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/acp/test_agent_thought.py +0 -0
  420. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/acp/test_bash.py +0 -0
  421. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/acp/test_compact_session_updates.py +0 -0
  422. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/acp/test_content.py +0 -0
  423. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/acp/test_initialize.py +0 -0
  424. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/acp/test_list_sessions.py +0 -0
  425. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/acp/test_load_session.py +0 -0
  426. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/acp/test_multi_session.py +0 -0
  427. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/acp/test_new_session.py +0 -0
  428. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/acp/test_proxy_setup_acp.py +0 -0
  429. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/acp/test_read_file.py +0 -0
  430. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/acp/test_search_replace.py +0 -0
  431. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/acp/test_set_config_option.py +0 -0
  432. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/acp/test_set_mode.py +0 -0
  433. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/acp/test_set_model.py +0 -0
  434. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/acp/test_tool_call_session_update.py +0 -0
  435. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/acp/test_utils.py +0 -0
  436. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/acp/test_write_file.py +0 -0
  437. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/autocompletion/test_file_indexer.py +0 -0
  438. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/autocompletion/test_fuzzy.py +0 -0
  439. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/autocompletion/test_path_completer_fuzzy.py +0 -0
  440. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/autocompletion/test_path_completer_recursive.py +0 -0
  441. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/autocompletion/test_path_completion_controller.py +0 -0
  442. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/autocompletion/test_path_prompt_transformer.py +0 -0
  443. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/autocompletion/test_slash_command_controller.py +0 -0
  444. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/autocompletion/test_ui_chat_autocompletion.py +0 -0
  445. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/backend/__init__.py +0 -0
  446. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/backend/data/__init__.py +0 -0
  447. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/backend/data/fireworks.py +0 -0
  448. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/backend/data/mistral.py +0 -0
  449. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/backend/test_anthropic_adapter.py +0 -0
  450. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/backend/test_backend.py +0 -0
  451. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/backend/test_generic_adapter_sanitize.py +0 -0
  452. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/backend/test_reasoning_adapter.py +0 -0
  453. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/backend/test_vertex_anthropic_adapter.py +0 -0
  454. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/cli/plan_offer/adapters/fake_whoami_gateway.py +0 -0
  455. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/cli/plan_offer/test_decide_plan_offer.py +0 -0
  456. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/cli/plan_offer/test_http_whoami_gateway.py +0 -0
  457. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/cli/test_bell_notifications.py +0 -0
  458. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/cli/test_braille_renderer.py +0 -0
  459. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/cli/test_clipboard.py +0 -0
  460. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/cli/test_commands.py +0 -0
  461. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/cli/test_copy_shortcuts.py +0 -0
  462. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/cli/test_external_editor.py +0 -0
  463. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/cli/test_no_markup_static.py +0 -0
  464. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/cli/test_question_app.py +0 -0
  465. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/cli/test_spinner.py +0 -0
  466. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/cli/test_switching_mode.py +0 -0
  467. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/cli/test_ui_clipboard_notifications.py +0 -0
  468. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/cli/test_ui_session_incremental_renderer.py +0 -0
  469. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/cli/test_ui_session_resume.py +0 -0
  470. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/cli/test_ui_skill_dispatch.py +0 -0
  471. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/cli/textual_ui/__init__.py +0 -0
  472. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/cli/textual_ui/test_session_picker.py +0 -0
  473. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/conftest.py +0 -0
  474. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/core/test_agents.py +0 -0
  475. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/core/test_auth_crypto.py +0 -0
  476. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/core/test_auth_github.py +0 -0
  477. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/core/test_config_load_dotenv.py +0 -0
  478. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/core/test_config_paths.py +0 -0
  479. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/core/test_config_resolution.py +0 -0
  480. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/core/test_file_logging.py +0 -0
  481. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/core/test_plan_session.py +0 -0
  482. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/core/test_proxy_setup.py +0 -0
  483. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/core/test_slug.py +0 -0
  484. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/core/test_telemetry_send.py +0 -0
  485. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/core/test_teleport_git.py +0 -0
  486. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/core/test_teleport_nuage.py +0 -0
  487. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/core/test_teleport_service.py +0 -0
  488. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/core/test_trusted_folders.py +0 -0
  489. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/core/test_utils.py +0 -0
  490. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/e2e/common.py +0 -0
  491. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/e2e/conftest.py +0 -0
  492. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/e2e/mock_server.py +0 -0
  493. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/e2e/test_cli_tui_onboarding.py +0 -0
  494. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/e2e/test_cli_tui_streaming.py +0 -0
  495. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/e2e/test_cli_tui_tool_approval.py +0 -0
  496. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/fixtures/doc_qa_system_prd.md +0 -0
  497. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/mock/__init__.py +0 -0
  498. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/mock/mock_backend_factory.py +0 -0
  499. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/mock/mock_entrypoint.py +0 -0
  500. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/mock/utils.py +0 -0
  501. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/onboarding/test_run_onboarding.py +0 -0
  502. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/onboarding/test_ui_onboarding.py +0 -0
  503. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/session/test_session_loader.py +0 -0
  504. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/session/test_session_logger.py +0 -0
  505. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/session/test_session_migration.py +0 -0
  506. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/skills/conftest.py +0 -0
  507. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/skills/test_manager.py +0 -0
  508. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/skills/test_models.py +0 -0
  509. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/skills/test_parser.py +0 -0
  510. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_ask_user_question/test_snapshot_ask_user_question_collapsed.svg +0 -0
  511. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_ask_user_question/test_snapshot_ask_user_question_expanded.svg +0 -0
  512. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_basic_conversation/test_snapshot_shows_basic_conversation.svg +0 -0
  513. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_code_block_horizontal_scrolling/test_snapshot_allows_horizontal_scrolling_for_long_code_blocks.svg +0 -0
  514. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_empty_assistant_before_reasoning/test_snapshot_empty_assistant_removed_when_reasoning_starts.svg +0 -0
  515. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_cycle_to_accept_edits_mode.svg +0 -0
  516. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_cycle_to_auto_approve_mode.svg +0 -0
  517. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_cycle_to_plan_mode.svg +0 -0
  518. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_cycle_wraps_to_default.svg +0 -0
  519. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_default_mode.svg +0 -0
  520. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_parallel_tool_calls/test_snapshot_parallel_tool_calls_pending.svg +0 -0
  521. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_parallel_tool_calls/test_snapshot_parallel_tool_calls_resolved.svg +0 -0
  522. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_cancel_discards_changes.svg +0 -0
  523. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_edit_existing_values.svg +0 -0
  524. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_initial_empty.svg +0 -0
  525. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_initial_with_values.svg +0 -0
  526. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_save_error.svg +0 -0
  527. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_save_new_values.svg +0 -0
  528. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_answer_first_advance.svg +0 -0
  529. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_first_answered_checkmark.svg +0 -0
  530. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_initial.svg +0 -0
  531. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_navigate_left_wraps.svg +0 -0
  532. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_navigate_right.svg +0 -0
  533. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_tab_to_second.svg +0 -0
  534. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_initial.svg +0 -0
  535. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_mixed_selection.svg +0 -0
  536. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_navigate_to_submit.svg +0 -0
  537. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_other_with_text.svg +0 -0
  538. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_toggle_first.svg +0 -0
  539. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_toggle_multiple.svg +0 -0
  540. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_untoggle.svg +0 -0
  541. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_initial.svg +0 -0
  542. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_navigate_down.svg +0 -0
  543. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_navigate_to_other.svg +0 -0
  544. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_navigate_to_third_option.svg +0 -0
  545. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_navigate_up_wraps.svg +0 -0
  546. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_other_typing.svg +0 -0
  547. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_reasoning_content/test_snapshot_buffered_reasoning_yields_before_content.svg +0 -0
  548. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_reasoning_content/test_snapshot_shows_interleaved_reasoning.svg +0 -0
  549. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_reasoning_content/test_snapshot_shows_reasoning_content.svg +0 -0
  550. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_reasoning_content/test_snapshot_shows_reasoning_content_expanded.svg +0 -0
  551. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_release_update_notification/test_snapshot_shows_release_update_notification.svg +0 -0
  552. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_session_resume/test_snapshot_shows_resumed_session_messages.svg +0 -0
  553. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_streaming_tool_call/test_snapshot_tool_call_partial.svg +0 -0
  554. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_streaming_tool_call/test_snapshot_tool_call_updated.svg +0 -0
  555. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_push_confirmation_cancel_selected.svg +0 -0
  556. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_push_confirmation_multiple_commits.svg +0 -0
  557. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_push_confirmation_single_commit.svg +0 -0
  558. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_auth_complete.svg +0 -0
  559. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_auth_required.svg +0 -0
  560. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_checking_git.svg +0 -0
  561. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_complete.svg +0 -0
  562. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_error.svg +0 -0
  563. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_pushing.svg +0 -0
  564. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_sending_token.svg +0 -0
  565. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_starting_workflow.svg +0 -0
  566. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_whats_new/test_snapshot_shows_no_plan_message.svg +0 -0
  567. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_whats_new/test_snapshot_shows_switch_message.svg +0 -0
  568. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_whats_new/test_snapshot_shows_upgrade_message.svg +0 -0
  569. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/__snapshots__/test_ui_snapshot_whats_new/test_snapshot_shows_whats_new_message.svg +0 -0
  570. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/base_snapshot_test_app.py +0 -0
  571. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/conftest.py +0 -0
  572. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/snap_compare.py +0 -0
  573. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/test_ui_snapshot_ask_user_question.py +0 -0
  574. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/test_ui_snapshot_basic_conversation.py +0 -0
  575. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/test_ui_snapshot_code_block_horizontal_scrolling.py +0 -0
  576. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/test_ui_snapshot_empty_assistant_before_reasoning.py +0 -0
  577. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/test_ui_snapshot_modes.py +0 -0
  578. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/test_ui_snapshot_parallel_tool_calls.py +0 -0
  579. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/test_ui_snapshot_proxy_setup.py +0 -0
  580. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/test_ui_snapshot_question_app.py +0 -0
  581. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/test_ui_snapshot_reasoning_content.py +0 -0
  582. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/test_ui_snapshot_release_update_notification.py +0 -0
  583. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/test_ui_snapshot_session_resume.py +0 -0
  584. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/test_ui_snapshot_streaming_tool_call.py +0 -0
  585. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/test_ui_snapshot_teleport.py +0 -0
  586. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/snapshots/test_ui_snapshot_whats_new.py +0 -0
  587. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/stubs/fake_backend.py +0 -0
  588. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/stubs/fake_client.py +0 -0
  589. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/stubs/fake_tool.py +0 -0
  590. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_admiral.py +0 -0
  591. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_admiral_phase3.py +0 -0
  592. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_admiral_proposed.py +0 -0
  593. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_agent_auto_compact.py +0 -0
  594. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_agent_backend.py +0 -0
  595. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_agent_observer_streaming.py +0 -0
  596. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_agent_stats.py +0 -0
  597. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_agent_tasks.py +0 -0
  598. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_agent_tool_call.py +0 -0
  599. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_agents.py +0 -0
  600. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_bank_build.py +0 -0
  601. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_bank_debug.py +0 -0
  602. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_bank_multiagent.py +0 -0
  603. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_bank_prd.py +0 -0
  604. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_bank_prd_extended.py +0 -0
  605. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_bank_tools.py +0 -0
  606. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_bank_update.py +0 -0
  607. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_build_projects.py +0 -0
  608. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_checkpoint.py +0 -0
  609. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_cli_programmatic_preload.py +0 -0
  610. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_current_bugs.py +0 -0
  611. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_drydock_regression.py +0 -0
  612. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_drydock_tasks.py +0 -0
  613. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_fake_tool_call_paren_syntax.py +0 -0
  614. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_full_regression.py +0 -0
  615. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_history_manager.py +0 -0
  616. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_integration.py +0 -0
  617. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_issue_fixes.py +0 -0
  618. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_loop_detection.py +0 -0
  619. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_message_id.py +0 -0
  620. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_message_merging.py +0 -0
  621. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_middleware.py +0 -0
  622. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_multi_agent.py +0 -0
  623. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_read_file_not_found_listing.py +0 -0
  624. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_real_failures.py +0 -0
  625. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_real_issues.py +0 -0
  626. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_real_workflow.py +0 -0
  627. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_reasoning_content.py +0 -0
  628. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_smoke.py +0 -0
  629. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_system_prompt.py +0 -0
  630. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_tagged_text.py +0 -0
  631. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_tool_args.py +0 -0
  632. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_truncate_args_valid_json.py +0 -0
  633. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_ui_external_editor.py +0 -0
  634. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_ui_input_history.py +0 -0
  635. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_user_issues.py +0 -0
  636. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_wall_of_text_rescue.py +0 -0
  637. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/test_workloads.py +0 -0
  638. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/testbank_helpers.py +0 -0
  639. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/tools/test_ask_user_question.py +0 -0
  640. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/tools/test_bash.py +0 -0
  641. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/tools/test_exit_plan_mode.py +0 -0
  642. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/tools/test_grep.py +0 -0
  643. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/tools/test_invoke_context.py +0 -0
  644. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/tools/test_manager_gemma_derived_models.py +0 -0
  645. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/tools/test_manager_get_tool_config.py +0 -0
  646. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/tools/test_mcp.py +0 -0
  647. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/tools/test_mcp_sampling.py +0 -0
  648. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/tools/test_read_file_directory.py +0 -0
  649. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/tools/test_search_replace_append_fallback.py +0 -0
  650. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/tools/test_search_replace_no_op_loop_breaker.py +0 -0
  651. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/tools/test_search_replace_refused_loop_breaker.py +0 -0
  652. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/tools/test_task.py +0 -0
  653. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/tools/test_ui_bash_execution.py +0 -0
  654. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/tools/test_webfetch.py +0 -0
  655. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/tools/test_websearch.py +0 -0
  656. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/tools/test_write_file_dedup_missing_imports.py +0 -0
  657. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/tools/test_write_file_missing_path_hint.py +0 -0
  658. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/update_notifier/adapters/fake_update_cache_repository.py +0 -0
  659. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/update_notifier/adapters/fake_update_gateway.py +0 -0
  660. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/update_notifier/test_do_update.py +0 -0
  661. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/update_notifier/test_filesystem_update_cache_repository.py +0 -0
  662. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/update_notifier/test_github_update_gateway.py +0 -0
  663. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/update_notifier/test_pypi_update_gateway.py +0 -0
  664. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/update_notifier/test_ui_update_notification.py +0 -0
  665. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/update_notifier/test_update_use_case.py +0 -0
  666. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/tests/update_notifier/test_whats_new.py +0 -0
  667. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/worked_examples/README.md +0 -0
  668. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/worked_examples/cli_subcommand_dispatch.py +0 -0
  669. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/worked_examples/lookup.json +0 -0
  670. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/worked_examples/sql_parser.py +0 -0
  671. {drydock_cli-2.7.16 → drydock_cli-2.7.18}/worked_examples/tree_walking_interpreter.py +0 -0
@@ -0,0 +1 @@
1
+ 341821
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: drydock-cli
3
- Version: 2.7.16
3
+ Version: 2.7.18
4
4
  Summary: Local-first CLI coding agent — tested with Gemma 4 26B via vLLM
5
5
  Project-URL: Homepage, https://github.com/fbobe321/drydock
6
6
  Project-URL: Repository, https://github.com/fbobe321/drydock
@@ -80,18 +80,28 @@ def detect_struggle(messages: Sequence[LLMMessage], threshold: int = 20) -> Find
80
80
  calls_since_write += 1
81
81
  if calls_since_write < threshold:
82
82
  return None
83
- hint = (
84
- "Either (a) you already have enough context commit to a plan and "
85
- "start writing code now, or (b) you're genuinely stuck stop and "
86
- "report what's blocking you to the user."
87
- )
88
- return Finding(
89
- code=f"struggle:{calls_since_write}:{last_write_tool or 'none'}",
90
- directive=(
83
+ # Stable code (no count) so DEDUP_WINDOW_SEC suppresses repeated firings.
84
+ # Previously included the count, which caused 33 identical interventions
85
+ # in a single session (each with a unique key that bypassed dedup).
86
+ code = f"struggle:{last_write_tool or 'none'}"
87
+ if calls_since_write >= 30:
88
+ directive = (
89
+ f"Admiral: you have made {calls_since_write} tool calls without "
90
+ f"writing any file — search_replace is clearly not finding the text. "
91
+ f"STOP retrying. Call `write_file` with `overwrite=True` to rewrite "
92
+ f"the target file from scratch right now."
93
+ )
94
+ else:
95
+ hint = (
96
+ "Either (a) you already have enough context — commit to a plan and "
97
+ "start writing code now, or (b) you're genuinely stuck — stop and "
98
+ "report what's blocking you to the user."
99
+ )
100
+ directive = (
91
101
  f"Admiral: you have made {calls_since_write} tool calls without "
92
102
  f"writing or editing any file. {hint}"
93
- ),
94
- )
103
+ )
104
+ return Finding(code=code, directive=directive)
95
105
 
96
106
 
97
107
  def run_all(messages: Sequence[LLMMessage]) -> list[Finding]:
@@ -1131,10 +1131,12 @@ class AgentLoop:
1131
1131
  token-level sampling bumps don't help when the model picks
1132
1132
  the SAME serialized args every time.
1133
1133
 
1134
- Conservative thresholds only fires on truly pathological
1135
- repeat counts that would never be a "valid retry":
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 12 identical calls
1139
+ read_file, grep, glob, ls: after 5 identical calls
1138
1140
  """
1139
1141
  args_str = json.dumps(tool_call.args_dict, sort_keys=True, default=str)
1140
1142
  sig = hashlib.sha256(
@@ -1143,7 +1145,7 @@ class AgentLoop:
1143
1145
  count, last_result = self._tool_call_history.get(sig, (0, ""))
1144
1146
  tool_name = tool_call.tool_name
1145
1147
  is_readonly = tool_name in ("grep", "read_file", "glob", "ls")
1146
- threshold = 12 if is_readonly else 8
1148
+ threshold = 5 if is_readonly else 8
1147
1149
  if count < threshold:
1148
1150
  return None
1149
1151
  return (
@@ -2379,6 +2381,30 @@ class AgentLoop:
2379
2381
  if len(recent_sr) >= 2 and recent_sr[0] == recent_sr[1]:
2380
2382
  return "WARNING|search_replace"
2381
2383
 
2384
+ # Early check: write_file with _truncated args twice in a row for the
2385
+ # same path. format.py already embeds the file content in the error,
2386
+ # but Gemma 4 ignores the advisory and retries identically. Mute
2387
+ # write_file for 1 turn so the model must use read_file or
2388
+ # search_replace instead — same pattern as the search_replace check.
2389
+ recent_wf_truncated: list[str] = []
2390
+ for msg in reversed(self.messages[-20:]):
2391
+ if msg.role == Role.assistant and msg.tool_calls:
2392
+ for tc in msg.tool_calls:
2393
+ if tc.function and tc.function.name == "write_file":
2394
+ try:
2395
+ args = json.loads(tc.function.arguments or "{}")
2396
+ if args.get("_truncated"):
2397
+ p = (args.get("file_path") or args.get("path") or "")
2398
+ recent_wf_truncated.append(p)
2399
+ except (json.JSONDecodeError, AttributeError):
2400
+ pass
2401
+ if len(recent_wf_truncated) >= 2:
2402
+ break
2403
+ if (len(recent_wf_truncated) >= 2
2404
+ and recent_wf_truncated[0] == recent_wf_truncated[1]):
2405
+ self._hot_tool_path = ("write_file", recent_wf_truncated[0])
2406
+ return "FORCE_STOP"
2407
+
2382
2408
  sigs: list[str] = []
2383
2409
  tool_names: list[str] = []
2384
2410
  lookback = 0
@@ -3,6 +3,7 @@ from __future__ import annotations
3
3
  import json
4
4
  import logging
5
5
  import re as _re
6
+ from pathlib import Path
6
7
  from typing import TYPE_CHECKING, Any
7
8
 
8
9
  from pydantic import BaseModel, ConfigDict, Field, ValidationError
@@ -378,16 +379,43 @@ class APIToolFormatHandler:
378
379
  path_hint = (parsed_call.raw_args.get("path")
379
380
  or parsed_call.raw_args.get("file_path")
380
381
  or "")
381
- hint = f" Re-read `{path_hint}` with read_file first." if path_hint else ""
382
+ # Auto-embed the current file content so the model can
383
+ # rewrite immediately without an extra read_file round-trip.
384
+ file_embed = ""
385
+ if path_hint:
386
+ try:
387
+ p = Path(path_hint)
388
+ if p.exists() and p.is_file():
389
+ raw = p.read_text(errors="replace")
390
+ lines = raw.splitlines()
391
+ max_lines = 120
392
+ if len(lines) <= max_lines:
393
+ file_embed = (
394
+ f"\n\nCurrent file content of `{path_hint}`:\n"
395
+ f"```\n{raw}\n```\n"
396
+ f"Rewrite it now using write_file with the correct content."
397
+ )
398
+ else:
399
+ snippet = "\n".join(lines[:max_lines])
400
+ file_embed = (
401
+ f"\n\nCurrent file content of `{path_hint}` "
402
+ f"(first {max_lines} of {len(lines)} lines):\n"
403
+ f"```\n{snippet}\n```\n"
404
+ f"Use read_file to see the rest, then rewrite with write_file."
405
+ )
406
+ except Exception:
407
+ pass
408
+ if not file_embed and path_hint:
409
+ file_embed = f" Re-read `{path_hint}` with read_file first."
382
410
  failed_calls.append(
383
411
  FailedToolCall(
384
412
  tool_name=parsed_call.tool_name,
385
413
  call_id=parsed_call.call_id,
386
414
  error=(
387
- f"{parsed_call.tool_name}: your call used a "
415
+ f"your call used a "
388
416
  f"truncated history entry as a template (it contained "
389
417
  f"'_truncated'/'_original_bytes' instead of real "
390
- f"arguments).{hint} Provide the full required arguments."
418
+ f"arguments).{file_embed} Provide the full required arguments."
391
419
  ),
392
420
  )
393
421
  )
@@ -410,11 +438,56 @@ class APIToolFormatHandler:
410
438
  and "path" in error_str
411
439
  and "Field required" in error_str
412
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
+ )
413
486
  error_msg = (
414
- "write_file: missing required `path` parameter. "
415
- "You must pass BOTH `path` AND `content` as separate arguments. "
416
- 'Fix: write_file(path="your/file.py", content="..."). '
417
- "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}"
418
491
  )
419
492
  else:
420
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
 
@@ -130,6 +130,19 @@ class ReadFile(
130
130
  read_result = await self._read_file(args, file_path)
131
131
  content = "".join(read_result.lines)
132
132
 
133
+ # When stopped by the line limit (not byte limit), append a hint so
134
+ # the model knows to paginate with offset= instead of re-reading.
135
+ if (
136
+ read_result.was_truncated
137
+ and args.limit is not None
138
+ and len(read_result.lines) == args.limit
139
+ ):
140
+ next_offset = args.offset + args.limit
141
+ content += (
142
+ f"\n[lines {args.offset + 1}–{next_offset} shown; "
143
+ f"use offset={next_offset} to read more]"
144
+ )
145
+
133
146
  # Record read state so Write/Edit can enforce Read-before-Write
134
147
  # and so future re-reads can dedup against this one.
135
148
  if read_state is not None:
@@ -195,6 +208,7 @@ class ReadFile(
195
208
  continue
196
209
 
197
210
  if args.limit is not None and len(lines_to_return) >= args.limit:
211
+ was_truncated = True
198
212
  break
199
213
 
200
214
  line_bytes = len(line.encode("utf-8"))
@@ -131,6 +131,74 @@ 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
174
+ if err_msg.startswith("Path is not a file:"):
175
+ # Model passed a directory instead of a file path.
176
+ # Return a result (not raise) so the model corrects the call
177
+ # rather than retrying the same directory path in a loop.
178
+ dir_path_str = args.file_path.strip()
179
+ dir_path = Path(dir_path_str).expanduser()
180
+ if not dir_path.is_absolute():
181
+ dir_path = Path.cwd() / dir_path
182
+ dir_path = dir_path.resolve()
183
+ if dir_path.is_dir():
184
+ try:
185
+ files = sorted(p.name for p in dir_path.iterdir() if p.is_file())
186
+ except OSError:
187
+ files = []
188
+ files_list = "\n".join(f" {f}" for f in files[:20]) or " (empty directory)"
189
+ yield SearchReplaceResult(
190
+ file=str(dir_path),
191
+ blocks_applied=0,
192
+ lines_changed=0,
193
+ content=(
194
+ f"PATH ERROR: '{dir_path}' is a directory, not a file. "
195
+ f"search_replace requires a path to a specific file.\n"
196
+ f"Files in that directory:\n{files_list}\n"
197
+ f"Specify the full path including the filename, e.g. "
198
+ f"'{dir_path}/<filename.py>'"
199
+ ),
200
+ )
201
+ return
134
202
  if err_msg.startswith("NO_BLOCKS:"):
135
203
  # Gemma 4 sent raw code without SEARCH/REPLACE markers.
136
204
  # CAREFULLY fall back to full file overwrite — but refuse if
@@ -383,18 +451,38 @@ class SearchReplace(
383
451
  state[fail_key] = entry
384
452
  if entry["count"] >= 2:
385
453
  try:
386
- head = original_content[:2000]
387
454
  line_count = original_content.count("\n")
388
- error_message += (
389
- f"\n\n[LOOP-BREAKER: this is the #{entry['count']} "
390
- f"consecutive search_replace failure on "
391
- f"{file_path.name}. Stop retrying the same search. "
392
- f"Actual file content (first 2000 chars of "
393
- f"{line_count} lines):\n"
394
- f"-----FILE START-----\n{head}\n-----FILE END-----\n"
395
- f"Use THIS exact text as your search target, OR "
396
- f"abandon this edit and try write_file.]"
397
- )
455
+ count = entry["count"]
456
+ if count >= 3:
457
+ # Show full file (up to 4000 chars) and prohibit retry.
458
+ body = original_content[:4000]
459
+ tail = (
460
+ f"\n...[truncated, {line_count} lines total]"
461
+ if len(original_content) > 4000 else ""
462
+ )
463
+ error_message += (
464
+ f"\n\n[HARD-STOP: this is the #{count} consecutive "
465
+ f"search_replace failure on {file_path.name}. "
466
+ f"Your search text was NOT found in the file. "
467
+ f"DO NOT retry search_replace with the same or similar text. "
468
+ f"REQUIRED action: call write_file with overwrite=True "
469
+ f"and provide the complete new file content. "
470
+ f"Full file content below — use this as the basis "
471
+ f"for your write_file call:\n"
472
+ f"-----FILE START-----\n{body}{tail}\n-----FILE END-----]"
473
+ )
474
+ else:
475
+ head = original_content[:2000]
476
+ error_message += (
477
+ f"\n\n[LOOP-BREAKER: this is the #{count} "
478
+ f"consecutive search_replace failure on "
479
+ f"{file_path.name}. Stop retrying the same search. "
480
+ f"Actual file content (first 2000 chars of "
481
+ f"{line_count} lines):\n"
482
+ f"-----FILE START-----\n{head}\n-----FILE END-----\n"
483
+ f"Use THIS exact text as your search target, OR "
484
+ f"abandon this edit and try write_file.]"
485
+ )
398
486
  except Exception:
399
487
  pass
400
488
 
@@ -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:
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "drydock-cli"
3
- version = "2.7.16"
3
+ version = "2.7.18"
4
4
  description = "Local-first CLI coding agent — tested with Gemma 4 26B via vLLM"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -0,0 +1,93 @@
1
+ """Regression test: read_file circuit breaker fires at threshold 5, not 12.
2
+
3
+ Stress sessions reset every 45 prompts. With threshold=12, the model could
4
+ loop 11× on the same read_file call before being blocked — admiral advisories
5
+ fire at 3× but are ignored. Threshold=5 actually engages the block before
6
+ the session's budget is exhausted.
7
+ """
8
+ import hashlib
9
+ import json
10
+ import unittest
11
+ from unittest.mock import MagicMock
12
+
13
+
14
+ def _make_circuit_breaker_check():
15
+ """Import and bind just the circuit breaker logic for unit testing."""
16
+ from drydock.core.agent_loop import AgentLoop
17
+
18
+ loop = AgentLoop.__new__(AgentLoop)
19
+ loop._tool_call_history = {}
20
+ loop._get_attempted_summary = lambda: ""
21
+ return loop
22
+
23
+
24
+ class TestCircuitBreakerReadonlyThreshold(unittest.TestCase):
25
+ def _make_tool_call(self, name, args):
26
+ tc = MagicMock()
27
+ tc.tool_name = name
28
+ tc.args_dict = args
29
+ tc.call_id = "test-id"
30
+ return tc
31
+
32
+ def _record(self, loop, tool_call, result="some content"):
33
+ from drydock.core.agent_loop import AgentLoop
34
+ AgentLoop._circuit_breaker_record(loop, tool_call, result)
35
+
36
+ def test_read_file_blocks_at_5(self):
37
+ """Circuit breaker fires on the 6th identical call (threshold=5 means count>=5 blocks)."""
38
+ loop = _make_circuit_breaker_check()
39
+ tc = self._make_tool_call("read_file", {"path": "foo.py", "offset": 150, "limit": 100})
40
+
41
+ # First 5 calls: should not block
42
+ for i in range(5):
43
+ result = loop._circuit_breaker_check(tc)
44
+ self.assertIsNone(result, f"Expected no block on call {i+1}, got: {result}")
45
+ self._record(loop, tc)
46
+
47
+ # 6th call: should block (count=5 >= threshold=5)
48
+ result = loop._circuit_breaker_check(tc)
49
+ self.assertIsNotNone(result, "Expected circuit breaker to fire on 6th identical read_file")
50
+ self.assertIn("read_file", result)
51
+
52
+ def test_bash_still_blocks_at_8(self):
53
+ """bash threshold=8, so blocks on 9th call (count=8 >= threshold=8)."""
54
+ loop = _make_circuit_breaker_check()
55
+ tc = self._make_tool_call("bash", {"command": "ls -la"})
56
+
57
+ for i in range(8):
58
+ result = loop._circuit_breaker_check(tc)
59
+ self.assertIsNone(result, f"Expected no block on bash call {i+1}")
60
+ self._record(loop, tc)
61
+
62
+ result = loop._circuit_breaker_check(tc)
63
+ self.assertIsNotNone(result, "Expected circuit breaker to fire on 9th identical bash")
64
+
65
+ def test_grep_blocks_at_5(self):
66
+ loop = _make_circuit_breaker_check()
67
+ tc = self._make_tool_call("grep", {"pattern": "def foo", "path": "bar.py"})
68
+
69
+ for i in range(5):
70
+ result = loop._circuit_breaker_check(tc)
71
+ self.assertIsNone(result)
72
+ self._record(loop, tc)
73
+
74
+ # 6th call blocks (count=5 >= threshold=5)
75
+ result = loop._circuit_breaker_check(tc)
76
+ self.assertIsNotNone(result, "Expected circuit breaker to fire on 6th identical grep")
77
+
78
+ def test_different_args_not_blocked(self):
79
+ loop = _make_circuit_breaker_check()
80
+
81
+ # 5 reads of foo.py at offset 150
82
+ tc1 = self._make_tool_call("read_file", {"path": "foo.py", "offset": 150})
83
+ for _ in range(5):
84
+ self._record(loop, tc1)
85
+
86
+ # Different offset should not be blocked
87
+ tc2 = self._make_tool_call("read_file", {"path": "foo.py", "offset": 200})
88
+ result = loop._circuit_breaker_check(tc2)
89
+ self.assertIsNone(result, "Different args should not be blocked")
90
+
91
+
92
+ if __name__ == "__main__":
93
+ unittest.main()
@@ -0,0 +1,68 @@
1
+ """Regression tests for struggle detector dedup fix.
2
+
3
+ Before the fix, the finding code was f"struggle:{count}:{tool}" — each count
4
+ was a unique key, bypassing DEDUP_WINDOW_SEC and producing 33 identical
5
+ interventions in one session that the model ignored.
6
+
7
+ After the fix, the code is stable (f"struggle:{tool}") so a single entry
8
+ in recent_findings suppresses repeat firings within the 60-second window.
9
+ """
10
+ from __future__ import annotations
11
+
12
+ from drydock.admiral.detectors import detect_struggle
13
+ from drydock.core.types import FunctionCall, LLMMessage, Role, ToolCall
14
+
15
+
16
+ def _assistant(tool: str, args: str = "{}") -> LLMMessage:
17
+ return LLMMessage(
18
+ role=Role.assistant,
19
+ content="",
20
+ tool_calls=[ToolCall(function=FunctionCall(name=tool, arguments=args))],
21
+ )
22
+
23
+
24
+ def _make_msgs(write_tool: str, non_write_count: int) -> list[LLMMessage]:
25
+ msgs: list[LLMMessage] = [LLMMessage(role=Role.user, content="build it")]
26
+ msgs.append(_assistant(write_tool, '{"path":"x.py","content":"x"}'))
27
+ msgs.append(LLMMessage(role=Role.tool, content="ok"))
28
+ for i in range(non_write_count):
29
+ msgs.append(_assistant("read_file", f'{{"path":"f{i}.py"}}'))
30
+ msgs.append(LLMMessage(role=Role.tool, content="content"))
31
+ return msgs
32
+
33
+
34
+ def test_struggle_code_is_stable_no_count() -> None:
35
+ """Finding code must NOT include the count so dedup works across counts."""
36
+ msgs20 = _make_msgs("search_replace", 20)
37
+ msgs33 = _make_msgs("search_replace", 33)
38
+ f20 = detect_struggle(msgs20)
39
+ f33 = detect_struggle(msgs33)
40
+ assert f20 is not None
41
+ assert f33 is not None
42
+ # Same stable code regardless of count
43
+ assert f20.code == f33.code
44
+ assert "20" not in f20.code
45
+ assert "33" not in f33.code
46
+
47
+
48
+ def test_struggle_escalated_directive_at_30() -> None:
49
+ """At 30+ non-write calls, directive must mention write_file overwrite."""
50
+ msgs = _make_msgs("search_replace", 30)
51
+ f = detect_struggle(msgs)
52
+ assert f is not None
53
+ assert "write_file" in f.directive
54
+ assert "overwrite" in f.directive
55
+
56
+
57
+ def test_struggle_gentle_directive_below_30() -> None:
58
+ """Below 30, directive is the gentle nudge (no overwrite mention)."""
59
+ msgs = _make_msgs("search_replace", 22)
60
+ f = detect_struggle(msgs)
61
+ assert f is not None
62
+ assert "overwrite" not in f.directive
63
+ assert "commit to a plan" in f.directive
64
+
65
+
66
+ def test_struggle_no_fire_below_threshold() -> None:
67
+ msgs = _make_msgs("write_file", 5)
68
+ assert detect_struggle(msgs) is None
@@ -92,3 +92,33 @@ class TestTruncatedArgPathHint:
92
92
  assert len(result.failed_calls) == 1
93
93
  assert "Re-read" not in result.failed_calls[0].error
94
94
  assert "_truncated" in result.failed_calls[0].error or "truncated" in result.failed_calls[0].error
95
+
96
+ def test_existing_file_content_embedded(self, tmp_path):
97
+ """When the target file exists, its content is embedded in the error
98
+ so the model can rewrite without an extra read_file round-trip."""
99
+ target = tmp_path / "utils.py"
100
+ target.write_text("def hello():\n return 42\n")
101
+
102
+ handler = APIToolFormatHandler()
103
+ parsed = ParsedMessage(
104
+ tool_calls=[
105
+ ParsedToolCall(
106
+ tool_name="write_file",
107
+ call_id="tc4",
108
+ raw_args={
109
+ "_truncated": True,
110
+ "_original_bytes": 4096,
111
+ "file_path": str(target),
112
+ },
113
+ )
114
+ ]
115
+ )
116
+ tm = _make_tool_manager_with("write_file", _make_write_file_class())
117
+ result = handler.resolve_tool_calls(parsed, tm)
118
+ assert len(result.failed_calls) == 1
119
+ err = result.failed_calls[0].error
120
+ # Content should be embedded, not just a Re-read directive
121
+ assert "def hello():" in err
122
+ assert "return 42" in err
123
+ # Re-read advisory should NOT appear when content is embedded
124
+ assert "Re-read" not in err