drydock-cli 0.7.1__tar.gz → 0.7.3__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 (461) hide show
  1. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/PKG-INFO +12 -1
  2. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/PRD.md +14 -0
  3. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/README.md +11 -0
  4. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/textual_ui/app.py +8 -0
  5. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/agent_loop.py +38 -2
  6. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/consultant.py +7 -1
  7. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/prompts/cli.md +1 -1
  8. drydock_cli-0.7.3/drydock/skills/deep-research/SKILL.md +57 -0
  9. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/pyproject.toml +2 -1
  10. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/scripts/deploy_to_github.sh +1 -1
  11. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/scripts/publish_to_pypi.sh +1 -1
  12. drydock_cli-0.7.3/tests/test_real_failures.py +95 -0
  13. drydock_cli-0.7.3/tests/test_real_issues.py +252 -0
  14. drydock_cli-0.7.3/tests/test_user_issues.py +259 -0
  15. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/.github/CODEOWNERS +0 -0
  16. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/.github/DISCUSSION_TEMPLATE/ideas.yml +0 -0
  17. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
  18. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  19. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/.github/workflows/build-and-upload.yml +0 -0
  20. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/.github/workflows/ci.yml +0 -0
  21. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/.github/workflows/issue-labeler.yml +0 -0
  22. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/.github/workflows/release.yml +0 -0
  23. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/.gitignore +0 -0
  24. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/.pre-commit-config.yaml +0 -0
  25. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/.python-version +0 -0
  26. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/.typos.toml +0 -0
  27. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/.vscode/extensions.json +0 -0
  28. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/.vscode/launch.json +0 -0
  29. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/.vscode/settings.json +0 -0
  30. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/AGENTS.md +0 -0
  31. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/CHANGELOG.md +0 -0
  32. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/CLAUDE.md +0 -0
  33. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/CONTRIBUTING.md +0 -0
  34. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/Drydock_rebrand.md +0 -0
  35. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/LICENSE +0 -0
  36. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/NOTICE +0 -0
  37. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/action.yml +0 -0
  38. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/distribution/zed/LICENSE +0 -0
  39. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/distribution/zed/extension.toml +0 -0
  40. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/distribution/zed/icons/mistral_vibe.svg +0 -0
  41. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/docs/README.md +0 -0
  42. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/docs/acp-setup.md +0 -0
  43. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/docs/proxy-setup.md +0 -0
  44. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/__init__.py +0 -0
  45. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/acp/__init__.py +0 -0
  46. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/acp/acp_agent_loop.py +0 -0
  47. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/acp/acp_logger.py +0 -0
  48. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/acp/entrypoint.py +0 -0
  49. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/acp/tools/__init__.py +0 -0
  50. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/acp/tools/base.py +0 -0
  51. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/acp/tools/builtins/bash.py +0 -0
  52. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/acp/tools/builtins/read_file.py +0 -0
  53. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/acp/tools/builtins/search_replace.py +0 -0
  54. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/acp/tools/builtins/todo.py +0 -0
  55. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/acp/tools/builtins/write_file.py +0 -0
  56. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/acp/tools/session_update.py +0 -0
  57. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/acp/utils.py +0 -0
  58. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/__init__.py +0 -0
  59. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/autocompletion/__init__.py +0 -0
  60. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/autocompletion/base.py +0 -0
  61. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/autocompletion/path_completion.py +0 -0
  62. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/autocompletion/slash_command.py +0 -0
  63. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/cli.py +0 -0
  64. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/clipboard.py +0 -0
  65. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/commands.py +0 -0
  66. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/entrypoint.py +0 -0
  67. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/history_manager.py +0 -0
  68. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/plan_offer/adapters/http_whoami_gateway.py +0 -0
  69. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/plan_offer/decide_plan_offer.py +0 -0
  70. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/plan_offer/ports/whoami_gateway.py +0 -0
  71. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/terminal_setup.py +0 -0
  72. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/textual_ui/__init__.py +0 -0
  73. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/textual_ui/ansi_markdown.py +0 -0
  74. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/textual_ui/app.tcss +0 -0
  75. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/textual_ui/external_editor.py +0 -0
  76. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/textual_ui/handlers/__init__.py +0 -0
  77. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/textual_ui/handlers/event_handler.py +0 -0
  78. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/textual_ui/notifications/__init__.py +0 -0
  79. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/textual_ui/notifications/adapters/__init__.py +0 -0
  80. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/textual_ui/notifications/adapters/textual_notification_adapter.py +0 -0
  81. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/textual_ui/notifications/ports/__init__.py +0 -0
  82. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/textual_ui/notifications/ports/notification_port.py +0 -0
  83. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/textual_ui/widgets/__init__.py +0 -0
  84. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/textual_ui/widgets/approval_app.py +0 -0
  85. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/textual_ui/widgets/banner/banner.py +0 -0
  86. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/textual_ui/widgets/banner/petit_chat.py +0 -0
  87. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/textual_ui/widgets/braille_renderer.py +0 -0
  88. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/textual_ui/widgets/chat_input/__init__.py +0 -0
  89. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/textual_ui/widgets/chat_input/body.py +0 -0
  90. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/textual_ui/widgets/chat_input/completion_manager.py +0 -0
  91. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/textual_ui/widgets/chat_input/completion_popup.py +0 -0
  92. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/textual_ui/widgets/chat_input/container.py +0 -0
  93. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/textual_ui/widgets/chat_input/text_area.py +0 -0
  94. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/textual_ui/widgets/compact.py +0 -0
  95. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/textual_ui/widgets/config_app.py +0 -0
  96. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/textual_ui/widgets/context_progress.py +0 -0
  97. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/textual_ui/widgets/load_more.py +0 -0
  98. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/textual_ui/widgets/loading.py +0 -0
  99. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/textual_ui/widgets/messages.py +0 -0
  100. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/textual_ui/widgets/no_markup_static.py +0 -0
  101. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/textual_ui/widgets/path_display.py +0 -0
  102. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/textual_ui/widgets/proxy_setup_app.py +0 -0
  103. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/textual_ui/widgets/question_app.py +0 -0
  104. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/textual_ui/widgets/session_picker.py +0 -0
  105. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/textual_ui/widgets/spinner.py +0 -0
  106. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/textual_ui/widgets/status_message.py +0 -0
  107. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/textual_ui/widgets/teleport_message.py +0 -0
  108. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/textual_ui/widgets/tool_widgets.py +0 -0
  109. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/textual_ui/widgets/tools.py +0 -0
  110. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/textual_ui/widgets/vscode_compat.py +0 -0
  111. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/textual_ui/windowing/__init__.py +0 -0
  112. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/textual_ui/windowing/history.py +0 -0
  113. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/textual_ui/windowing/history_windowing.py +0 -0
  114. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/textual_ui/windowing/state.py +0 -0
  115. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/update_notifier/__init__.py +0 -0
  116. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/update_notifier/adapters/filesystem_update_cache_repository.py +0 -0
  117. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/update_notifier/adapters/github_update_gateway.py +0 -0
  118. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/update_notifier/adapters/pypi_update_gateway.py +0 -0
  119. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/update_notifier/ports/update_cache_repository.py +0 -0
  120. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/update_notifier/ports/update_gateway.py +0 -0
  121. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/update_notifier/update.py +0 -0
  122. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/cli/update_notifier/whats_new.py +0 -0
  123. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/__init__.py +0 -0
  124. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/agents/__init__.py +0 -0
  125. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/agents/manager.py +0 -0
  126. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/agents/models.py +0 -0
  127. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/auth/__init__.py +0 -0
  128. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/auth/crypto.py +0 -0
  129. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/auth/github.py +0 -0
  130. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/autocompletion/__init__.py +0 -0
  131. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/autocompletion/completers.py +0 -0
  132. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/autocompletion/file_indexer/__init__.py +0 -0
  133. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/autocompletion/file_indexer/ignore_rules.py +0 -0
  134. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/autocompletion/file_indexer/indexer.py +0 -0
  135. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/autocompletion/file_indexer/store.py +0 -0
  136. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/autocompletion/file_indexer/watcher.py +0 -0
  137. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/autocompletion/fuzzy.py +0 -0
  138. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/autocompletion/path_prompt.py +0 -0
  139. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/autocompletion/path_prompt_adapter.py +0 -0
  140. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/config/__init__.py +0 -0
  141. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/config/_settings.py +0 -0
  142. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/config/harness_files/__init__.py +0 -0
  143. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/config/harness_files/_harness_manager.py +0 -0
  144. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/config/harness_files/_paths.py +0 -0
  145. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/drydock_states.py +0 -0
  146. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/llm/__init__.py +0 -0
  147. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/llm/backend/anthropic.py +0 -0
  148. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/llm/backend/base.py +0 -0
  149. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/llm/backend/factory.py +0 -0
  150. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/llm/backend/generic.py +0 -0
  151. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/llm/backend/mistral.py +0 -0
  152. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/llm/backend/reasoning_adapter.py +0 -0
  153. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/llm/backend/vertex.py +0 -0
  154. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/llm/exceptions.py +0 -0
  155. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/llm/format.py +0 -0
  156. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/llm/message_utils.py +0 -0
  157. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/llm/types.py +0 -0
  158. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/logger.py +0 -0
  159. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/middleware.py +0 -0
  160. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/output_formatters.py +0 -0
  161. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/paths/__init__.py +0 -0
  162. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/paths/_local_config_walk.py +0 -0
  163. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/paths/_vibe_home.py +0 -0
  164. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/paths/conventions.py +0 -0
  165. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/plan_session.py +0 -0
  166. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/programmatic.py +0 -0
  167. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/prompts/__init__.py +0 -0
  168. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/prompts/compact.md +0 -0
  169. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/prompts/dangerous_directory.md +0 -0
  170. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/prompts/diagnostic.md +0 -0
  171. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/prompts/explore.md +0 -0
  172. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/prompts/planner.md +0 -0
  173. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/prompts/project_context.md +0 -0
  174. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/prompts/tests.md +0 -0
  175. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/proxy_setup.py +0 -0
  176. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/session/session_loader.py +0 -0
  177. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/session/session_logger.py +0 -0
  178. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/session/session_migration.py +0 -0
  179. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/session/state_file.py +0 -0
  180. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/skills/__init__.py +0 -0
  181. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/skills/manager.py +0 -0
  182. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/skills/models.py +0 -0
  183. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/skills/parser.py +0 -0
  184. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/slug.py +0 -0
  185. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/system_prompt.py +0 -0
  186. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/telemetry/__init__.py +0 -0
  187. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/telemetry/send.py +0 -0
  188. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/teleport/errors.py +0 -0
  189. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/teleport/git.py +0 -0
  190. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/teleport/nuage.py +0 -0
  191. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/teleport/teleport.py +0 -0
  192. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/teleport/types.py +0 -0
  193. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/tools/base.py +0 -0
  194. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/tools/builtins/ask_user_question.py +0 -0
  195. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/tools/builtins/bash.py +0 -0
  196. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/tools/builtins/exit_plan_mode.py +0 -0
  197. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/tools/builtins/grep.py +0 -0
  198. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/tools/builtins/prompts/__init__.py +0 -0
  199. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/tools/builtins/prompts/ask_user_question.md +0 -0
  200. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/tools/builtins/prompts/bash.md +0 -0
  201. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/tools/builtins/prompts/grep.md +0 -0
  202. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/tools/builtins/prompts/read_file.md +0 -0
  203. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/tools/builtins/prompts/search_replace.md +0 -0
  204. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/tools/builtins/prompts/swe_bench.md +0 -0
  205. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/tools/builtins/prompts/task.md +0 -0
  206. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/tools/builtins/prompts/todo.md +0 -0
  207. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/tools/builtins/prompts/webfetch.md +0 -0
  208. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/tools/builtins/prompts/websearch.md +0 -0
  209. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/tools/builtins/prompts/write_file.md +0 -0
  210. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/tools/builtins/read_file.py +0 -0
  211. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/tools/builtins/search_replace.py +0 -0
  212. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/tools/builtins/task.py +0 -0
  213. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/tools/builtins/todo.py +0 -0
  214. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/tools/builtins/webfetch.py +0 -0
  215. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/tools/builtins/websearch.py +0 -0
  216. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/tools/builtins/write_file.py +0 -0
  217. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/tools/injection_guard.py +0 -0
  218. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/tools/manager.py +0 -0
  219. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/tools/mcp/__init__.py +0 -0
  220. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/tools/mcp/registry.py +0 -0
  221. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/tools/mcp/tools.py +0 -0
  222. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/tools/mcp_sampling.py +0 -0
  223. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/tools/ui.py +0 -0
  224. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/tools/utils.py +0 -0
  225. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/trusted_folders.py +0 -0
  226. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/types.py +0 -0
  227. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/core/utils.py +0 -0
  228. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/setup/onboarding/__init__.py +0 -0
  229. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/setup/onboarding/base.py +0 -0
  230. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/setup/onboarding/onboarding.tcss +0 -0
  231. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/setup/onboarding/screens/__init__.py +0 -0
  232. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/setup/onboarding/screens/api_key.py +0 -0
  233. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/setup/onboarding/screens/welcome.py +0 -0
  234. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/setup/trusted_folders/trust_folder_dialog.py +0 -0
  235. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/setup/trusted_folders/trust_folder_dialog.tcss +0 -0
  236. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/skills/__init__.py +0 -0
  237. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/skills/create-presentation/SKILL.md +0 -0
  238. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock/whats_new.md +0 -0
  239. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock-acp.spec +0 -0
  240. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/drydock_terms.md +0 -0
  241. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/flake.lock +0 -0
  242. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/flake.nix +0 -0
  243. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/scripts/README.md +0 -0
  244. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/scripts/bump_version.py +0 -0
  245. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/scripts/install.sh +0 -0
  246. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/scripts/prepare_release.py +0 -0
  247. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/__init__.py +0 -0
  248. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/acp/conftest.py +0 -0
  249. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/acp/test_acp.py +0 -0
  250. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/acp/test_agent_thought.py +0 -0
  251. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/acp/test_bash.py +0 -0
  252. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/acp/test_compact_session_updates.py +0 -0
  253. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/acp/test_content.py +0 -0
  254. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/acp/test_initialize.py +0 -0
  255. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/acp/test_list_sessions.py +0 -0
  256. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/acp/test_load_session.py +0 -0
  257. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/acp/test_multi_session.py +0 -0
  258. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/acp/test_new_session.py +0 -0
  259. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/acp/test_proxy_setup_acp.py +0 -0
  260. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/acp/test_read_file.py +0 -0
  261. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/acp/test_search_replace.py +0 -0
  262. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/acp/test_set_config_option.py +0 -0
  263. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/acp/test_set_mode.py +0 -0
  264. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/acp/test_set_model.py +0 -0
  265. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/acp/test_tool_call_session_update.py +0 -0
  266. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/acp/test_utils.py +0 -0
  267. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/acp/test_write_file.py +0 -0
  268. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/autocompletion/test_file_indexer.py +0 -0
  269. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/autocompletion/test_fuzzy.py +0 -0
  270. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/autocompletion/test_path_completer_fuzzy.py +0 -0
  271. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/autocompletion/test_path_completer_recursive.py +0 -0
  272. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/autocompletion/test_path_completion_controller.py +0 -0
  273. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/autocompletion/test_path_prompt_transformer.py +0 -0
  274. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/autocompletion/test_slash_command_controller.py +0 -0
  275. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/autocompletion/test_ui_chat_autocompletion.py +0 -0
  276. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/backend/__init__.py +0 -0
  277. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/backend/data/__init__.py +0 -0
  278. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/backend/data/fireworks.py +0 -0
  279. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/backend/data/mistral.py +0 -0
  280. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/backend/test_anthropic_adapter.py +0 -0
  281. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/backend/test_backend.py +0 -0
  282. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/backend/test_reasoning_adapter.py +0 -0
  283. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/backend/test_vertex_anthropic_adapter.py +0 -0
  284. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/cli/plan_offer/adapters/fake_whoami_gateway.py +0 -0
  285. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/cli/plan_offer/test_decide_plan_offer.py +0 -0
  286. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/cli/plan_offer/test_http_whoami_gateway.py +0 -0
  287. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/cli/test_bell_notifications.py +0 -0
  288. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/cli/test_braille_renderer.py +0 -0
  289. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/cli/test_clipboard.py +0 -0
  290. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/cli/test_commands.py +0 -0
  291. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/cli/test_copy_shortcuts.py +0 -0
  292. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/cli/test_external_editor.py +0 -0
  293. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/cli/test_no_markup_static.py +0 -0
  294. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/cli/test_question_app.py +0 -0
  295. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/cli/test_spinner.py +0 -0
  296. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/cli/test_switching_mode.py +0 -0
  297. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/cli/test_ui_clipboard_notifications.py +0 -0
  298. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/cli/test_ui_session_incremental_renderer.py +0 -0
  299. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/cli/test_ui_session_resume.py +0 -0
  300. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/cli/test_ui_skill_dispatch.py +0 -0
  301. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/cli/textual_ui/__init__.py +0 -0
  302. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/cli/textual_ui/test_session_picker.py +0 -0
  303. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/conftest.py +0 -0
  304. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/core/test_agents.py +0 -0
  305. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/core/test_auth_crypto.py +0 -0
  306. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/core/test_auth_github.py +0 -0
  307. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/core/test_config_load_dotenv.py +0 -0
  308. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/core/test_config_paths.py +0 -0
  309. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/core/test_config_resolution.py +0 -0
  310. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/core/test_file_logging.py +0 -0
  311. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/core/test_plan_session.py +0 -0
  312. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/core/test_proxy_setup.py +0 -0
  313. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/core/test_slug.py +0 -0
  314. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/core/test_telemetry_send.py +0 -0
  315. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/core/test_teleport_git.py +0 -0
  316. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/core/test_teleport_nuage.py +0 -0
  317. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/core/test_teleport_service.py +0 -0
  318. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/core/test_trusted_folders.py +0 -0
  319. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/core/test_utils.py +0 -0
  320. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/e2e/common.py +0 -0
  321. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/e2e/conftest.py +0 -0
  322. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/e2e/mock_server.py +0 -0
  323. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/e2e/test_cli_tui_onboarding.py +0 -0
  324. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/e2e/test_cli_tui_streaming.py +0 -0
  325. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/e2e/test_cli_tui_tool_approval.py +0 -0
  326. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/mock/__init__.py +0 -0
  327. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/mock/mock_backend_factory.py +0 -0
  328. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/mock/mock_entrypoint.py +0 -0
  329. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/mock/utils.py +0 -0
  330. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/onboarding/test_run_onboarding.py +0 -0
  331. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/onboarding/test_ui_onboarding.py +0 -0
  332. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/session/test_session_loader.py +0 -0
  333. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/session/test_session_logger.py +0 -0
  334. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/session/test_session_migration.py +0 -0
  335. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/skills/conftest.py +0 -0
  336. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/skills/test_manager.py +0 -0
  337. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/skills/test_models.py +0 -0
  338. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/skills/test_parser.py +0 -0
  339. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_ask_user_question/test_snapshot_ask_user_question_collapsed.svg +0 -0
  340. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_ask_user_question/test_snapshot_ask_user_question_expanded.svg +0 -0
  341. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_basic_conversation/test_snapshot_shows_basic_conversation.svg +0 -0
  342. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_code_block_horizontal_scrolling/test_snapshot_allows_horizontal_scrolling_for_long_code_blocks.svg +0 -0
  343. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_empty_assistant_before_reasoning/test_snapshot_empty_assistant_removed_when_reasoning_starts.svg +0 -0
  344. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_cycle_to_accept_edits_mode.svg +0 -0
  345. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_cycle_to_auto_approve_mode.svg +0 -0
  346. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_cycle_to_plan_mode.svg +0 -0
  347. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_cycle_wraps_to_default.svg +0 -0
  348. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_default_mode.svg +0 -0
  349. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_parallel_tool_calls/test_snapshot_parallel_tool_calls_pending.svg +0 -0
  350. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_parallel_tool_calls/test_snapshot_parallel_tool_calls_resolved.svg +0 -0
  351. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_cancel_discards_changes.svg +0 -0
  352. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_edit_existing_values.svg +0 -0
  353. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_initial_empty.svg +0 -0
  354. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_initial_with_values.svg +0 -0
  355. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_save_error.svg +0 -0
  356. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_save_new_values.svg +0 -0
  357. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_answer_first_advance.svg +0 -0
  358. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_first_answered_checkmark.svg +0 -0
  359. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_initial.svg +0 -0
  360. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_navigate_left_wraps.svg +0 -0
  361. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_navigate_right.svg +0 -0
  362. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_tab_to_second.svg +0 -0
  363. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_initial.svg +0 -0
  364. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_mixed_selection.svg +0 -0
  365. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_navigate_to_submit.svg +0 -0
  366. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_other_with_text.svg +0 -0
  367. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_toggle_first.svg +0 -0
  368. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_toggle_multiple.svg +0 -0
  369. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_untoggle.svg +0 -0
  370. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_initial.svg +0 -0
  371. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_navigate_down.svg +0 -0
  372. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_navigate_to_other.svg +0 -0
  373. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_navigate_to_third_option.svg +0 -0
  374. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_navigate_up_wraps.svg +0 -0
  375. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_other_typing.svg +0 -0
  376. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_reasoning_content/test_snapshot_buffered_reasoning_yields_before_content.svg +0 -0
  377. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_reasoning_content/test_snapshot_shows_interleaved_reasoning.svg +0 -0
  378. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_reasoning_content/test_snapshot_shows_reasoning_content.svg +0 -0
  379. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_reasoning_content/test_snapshot_shows_reasoning_content_expanded.svg +0 -0
  380. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_release_update_notification/test_snapshot_shows_release_update_notification.svg +0 -0
  381. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_session_resume/test_snapshot_shows_resumed_session_messages.svg +0 -0
  382. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_streaming_tool_call/test_snapshot_tool_call_partial.svg +0 -0
  383. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_streaming_tool_call/test_snapshot_tool_call_updated.svg +0 -0
  384. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_push_confirmation_cancel_selected.svg +0 -0
  385. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_push_confirmation_multiple_commits.svg +0 -0
  386. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_push_confirmation_single_commit.svg +0 -0
  387. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_auth_complete.svg +0 -0
  388. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_auth_required.svg +0 -0
  389. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_checking_git.svg +0 -0
  390. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_complete.svg +0 -0
  391. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_error.svg +0 -0
  392. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_pushing.svg +0 -0
  393. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_sending_token.svg +0 -0
  394. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_starting_workflow.svg +0 -0
  395. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_whats_new/test_snapshot_shows_no_plan_message.svg +0 -0
  396. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_whats_new/test_snapshot_shows_switch_message.svg +0 -0
  397. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_whats_new/test_snapshot_shows_upgrade_message.svg +0 -0
  398. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/__snapshots__/test_ui_snapshot_whats_new/test_snapshot_shows_whats_new_message.svg +0 -0
  399. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/base_snapshot_test_app.py +0 -0
  400. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/conftest.py +0 -0
  401. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/snap_compare.py +0 -0
  402. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/test_ui_snapshot_ask_user_question.py +0 -0
  403. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/test_ui_snapshot_basic_conversation.py +0 -0
  404. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/test_ui_snapshot_code_block_horizontal_scrolling.py +0 -0
  405. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/test_ui_snapshot_empty_assistant_before_reasoning.py +0 -0
  406. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/test_ui_snapshot_modes.py +0 -0
  407. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/test_ui_snapshot_parallel_tool_calls.py +0 -0
  408. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/test_ui_snapshot_proxy_setup.py +0 -0
  409. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/test_ui_snapshot_question_app.py +0 -0
  410. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/test_ui_snapshot_reasoning_content.py +0 -0
  411. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/test_ui_snapshot_release_update_notification.py +0 -0
  412. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/test_ui_snapshot_session_resume.py +0 -0
  413. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/test_ui_snapshot_streaming_tool_call.py +0 -0
  414. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/test_ui_snapshot_teleport.py +0 -0
  415. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/snapshots/test_ui_snapshot_whats_new.py +0 -0
  416. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/stubs/fake_backend.py +0 -0
  417. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/stubs/fake_client.py +0 -0
  418. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/stubs/fake_tool.py +0 -0
  419. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/test_agent_auto_compact.py +0 -0
  420. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/test_agent_backend.py +0 -0
  421. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/test_agent_observer_streaming.py +0 -0
  422. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/test_agent_stats.py +0 -0
  423. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/test_agent_tasks.py +0 -0
  424. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/test_agent_tool_call.py +0 -0
  425. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/test_agents.py +0 -0
  426. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/test_cli_programmatic_preload.py +0 -0
  427. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/test_drydock_regression.py +0 -0
  428. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/test_drydock_tasks.py +0 -0
  429. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/test_history_manager.py +0 -0
  430. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/test_integration.py +0 -0
  431. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/test_loop_detection.py +0 -0
  432. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/test_message_id.py +0 -0
  433. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/test_message_merging.py +0 -0
  434. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/test_middleware.py +0 -0
  435. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/test_reasoning_content.py +0 -0
  436. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/test_system_prompt.py +0 -0
  437. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/test_tagged_text.py +0 -0
  438. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/test_ui_external_editor.py +0 -0
  439. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/test_ui_input_history.py +0 -0
  440. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/tools/test_ask_user_question.py +0 -0
  441. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/tools/test_bash.py +0 -0
  442. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/tools/test_exit_plan_mode.py +0 -0
  443. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/tools/test_grep.py +0 -0
  444. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/tools/test_invoke_context.py +0 -0
  445. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/tools/test_manager_get_tool_config.py +0 -0
  446. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/tools/test_mcp.py +0 -0
  447. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/tools/test_mcp_sampling.py +0 -0
  448. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/tools/test_task.py +0 -0
  449. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/tools/test_ui_bash_execution.py +0 -0
  450. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/tools/test_webfetch.py +0 -0
  451. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/tools/test_websearch.py +0 -0
  452. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/update_notifier/adapters/fake_update_cache_repository.py +0 -0
  453. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/update_notifier/adapters/fake_update_gateway.py +0 -0
  454. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/update_notifier/test_do_update.py +0 -0
  455. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/update_notifier/test_filesystem_update_cache_repository.py +0 -0
  456. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/update_notifier/test_github_update_gateway.py +0 -0
  457. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/update_notifier/test_pypi_update_gateway.py +0 -0
  458. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/update_notifier/test_ui_update_notification.py +0 -0
  459. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/update_notifier/test_update_use_case.py +0 -0
  460. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/tests/update_notifier/test_whats_new.py +0 -0
  461. {drydock_cli-0.7.1 → drydock_cli-0.7.3}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: drydock-cli
