drydock-cli 2.6.81__tar.gz → 2.6.83__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 (595) hide show
  1. drydock_cli-2.6.83/.auto_release.lock +1 -0
  2. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/PKG-INFO +1 -1
  3. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/entrypoint.py +17 -0
  4. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/textual_ui/handlers/event_handler.py +10 -1
  5. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/agent_loop.py +7 -0
  6. drydock_cli-2.6.83/drydock/core/config/doctor.py +222 -0
  7. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/llm/format.py +36 -9
  8. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/base.py +5 -0
  9. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/builtins/bash.py +71 -23
  10. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/builtins/read_file.py +45 -52
  11. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/builtins/search_replace.py +61 -0
  12. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/builtins/write_file.py +136 -86
  13. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/pyproject.toml +1 -1
  14. drydock_cli-2.6.81/.auto_release.lock +0 -1
  15. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/.claude/scheduled_tasks.lock +0 -0
  16. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/.github/CODEOWNERS +0 -0
  17. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/.github/DISCUSSION_TEMPLATE/ideas.yml +0 -0
  18. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
  19. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  20. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/.github/workflows/build-and-upload.yml +0 -0
  21. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/.github/workflows/ci.yml +0 -0
  22. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/.github/workflows/issue-labeler.yml +0 -0
  23. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/.github/workflows/release.yml +0 -0
  24. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/.gitignore +0 -0
  25. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/.pre-commit-config.yaml +0 -0
  26. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/.python-version +0 -0
  27. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/.typos.toml +0 -0
  28. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/.vscode/extensions.json +0 -0
  29. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/.vscode/launch.json +0 -0
  30. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/.vscode/settings.json +0 -0
  31. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/AGENTS.md +0 -0
  32. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/BASELINE_412.md +0 -0
  33. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/CHANGELOG.md +0 -0
  34. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/CLAUDE.md +0 -0
  35. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/CONTRIBUTING.md +0 -0
  36. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/Drydock_rebrand.md +0 -0
  37. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/LICENSE +0 -0
  38. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/MODEL_SHORTCOMINGS.md +0 -0
  39. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/NOTICE +0 -0
  40. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/OVERNIGHT_REPORT_2026_04_13.md +0 -0
  41. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/PRD.md +0 -0
  42. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/README.md +0 -0
  43. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/action.yml +0 -0
  44. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/baseline_history/README.md +0 -0
  45. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/baseline_history/results1.tsv +0 -0
  46. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/baseline_history/results13.tsv +0 -0
  47. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/baseline_history/results14.tsv +0 -0
  48. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/baseline_history/results15.tsv +0 -0
  49. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/baseline_history/results16.tsv +0 -0
  50. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/baseline_history/results17.tsv +0 -0
  51. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/baseline_history/results18.tsv +0 -0
  52. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/baseline_history/results19.tsv +0 -0
  53. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/baseline_history/results2.tsv +0 -0
  54. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/baseline_history/results20.tsv +0 -0
  55. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/baseline_history/results3.tsv +0 -0
  56. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/baseline_history/results4.tsv +0 -0
  57. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/baseline_history/results5.tsv +0 -0
  58. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/baseline_history/results6.tsv +0 -0
  59. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/baseline_history/results7.tsv +0 -0
  60. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/baseline_history/results8.tsv +0 -0
  61. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/baseline_history/results9.tsv +0 -0
  62. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/baseline_history/results_evolved_v1.tsv +0 -0
  63. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/distribution/zed/LICENSE +0 -0
  64. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/distribution/zed/extension.toml +0 -0
  65. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/distribution/zed/icons/mistral_vibe.svg +0 -0
  66. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/docs/README.md +0 -0
  67. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/docs/acp-setup.md +0 -0
  68. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/docs/proxy-setup.md +0 -0
  69. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/__init__.py +0 -0
  70. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/acp/__init__.py +0 -0
  71. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/acp/acp_agent_loop.py +0 -0
  72. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/acp/acp_logger.py +0 -0
  73. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/acp/entrypoint.py +0 -0
  74. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/acp/tools/__init__.py +0 -0
  75. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/acp/tools/base.py +0 -0
  76. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/acp/tools/builtins/bash.py +0 -0
  77. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/acp/tools/builtins/read_file.py +0 -0
  78. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/acp/tools/builtins/search_replace.py +0 -0
  79. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/acp/tools/builtins/todo.py +0 -0
  80. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/acp/tools/builtins/write_file.py +0 -0
  81. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/acp/tools/session_update.py +0 -0
  82. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/acp/utils.py +0 -0
  83. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/__init__.py +0 -0
  84. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/autocompletion/__init__.py +0 -0
  85. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/autocompletion/base.py +0 -0
  86. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/autocompletion/path_completion.py +0 -0
  87. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/autocompletion/slash_command.py +0 -0
  88. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/cli.py +0 -0
  89. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/clipboard.py +0 -0
  90. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/commands.py +0 -0
  91. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/history_manager.py +0 -0
  92. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/plan_offer/adapters/http_whoami_gateway.py +0 -0
  93. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/plan_offer/decide_plan_offer.py +0 -0
  94. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/plan_offer/ports/whoami_gateway.py +0 -0
  95. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/terminal_setup.py +0 -0
  96. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/textual_ui/__init__.py +0 -0
  97. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/textual_ui/ansi_markdown.py +0 -0
  98. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/textual_ui/app.py +0 -0
  99. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/textual_ui/app.tcss +0 -0
  100. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/textual_ui/external_editor.py +0 -0
  101. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/textual_ui/handlers/__init__.py +0 -0
  102. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/textual_ui/notifications/__init__.py +0 -0
  103. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/textual_ui/notifications/adapters/__init__.py +0 -0
  104. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/textual_ui/notifications/adapters/textual_notification_adapter.py +0 -0
  105. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/textual_ui/notifications/ports/__init__.py +0 -0
  106. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/textual_ui/notifications/ports/notification_port.py +0 -0
  107. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/textual_ui/widgets/__init__.py +0 -0
  108. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/textual_ui/widgets/approval_app.py +0 -0
  109. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/textual_ui/widgets/banner/banner.py +0 -0
  110. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/textual_ui/widgets/banner/petit_chat.py +0 -0
  111. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/textual_ui/widgets/braille_renderer.py +0 -0
  112. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/textual_ui/widgets/chat_input/__init__.py +0 -0
  113. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/textual_ui/widgets/chat_input/body.py +0 -0
  114. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/textual_ui/widgets/chat_input/completion_manager.py +0 -0
  115. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/textual_ui/widgets/chat_input/completion_popup.py +0 -0
  116. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/textual_ui/widgets/chat_input/container.py +0 -0
  117. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/textual_ui/widgets/chat_input/text_area.py +0 -0
  118. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/textual_ui/widgets/compact.py +0 -0
  119. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/textual_ui/widgets/config_app.py +0 -0
  120. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/textual_ui/widgets/context_progress.py +0 -0
  121. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/textual_ui/widgets/load_more.py +0 -0
  122. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/textual_ui/widgets/loading.py +0 -0
  123. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/textual_ui/widgets/messages.py +0 -0
  124. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/textual_ui/widgets/no_markup_static.py +0 -0
  125. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/textual_ui/widgets/path_display.py +0 -0
  126. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/textual_ui/widgets/proxy_setup_app.py +0 -0
  127. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/textual_ui/widgets/question_app.py +0 -0
  128. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/textual_ui/widgets/session_picker.py +0 -0
  129. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/textual_ui/widgets/spinner.py +0 -0
  130. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/textual_ui/widgets/status_message.py +0 -0
  131. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/textual_ui/widgets/teleport_message.py +0 -0
  132. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/textual_ui/widgets/tool_widgets.py +0 -0
  133. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/textual_ui/widgets/tools.py +0 -0
  134. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/textual_ui/widgets/vscode_compat.py +0 -0
  135. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/textual_ui/windowing/__init__.py +0 -0
  136. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/textual_ui/windowing/history.py +0 -0
  137. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/textual_ui/windowing/history_windowing.py +0 -0
  138. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/textual_ui/windowing/state.py +0 -0
  139. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/update_notifier/__init__.py +0 -0
  140. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/update_notifier/adapters/filesystem_update_cache_repository.py +0 -0
  141. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/update_notifier/adapters/github_update_gateway.py +0 -0
  142. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/update_notifier/adapters/pypi_update_gateway.py +0 -0
  143. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/update_notifier/ports/update_cache_repository.py +0 -0
  144. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/update_notifier/ports/update_gateway.py +0 -0
  145. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/update_notifier/update.py +0 -0
  146. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/cli/update_notifier/whats_new.py +0 -0
  147. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/__init__.py +0 -0
  148. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/agents/__init__.py +0 -0
  149. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/agents/manager.py +0 -0
  150. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/agents/models.py +0 -0
  151. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/auth/__init__.py +0 -0
  152. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/auth/crypto.py +0 -0
  153. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/auth/github.py +0 -0
  154. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/autocompletion/__init__.py +0 -0
  155. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/autocompletion/completers.py +0 -0
  156. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/autocompletion/file_indexer/__init__.py +0 -0
  157. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/autocompletion/file_indexer/ignore_rules.py +0 -0
  158. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/autocompletion/file_indexer/indexer.py +0 -0
  159. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/autocompletion/file_indexer/store.py +0 -0
  160. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/autocompletion/file_indexer/watcher.py +0 -0
  161. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/autocompletion/fuzzy.py +0 -0
  162. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/autocompletion/path_prompt.py +0 -0
  163. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/autocompletion/path_prompt_adapter.py +0 -0
  164. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/build_orchestrator.py +0 -0
  165. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/config/__init__.py +0 -0
  166. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/config/_settings.py +0 -0
  167. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/config/harness_files/__init__.py +0 -0
  168. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/config/harness_files/_harness_manager.py +0 -0
  169. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/config/harness_files/_paths.py +0 -0
  170. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/consultant.py +0 -0
  171. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/drydock_states.py +0 -0
  172. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/hooks.py +0 -0
  173. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/llm/__init__.py +0 -0
  174. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/llm/backend/anthropic.py +0 -0
  175. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/llm/backend/base.py +0 -0
  176. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/llm/backend/factory.py +0 -0
  177. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/llm/backend/generic.py +0 -0
  178. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/llm/backend/mistral.py +0 -0
  179. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/llm/backend/reasoning_adapter.py +0 -0
  180. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/llm/backend/vertex.py +0 -0
  181. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/llm/exceptions.py +0 -0
  182. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/llm/message_utils.py +0 -0
  183. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/llm/types.py +0 -0
  184. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/logger.py +0 -0
  185. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/middleware.py +0 -0
  186. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/output_formatters.py +0 -0
  187. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/paths/__init__.py +0 -0
  188. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/paths/_local_config_walk.py +0 -0
  189. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/paths/_vibe_home.py +0 -0
  190. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/paths/conventions.py +0 -0
  191. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/plan_session.py +0 -0
  192. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/plugins.py +0 -0
  193. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/programmatic.py +0 -0
  194. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/prompts/__init__.py +0 -0
  195. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/prompts/builder.md +0 -0
  196. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/prompts/cli.md +0 -0
  197. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/prompts/compact.md +0 -0
  198. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/prompts/dangerous_directory.md +0 -0
  199. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/prompts/diagnostic.md +0 -0
  200. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/prompts/explore.md +0 -0
  201. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/prompts/gemma4.md +0 -0
  202. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/prompts/planner.md +0 -0
  203. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/prompts/project_context.md +0 -0
  204. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/prompts/tests.md +0 -0
  205. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/proxy_setup.py +0 -0
  206. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/session/agent_memory.py +0 -0
  207. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/session/checkpoints.py +0 -0
  208. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/session/session_loader.py +0 -0
  209. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/session/session_logger.py +0 -0
  210. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/session/session_migration.py +0 -0
  211. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/session/state_file.py +0 -0
  212. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/session_checker.py +0 -0
  213. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/skills/__init__.py +0 -0
  214. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/skills/manager.py +0 -0
  215. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/skills/models.py +0 -0
  216. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/skills/parser.py +0 -0
  217. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/slug.py +0 -0
  218. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/system_prompt.py +0 -0
  219. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/telemetry/__init__.py +0 -0
  220. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/telemetry/send.py +0 -0
  221. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/teleport/errors.py +0 -0
  222. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/teleport/git.py +0 -0
  223. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/teleport/nuage.py +0 -0
  224. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/teleport/teleport.py +0 -0
  225. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/teleport/types.py +0 -0
  226. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/builtins/_task_manager.py +0 -0
  227. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/builtins/ask_user_question.py +0 -0
  228. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/builtins/cron.py +0 -0
  229. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/builtins/exit_plan_mode.py +0 -0
  230. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/builtins/glob_tool.py +0 -0
  231. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/builtins/grep.py +0 -0
  232. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/builtins/invoke_skill.py +0 -0
  233. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/builtins/lsp.py +0 -0
  234. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/builtins/mcp_resources.py +0 -0
  235. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/builtins/notebook_edit.py +0 -0
  236. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/builtins/powershell.py +0 -0
  237. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/builtins/prompts/__init__.py +0 -0
  238. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/builtins/prompts/ask_user_question.md +0 -0
  239. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/builtins/prompts/bash.md +0 -0
  240. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/builtins/prompts/cron.md +0 -0
  241. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/builtins/prompts/glob.md +0 -0
  242. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/builtins/prompts/grep.md +0 -0
  243. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/builtins/prompts/invoke_skill.md +0 -0
  244. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/builtins/prompts/lsp.md +0 -0
  245. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/builtins/prompts/mcp_resources.md +0 -0
  246. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/builtins/prompts/notebook_edit.md +0 -0
  247. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/builtins/prompts/powershell.md +0 -0
  248. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/builtins/prompts/read_file.md +0 -0
  249. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/builtins/prompts/search_replace.md +0 -0
  250. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/builtins/prompts/swe_bench.md +0 -0
  251. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/builtins/prompts/task.md +0 -0
  252. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/builtins/prompts/task_manager.md +0 -0
  253. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/builtins/prompts/todo.md +0 -0
  254. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/builtins/prompts/tool_search.md +0 -0
  255. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/builtins/prompts/webfetch.md +0 -0
  256. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/builtins/prompts/websearch.md +0 -0
  257. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/builtins/prompts/worktree.md +0 -0
  258. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/builtins/prompts/write_file.md +0 -0
  259. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/builtins/task.py +0 -0
  260. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/builtins/todo.py +0 -0
  261. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/builtins/tool_search.py +0 -0
  262. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/builtins/webfetch.py +0 -0
  263. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/builtins/websearch.py +0 -0
  264. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/builtins/worktree.py +0 -0
  265. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/injection_guard.py +0 -0
  266. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/manager.py +0 -0
  267. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/mcp/__init__.py +0 -0
  268. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/mcp/registry.py +0 -0
  269. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/mcp/tools.py +0 -0
  270. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/mcp_sampling.py +0 -0
  271. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/ui.py +0 -0
  272. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/tools/utils.py +0 -0
  273. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/trusted_folders.py +0 -0
  274. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/types.py +0 -0
  275. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/core/utils.py +0 -0
  276. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/setup/onboarding/__init__.py +0 -0
  277. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/setup/onboarding/base.py +0 -0
  278. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/setup/onboarding/onboarding.tcss +0 -0
  279. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/setup/onboarding/screens/__init__.py +0 -0
  280. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/setup/onboarding/screens/api_key.py +0 -0
  281. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/setup/onboarding/screens/welcome.py +0 -0
  282. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/setup/trusted_folders/trust_folder_dialog.py +0 -0
  283. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/setup/trusted_folders/trust_folder_dialog.tcss +0 -0
  284. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/skills/__init__.py +0 -0
  285. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/skills/api-design/SKILL.md +0 -0
  286. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/skills/audit-tests/SKILL.md +0 -0
  287. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/skills/batch/SKILL.md +0 -0
  288. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/skills/commit-code/SKILL.md +0 -0
  289. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/skills/context-summary/SKILL.md +0 -0
  290. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/skills/create-presentation/SKILL.md +0 -0
  291. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/skills/deep-research/SKILL.md +0 -0
  292. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/skills/deploy/SKILL.md +0 -0
  293. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/skills/diff-review/SKILL.md +0 -0
  294. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/skills/doc-gen/SKILL.md +0 -0
  295. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/skills/explain-code/SKILL.md +0 -0
  296. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/skills/explore-code/SKILL.md +0 -0
  297. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/skills/fix-issue/SKILL.md +0 -0
  298. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/skills/git-ops/SKILL.md +0 -0
  299. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/skills/init-project/SKILL.md +0 -0
  300. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/skills/investigate/SKILL.md +0 -0
  301. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/skills/loop/SKILL.md +0 -0
  302. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/skills/migrate/SKILL.md +0 -0
  303. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/skills/perf-analyze/SKILL.md +0 -0
  304. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/skills/plan-impl/SKILL.md +0 -0
  305. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/skills/pr-review/SKILL.md +0 -0
  306. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/skills/refactor/SKILL.md +0 -0
  307. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/skills/regex-help/SKILL.md +0 -0
  308. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/skills/review/SKILL.md +0 -0
  309. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/skills/security-review/SKILL.md +0 -0
  310. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/skills/ship/SKILL.md +0 -0
  311. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/skills/simplify/SKILL.md +0 -0
  312. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/skills/strong-tests/SKILL.md +0 -0
  313. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/skills/test-verify/SKILL.md +0 -0
  314. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock/whats_new.md +0 -0
  315. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock-acp.spec +0 -0
  316. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/drydock_terms.md +0 -0
  317. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/flake.lock +0 -0
  318. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/flake.nix +0 -0
  319. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/scripts/README.md +0 -0
  320. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/scripts/audit_sampler.py +0 -0
  321. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/scripts/auto_generate_tests.py +0 -0
  322. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/scripts/auto_release.sh +0 -0
  323. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/scripts/auto_test_loop.sh +0 -0
  324. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/scripts/backup.sh +0 -0
  325. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/scripts/bump_version.py +0 -0
  326. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/scripts/comprehensive_loop.py +0 -0
  327. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/scripts/deploy_to_github.sh +0 -0
  328. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/scripts/discover_cli_tools.sh +0 -0
  329. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/scripts/evolve_tests.py +0 -0
  330. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/scripts/install.sh +0 -0
  331. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/scripts/llm_balancer.py +0 -0
  332. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/scripts/mega_loop.py +0 -0
  333. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/scripts/meta_ralph_loop.py +0 -0
  334. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/scripts/monitor_swebench.sh +0 -0
  335. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/scripts/monitor_test_battery.sh +0 -0
  336. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/scripts/notify_release.py +0 -0
  337. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/scripts/oss_task_harness.py +0 -0
  338. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/scripts/overnight_agents_test.sh +0 -0
  339. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/scripts/port_task.py +0 -0
  340. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/scripts/prepare_release.py +0 -0
  341. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/scripts/publish_to_pypi.sh +0 -0
  342. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/scripts/ralph_loop.py +0 -0
  343. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/scripts/session_loop_audit.py +0 -0
  344. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/scripts/shakedown.py +0 -0
  345. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/scripts/shakedown_interactive.py +0 -0
  346. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/scripts/shakedown_regression.sh +0 -0
  347. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/scripts/shakedown_suite.sh +0 -0
  348. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/scripts/shakedown_variance.sh +0 -0
  349. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/scripts/telegram_bot.py +0 -0
  350. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/scripts/test_bank.sh +0 -0
  351. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/scripts/test_full.sh +0 -0
  352. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/scripts/test_smoke.sh +0 -0
  353. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/scripts/test_tui_path.py +0 -0
  354. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/scripts/tui_test.py +0 -0
  355. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/scripts/vllm_failover.sh +0 -0
  356. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/__init__.py +0 -0
  357. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/acp/conftest.py +0 -0
  358. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/acp/test_acp.py +0 -0
  359. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/acp/test_agent_thought.py +0 -0
  360. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/acp/test_bash.py +0 -0
  361. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/acp/test_compact_session_updates.py +0 -0
  362. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/acp/test_content.py +0 -0
  363. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/acp/test_initialize.py +0 -0
  364. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/acp/test_list_sessions.py +0 -0
  365. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/acp/test_load_session.py +0 -0
  366. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/acp/test_multi_session.py +0 -0
  367. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/acp/test_new_session.py +0 -0
  368. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/acp/test_proxy_setup_acp.py +0 -0
  369. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/acp/test_read_file.py +0 -0
  370. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/acp/test_search_replace.py +0 -0
  371. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/acp/test_set_config_option.py +0 -0
  372. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/acp/test_set_mode.py +0 -0
  373. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/acp/test_set_model.py +0 -0
  374. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/acp/test_tool_call_session_update.py +0 -0
  375. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/acp/test_utils.py +0 -0
  376. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/acp/test_write_file.py +0 -0
  377. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/autocompletion/test_file_indexer.py +0 -0
  378. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/autocompletion/test_fuzzy.py +0 -0
  379. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/autocompletion/test_path_completer_fuzzy.py +0 -0
  380. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/autocompletion/test_path_completer_recursive.py +0 -0
  381. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/autocompletion/test_path_completion_controller.py +0 -0
  382. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/autocompletion/test_path_prompt_transformer.py +0 -0
  383. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/autocompletion/test_slash_command_controller.py +0 -0
  384. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/autocompletion/test_ui_chat_autocompletion.py +0 -0
  385. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/backend/__init__.py +0 -0
  386. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/backend/data/__init__.py +0 -0
  387. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/backend/data/fireworks.py +0 -0
  388. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/backend/data/mistral.py +0 -0
  389. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/backend/test_anthropic_adapter.py +0 -0
  390. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/backend/test_backend.py +0 -0
  391. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/backend/test_reasoning_adapter.py +0 -0
  392. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/backend/test_vertex_anthropic_adapter.py +0 -0
  393. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/cli/plan_offer/adapters/fake_whoami_gateway.py +0 -0
  394. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/cli/plan_offer/test_decide_plan_offer.py +0 -0
  395. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/cli/plan_offer/test_http_whoami_gateway.py +0 -0
  396. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/cli/test_bell_notifications.py +0 -0
  397. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/cli/test_braille_renderer.py +0 -0
  398. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/cli/test_clipboard.py +0 -0
  399. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/cli/test_commands.py +0 -0
  400. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/cli/test_copy_shortcuts.py +0 -0
  401. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/cli/test_external_editor.py +0 -0
  402. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/cli/test_no_markup_static.py +0 -0
  403. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/cli/test_question_app.py +0 -0
  404. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/cli/test_spinner.py +0 -0
  405. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/cli/test_switching_mode.py +0 -0
  406. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/cli/test_ui_clipboard_notifications.py +0 -0
  407. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/cli/test_ui_session_incremental_renderer.py +0 -0
  408. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/cli/test_ui_session_resume.py +0 -0
  409. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/cli/test_ui_skill_dispatch.py +0 -0
  410. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/cli/textual_ui/__init__.py +0 -0
  411. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/cli/textual_ui/test_session_picker.py +0 -0
  412. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/conftest.py +0 -0
  413. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/core/test_agents.py +0 -0
  414. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/core/test_auth_crypto.py +0 -0
  415. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/core/test_auth_github.py +0 -0
  416. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/core/test_config_load_dotenv.py +0 -0
  417. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/core/test_config_paths.py +0 -0
  418. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/core/test_config_resolution.py +0 -0
  419. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/core/test_file_logging.py +0 -0
  420. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/core/test_plan_session.py +0 -0
  421. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/core/test_proxy_setup.py +0 -0
  422. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/core/test_slug.py +0 -0
  423. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/core/test_telemetry_send.py +0 -0
  424. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/core/test_teleport_git.py +0 -0
  425. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/core/test_teleport_nuage.py +0 -0
  426. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/core/test_teleport_service.py +0 -0
  427. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/core/test_trusted_folders.py +0 -0
  428. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/core/test_utils.py +0 -0
  429. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/e2e/common.py +0 -0
  430. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/e2e/conftest.py +0 -0
  431. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/e2e/mock_server.py +0 -0
  432. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/e2e/test_cli_tui_onboarding.py +0 -0
  433. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/e2e/test_cli_tui_streaming.py +0 -0
  434. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/e2e/test_cli_tui_tool_approval.py +0 -0
  435. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/fixtures/doc_qa_system_prd.md +0 -0
  436. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/mock/__init__.py +0 -0
  437. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/mock/mock_backend_factory.py +0 -0
  438. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/mock/mock_entrypoint.py +0 -0
  439. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/mock/utils.py +0 -0
  440. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/onboarding/test_run_onboarding.py +0 -0
  441. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/onboarding/test_ui_onboarding.py +0 -0
  442. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/session/test_session_loader.py +0 -0
  443. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/session/test_session_logger.py +0 -0
  444. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/session/test_session_migration.py +0 -0
  445. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/skills/conftest.py +0 -0
  446. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/skills/test_manager.py +0 -0
  447. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/skills/test_models.py +0 -0
  448. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/skills/test_parser.py +0 -0
  449. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_ask_user_question/test_snapshot_ask_user_question_collapsed.svg +0 -0
  450. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_ask_user_question/test_snapshot_ask_user_question_expanded.svg +0 -0
  451. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_basic_conversation/test_snapshot_shows_basic_conversation.svg +0 -0
  452. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_code_block_horizontal_scrolling/test_snapshot_allows_horizontal_scrolling_for_long_code_blocks.svg +0 -0
  453. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_empty_assistant_before_reasoning/test_snapshot_empty_assistant_removed_when_reasoning_starts.svg +0 -0
  454. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_cycle_to_accept_edits_mode.svg +0 -0
  455. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_cycle_to_auto_approve_mode.svg +0 -0
  456. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_cycle_to_plan_mode.svg +0 -0
  457. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_cycle_wraps_to_default.svg +0 -0
  458. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_default_mode.svg +0 -0
  459. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_parallel_tool_calls/test_snapshot_parallel_tool_calls_pending.svg +0 -0
  460. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_parallel_tool_calls/test_snapshot_parallel_tool_calls_resolved.svg +0 -0
  461. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_cancel_discards_changes.svg +0 -0
  462. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_edit_existing_values.svg +0 -0
  463. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_initial_empty.svg +0 -0
  464. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_initial_with_values.svg +0 -0
  465. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_save_error.svg +0 -0
  466. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_save_new_values.svg +0 -0
  467. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_answer_first_advance.svg +0 -0
  468. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_first_answered_checkmark.svg +0 -0
  469. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_initial.svg +0 -0
  470. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_navigate_left_wraps.svg +0 -0
  471. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_navigate_right.svg +0 -0
  472. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_tab_to_second.svg +0 -0
  473. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_initial.svg +0 -0
  474. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_mixed_selection.svg +0 -0
  475. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_navigate_to_submit.svg +0 -0
  476. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_other_with_text.svg +0 -0
  477. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_toggle_first.svg +0 -0
  478. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_toggle_multiple.svg +0 -0
  479. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_untoggle.svg +0 -0
  480. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_initial.svg +0 -0
  481. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_navigate_down.svg +0 -0
  482. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_navigate_to_other.svg +0 -0
  483. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_navigate_to_third_option.svg +0 -0
  484. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_navigate_up_wraps.svg +0 -0
  485. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_other_typing.svg +0 -0
  486. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_reasoning_content/test_snapshot_buffered_reasoning_yields_before_content.svg +0 -0
  487. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_reasoning_content/test_snapshot_shows_interleaved_reasoning.svg +0 -0
  488. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_reasoning_content/test_snapshot_shows_reasoning_content.svg +0 -0
  489. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_reasoning_content/test_snapshot_shows_reasoning_content_expanded.svg +0 -0
  490. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_release_update_notification/test_snapshot_shows_release_update_notification.svg +0 -0
  491. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_session_resume/test_snapshot_shows_resumed_session_messages.svg +0 -0
  492. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_streaming_tool_call/test_snapshot_tool_call_partial.svg +0 -0
  493. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_streaming_tool_call/test_snapshot_tool_call_updated.svg +0 -0
  494. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_push_confirmation_cancel_selected.svg +0 -0
  495. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_push_confirmation_multiple_commits.svg +0 -0
  496. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_push_confirmation_single_commit.svg +0 -0
  497. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_auth_complete.svg +0 -0
  498. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_auth_required.svg +0 -0
  499. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_checking_git.svg +0 -0
  500. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_complete.svg +0 -0
  501. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_error.svg +0 -0
  502. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_pushing.svg +0 -0
  503. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_sending_token.svg +0 -0
  504. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_starting_workflow.svg +0 -0
  505. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_whats_new/test_snapshot_shows_no_plan_message.svg +0 -0
  506. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_whats_new/test_snapshot_shows_switch_message.svg +0 -0
  507. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_whats_new/test_snapshot_shows_upgrade_message.svg +0 -0
  508. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/__snapshots__/test_ui_snapshot_whats_new/test_snapshot_shows_whats_new_message.svg +0 -0
  509. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/base_snapshot_test_app.py +0 -0
  510. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/conftest.py +0 -0
  511. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/snap_compare.py +0 -0
  512. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/test_ui_snapshot_ask_user_question.py +0 -0
  513. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/test_ui_snapshot_basic_conversation.py +0 -0
  514. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/test_ui_snapshot_code_block_horizontal_scrolling.py +0 -0
  515. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/test_ui_snapshot_empty_assistant_before_reasoning.py +0 -0
  516. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/test_ui_snapshot_modes.py +0 -0
  517. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/test_ui_snapshot_parallel_tool_calls.py +0 -0
  518. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/test_ui_snapshot_proxy_setup.py +0 -0
  519. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/test_ui_snapshot_question_app.py +0 -0
  520. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/test_ui_snapshot_reasoning_content.py +0 -0
  521. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/test_ui_snapshot_release_update_notification.py +0 -0
  522. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/test_ui_snapshot_session_resume.py +0 -0
  523. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/test_ui_snapshot_streaming_tool_call.py +0 -0
  524. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/test_ui_snapshot_teleport.py +0 -0
  525. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/snapshots/test_ui_snapshot_whats_new.py +0 -0
  526. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/stubs/fake_backend.py +0 -0
  527. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/stubs/fake_client.py +0 -0
  528. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/stubs/fake_tool.py +0 -0
  529. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/test_agent_auto_compact.py +0 -0
  530. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/test_agent_backend.py +0 -0
  531. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/test_agent_observer_streaming.py +0 -0
  532. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/test_agent_stats.py +0 -0
  533. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/test_agent_tasks.py +0 -0
  534. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/test_agent_tool_call.py +0 -0
  535. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/test_agents.py +0 -0
  536. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/test_bank_build.py +0 -0
  537. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/test_bank_debug.py +0 -0
  538. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/test_bank_multiagent.py +0 -0
  539. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/test_bank_prd.py +0 -0
  540. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/test_bank_prd_extended.py +0 -0
  541. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/test_bank_tools.py +0 -0
  542. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/test_bank_update.py +0 -0
  543. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/test_build_projects.py +0 -0
  544. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/test_cli_programmatic_preload.py +0 -0
  545. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/test_current_bugs.py +0 -0
  546. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/test_drydock_regression.py +0 -0
  547. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/test_drydock_tasks.py +0 -0
  548. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/test_full_regression.py +0 -0
  549. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/test_history_manager.py +0 -0
  550. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/test_integration.py +0 -0
  551. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/test_loop_detection.py +0 -0
  552. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/test_message_id.py +0 -0
  553. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/test_message_merging.py +0 -0
  554. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/test_middleware.py +0 -0
  555. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/test_multi_agent.py +0 -0
  556. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/test_real_failures.py +0 -0
  557. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/test_real_issues.py +0 -0
  558. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/test_real_workflow.py +0 -0
  559. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/test_reasoning_content.py +0 -0
  560. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/test_smoke.py +0 -0
  561. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/test_system_prompt.py +0 -0
  562. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/test_tagged_text.py +0 -0
  563. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/test_tool_args.py +0 -0
  564. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/test_ui_external_editor.py +0 -0
  565. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/test_ui_input_history.py +0 -0
  566. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/test_user_issues.py +0 -0
  567. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/test_workloads.py +0 -0
  568. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/testbank_helpers.py +0 -0
  569. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/tools/test_ask_user_question.py +0 -0
  570. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/tools/test_bash.py +0 -0
  571. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/tools/test_exit_plan_mode.py +0 -0
  572. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/tools/test_grep.py +0 -0
  573. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/tools/test_invoke_context.py +0 -0
  574. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/tools/test_manager_get_tool_config.py +0 -0
  575. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/tools/test_mcp.py +0 -0
  576. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/tools/test_mcp_sampling.py +0 -0
  577. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/tools/test_task.py +0 -0
  578. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/tools/test_ui_bash_execution.py +0 -0
  579. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/tools/test_webfetch.py +0 -0
  580. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/tools/test_websearch.py +0 -0
  581. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/update_notifier/adapters/fake_update_cache_repository.py +0 -0
  582. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/update_notifier/adapters/fake_update_gateway.py +0 -0
  583. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/update_notifier/test_do_update.py +0 -0
  584. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/update_notifier/test_filesystem_update_cache_repository.py +0 -0
  585. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/update_notifier/test_github_update_gateway.py +0 -0
  586. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/update_notifier/test_pypi_update_gateway.py +0 -0
  587. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/update_notifier/test_ui_update_notification.py +0 -0
  588. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/update_notifier/test_update_use_case.py +0 -0
  589. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/tests/update_notifier/test_whats_new.py +0 -0
  590. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/uv.lock +0 -0
  591. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/worked_examples/README.md +0 -0
  592. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/worked_examples/cli_subcommand_dispatch.py +0 -0
  593. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/worked_examples/lookup.json +0 -0
  594. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/worked_examples/sql_parser.py +0 -0
  595. {drydock_cli-2.6.81 → drydock_cli-2.6.83}/worked_examples/tree_walking_interpreter.py +0 -0