3
- Version: 0.7.1
3
+ Version: 0.7.3
4
4
  Summary: Drydock — nautical CLI coding agent
5
5
  Project-URL: Homepage, https://github.com/fbobe321/drydock
6
6
  Project-URL: Repository, https://github.com/fbobe321/drydock
@@ -168,6 +168,17 @@ export MISTRAL_API_KEY="your_key" # Or set env var
168
168
 
169
169
  Keys are saved to `~/.drydock/.env`.
170
170
 
171
+ ### Consultant Model
172
+
173
+ Set a smarter model for the `/consult` command:
174
+
175
+ ```toml
176
+ # In ~/.drydock/config.toml
177
+ consultant_model = "gemini-2.5-pro"
178
+ ```
179
+
180
+ The consultant provides read-only advice — it never calls tools. Use `/consult <question>` to ask it. The response appears in your conversation so the local model can see it.
181
+
171
182
  ### Custom Agents
172
183
 
173
184
  Create agent configs in `~/.drydock/agents/`:
@@ -178,3 +178,17 @@ Show the user what the agent has planned in its execution pipeline.
178
178
 
179
179
  ### P4: Support more LLM backends
180
180
  Test with Claude, GPT-4, Gemini to understand which improvements are model-specific.
181
+
182
+ ### Phase 7: Real Test-Driven Fixes (Mar 26)
183
+
184
+ Shifted to test-driven development with real vLLM backend — no more mocks for critical bugs.
185
+
186
+ | Issue | Test Result (before fix) | Fix | Test Result (after fix) |
187
+ |-------|------------------------|-----|----------------------|
188
+ | Circuit breaker fires but model keeps calling | FAILED: 20 bash calls, 17 breaker fires ignored | Force-stop conversation after 3 consecutive breaker fires + break tool loop | PASSED: stops within 3 calls |
189
+
190
+ **Testing methodology changed:**
191
+ - All critical tests run against real vLLM at localhost:8000
192
+ - Tests must FAIL first (proving the bug exists)
193
+ - Then fix code, re-run until PASS
194
+ - 166 total tests (155 mock + 11 real backend)
@@ -114,6 +114,17 @@ export MISTRAL_API_KEY="your_key" # Or set env var
114
114
 
115
115
  Keys are saved to `~/.drydock/.env`.
116
116
 
117
+ ### Consultant Model
118
+
119
+ Set a smarter model for the `/consult` command:
120
+
121
+ ```toml
122
+ # In ~/.drydock/config.toml
123
+ consultant_model = "gemini-2.5-pro"
124
+ ```
125
+
126
+ The consultant provides read-only advice — it never calls tools. Use `/consult <question>` to ask it. The response appears in your conversation so the local model can see it.
127
+
117
128
  ### Custom Agents
118
129
 
119
130
  Create agent configs in `~/.drydock/agents/`:
@@ -977,10 +977,18 @@ class VibeApp(App): # noqa: PLR0904
977
977
 
978
978
  try:
979
979
  from drydock.core.consultant import ask_consultant
980
+ # Build conversation history for context
981
+ history_lines = []
982
+ for msg in self.agent_loop.messages[-10:]: # Last 10 messages
983
+ if msg.role.value in ("user", "assistant") and msg.content:
984
+ history_lines.append(f"[{msg.role.value}]: {msg.content[:200]}")
985
+ conversation_history = "\n".join(history_lines)
986
+
980
987
  advice = await ask_consultant(
981
988
  question,
982
989
  config=self.agent_loop.config,
983
990
  model=consultant_model,
991
+ conversation_history=conversation_history,
984
992
  )