@@ -0,0 +1 @@
1
+ 1426724
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: drydock-cli
3
- Version: 2.6.81
3
+ Version: 2.6.83
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
@@ -82,6 +82,17 @@ def parse_arguments() -> argparse.Namespace:
82
82
  "or custom from ~/.drydock/agents/NAME.toml)",
83
83
  )
84
84
  parser.add_argument("--setup", action="store_true", help="Setup API key and exit")
85
+ parser.add_argument(
86
+ "--doctor",
87
+ action="store_true",
88
+ help="Check ~/.drydock/config.toml for drift vs. package defaults and exit",
89
+ )
90
+ parser.add_argument(
91
+ "--fix",
92
+ action="store_true",
93
+ help="With --doctor: rewrite ~/.drydock/config.toml to union missing "
94
+ "defaults (writes .bak backup first). No effect without --doctor.",
95
+ )
85
96
  parser.add_argument(
86
97
  "--workdir",
87
98
  type=Path,
@@ -175,6 +186,12 @@ def check_and_resolve_trusted_folder() -> None:
175
186
  def main() -> None:
176
187
  args = parse_arguments()
177
188
 
189
+ if getattr(args, "doctor", False):
190
+ from drydock.core.config.harness_files import init_harness_files_manager
191
+ from drydock.core.config.doctor import run_doctor
192
+ init_harness_files_manager("user", "project")
193
+ sys.exit(run_doctor(apply=bool(getattr(args, "fix", False))))
194
+
178
195
  if args.workdir:
179
196
  workdir = args.workdir.expanduser().resolve()
180
197
  if not workdir.is_dir():
@@ -84,7 +84,16 @@ class EventHandler:
84
84
  )