985
993
 
986
994
  if not advice or advice.startswith("(Consultant unavailable"):
@@ -191,6 +191,7 @@ class AgentLoop:
191
191
  # Circuit breaker: track tool call signatures to prevent exact repeats
192
192
  # Key: hash(tool_name + args), Value: (count, last_result_snippet)
193
193
  self._tool_call_history: dict[str, tuple[int, str]] = {}
194
+ self._consecutive_circuit_breaker_fires: int = 0
194
195
 
195
196
  system_prompt = get_universal_system_prompt(
196
197
  self.tool_manager, self.config, self.skill_manager, self.agent_manager
@@ -512,11 +513,16 @@ class AgentLoop:
512
513
  self.stats.steps += 1
513
514
  user_cancelled = False
514
515
  try:
516
+ force_stopped = False
515
517
  async for event in self._perform_llm_turn():
516
518
  if is_user_cancellation_event(event):
517
519
  user_cancelled = True
520
+ if isinstance(event, AssistantEvent) and event.stopped_by_middleware:
521
+ force_stopped = True
518
522
  yield event
519
523
  await self._save_messages()
524
+ if force_stopped:
525
+ return
520
526
  # Reset API error count on successful turn
521
527
  api_error_count = 0
522
528
  except (RuntimeError, AgentLoopLLMResponseError) as e:
@@ -896,6 +902,29 @@ class AgentLoop:
896
902
  ) -> AsyncGenerator[ToolResultEvent | ToolStreamEvent]:
897
903
  # Circuit breaker: block exact duplicate calls after 2 attempts
898
904
  if blocked := self._circuit_breaker_check(tool_call):
905
+ self._consecutive_circuit_breaker_fires += 1
906
+
907
+ if self._consecutive_circuit_breaker_fires >= 3:
908
+ # Model is ignoring the circuit breaker — force stop
909
+ force_msg = (
910
+ f"FORCED STOP: You ignored the circuit breaker {self._consecutive_circuit_breaker_fires} times. "
911
+ f"The session is being terminated because you keep running the same command. "
912
+ f"You MUST try a completely different approach."
913
+ )
914
+ yield ToolResultEvent(
915
+ tool_name=tool_call.tool_name,
916
+ tool_class=tool_call.tool_class,
917
+ error=force_msg,
918
+ tool_call_id=tool_call.call_id,
919
+ )
920
+ self._handle_tool_response(tool_call, force_msg, "failure")
921
+ # Inject stop signal into messages
922
+ yield AssistantEvent(
923
+ content=f"\n\n[{force_msg}]\n",
924
+ stopped_by_middleware=True,
925
+ )
926
+ return
927
+
899
928
  yield ToolResultEvent(
900
929
  tool_name=tool_call.tool_name,
901
930
  tool_class=tool_call.tool_class,
@@ -904,6 +933,9 @@ class AgentLoop:
904
933
  )
905
934
  self._handle_tool_response(tool_call, blocked, "failure")
906
935
  return
936
+ else:
937
+ # Reset consecutive fires when a non-blocked call happens
938
+ self._consecutive_circuit_breaker_fires = 0
907
939
 
908
940
  try:
909
941
  tool_instance = self.tool_manager.get(tool_call.tool_name)
@@ -1060,10 +1092,14 @@ class AgentLoop:
1060
1092
 
1061
1093
  async def _handle_tool_calls(
1062
1094
  self, resolved: ResolvedMessage
1063
- ) -> AsyncGenerator[ToolCallEvent | ToolResultEvent | ToolStreamEvent]:
1095
+ ) -> AsyncGenerator[ToolCallEvent | ToolResultEvent | ToolStreamEvent | AssistantEvent]:
1064
1096
  async for event in self._emit_failed_tool_events(resolved.failed_calls):
1065
1097
  yield event
1066
1098
  for tool_call in resolved.tool_calls:
1099
+ # Stop processing more tool calls if circuit breaker force-stopped
1100
+ if self._consecutive_circuit_breaker_fires >= 3:
1101
+ break
1102
+
1067
1103
  yield ToolCallEvent(
1068
1104
  tool_name=tool_call.tool_name,
1069
1105
  tool_class=tool_call.tool_class,
@@ -1518,7 +1554,7 @@ class AgentLoop:
1518
1554
 
1519
1555
  last_msg = self.messages[-1]
1520
1556
  if last_msg.role is Role.tool:
1521
- empty_assistant_msg = LLMMessage(role=Role.assistant, content="Understood.")
1557
+ empty_assistant_msg = LLMMessage(role=Role.assistant, content="Continuing...")
1522
1558
  self.messages.append(empty_assistant_msg)
1523
1559
 
1524
1560
  def _reset_session(self) -> None:
@@ -28,6 +28,7 @@ async def ask_consultant(
28
28
  question: str,
29
29
  config: object | None = None,
30
30
  model: str | None = None,
31
+ conversation_history: str = "",
31
32
  ) -> str:
32
33
  """Ask the consultant model a question using DryDock's backend.
33
34
 
@@ -52,10 +53,15 @@ async def ask_consultant(
52
53
  if not model_name:
53
54
  return ""
54
55
 
56
+ history_section = ""
57
+ if conversation_history:
58
+ history_section = f"\nCONVERSATION CONTEXT (recent messages):\n{conversation_history[:3000]}\n"
59
+
55
60
  prompt = (
56
61
  "You are a senior software engineering consultant. An AI coding agent is "
57
62
  "asking for your advice. Give concise, actionable guidance. Do NOT provide "
58
- "code unless specifically asked — just say WHAT to do and WHERE to look.\n\n"
63
+ "code unless specifically asked — just say WHAT to do and WHERE to look.\n"
64
+ f"{history_section}\n"
59
65
  f"QUESTION:\n{question}"
60
66
  )
61
67
 
@@ -1,4 +1,4 @@
1
- You are Drydock, a CLI coding agent. You interact with a local codebase through tools. You have no internet access.
1
+ You are DryDock, a CLI coding agent. You interact with a local codebase through tools. You have no internet access.
2
2
  CRITICAL: Users complain you are too verbose. Your responses must be minimal. Most tasks need <100 words. Code speaks for itself.
3
3
 
4
4
  Skills are markdown files in your skill directories, NOT tools or agents. To use a skill:
@@ -0,0 +1,57 @@
1
+ ---
2
+ name: deep-research
3
+ description: Deep research a topic using web search, code exploration, and multi-step analysis. Produces a structured report.
4
+ user-invocable: true
5
+ allowed-tools:
6
+ - bash
7
+ - grep
8
+ - read_file
9
+ - webfetch
10
+ - websearch
11
+ - write_file
12
+ ---
13
+
14
+ # Deep Research
15
+
16
+ Conduct thorough research on a topic and produce a structured report.
17
+
18
+ ## Workflow
19
+
20
+ 1. **Clarify scope**: What exactly needs to be researched? Ask if unclear.
21
+ 2. **Web search**: Use `websearch` for current information, articles, docs.
22
+ 3. **Code exploration**: Use `grep` and `read_file` to find relevant code patterns.
23
+ 4. **Cross-reference**: Compare web findings with codebase reality.
24
+ 5. **Write report**: Produce a structured markdown report with findings.
25
+
26
+ ## Report Template
27
+
28
+ Write the report to `research_report.md`:
29
+
30
+ ```markdown
31
+ # Research: [Topic]
32
+
33
+ ## Summary
34
+ One paragraph overview of findings.
35
+
36
+ ## Key Findings
37
+ - Finding 1 with source
38
+ - Finding 2 with source
39
+ - Finding 3 with source
40
+
41
+ ## Code Analysis
42
+ Relevant code patterns found in the codebase.
43
+
44
+ ## Recommendations
45
+ Actionable next steps based on research.
46
+
47
+ ## Sources
48
+ - [Source 1](url)
49
+ - [Source 2](url)
50
+ ```
51
+
52
+ ## Rules
53
+
54
+ - Always cite sources (URLs for web, file:line for code)
55
+ - If websearch fails (SSL/network), fall back to code-only analysis
56
+ - Keep the report under 500 lines
57
+ - Focus on actionable findings, not background
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "drydock-cli"
3
- version = "0.7.1"
3
+ version = "0.7.3"
4
4
  description = "Drydock — nautical CLI coding agent"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -76,6 +76,7 @@ include = ["drydock/"]
76
76
 
77
77
  [tool.hatch.build.targets.wheel.force-include]
78
78
  "drydock/skills/create-presentation" = "drydock/skills/create-presentation"
79
+ "drydock/skills/deep-research" = "drydock/skills/deep-research"
79
80
 
80
81
 
81
82
  [project.scripts]
@@ -37,7 +37,7 @@ AUTH_URL="https://${GITHUB_TOKEN}@github.com/fbobe321/drydock.git"
37
37
 
38
38
  log "Running regression tests..."
39
39
  cd "$DRYDOCK_SRC"
40
- if ! python3 -m pytest tests/test_drydock_regression.py tests/test_drydock_tasks.py tests/test_loop_detection.py tests/test_agent_tasks.py tests/test_integration.py \
40
+ if ! python3 -m pytest tests/test_drydock_regression.py tests/test_drydock_tasks.py tests/test_loop_detection.py tests/test_agent_tasks.py tests/test_integration.py tests/test_user_issues.py tests/test_real_issues.py \
41
41
  -p no:xdist -p no:cov --override-ini="addopts=" -q 2>&1; then
42
42
  log "TESTS FAILED — deploy aborted. Fix the tests before deploying."
43
43
  exit 1
@@ -25,7 +25,7 @@ PYPI_TOKEN=$(cat "$TOKEN_FILE")
25
25
 
26
26
  # --- Run tests ---
27
27
  log "Running regression tests..."
28
- if ! $PYTHON -m pytest tests/test_drydock_regression.py tests/test_drydock_tasks.py tests/test_loop_detection.py tests/test_agent_tasks.py tests/test_integration.py \
28
+ if ! $PYTHON -m pytest tests/test_drydock_regression.py tests/test_drydock_tasks.py tests/test_loop_detection.py tests/test_agent_tasks.py tests/test_integration.py tests/test_user_issues.py tests/test_real_issues.py \
29
29
  -p no:xdist -p no:cov --override-ini="addopts=" -q 2>&1; then
30
30
  log "TESTS FAILED — publish aborted."
31
31
  exit 1
@@ -0,0 +1,95 @@
1
+ """Tests that FAIL — proving real bugs exist.
2
+
3
+ These tests reproduce actual user-reported failures against the real backend.
4
+ They should FAIL until the underlying code is fixed.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import asyncio
10
+ import os
11
+ from pathlib import Path
12
+
13
+ import httpx
14
+ import pytest
15
+
16
+ from drydock.core.config.harness_files import init_harness_files_manager
17
+
18
+ # Initialize harness before importing agent
19
+ try:
20
+ init_harness_files_manager("user", "project")
21
+ except RuntimeError:
22
+ pass
23
+
24
+ from drydock.core.agent_loop import AgentLoop
25
+ from drydock.core.agents.models import BuiltinAgentName
26
+ from drydock.core.config import Backend, ModelConfig, ProviderConfig, VibeConfig
27
+ from drydock.core.types import (
28
+ AssistantEvent,
29
+ BaseEvent,
30
+ Role,
31
+ ToolCallEvent,
32
+ ToolResultEvent,
33
+ )
34
+
35
+
36
+ def _vllm_ok() -> bool:
37
+ try:
38
+ return httpx.get("http://localhost:8000/v1/models", timeout=3).status_code == 200
39
+ except Exception:
40
+ return False
41
+
42
+ pytestmark = pytest.mark.skipif(not _vllm_ok(), reason="vLLM not running")
43
+
44
+
45
+ def _config(tmp_path: Path) -> VibeConfig:
46
+ return VibeConfig(
47
+ active_model="devstral", auto_approve=True, enable_telemetry=False,
48
+ include_project_context=False, system_prompt_id="tests",
49
+ providers=[ProviderConfig(name="local", api_base="http://localhost:8000/v1", api_key_env_var="", backend=Backend.GENERIC)],
50
+ models=[ModelConfig(name="devstral", provider="local", input_price=0, output_price=0)],
51
+ session_logging={"enabled": False, "save_dir": str(tmp_path / "logs")},
52
+ )
53
+
54
+
55
+ def _agent(tmp_path: Path, max_turns: int = 15) -> AgentLoop:
56
+ return AgentLoop(config=_config(tmp_path), agent_name=BuiltinAgentName.AUTO_APPROVE, max_turns=max_turns)
57
+
58
+
59
+ async def _run(agent, prompt, max_events=100):
60
+ events = []
61
+ async for ev in agent.act(prompt):
62
+ events.append(ev)
63
+ if len(events) >= max_events:
64
+ break
65
+ return events
66
+
67
+
68
+ # ============================================================================
69
+ # ISSUE: Circuit breaker fires but model KEEPS calling the same tool
70
+ # The breaker returns an error, but the model ignores it and calls again.
71
+ # Proven: 20 bash calls despite 17 circuit breaker fires.
72
+ # ============================================================================
73
+
74
+ @pytest.mark.asyncio
75
+ async def test_circuit_breaker_actually_stops_execution(tmp_path):
76
+ """After circuit breaker fires, model should NOT make more than 3 additional
77
+ identical calls. Currently it makes 17+."""
78
+ agent = _agent(tmp_path, max_turns=20)
79
+ events = await _run(agent, "Run the command 'echo hello' ten separate times", max_events=120)
80
+
81
+ tool_calls = [e for e in events if isinstance(e, ToolCallEvent)]
82
+ cb_fires = [e for e in events if isinstance(e, ToolResultEvent)
83
+ and e.error and "CIRCUIT" in str(e.error)]
84
+
85
+ # Circuit breaker should fire
86
+ if not cb_fires:
87
+ pytest.skip("Model didn't repeat — can't test circuit breaker")
88
+
89
+ # After first circuit breaker fire, model should stop within 3 more calls
90
+ first_cb_idx = next(i for i, e in enumerate(events) if isinstance(e, ToolResultEvent) and e.error and "CIRCUIT" in str(e.error))
91
+ calls_after_cb = [e for e in events[first_cb_idx:] if isinstance(e, ToolCallEvent)]
92
+
93
+ assert len(calls_after_cb) <= 3, \
94
+ f"Model made {len(calls_after_cb)} tool calls AFTER circuit breaker fired. " \
95
+ f"It should stop, not keep going. Total: {len(tool_calls)} calls, {len(cb_fires)} breaker fires."
@@ -0,0 +1,252 @@
1
+ """Real backend tests for user-reported issues.
2
+
3
+ Every test hits the ACTUAL vLLM backend at localhost:8000.
4
+ NO mocks, NO fakes — real DryDock execution.
5
+
6
+ Skip if vLLM is not running.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import asyncio
12
+ import os
13
+ from pathlib import Path
14
+
15
+ import httpx
16
+ import pytest
17
+
18
+ from drydock.core.agent_loop import AgentLoop
19
+ from drydock.core.agents.models import BuiltinAgentName
20
+ from drydock.core.config import Backend, ModelConfig, ProviderConfig, VibeConfig
21
+ from drydock.core.types import (
22
+ AssistantEvent,
23
+ BaseEvent,
24
+ Role,
25
+ ToolCallEvent,
26
+ ToolResultEvent,
27
+ )
28
+
29
+
30
+ def _vllm_available() -> bool:
31
+ try:
32
+ return httpx.get("http://localhost:8000/v1/models", timeout=3).status_code == 200
33
+ except Exception:
34
+ return False
35
+
36
+
37
+ pytestmark = pytest.mark.skipif(not _vllm_available(), reason="vLLM not running")
38
+
39
+
40
+ def _config(tmp_path: Path) -> VibeConfig:
41
+ return VibeConfig(
42
+ active_model="devstral",
43
+ auto_approve=True,
44
+ enable_telemetry=False,
45
+ include_project_context=False,
46
+ system_prompt_id="cli",
47
+ providers=[ProviderConfig(
48
+ name="local", api_base="http://localhost:8000/v1",
49
+ api_key_env_var="", backend=Backend.GENERIC,
50
+ )],
51
+ models=[ModelConfig(
52
+ name="devstral", provider="local", alias="devstral",
53
+ input_price=0.0, output_price=0.0,
54
+ )],
55
+ session_logging={"enabled": False, "save_dir": str(tmp_path / "logs")},
56
+ )
57
+
58
+
59
+ def _agent(tmp_path: Path, max_turns: int = 5) -> AgentLoop:
60
+ return AgentLoop(
61
+ config=_config(tmp_path),
62
+ agent_name=BuiltinAgentName.AUTO_APPROVE,
63
+ max_turns=max_turns,
64
+ )
65
+
66
+
67
+ async def _run(agent: AgentLoop, prompt: str, max_events: int = 100) -> list[BaseEvent]:
68
+ events = []
69
+ async for ev in agent.act(prompt):
70
+ events.append(ev)
71
+ if len(events) >= max_events:
72
+ break
73
+ return events
74
+
75
+
76
+ # ============================================================================
77
+ # Test 1: "Understood" after error — agent should NOT stop with "Understood."
78
+ # ============================================================================
79
+
80
+ @pytest.mark.asyncio
81
+ async def test_no_understood_stops_agent(tmp_path):
82
+ """Agent should never inject 'Understood.' into conversation."""
83
+ agent = _agent(tmp_path)
84
+ events = await _run(agent, "Read the file /nonexistent/path/fake.py")
85
+
86
+ # Check messages — none should contain "Understood."
87
+ for msg in agent.messages:
88
+ if msg.role == Role.assistant and msg.content:
89
+ assert "Understood." not in msg.content, \
90
+ f"Found 'Understood.' in assistant message — causes premature stops"
91
+
92
+
93
+ # ============================================================================
94
+ # Test 2: Circuit breaker actually blocks (not just warns)
95
+ # ============================================================================
96
+
97
+ @pytest.mark.asyncio
98
+ async def test_circuit_breaker_blocks_real(tmp_path):
99
+ """After 2 identical tool calls, the 3rd should be blocked with error."""
100
+ agent = _agent(tmp_path, max_turns=10)
101
+ # Ask something that will likely trigger repeated tool calls
102
+ events = await _run(agent, "Run 'echo hello' five times in a row, each as a separate bash command")
103
+
104
+ tool_results = [e for e in events if isinstance(e, ToolResultEvent)]
105
+ # Should have some blocked results if circuit breaker works
106
+ errors = [e for e in tool_results if e.error and "CIRCUIT BREAKER" in str(e.error)]
107
+
108
+ # The model might not repeat exactly, but circuit breaker state should exist
109
+ assert hasattr(agent, "_tool_call_history")
110
+ assert isinstance(agent._tool_call_history, dict)
111
+ # At least verify no AttributeError crash
112
+ for e in tool_results:
113
+ if e.error:
114
+ assert "AttributeError" not in str(e.error), f"Crash: {e.error}"
115
+
116
+
117
+ # ============================================================================
118
+ # Test 3: Tool calls don't crash with AttributeError
119
+ # ============================================================================
120
+
121
+ @pytest.mark.asyncio
122
+ async def test_no_attribute_error_on_tools(tmp_path):
123
+ """No AttributeError should occur during tool execution."""
124
+ agent = _agent(tmp_path)
125
+ events = await _run(agent, "List the files in the current directory")
126
+
127
+ for e in events:
128
+ if isinstance(e, ToolResultEvent) and e.error:
129
+ assert "AttributeError" not in str(e.error), \
130
+ f"AttributeError in tool result: {e.error}"
131
+ assert "raw_arguments" not in str(e.error), \
132
+ f"Old raw_arguments bug: {e.error}"
133
+
134
+
135
+ # ============================================================================
136
+ # Test 4: Agent doesn't loop on ambiguous prompt
137
+ # ============================================================================
138
+
139
+ @pytest.mark.asyncio
140
+ async def test_ambiguous_prompt_limited(tmp_path):
141
+ """Typing 'test' should not cause 20+ tool calls."""
142
+ agent = _agent(tmp_path, max_turns=8)
143
+ events = await _run(agent, "test", max_events=60)
144
+
145
+ tool_calls = [e for e in events if isinstance(e, ToolCallEvent)]
146
+ assert len(tool_calls) < 25, \
147
+ f"Ambiguous prompt 'test' caused {len(tool_calls)} tool calls — too many"
148
+
149
+
150
+ # ============================================================================
151
+ # Test 5: Message ordering clean after real tool calls
152
+ # ============================================================================
153
+
154
+ @pytest.mark.asyncio
155
+ async def test_no_user_after_tool(tmp_path):
156
+ """No user message should follow a tool message in the history."""
157
+ agent = _agent(tmp_path)
158
+ events = await _run(agent, "What Python version is installed? Run python3 --version")
159
+
160
+ for i in range(1, len(agent.messages)):
161
+ if agent.messages[i].role == Role.user and agent.messages[i-1].role == Role.tool:
162
+ pytest.fail(f"user after tool at position {i}: "
163
+ f"'{agent.messages[i].content[:50]}' after tool '{agent.messages[i-1].content[:50]}'")
164
+
165
+
166
+ # ============================================================================
167
+ # Test 6: Agent actually uses tools (not just text responses)
168
+ # ============================================================================
169
+
170
+ @pytest.mark.asyncio
171
+ async def test_agent_uses_tools(tmp_path):
172
+ """Agent should call bash/grep/read_file when asked to do something concrete."""
173
+ agent = _agent(tmp_path)
174
+ events = await _run(agent, "Run: echo 'drydock integration test'")
175
+
176
+ tool_calls = [e for e in events if isinstance(e, ToolCallEvent)]
177
+ # Should have at least one tool call for a concrete command request
178
+ assert len(tool_calls) >= 1, \
179
+ "Agent gave text-only response when asked to run a command"
180
+
181
+
182
+ # ============================================================================
183
+ # Test 7: DryDock branding in system prompt (real check)
184
+ # ============================================================================
185
+
186
+ @pytest.mark.asyncio
187
+ async def test_system_prompt_branding(tmp_path):
188
+ """System prompt should say 'DryDock' not 'Drydock' or 'Vibe'."""
189
+ agent = _agent(tmp_path)
190
+ # Don't even need to run — just check the system prompt
191
+ system_msg = agent.messages[0]
192
+ assert system_msg.role == Role.system
193
+ assert "DryDock" in system_msg.content, "System prompt missing 'DryDock'"
194
+ assert "Vibe" not in system_msg.content or "mistral-vibe" in system_msg.content, \
195
+ "System prompt still references 'Vibe'"
196
+
197
+
198
+ # ============================================================================
199
+ # Test 8: Write file doesn't hang (has timeout)
200
+ # ============================================================================
201
+
202
+ @pytest.mark.asyncio
203
+ async def test_write_file_timeout_exists(tmp_path):
204
+ """write_file should complete within reasonable time, not hang."""
205
+ agent = _agent(tmp_path)
206
+ test_file = tmp_path / "test_write.txt"
207
+
208
+ events = await _run(agent,
209
+ f"Write the text 'hello world' to the file {test_file}")
210
+
211
+ # Should complete (not hang) — if it hangs, the test runner will timeout
212
+ assert len(events) >= 1
213
+ # Check if file was created (model might or might not do it)
214
+ # The important thing is it didn't hang
215
+
216
+
217
+ # ============================================================================
218
+ # Test 9: Agent stops cleanly (not infinite loop)
219
+ # ============================================================================
220
+
221
+ @pytest.mark.asyncio
222
+ async def test_agent_stops_cleanly(tmp_path):
223
+ """Agent should stop after completing a task, not loop forever."""
224
+ agent = _agent(tmp_path, max_turns=5)
225
+ events = await _run(agent, "What is 2+2? Just say the number.", max_events=30)
226
+
227
+ # Should stop within reasonable events
228
+ assert len(events) < 30, f"Agent produced {len(events)} events — possible loop"
229
+
230
+
231
+ # ============================================================================
232
+ # Test 10: Consultant config field exists and works
233
+ # ============================================================================
234
+
235
+ @pytest.mark.asyncio
236
+ async def test_consultant_config_real(tmp_path):
237
+ """VibeConfig should accept consultant_model field without error."""
238
+ config = VibeConfig(
239
+ active_model="devstral",
240
+ consultant_model="gemini-2.5-pro",
241
+ auto_approve=True,
242
+ enable_telemetry=False,
243
+ providers=[ProviderConfig(
244
+ name="local", api_base="http://localhost:8000/v1",
245
+ api_key_env_var="", backend=Backend.GENERIC,
246
+ )],
247
+ models=[ModelConfig(
248
+ name="devstral", provider="local",
249
+ input_price=0.0, output_price=0.0,
250
+ )],
251
+ )
252
+ assert config.consultant_model == "gemini-2.5-pro"