85
85
  await self._handle_assistant_message(event)
86
86
  case ToolCallEvent():
87
- await self.finalize_streaming()
87
+ # Finalize assistant content stream (user-visible text) but
88
+ # KEEP the reasoning widget open across tool calls. Closing
89
+ # it spawns a fresh "Thought" widget for every reasoning
90
+ # chunk between calls — a turn with N tool calls shows N
91
+ # "Thought" widgets stacked down the screen.
92
+ if self.current_streaming_message is not None:
93
+ await self.current_streaming_message.stop_stream()
94
+ if self.current_streaming_message.is_stripped_content_empty():
95
+ await self.current_streaming_message.remove()
96
+ self.current_streaming_message = None
88
97
  return await self._handle_tool_call(event, loading_widget)
89
98
  case ToolResultEvent():
90
99
  await self.finalize_streaming()
@@ -195,6 +195,12 @@ class AgentLoop:
195
195
  self._empty_responses: int = 0
196
196
  self._successful_test_runs: int = 0
197
197
 
198
+ # Shared read-file state — used by write_file / search_replace to
199
+ # enforce Read-before-Write (per Claude Code's tool contract) and
200
+ # by read_file to dedup unchanged-mtime re-reads. Keyed by resolved
201
+ # absolute path; value is {"content", "timestamp", "offset", "limit"}.
202
+ self._read_file_state: dict[str, dict] = {}
203
+
198
204
  system_prompt = get_universal_system_prompt(
199
205
  self.tool_manager, self.config, self.skill_manager, self.agent_manager
200
206
  )
@@ -970,6 +976,7 @@ class AgentLoop:
970
976
  sampling_callback=self._sampling_handler,
971
977
  plan_file_path=self._plan_session.plan_file_path,
972
978
  switch_agent_callback=self.switch_agent,
979
+ read_file_state=self._read_file_state,
973
980
  ),
974
981
  **tool_call.args_dict,
975
982
  ):
@@ -0,0 +1,222 @@
1
+ """Config drift diagnostics (Option C — `drydock doctor`).
2
+
3
+ Reads the user's ~/.drydock/config.toml, compares each field against the
4
+ pydantic default, and reports drift. Designed to complement the auto-merge
5
+ behavior in Option A: even though list fields union with defaults at
6
+ load time, the user's config.toml FILE still shows the old values —
7
+ the merge is runtime-only. `drydock doctor --fix` rewrites the TOML with
8
+ the merged values so the file matches what's actually loaded.
9
+
10
+ Separately reports scalar drift (e.g., auto_compact_threshold=200000 when
11
+ the sensible value for the active model is lower). Those are advisory —
12
+ doctor prints them but won't change them without --fix.
13
+ """
14
+ from __future__ import annotations
15
+
16
+ from dataclasses import dataclass
17
+ from pathlib import Path
18
+ from typing import Any
19
+
20
+ try:
21
+ import tomllib
22
+ except ImportError: # pragma: no cover
23
+ import tomli as tomllib # type: ignore
24
+
25
+ try:
26
+ import tomli_w
27
+ except ImportError: # pragma: no cover
28
+ tomli_w = None # type: ignore
29
+
30
+
31
+ # Fields known to be mergeable (user value unioned with package default).
32
+ # When drift is detected on these, `--fix` unions them.
33
+ MERGEABLE_LIST_FIELDS: dict[str, str] = {
34
+ # "section.field": "human_label"
35
+ "bash.allowlist": "bash allowlist (auto-approved commands)",
36
+ "bash.denylist": "bash denylist (blocked commands)",
37
+ "bash.denylist_standalone": "bash denylist_standalone",
38
+ }
39
+
40
+
41
+ @dataclass
42
+ class DriftReport:
43
+ field: str
44
+ user_value: Any
45
+ default_value: Any
46
+ kind: str # "list_merge" | "missing_in_user" | "scalar_stale"
47
+ fix_description: str
48
+
49
+ def to_row(self) -> tuple[str, str, str, str]:
50
+ u = str(self.user_value)
51
+ d = str(self.default_value)
52
+ if len(u) > 40:
53
+ u = u[:37] + "..."
54
+ if len(d) > 40:
55
+ d = d[:37] + "..."
56
+ return (self.field, u, d, self.kind)
57
+
58
+
59
+ def _get_tool_section(toml_data: dict, section: str) -> dict | None:
60
+ """Walk `tools.bash` → toml_data.get('tools', {}).get('bash', {})."""
61
+ cur: Any = toml_data
62
+ for part in section.split("."):
63
+ if not isinstance(cur, dict):
64
+ return None
65
+ cur = cur.get(part)
66
+ if cur is None:
67
+ return None
68
+ return cur if isinstance(cur, dict) else None
69
+
70
+
71
+ def _get_default_list(field_path: str) -> list[str]:
72
+ """Resolve the package-default factory for a dotted field path."""
73
+ section, field = field_path.rsplit(".", 1)
74
+ if section == "bash":
75
+ from drydock.core.tools.builtins.bash import (
76
+ _get_default_allowlist,
77
+ _get_default_denylist,
78
+ _get_default_denylist_standalone,
79
+ )
80
+ factories = {
81
+ "allowlist": _get_default_allowlist,
82
+ "denylist": _get_default_denylist,
83
+ "denylist_standalone": _get_default_denylist_standalone,
84
+ }
85
+ fn = factories.get(field)
86
+ return list(fn()) if fn else []
87
+ return []
88
+
89
+
90
+ def analyze_config(config_path: Path) -> tuple[dict, list[DriftReport]]:
91
+ """Load the user's config.toml and compare each mergeable field against
92
+ its package default. Returns (raw_toml_data, drift_reports)."""
93
+ if not config_path.exists():
94
+ return {}, []
95
+ with config_path.open("rb") as f:
96
+ data = tomllib.load(f)
97
+
98
+ reports: list[DriftReport] = []
99
+
100
+ # Mergeable list fields — check for defaults missing from user config.
101
+ for field_path, _label in MERGEABLE_LIST_FIELDS.items():
102
+ section, field = field_path.rsplit(".", 1)
103
+ # Drydock TOML structure: [tools.bash] allowlist = [...]
104
+ user_section = _get_tool_section(data, f"tools.{section}")
105
+ user_value = user_section.get(field) if user_section else None
106
+ defaults = _get_default_list(field_path)
107
+ if user_value is None:
108
+ # User has no entry — pydantic uses full defaults. No drift.
109
+ continue
110
+ if not isinstance(user_value, list):
111
+ continue
112
+ if "__override__" in user_value:
113
+ continue # explicit opt-out, respect it
114
+ missing = [d for d in defaults if d not in user_value]
115
+ if missing:
116
+ reports.append(DriftReport(
117
+ field=f"tools.{field_path}",
118
+ user_value=f"{len(user_value)} entries",
119
+ default_value=f"{len(defaults)} in package",
120
+ kind="list_merge",
121
+ fix_description=(
122
+ f"Add {len(missing)} missing default(s): "
123
+ + ", ".join(missing[:5])
124
+ + (f" … (+{len(missing) - 5} more)" if len(missing) > 5 else "")
125
+ ),
126
+ ))
127
+
128
+ return data, reports
129
+
130
+
131
+ def print_drift_report(reports: list[DriftReport]) -> None:
132
+ """Print a table of drift findings."""
133
+ from rich.console import Console
134
+ from rich.table import Table
135
+ console = Console()
136
+ if not reports:
137
+ console.print("[green]No config drift detected.[/green]")
138
+ console.print(
139
+ "Your ~/.drydock/config.toml is in sync with the package defaults."
140
+ )
141
+ return
142
+ table = Table(title="Config drift vs. package defaults", show_lines=True)
143
+ table.add_column("Field")
144
+ table.add_column("User", overflow="fold")
145
+ table.add_column("Package default", overflow="fold")
146
+ table.add_column("Kind")
147
+ for r in reports:
148
+ row = r.to_row()
149
+ table.add_row(*row)
150
+ console.print(table)
151
+ console.print("\n[bold]Details:[/bold]")
152
+ for r in reports:
153
+ console.print(f" • [cyan]{r.field}[/cyan]: {r.fix_description}")
154
+ console.print(
155
+ "\nRun [bold]drydock --doctor --fix[/bold] to apply safe corrections "
156
+ "(writes a backup to config.toml.bak).\n"
157
+ "Auto-mergeable lists are ALREADY merged at runtime — fixing only "
158
+ "updates the FILE to reflect what's loaded.\n"
159
+ )
160
+
161
+
162
+ def apply_fix(config_path: Path, data: dict, reports: list[DriftReport]) -> int:
163
+ """Union missing defaults into the user's TOML file. Returns count of fields updated."""
164
+ if tomli_w is None:
165
+ raise RuntimeError(
166
+ "tomli_w is not installed. Add `pip install tomli_w` to use --fix."
167
+ )
168
+ updated = 0
169
+ for r in reports:
170
+ if r.kind != "list_merge":
171
+ continue
172
+ # r.field is e.g. "tools.bash.allowlist"
173
+ parts = r.field.split(".")
174
+ cur: Any = data
175
+ for p in parts[:-1]:
176
+ if p not in cur or not isinstance(cur[p], dict):
177
+ cur[p] = {}
178
+ cur = cur[p]
179
+ final_field = parts[-1]
180
+ defaults_path = ".".join(parts[1:]) # strip leading "tools."
181
+ defaults = _get_default_list(defaults_path)
182
+ user_list = cur.get(final_field, [])
183
+ merged = list(user_list) if isinstance(user_list, list) else []
184
+ for d in defaults:
185
+ if d not in merged:
186
+ merged.append(d)
187
+ cur[final_field] = merged
188
+ updated += 1
189
+
190
+ if updated == 0:
191
+ return 0
192
+
193
+ # Write backup then new file.
194
+ backup = config_path.with_suffix(config_path.suffix + ".bak")
195
+ if config_path.exists():
196
+ backup.write_bytes(config_path.read_bytes())
197
+ with config_path.open("wb") as f:
198
+ tomli_w.dump(data, f)
199
+ return updated
200
+
201
+
202
+ def run_doctor(apply: bool = False) -> int:
203
+ """Entry point for `drydock --doctor [--fix]`. Returns shell exit code."""
204
+ from drydock.core.config.harness_files import get_harness_files_manager
205
+ from rich.console import Console
206
+ console = Console()
207
+
208
+ mgr = get_harness_files_manager()
209
+ config_path = mgr.config_file
210
+ if config_path is None:
211
+ console.print("[yellow]No user config file found.[/yellow]")
212
+ return 0
213
+ console.print(f"Analyzing [bold]{config_path}[/bold] ...\n")
214
+ data, reports = analyze_config(config_path)
215
+ print_drift_report(reports)
216
+ if apply and reports:
217
+ updated = apply_fix(config_path, data, reports)
218
+ console.print(
219
+ f"\n[green]Applied fixes to {updated} field(s). "
220
+ f"Backup saved to {config_path}.bak[/green]"
221
+ )
222
+ return 0
@@ -164,25 +164,52 @@ class APIToolFormatHandler:
164
164
  try:
165
165
  args = json.loads(raw_json)
166
166
  except json.JSONDecodeError:
167
- # Don't silently use {} log the malformed args and skip
167
+ # Gemma 4 frequently leaks thinking-token markers INSIDE
168
+ # JSON string values. Tokens like "<|\Fix" make `\F` an
169
+ # invalid JSON escape, which crashes the decoder and loses
170
+ # the whole tool call. Sanitize and retry before giving up.
168
171
  import logging
172
+ import re as _re
169
173
  logging.getLogger(__name__).warning(
170
174
  "Malformed tool call JSON for %s: %s",
171
175
  function_call.name,
172
176
  (function_call.arguments or "")[:200],
173
177
  )
174
- # Try to salvage partial JSON by closing brackets
175
178
  raw = (function_call.arguments or "").strip()
179
+ args = {}
176
180
  if raw:
177
- # Count open/close braces and try to fix
178
- opens = raw.count('{') - raw.count('}')
179
- raw_fixed = raw + '}' * max(0, opens)
181
+ sanitized = raw
182
+ # Strip complete <|channel>...<channel|>/<tool_call|> blocks
183
+ sanitized = _re.sub(
184
+ r"<\|channel\>.*?(?:<channel\|>|<tool_call\|>)",
185
+ "", sanitized, flags=_re.DOTALL,
186
+ )
187
+ sanitized = _re.sub(
188
+ r"<\|tool_call\>.*?<tool_call\|>",
189
+ "", sanitized, flags=_re.DOTALL,
190
+ )
191
+ # Strip unpaired/truncated <|...|> and <|...> tokens.
192
+ sanitized = _re.sub(r"<\|[^>]{0,200}\|>", "", sanitized)
193
+ sanitized = _re.sub(r"<\|[^>]{0,200}>", "", sanitized)
194
+ sanitized = _re.sub(r"<[^>]{0,200}\|>", "", sanitized)
195
+ # Escape any remaining invalid backslash escapes (JSON
196
+ # only allows \" \\ \/ \b \f \n \r \t \u). Catches e.g.
197
+ # `<|\Fix` residue where `\F` would abort the decoder.
198
+ sanitized = _re.sub(
199
+ r'\\(?!["\\/bfnrtu])', r'\\\\', sanitized,
200
+ )
180
201
  try:
181
- args = json.loads(raw_fixed)
202
+ args = json.loads(sanitized)
182
203
  except json.JSONDecodeError:
183
- args = {"_parse_error": f"Malformed JSON: {raw[:100]}..."}
184
- else:
185
- args = {}
204
+ # Last-ditch: try closing any unbalanced braces.
205
+ opens = sanitized.count("{") - sanitized.count("}")
206
+ if opens > 0:
207
+ try:
208
+ args = json.loads(sanitized + "}" * opens)
209
+ except json.JSONDecodeError:
210
+ args = {"_parse_error": f"Malformed JSON after sanitize: {sanitized[:100]}..."}
211
+ else:
212
+ args = {"_parse_error": f"Malformed JSON: {raw[:100]}..."}
186
213
 
187
214
  tool_calls.append(
188
215
  ParsedToolCall(
@@ -51,6 +51,11 @@ class InvokeContext:
51
51
  entrypoint_metadata: EntrypointMetadata | None = field(default=None)
52
52
  plan_file_path: Path | None = field(default=None)
53
53
  switch_agent_callback: SwitchAgentCallback | None = field(default=None)
54
+ # Shared across all tool invocations within a session. The same dict
55
+ # reference lives on AgentLoop; write_file / read_file / search_replace
56
+ # mutate it to track what the model has observed (Read-before-Write
57
+ # + read dedup, per Claude Code's tool contract model).
58
+ read_file_state: dict[str, dict] | None = field(default=None)
54
59
 
55
60
 
56
61
  class ToolError(Exception):
@@ -1,7 +1,8 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import asyncio
4
- from collections.abc import AsyncGenerator
4
+ from collections.abc import AsyncGenerator, Callable
5
+ from typing import Any
5
6
  from functools import lru_cache
6
7
  import os
7
8
  from pathlib import Path
@@ -9,7 +10,7 @@ import signal
9
10
  import sys
10
11
  from typing import ClassVar, Literal, final
11
12
 
12
- from pydantic import BaseModel, Field
13
+ from pydantic import BaseModel, Field, field_validator
13
14
  from tree_sitter import Language, Node, Parser
14
15
  import tree_sitter_bash as tsbash
15
16
 
@@ -161,8 +162,25 @@ async def _kill_process_tree(proc: asyncio.subprocess.Process) -> None:
161
162
 
162
163
 
163
164
  def _get_default_allowlist() -> list[str]:
165
+ # Auto-accepted because they are read-only / non-destructive.
166
+ # Each entry is a prefix — commands starting with any of these are
167
+ # ALWAYS allowed. Parser splits at pipes/chains so `ls | rm` is
168
+ # checked as two separate commands.
164
169
  common = [
165
- "echo", "find", "git diff", "git log", "git status", "tree", "whoami",
170
+ "echo", "find", "tree", "whoami",
171
+ # Git read-only subcommands
172
+ "git diff", "git log", "git status", "git show",
173
+ "git branch", "git ls-files", "git grep", "git remote",
174
+ "git rev-parse", "git blame", "git config --get",
175
+ "git tag", "git stash list",
176
+ # Search tools (read-only by design)
177
+ "grep", "rg", "fd", "fdfind", "ag",
178
+ # Text/file inspection
179
+ "diff", "cmp", "sort", "uniq", "awk", "cut", "tr",
180
+ "basename", "dirname", "realpath", "readlink",
181
+ # System info (read-only)
182
+ "date", "id", "hostname", "pwd", "env", "printenv",
183
+ "du", "df", "ps", "free", "uptime",
166
184
  # Python project management — safe read/install operations
167
185
  "pip install", "pip list", "pip show", "pip freeze", "pip check",
168
186
  "pip install -e", "pip install -r",
@@ -221,6 +239,26 @@ def _get_default_denylist_standalone() -> list[str]:
221
239
  return common + ["bash", "sh", "nohup", "vi", "vim", "emacs", "nano", "su"]
222
240
 
223
241
 
242
+ def _merge_with_defaults(user_value: Any, defaults_fn: Callable[[], list[str]]) -> list[str]:
243
+ """Union user list with package defaults so `pip install -U` propagates
244
+ new defaults without clobbering user additions (Config Option A). If the
245
+ user list ends with an entry '__override__', their list is used verbatim
246
+ (escape hatch for anyone who needs to intentionally remove a default).
247
+ """
248
+ if user_value is None:
249
+ return defaults_fn()
250
+ if not isinstance(user_value, list):
251
+ return user_value # pydantic will re-type-check and fail cleanly
252
+ if "__override__" in user_value:
253
+ return [v for v in user_value if v != "__override__"]
254
+ defaults = defaults_fn()
255
+ merged = list(defaults)
256
+ for item in user_value:
257
+ if item not in merged:
258
+ merged.append(item)
259
+ return merged
260
+
261
+
224
262
  class BashToolConfig(BaseToolConfig):
225
263
  permission: ToolPermission = ToolPermission.ASK
226
264
  max_output_bytes: int = Field(
@@ -231,17 +269,40 @@ class BashToolConfig(BaseToolConfig):
231
269
  )
232
270
  allowlist: list[str] = Field(
233
271
  default_factory=_get_default_allowlist,
234
- description="Command prefixes that are automatically allowed",
272
+ description=(
273
+ "Command prefixes that are automatically allowed. User entries "
274
+ "are UNIONED with package defaults (new defaults auto-propagate "
275
+ "on pip install -U). Include '__override__' in the list to use "
276
+ "your list verbatim and skip defaults."
277
+ ),
235
278
  )
236
279
  denylist: list[str] = Field(
237
280
  default_factory=_get_default_denylist,
238
- description="Command prefixes that are automatically denied",
281
+ description=(
282
+ "Command prefixes that are automatically denied. User entries "
283
+ "unioned with package defaults; see allowlist for override."
284
+ ),
239
285
  )
240
286
  denylist_standalone: list[str] = Field(
241
287
  default_factory=_get_default_denylist_standalone,
242
288
  description="Commands that are denied only when run without arguments",
243
289
  )
244
290
 
291
+ @field_validator("allowlist", mode="before")
292
+ @classmethod
293
+ def _merge_allowlist(cls, v: Any) -> list[str]:
294
+ return _merge_with_defaults(v, _get_default_allowlist)
295
+
296
+ @field_validator("denylist", mode="before")
297
+ @classmethod
298
+ def _merge_denylist(cls, v: Any) -> list[str]:
299
+ return _merge_with_defaults(v, _get_default_denylist)
300
+
301
+ @field_validator("denylist_standalone", mode="before")
302
+ @classmethod
303
+ def _merge_denylist_standalone(cls, v: Any) -> list[str]:
304
+ return _merge_with_defaults(v, _get_default_denylist_standalone)
305
+
245
306
 
246
307
  class BashArgs(BaseModel):
247
308
  command: str
@@ -388,30 +449,17 @@ class Bash(
388
449
 
389
450
  returncode = proc.returncode or 0
390
451
 
391
- # Mechanical loop-breaker.
392
- # Tier 1 (3rd identical call): collapse body to short notice.
393
- # Tier 2 (5th identical call): raise ToolError. Notice-in-
394
- # tool-result was being ignored 75/75 times by Gemma 4
395
- # (session 20260414_003629 had 99 bash calls, 75 were NOTICE
396
- # re-runs). ToolError goes through the error-handling path
397
- # and the model visibly reacts to those.
452
+ # Mechanical loop-breaker (ADVISORY ONLY — never raise
453
+ # ToolError; see feedback_no_tool_errors_for_loop_detection.md).
454
+ # 3rd+ identical call: collapse body to short notice so the
455
+ # model sees "this ran already with same output" without
456
+ # getting refused into a block-loop.
398
457
  state = self.state.__dict__.setdefault("_bash_history", {})
399
458
  combined = stdout + "\n---STDERR---\n" + stderr
400
459
  out_hash = hash((combined, returncode))
401
460
  entry = state.get(args.command)
402
461
  if entry and entry["hash"] == out_hash:
403
462
  entry["count"] += 1
404
- if entry["count"] >= 5:
405
- raise ToolError(
406
- f"REFUSED: `{args.command[:80]}` has run "
407
- f"{entry['count']} times with IDENTICAL output "
408
- f"(rc={returncode}). Re-running will NOT change "
409
- f"anything. You MUST do something DIFFERENT: "
410
- f"edit source files, write tests, read a DIFFERENT "
411
- f"file, or move on. This exact command is blocked "
412
- f"until you take a different action. Last stdout "
413
- f"(first 300): {stdout[:300]!r}"
414
- )
415
463
  if entry["count"] >= 3:
416
464
  notice = (
417
465
  f"[NOTICE: this is the #{entry['count']} identical "
@@ -92,63 +92,56 @@ class ReadFile(
92
92
  )
93
93
  return
94
94
 
95
+ # mtime-based read dedup (Claude Code tool-contract pattern).
96
+ # If the model reads a file it has already read this session and
97
+ # nothing has changed on disk since, return a compact stub
98
+ # pointing to the earlier tool_result. Saves context + kills the
99
+ # "re-read 50x for no reason" pattern. Also preserves Read-before-
100
+ # Write because the stub still counts as having read the file.
101
+ read_state = ctx.read_file_state if ctx else None
102
+ path_key = str(file_path)
103
+ try:
104
+ current_mtime = file_path.stat().st_mtime_ns
105
+ except OSError:
106
+ current_mtime = 0
107
+ prior = read_state.get(path_key) if read_state is not None else None
108
+ if (
109
+ prior is not None
110
+ and prior.get("timestamp") == current_mtime
111
+ and prior.get("offset") == args.offset
112
+ and prior.get("limit") == args.limit
113
+ ):
114
+ yield ReadFileResult(
115
+ path=path_key,
116
+ content=(
117
+ "<system-reminder>\n"
118
+ f"File unchanged since your earlier read this session "
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,
127
+ )
128
+ return
129
+
95
130
  read_result = await self._read_file(args, file_path)
96
131
  content = "".join(read_result.lines)
97
132
 
98
- # Mechanical loop-breaker: if the model reads the SAME path with
99
- # the SAME (offset, limit) 3+ times in a row and the content
100
- # hasn't changed, replace the body with a compact notice so the
101
- # loop is visible. The model keeps burning context on identical
102
- # reads (confirmed: one session had 52 identical read_file calls
103
- # on lang_interp/lexer.py). This makes the re-read USELESS so it
104
- # stops being attractive.
105
- state = self.state.__dict__.setdefault("_read_history", {})
106
- key = (str(file_path), args.offset, args.limit)
107
- entry = state.get(key)
108
- now_hash = hash(content)
109
- if entry and entry["hash"] == now_hash:
110
- entry["count"] += 1
111
- # Tier 2 (5th identical read): ToolError — notice alone is
112
- # being ignored by Gemma 4. An error forces the model through
113
- # the error-handling path, which it reacts to.
114
- if entry["count"] >= 5:
115
- from drydock.core.tools.base import ToolError as _TE
116
- raise _TE(
117
- f"REFUSED: you have already read {file_path.name} "
118
- f"{entry['count']} times with no file changes in "
119
- f"between. The content is in your context already. "
120
- f"STOP re-reading and DO something: edit the file, "
121
- f"read a DIFFERENT file, or run the code. This read "
122
- f"is refused until a different action happens."
123
- )
124
- if entry["count"] >= 3:
125
- notice = (
126
- f"[NOTICE: this is read_file call #{entry['count']} "
127
- f"for {file_path.name} with no file changes since the "
128
- f"previous reads. The content below is IDENTICAL to "
129
- f"what you already have. STOP re-reading — use the "
130
- f"content from your context. Either edit the file "
131
- f"with search_replace/write_file, or call a different "
132
- f"tool.]\n"
133
- )
134
- # Return only the first 10 lines + the notice, so the
135
- # model isn't spending context on identical body.
136
- short = content.split("\n", 10)
137
- shortened = "\n".join(short[:10])
138
- if len(short) > 10:
139
- shortened += f"\n... [body elided on repeat read #{entry['count']}]"
140
- yield ReadFileResult(
141
- path=str(file_path),
142
- content=notice + shortened,
143
- lines_read=len(read_result.lines),
144
- was_truncated=True,
145
- )
146
- return
147
- else:
148
- state[key] = {"hash": now_hash, "count": 1}
133
+ # Record read state so Write/Edit can enforce Read-before-Write
134
+ # and so future re-reads can dedup against this one.
135
+ if read_state is not None:
136
+ read_state[path_key] = {
137
+ "content": content,
138
+ "timestamp": current_mtime,
139
+ "offset": args.offset,
140
+ "limit": args.limit,
141
+ }
149
142
 
150
143
  yield ReadFileResult(
151
- path=str(file_path),
144
+ path=path_key,
152
145
  content=content,
153
146
  lines_read=len(read_result.lines),
154
147
  was_truncated=read_result.was_truncated,