drydock-cli 0.6.1__tar.gz → 0.6.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 (455) hide show
  1. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/PKG-INFO +1 -1
  2. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/commands.py +19 -1
  3. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/textual_ui/app.py +88 -2
  4. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/agent_loop.py +13 -20
  5. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/config/_settings.py +8 -0
  6. drydock_cli-0.6.3/drydock/core/consultant.py +183 -0
  7. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/paths/_vibe_home.py +32 -4
  8. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/pyproject.toml +1 -1
  9. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/test_drydock_tasks.py +5 -5
  10. drydock_cli-0.6.1/drydock/core/consultant.py +0 -141
  11. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/.github/CODEOWNERS +0 -0
  12. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/.github/DISCUSSION_TEMPLATE/ideas.yml +0 -0
  13. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
  14. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  15. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/.github/workflows/build-and-upload.yml +0 -0
  16. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/.github/workflows/ci.yml +0 -0
  17. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/.github/workflows/issue-labeler.yml +0 -0
  18. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/.github/workflows/release.yml +0 -0
  19. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/.gitignore +0 -0
  20. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/.pre-commit-config.yaml +0 -0
  21. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/.python-version +0 -0
  22. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/.typos.toml +0 -0
  23. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/.vscode/extensions.json +0 -0
  24. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/.vscode/launch.json +0 -0
  25. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/.vscode/settings.json +0 -0
  26. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/AGENTS.md +0 -0
  27. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/CHANGELOG.md +0 -0
  28. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/CLAUDE.md +0 -0
  29. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/CONTRIBUTING.md +0 -0
  30. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/Drydock_rebrand.md +0 -0
  31. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/LICENSE +0 -0
  32. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/NOTICE +0 -0
  33. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/PRD.md +0 -0
  34. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/README.md +0 -0
  35. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/action.yml +0 -0
  36. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/distribution/zed/LICENSE +0 -0
  37. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/distribution/zed/extension.toml +0 -0
  38. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/distribution/zed/icons/mistral_vibe.svg +0 -0
  39. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/docs/README.md +0 -0
  40. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/docs/acp-setup.md +0 -0
  41. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/docs/proxy-setup.md +0 -0
  42. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/__init__.py +0 -0
  43. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/acp/__init__.py +0 -0
  44. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/acp/acp_agent_loop.py +0 -0
  45. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/acp/acp_logger.py +0 -0
  46. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/acp/entrypoint.py +0 -0
  47. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/acp/tools/__init__.py +0 -0
  48. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/acp/tools/base.py +0 -0
  49. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/acp/tools/builtins/bash.py +0 -0
  50. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/acp/tools/builtins/read_file.py +0 -0
  51. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/acp/tools/builtins/search_replace.py +0 -0
  52. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/acp/tools/builtins/todo.py +0 -0
  53. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/acp/tools/builtins/write_file.py +0 -0
  54. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/acp/tools/session_update.py +0 -0
  55. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/acp/utils.py +0 -0
  56. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/__init__.py +0 -0
  57. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/autocompletion/__init__.py +0 -0
  58. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/autocompletion/base.py +0 -0
  59. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/autocompletion/path_completion.py +0 -0
  60. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/autocompletion/slash_command.py +0 -0
  61. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/cli.py +0 -0
  62. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/clipboard.py +0 -0
  63. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/entrypoint.py +0 -0
  64. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/history_manager.py +0 -0
  65. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/plan_offer/adapters/http_whoami_gateway.py +0 -0
  66. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/plan_offer/decide_plan_offer.py +0 -0
  67. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/plan_offer/ports/whoami_gateway.py +0 -0
  68. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/terminal_setup.py +0 -0
  69. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/textual_ui/__init__.py +0 -0
  70. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/textual_ui/ansi_markdown.py +0 -0
  71. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/textual_ui/app.tcss +0 -0
  72. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/textual_ui/external_editor.py +0 -0
  73. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/textual_ui/handlers/__init__.py +0 -0
  74. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/textual_ui/handlers/event_handler.py +0 -0
  75. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/textual_ui/notifications/__init__.py +0 -0
  76. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/textual_ui/notifications/adapters/__init__.py +0 -0
  77. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/textual_ui/notifications/adapters/textual_notification_adapter.py +0 -0
  78. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/textual_ui/notifications/ports/__init__.py +0 -0
  79. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/textual_ui/notifications/ports/notification_port.py +0 -0
  80. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/textual_ui/widgets/__init__.py +0 -0
  81. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/textual_ui/widgets/approval_app.py +0 -0
  82. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/textual_ui/widgets/banner/banner.py +0 -0
  83. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/textual_ui/widgets/banner/petit_chat.py +0 -0
  84. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/textual_ui/widgets/braille_renderer.py +0 -0
  85. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/textual_ui/widgets/chat_input/__init__.py +0 -0
  86. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/textual_ui/widgets/chat_input/body.py +0 -0
  87. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/textual_ui/widgets/chat_input/completion_manager.py +0 -0
  88. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/textual_ui/widgets/chat_input/completion_popup.py +0 -0
  89. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/textual_ui/widgets/chat_input/container.py +0 -0
  90. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/textual_ui/widgets/chat_input/text_area.py +0 -0
  91. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/textual_ui/widgets/compact.py +0 -0
  92. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/textual_ui/widgets/config_app.py +0 -0
  93. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/textual_ui/widgets/context_progress.py +0 -0
  94. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/textual_ui/widgets/load_more.py +0 -0
  95. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/textual_ui/widgets/loading.py +0 -0
  96. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/textual_ui/widgets/messages.py +0 -0
  97. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/textual_ui/widgets/no_markup_static.py +0 -0
  98. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/textual_ui/widgets/path_display.py +0 -0
  99. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/textual_ui/widgets/proxy_setup_app.py +0 -0
  100. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/textual_ui/widgets/question_app.py +0 -0
  101. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/textual_ui/widgets/session_picker.py +0 -0
  102. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/textual_ui/widgets/spinner.py +0 -0
  103. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/textual_ui/widgets/status_message.py +0 -0
  104. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/textual_ui/widgets/teleport_message.py +0 -0
  105. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/textual_ui/widgets/tool_widgets.py +0 -0
  106. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/textual_ui/widgets/tools.py +0 -0
  107. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/textual_ui/widgets/vscode_compat.py +0 -0
  108. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/textual_ui/windowing/__init__.py +0 -0
  109. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/textual_ui/windowing/history.py +0 -0
  110. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/textual_ui/windowing/history_windowing.py +0 -0
  111. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/textual_ui/windowing/state.py +0 -0
  112. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/update_notifier/__init__.py +0 -0
  113. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/update_notifier/adapters/filesystem_update_cache_repository.py +0 -0
  114. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/update_notifier/adapters/github_update_gateway.py +0 -0
  115. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/update_notifier/adapters/pypi_update_gateway.py +0 -0
  116. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/update_notifier/ports/update_cache_repository.py +0 -0
  117. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/update_notifier/ports/update_gateway.py +0 -0
  118. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/update_notifier/update.py +0 -0
  119. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/cli/update_notifier/whats_new.py +0 -0
  120. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/__init__.py +0 -0
  121. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/agents/__init__.py +0 -0
  122. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/agents/manager.py +0 -0
  123. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/agents/models.py +0 -0
  124. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/auth/__init__.py +0 -0
  125. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/auth/crypto.py +0 -0
  126. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/auth/github.py +0 -0
  127. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/autocompletion/__init__.py +0 -0
  128. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/autocompletion/completers.py +0 -0
  129. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/autocompletion/file_indexer/__init__.py +0 -0
  130. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/autocompletion/file_indexer/ignore_rules.py +0 -0
  131. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/autocompletion/file_indexer/indexer.py +0 -0
  132. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/autocompletion/file_indexer/store.py +0 -0
  133. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/autocompletion/file_indexer/watcher.py +0 -0
  134. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/autocompletion/fuzzy.py +0 -0
  135. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/autocompletion/path_prompt.py +0 -0
  136. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/autocompletion/path_prompt_adapter.py +0 -0
  137. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/config/__init__.py +0 -0
  138. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/config/harness_files/__init__.py +0 -0
  139. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/config/harness_files/_harness_manager.py +0 -0
  140. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/config/harness_files/_paths.py +0 -0
  141. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/drydock_states.py +0 -0
  142. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/llm/__init__.py +0 -0
  143. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/llm/backend/anthropic.py +0 -0
  144. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/llm/backend/base.py +0 -0
  145. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/llm/backend/factory.py +0 -0
  146. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/llm/backend/generic.py +0 -0
  147. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/llm/backend/mistral.py +0 -0
  148. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/llm/backend/reasoning_adapter.py +0 -0
  149. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/llm/backend/vertex.py +0 -0
  150. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/llm/exceptions.py +0 -0
  151. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/llm/format.py +0 -0
  152. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/llm/message_utils.py +0 -0
  153. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/llm/types.py +0 -0
  154. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/logger.py +0 -0
  155. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/middleware.py +0 -0
  156. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/output_formatters.py +0 -0
  157. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/paths/__init__.py +0 -0
  158. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/paths/_local_config_walk.py +0 -0
  159. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/paths/conventions.py +0 -0
  160. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/plan_session.py +0 -0
  161. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/programmatic.py +0 -0
  162. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/prompts/__init__.py +0 -0
  163. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/prompts/cli.md +0 -0
  164. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/prompts/compact.md +0 -0
  165. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/prompts/dangerous_directory.md +0 -0
  166. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/prompts/diagnostic.md +0 -0
  167. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/prompts/explore.md +0 -0
  168. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/prompts/planner.md +0 -0
  169. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/prompts/project_context.md +0 -0
  170. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/prompts/tests.md +0 -0
  171. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/proxy_setup.py +0 -0
  172. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/session/session_loader.py +0 -0
  173. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/session/session_logger.py +0 -0
  174. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/session/session_migration.py +0 -0
  175. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/session/state_file.py +0 -0
  176. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/skills/__init__.py +0 -0
  177. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/skills/manager.py +0 -0
  178. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/skills/models.py +0 -0
  179. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/skills/parser.py +0 -0
  180. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/slug.py +0 -0
  181. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/system_prompt.py +0 -0
  182. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/telemetry/__init__.py +0 -0
  183. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/telemetry/send.py +0 -0
  184. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/teleport/errors.py +0 -0
  185. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/teleport/git.py +0 -0
  186. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/teleport/nuage.py +0 -0
  187. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/teleport/teleport.py +0 -0
  188. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/teleport/types.py +0 -0
  189. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/tools/base.py +0 -0
  190. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/tools/builtins/ask_user_question.py +0 -0
  191. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/tools/builtins/bash.py +0 -0
  192. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/tools/builtins/exit_plan_mode.py +0 -0
  193. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/tools/builtins/grep.py +0 -0
  194. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/tools/builtins/prompts/__init__.py +0 -0
  195. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/tools/builtins/prompts/ask_user_question.md +0 -0
  196. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/tools/builtins/prompts/bash.md +0 -0
  197. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/tools/builtins/prompts/grep.md +0 -0
  198. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/tools/builtins/prompts/read_file.md +0 -0
  199. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/tools/builtins/prompts/search_replace.md +0 -0
  200. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/tools/builtins/prompts/swe_bench.md +0 -0
  201. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/tools/builtins/prompts/task.md +0 -0
  202. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/tools/builtins/prompts/todo.md +0 -0
  203. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/tools/builtins/prompts/webfetch.md +0 -0
  204. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/tools/builtins/prompts/websearch.md +0 -0
  205. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/tools/builtins/prompts/write_file.md +0 -0
  206. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/tools/builtins/read_file.py +0 -0
  207. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/tools/builtins/search_replace.py +0 -0
  208. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/tools/builtins/task.py +0 -0
  209. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/tools/builtins/todo.py +0 -0
  210. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/tools/builtins/webfetch.py +0 -0
  211. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/tools/builtins/websearch.py +0 -0
  212. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/tools/builtins/write_file.py +0 -0
  213. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/tools/injection_guard.py +0 -0
  214. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/tools/manager.py +0 -0
  215. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/tools/mcp/__init__.py +0 -0
  216. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/tools/mcp/registry.py +0 -0
  217. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/tools/mcp/tools.py +0 -0
  218. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/tools/mcp_sampling.py +0 -0
  219. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/tools/ui.py +0 -0
  220. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/tools/utils.py +0 -0
  221. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/trusted_folders.py +0 -0
  222. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/types.py +0 -0
  223. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/core/utils.py +0 -0
  224. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/setup/onboarding/__init__.py +0 -0
  225. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/setup/onboarding/base.py +0 -0
  226. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/setup/onboarding/onboarding.tcss +0 -0
  227. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/setup/onboarding/screens/__init__.py +0 -0
  228. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/setup/onboarding/screens/api_key.py +0 -0
  229. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/setup/onboarding/screens/welcome.py +0 -0
  230. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/setup/trusted_folders/trust_folder_dialog.py +0 -0
  231. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/setup/trusted_folders/trust_folder_dialog.tcss +0 -0
  232. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/skills/__init__.py +0 -0
  233. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/skills/create-presentation/SKILL.md +0 -0
  234. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock/whats_new.md +0 -0
  235. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock-acp.spec +0 -0
  236. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/drydock_terms.md +0 -0
  237. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/flake.lock +0 -0
  238. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/flake.nix +0 -0
  239. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/scripts/README.md +0 -0
  240. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/scripts/bump_version.py +0 -0
  241. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/scripts/deploy_to_github.sh +0 -0
  242. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/scripts/install.sh +0 -0
  243. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/scripts/prepare_release.py +0 -0
  244. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/scripts/publish_to_pypi.sh +0 -0
  245. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/__init__.py +0 -0
  246. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/acp/conftest.py +0 -0
  247. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/acp/test_acp.py +0 -0
  248. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/acp/test_agent_thought.py +0 -0
  249. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/acp/test_bash.py +0 -0
  250. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/acp/test_compact_session_updates.py +0 -0
  251. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/acp/test_content.py +0 -0
  252. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/acp/test_initialize.py +0 -0
  253. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/acp/test_list_sessions.py +0 -0
  254. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/acp/test_load_session.py +0 -0
  255. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/acp/test_multi_session.py +0 -0
  256. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/acp/test_new_session.py +0 -0
  257. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/acp/test_proxy_setup_acp.py +0 -0
  258. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/acp/test_read_file.py +0 -0
  259. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/acp/test_search_replace.py +0 -0
  260. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/acp/test_set_config_option.py +0 -0
  261. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/acp/test_set_mode.py +0 -0
  262. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/acp/test_set_model.py +0 -0
  263. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/acp/test_tool_call_session_update.py +0 -0
  264. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/acp/test_utils.py +0 -0
  265. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/acp/test_write_file.py +0 -0
  266. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/autocompletion/test_file_indexer.py +0 -0
  267. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/autocompletion/test_fuzzy.py +0 -0
  268. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/autocompletion/test_path_completer_fuzzy.py +0 -0
  269. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/autocompletion/test_path_completer_recursive.py +0 -0
  270. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/autocompletion/test_path_completion_controller.py +0 -0
  271. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/autocompletion/test_path_prompt_transformer.py +0 -0
  272. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/autocompletion/test_slash_command_controller.py +0 -0
  273. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/autocompletion/test_ui_chat_autocompletion.py +0 -0
  274. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/backend/__init__.py +0 -0
  275. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/backend/data/__init__.py +0 -0
  276. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/backend/data/fireworks.py +0 -0
  277. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/backend/data/mistral.py +0 -0
  278. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/backend/test_anthropic_adapter.py +0 -0
  279. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/backend/test_backend.py +0 -0
  280. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/backend/test_reasoning_adapter.py +0 -0
  281. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/backend/test_vertex_anthropic_adapter.py +0 -0
  282. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/cli/plan_offer/adapters/fake_whoami_gateway.py +0 -0
  283. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/cli/plan_offer/test_decide_plan_offer.py +0 -0
  284. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/cli/plan_offer/test_http_whoami_gateway.py +0 -0
  285. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/cli/test_bell_notifications.py +0 -0
  286. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/cli/test_braille_renderer.py +0 -0
  287. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/cli/test_clipboard.py +0 -0
  288. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/cli/test_commands.py +0 -0
  289. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/cli/test_copy_shortcuts.py +0 -0
  290. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/cli/test_external_editor.py +0 -0
  291. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/cli/test_no_markup_static.py +0 -0
  292. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/cli/test_question_app.py +0 -0
  293. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/cli/test_spinner.py +0 -0
  294. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/cli/test_switching_mode.py +0 -0
  295. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/cli/test_ui_clipboard_notifications.py +0 -0
  296. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/cli/test_ui_session_incremental_renderer.py +0 -0
  297. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/cli/test_ui_session_resume.py +0 -0
  298. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/cli/test_ui_skill_dispatch.py +0 -0
  299. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/cli/textual_ui/__init__.py +0 -0
  300. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/cli/textual_ui/test_session_picker.py +0 -0
  301. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/conftest.py +0 -0
  302. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/core/test_agents.py +0 -0
  303. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/core/test_auth_crypto.py +0 -0
  304. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/core/test_auth_github.py +0 -0
  305. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/core/test_config_load_dotenv.py +0 -0
  306. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/core/test_config_paths.py +0 -0
  307. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/core/test_config_resolution.py +0 -0
  308. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/core/test_file_logging.py +0 -0
  309. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/core/test_plan_session.py +0 -0
  310. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/core/test_proxy_setup.py +0 -0
  311. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/core/test_slug.py +0 -0
  312. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/core/test_telemetry_send.py +0 -0
  313. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/core/test_teleport_git.py +0 -0
  314. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/core/test_teleport_nuage.py +0 -0
  315. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/core/test_teleport_service.py +0 -0
  316. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/core/test_trusted_folders.py +0 -0
  317. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/core/test_utils.py +0 -0
  318. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/e2e/common.py +0 -0
  319. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/e2e/conftest.py +0 -0
  320. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/e2e/mock_server.py +0 -0
  321. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/e2e/test_cli_tui_onboarding.py +0 -0
  322. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/e2e/test_cli_tui_streaming.py +0 -0
  323. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/e2e/test_cli_tui_tool_approval.py +0 -0
  324. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/mock/__init__.py +0 -0
  325. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/mock/mock_backend_factory.py +0 -0
  326. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/mock/mock_entrypoint.py +0 -0
  327. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/mock/utils.py +0 -0
  328. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/onboarding/test_run_onboarding.py +0 -0
  329. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/onboarding/test_ui_onboarding.py +0 -0
  330. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/session/test_session_loader.py +0 -0
  331. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/session/test_session_logger.py +0 -0
  332. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/session/test_session_migration.py +0 -0
  333. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/skills/conftest.py +0 -0
  334. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/skills/test_manager.py +0 -0
  335. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/skills/test_models.py +0 -0
  336. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/skills/test_parser.py +0 -0
  337. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_ask_user_question/test_snapshot_ask_user_question_collapsed.svg +0 -0
  338. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_ask_user_question/test_snapshot_ask_user_question_expanded.svg +0 -0
  339. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_basic_conversation/test_snapshot_shows_basic_conversation.svg +0 -0
  340. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_code_block_horizontal_scrolling/test_snapshot_allows_horizontal_scrolling_for_long_code_blocks.svg +0 -0
  341. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_empty_assistant_before_reasoning/test_snapshot_empty_assistant_removed_when_reasoning_starts.svg +0 -0
  342. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_cycle_to_accept_edits_mode.svg +0 -0
  343. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_cycle_to_auto_approve_mode.svg +0 -0
  344. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_cycle_to_plan_mode.svg +0 -0
  345. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_cycle_wraps_to_default.svg +0 -0
  346. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_default_mode.svg +0 -0
  347. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_parallel_tool_calls/test_snapshot_parallel_tool_calls_pending.svg +0 -0
  348. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_parallel_tool_calls/test_snapshot_parallel_tool_calls_resolved.svg +0 -0
  349. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_cancel_discards_changes.svg +0 -0
  350. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_edit_existing_values.svg +0 -0
  351. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_initial_empty.svg +0 -0
  352. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_initial_with_values.svg +0 -0
  353. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_save_error.svg +0 -0
  354. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_save_new_values.svg +0 -0
  355. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_answer_first_advance.svg +0 -0
  356. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_first_answered_checkmark.svg +0 -0
  357. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_initial.svg +0 -0
  358. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_navigate_left_wraps.svg +0 -0
  359. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_navigate_right.svg +0 -0
  360. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_tab_to_second.svg +0 -0
  361. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_initial.svg +0 -0
  362. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_mixed_selection.svg +0 -0
  363. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_navigate_to_submit.svg +0 -0
  364. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_other_with_text.svg +0 -0
  365. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_toggle_first.svg +0 -0
  366. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_toggle_multiple.svg +0 -0
  367. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_untoggle.svg +0 -0
  368. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_initial.svg +0 -0
  369. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_navigate_down.svg +0 -0
  370. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_navigate_to_other.svg +0 -0
  371. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_navigate_to_third_option.svg +0 -0
  372. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_navigate_up_wraps.svg +0 -0
  373. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_other_typing.svg +0 -0
  374. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_reasoning_content/test_snapshot_buffered_reasoning_yields_before_content.svg +0 -0
  375. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_reasoning_content/test_snapshot_shows_interleaved_reasoning.svg +0 -0
  376. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_reasoning_content/test_snapshot_shows_reasoning_content.svg +0 -0
  377. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_reasoning_content/test_snapshot_shows_reasoning_content_expanded.svg +0 -0
  378. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_release_update_notification/test_snapshot_shows_release_update_notification.svg +0 -0
  379. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_session_resume/test_snapshot_shows_resumed_session_messages.svg +0 -0
  380. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_streaming_tool_call/test_snapshot_tool_call_partial.svg +0 -0
  381. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_streaming_tool_call/test_snapshot_tool_call_updated.svg +0 -0
  382. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_push_confirmation_cancel_selected.svg +0 -0
  383. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_push_confirmation_multiple_commits.svg +0 -0
  384. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_push_confirmation_single_commit.svg +0 -0
  385. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_auth_complete.svg +0 -0
  386. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_auth_required.svg +0 -0
  387. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_checking_git.svg +0 -0
  388. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_complete.svg +0 -0
  389. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_error.svg +0 -0
  390. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_pushing.svg +0 -0
  391. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_sending_token.svg +0 -0
  392. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_starting_workflow.svg +0 -0
  393. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_whats_new/test_snapshot_shows_no_plan_message.svg +0 -0
  394. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_whats_new/test_snapshot_shows_switch_message.svg +0 -0
  395. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_whats_new/test_snapshot_shows_upgrade_message.svg +0 -0
  396. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/__snapshots__/test_ui_snapshot_whats_new/test_snapshot_shows_whats_new_message.svg +0 -0
  397. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/base_snapshot_test_app.py +0 -0
  398. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/conftest.py +0 -0
  399. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/snap_compare.py +0 -0
  400. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/test_ui_snapshot_ask_user_question.py +0 -0
  401. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/test_ui_snapshot_basic_conversation.py +0 -0
  402. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/test_ui_snapshot_code_block_horizontal_scrolling.py +0 -0
  403. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/test_ui_snapshot_empty_assistant_before_reasoning.py +0 -0
  404. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/test_ui_snapshot_modes.py +0 -0
  405. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/test_ui_snapshot_parallel_tool_calls.py +0 -0
  406. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/test_ui_snapshot_proxy_setup.py +0 -0
  407. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/test_ui_snapshot_question_app.py +0 -0
  408. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/test_ui_snapshot_reasoning_content.py +0 -0
  409. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/test_ui_snapshot_release_update_notification.py +0 -0
  410. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/test_ui_snapshot_session_resume.py +0 -0
  411. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/test_ui_snapshot_streaming_tool_call.py +0 -0
  412. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/test_ui_snapshot_teleport.py +0 -0
  413. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/snapshots/test_ui_snapshot_whats_new.py +0 -0
  414. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/stubs/fake_backend.py +0 -0
  415. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/stubs/fake_client.py +0 -0
  416. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/stubs/fake_tool.py +0 -0
  417. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/test_agent_auto_compact.py +0 -0
  418. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/test_agent_backend.py +0 -0
  419. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/test_agent_observer_streaming.py +0 -0
  420. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/test_agent_stats.py +0 -0
  421. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/test_agent_tool_call.py +0 -0
  422. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/test_agents.py +0 -0
  423. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/test_cli_programmatic_preload.py +0 -0
  424. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/test_drydock_regression.py +0 -0
  425. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/test_history_manager.py +0 -0
  426. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/test_message_id.py +0 -0
  427. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/test_message_merging.py +0 -0
  428. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/test_middleware.py +0 -0
  429. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/test_reasoning_content.py +0 -0
  430. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/test_system_prompt.py +0 -0
  431. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/test_tagged_text.py +0 -0
  432. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/test_ui_external_editor.py +0 -0
  433. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/test_ui_input_history.py +0 -0
  434. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/tools/test_ask_user_question.py +0 -0
  435. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/tools/test_bash.py +0 -0
  436. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/tools/test_exit_plan_mode.py +0 -0
  437. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/tools/test_grep.py +0 -0
  438. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/tools/test_invoke_context.py +0 -0
  439. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/tools/test_manager_get_tool_config.py +0 -0
  440. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/tools/test_mcp.py +0 -0
  441. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/tools/test_mcp_sampling.py +0 -0
  442. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/tools/test_task.py +0 -0
  443. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/tools/test_ui_bash_execution.py +0 -0
  444. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/tools/test_webfetch.py +0 -0
  445. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/tools/test_websearch.py +0 -0
  446. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/update_notifier/adapters/fake_update_cache_repository.py +0 -0
  447. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/update_notifier/adapters/fake_update_gateway.py +0 -0
  448. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/update_notifier/test_do_update.py +0 -0
  449. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/update_notifier/test_filesystem_update_cache_repository.py +0 -0
  450. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/update_notifier/test_github_update_gateway.py +0 -0
  451. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/update_notifier/test_pypi_update_gateway.py +0 -0
  452. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/update_notifier/test_ui_update_notification.py +0 -0
  453. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/update_notifier/test_update_use_case.py +0 -0
  454. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/tests/update_notifier/test_whats_new.py +0 -0
  455. {drydock_cli-0.6.1 → drydock_cli-0.6.3}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: drydock-cli
3
- Version: 0.6.1
3
+ Version: 0.6.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
@@ -72,6 +72,11 @@ class CommandRegistry:
72
72
  description="Configure proxy and SSL certificate settings",
73
73
  handler="_show_proxy_setup",
74
74
  ),
75
+ "consult": Command(
76
+ aliases=frozenset(["/consult"]),
77
+ description="Ask a smarter model for advice (response visible to local model)",
78
+ handler="_consult_command",
79
+ ),
75
80
  "resume": Command(
76
81
  aliases=frozenset(["/resume", "/continue"]),
77
82
  description="Browse and resume past sessions",
@@ -92,7 +97,20 @@ class CommandRegistry:
92
97
  return self.commands.get(cmd_name) if cmd_name else None
93
98
 
94
99
  def get_command_name(self, user_input: str) -> str | None:
95
- return self._alias_map.get(user_input.lower().strip())
100
+ stripped = user_input.lower().strip()
101
+ # Exact match first
102
+ if stripped in self._alias_map:
103
+ return self._alias_map[stripped]
104
+ # Prefix match for commands that take arguments (e.g., /consult <question>)
105
+ first_word = stripped.split()[0] if stripped else ""
106
+ if first_word in self._alias_map:
107
+ return self._alias_map[first_word]
108
+ return None
109
+
110
+ def get_command_args(self, user_input: str) -> str:
111
+ """Extract arguments after the command name."""
112
+ parts = user_input.strip().split(None, 1)
113
+ return parts[1] if len(parts) > 1 else ""
96
114
 
97
115
  def get_help_text(self) -> str:
98
116
  lines: list[str] = [
@@ -520,10 +520,18 @@ class VibeApp(App): # noqa: PLR0904
520
520
  )
521
521
  await self._mount_and_scroll(UserMessage(user_input))
522
522
  handler = getattr(self, command.handler)
523
+ # Pass command args to handlers that accept them
524
+ cmd_args = self.commands.get_command_args(user_input)
523
525
  if asyncio.iscoroutinefunction(handler):
524
- await handler()
526
+ try:
527
+ await handler(cmd_args)
528
+ except TypeError:
529
+ await handler() # Handler doesn't accept args
525
530
  else:
526
- handler()
531
+ try:
532
+ handler(cmd_args)
533
+ except TypeError:
534
+ handler()
527
535
  return True
528
536
  return False
529
537
 
@@ -927,6 +935,84 @@ class VibeApp(App): # noqa: PLR0904
927
935
  """
928
936
  await self._mount_and_scroll(UserCommandMessage(status_text))
929
937
 
938
+ async def _consult_command(self, question: str = "") -> None:
939
+ """Ask a consultant model for advice. Response goes into context."""
940
+ if not question:
941
+ await self._mount_and_scroll(
942
+ UserCommandMessage(
943
+ "Usage: `/consult <your question>`\n\n"
944
+ "Asks a smarter model for advice. The response appears in the "
945
+ "conversation so the local model can see and act on it.\n\n"
946
+ "Configure: set `consultant_model` in config.toml or use `--consultant MODEL`"
947
+ )
948
+ )
949
+ return
950
+
951
+ # Get consultant model from config, CLI flag, or env
952
+ import os
953
+ consultant_model = (
954
+ getattr(self.agent_loop.config, "consultant_model", "")
955
+ or os.environ.get("DRYDOCK_CONSULTANT_MODEL", "")
956
+ )
957
+
958
+ if not consultant_model:
959
+ # List available models to help the user
960
+ model_names = [m.name for m in self.agent_loop.config.models]
961
+ await self._mount_and_scroll(
962
+ ErrorMessage(
963
+ "No consultant model configured.\n\n"
964
+ f"Available models: {', '.join(model_names)}\n\n"
965
+ "Set in config.toml:\n"
966
+ " `consultant_model = \"gemini-2.5-pro\"`\n\n"
967
+ "Or via CLI:\n"
968
+ " `drydock --consultant gemini-2.5-pro`",
969
+ collapsed=self._tools_collapsed,
970
+ )
971
+ )
972
+ return
973
+
974
+ await self._mount_and_scroll(
975
+ UserCommandMessage(f"Consulting {consultant_model}...")
976
+ )
977
+
978
+ try:
979
+ from drydock.core.consultant import ask_consultant
980
+ advice = await ask_consultant(
981
+ question,
982
+ config=self.agent_loop.config,
983
+ model=consultant_model,
984
+ )
985
+
986
+ if not advice or advice.startswith("(Consultant unavailable"):
987
+ await self._mount_and_scroll(
988
+ ErrorMessage(
989
+ f"Consultant ({consultant_model}) unavailable: {advice}",
990
+ collapsed=self._tools_collapsed,
991
+ )
992
+ )
993
+ return
994
+
995
+ # Show the advice in the UI
996
+ response_text = f"**Consultant ({consultant_model}):**\n\n{advice}"
997
+ await self._mount_and_scroll(UserCommandMessage(response_text))
998
+
999
+ # Inject into the message history so the LOCAL model can see it
1000
+ from drydock.core.types import LLMMessage, Role
1001
+ self.agent_loop.messages.append(
1002
+ LLMMessage(
1003
+ role=Role.user,
1004
+ content=f"[CONSULTANT ADVICE from {consultant_model}]: {advice}"
1005
+ )
1006
+ )
1007
+
1008
+ except Exception as e:
1009
+ await self._mount_and_scroll(
1010
+ ErrorMessage(
1011
+ f"Consultant error: {e}",
1012
+ collapsed=self._tools_collapsed,
1013
+ )
1014
+ )
1015
+
930
1016
  async def _show_config(self) -> None:
931
1017
  """Switch to the configuration app in the bottom panel."""
932
1018
  if self._current_bottom_app == BottomApp.Config:
@@ -847,9 +847,8 @@ class AgentLoop:
847
847
  return "ALREADY ATTEMPTED (do NOT repeat):\n" + "\n".join(attempts[:10])
848
848
  return ""
849
849
 
850
- async def _circuit_breaker_check(self, tool_call: ResolvedToolCall) -> str | None:
851
- """Block exact-duplicate tool calls. Returns cached result or None.
852
- On 3rd attempt, auto-consults the smarter model if available."""
850
+ def _circuit_breaker_check(self, tool_call: ResolvedToolCall) -> str | None:
851
+ """Block exact-duplicate tool calls. Returns cached result or None."""
853
852
  sig = hashlib.md5(
854
853
  f"{tool_call.tool_name}:{tool_call.raw_arguments}".encode()
855
854
  ).hexdigest()
@@ -868,22 +867,16 @@ class AgentLoop:
868
867
  f"- Ask the user for clarification"
869
868
  )
870
869
 
871
- # Auto-consult smarter model if available
872
- if count == 2:
873
- try:
874
- from drydock.core.consultant import is_consultant_available, ask_consultant
875
- if is_consultant_available():
876
- question = (
877
- f"I'm stuck in a loop. I keep running `{tool_call.tool_name}` "
878
- f"with args: {tool_call.raw_arguments[:100]} "
879
- f"and getting: {last_result[:200]}. "
880
- f"What should I do differently?"
881
- )
882
- advice = await ask_consultant(question)
883
- if advice:
884
- msg += f"\n\nCONSULTANT ADVICE: {advice}"
885
- except Exception as e:
886
- logger.debug("Consultant call failed: %s", e)
870
+ # Suggest using /consult if a consultant model is configured
871
+ try:
872
+ from drydock.core.consultant import is_consultant_available
873
+ if is_consultant_available():
874
+ msg += (
875
+ "\n\nTIP: A consultant model is available. "
876
+ "The user can type `/consult <question>` to ask it for advice."
877
+ )
878
+ except Exception:
879
+ pass
887
880
 
888
881
  return msg
889
882
  return None
@@ -900,7 +893,7 @@ class AgentLoop:
900
893
  self, tool_call: ResolvedToolCall
901
894
  ) -> AsyncGenerator[ToolResultEvent | ToolStreamEvent]:
902
895
  # Circuit breaker: block exact duplicate calls after 2 attempts
903
- if blocked := await self._circuit_breaker_check(tool_call):
896
+ if blocked := self._circuit_breaker_check(tool_call):
904
897
  yield ToolResultEvent(
905
898
  tool_name=tool_call.tool_name,
906
899
  tool_class=tool_call.tool_class,
@@ -310,6 +310,14 @@ class VibeConfig(BaseSettings):
310
310
  enable_notifications: bool = True
311
311
  api_timeout: float = 720.0
312
312
  auto_compact_threshold: int = 200_000
313
+ consultant_model: str = Field(
314
+ default="",
315
+ description=(
316
+ "Model name for the /consult command. Must match a model defined in "
317
+ "your config. The consultant provides read-only advice — it never "
318
+ "calls tools. Leave empty to disable. Example: 'gemini-2.5-pro'"
319
+ ),
320
+ )
313
321
 
314
322
  # TODO(vibe-nuage): remove exclude=True once the feature is publicly available
315
323
  nuage_enabled: bool = Field(default=False, exclude=True)
@@ -0,0 +1,183 @@
1
+ """Consultant agent — asks a configured model for single-turn advice.
2
+
3
+ The consultant is a READ-ONLY advisor:
4
+ - Uses a model from DryDock's own config (providers + models)
5
+ - NEVER calls tools, writes files, or runs commands
6
+ - Only receives a question and returns reasoning/advice
7
+ - Response is injected into context so the local model can see it
8
+
9
+ Configure in config.toml:
10
+ consultant_model = "gemini-2.5-pro"
11
+
12
+ Or via CLI:
13
+ drydock --consultant gemini-2.5-pro
14
+
15
+ Or via /consult slash command:
16
+ /consult How should I fix this auth bug?
17
+ """
18
+
19
+ from __future__ import annotations
20
+
21
+ import logging
22
+ import os
23
+
24
+ logger = logging.getLogger(__name__)
25
+
26
+
27
+ async def ask_consultant(
28
+ question: str,
29
+ config: object | None = None,
30
+ model: str | None = None,
31
+ ) -> str:
32
+ """Ask the consultant model a question using DryDock's backend.
33
+
34
+ Parameters
35
+ ----------
36
+ question : str
37
+ The specific question to ask.
38
+ config : VibeConfig, optional
39
+ DryDock config with providers/models. If None, uses env vars.
40
+ model : str, optional
41
+ Model name override. If None, uses config.consultant_model or env var.
42
+
43
+ Returns
44
+ -------
45
+ str
46
+ The consultant's advice text, or an error message.
47
+ """
48
+ # Resolve model name
49
+ model_name = model or os.environ.get("DRYDOCK_CONSULTANT_MODEL", "")
50
+ if not model_name and config:
51
+ model_name = getattr(config, "consultant_model", "")
52
+ if not model_name:
53
+ return ""
54
+
55
+ prompt = (
56
+ "You are a senior software engineering consultant. An AI coding agent is "
57
+ "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"
59
+ f"QUESTION:\n{question}"
60
+ )
61
+
62
+ # Try to use DryDock's backend system
63
+ if config:
64
+ try:
65
+ return await _ask_via_backend(prompt, model_name, config)
66
+ except Exception as e:
67
+ logger.warning("Consultant via backend failed: %s — falling back to httpx", e)
68
+
69
+ # Fallback: direct API call
70
+ try:
71
+ return await _ask_via_httpx(prompt, model_name)
72
+ except Exception as e:
73
+ return f"(Consultant unavailable: {e})"
74
+
75
+
76
+ async def _ask_via_backend(prompt: str, model_name: str, config: object) -> str:
77
+ """Use DryDock's configured backend to call the consultant model."""
78
+ from drydock.core.config import ModelConfig, ProviderConfig
79
+ from drydock.core.llm.backend.factory import BACKEND_FACTORY
80
+ from drydock.core.types import LLMMessage, Role
81
+
82
+ # Find the model and its provider in the config
83
+ target_model: ModelConfig | None = None
84
+ for m in config.models:
85
+ if m.name == model_name or m.alias == model_name:
86
+ target_model = m
87
+ break
88
+
89
+ if not target_model:
90
+ raise ValueError(f"Model '{model_name}' not found in config. Available: {[m.name for m in config.models]}")
91
+
92
+ # Find the provider
93
+ target_provider: ProviderConfig | None = None
94
+ for p in config.providers:
95
+ if p.name == target_model.provider:
96
+ target_provider = p
97
+ break
98
+
99
+ if not target_provider:
100
+ raise ValueError(f"Provider '{target_model.provider}' not found for model '{model_name}'")
101
+
102
+ # Create a one-shot backend
103
+ backend = BACKEND_FACTORY[target_provider.backend](
104
+ provider=target_provider,
105
+ timeout=30,
106
+ )
107
+
108
+ messages = [LLMMessage(role=Role.user, content=prompt)]
109
+
110
+ result = await backend.complete(
111
+ model=target_model,
112
+ messages=messages,
113
+ temperature=0.3,
114
+ tools=None, # NO tools — read-only
115
+ tool_choice=None,
116
+ max_tokens=500,
117
+ )
118
+
119
+ return result.message.content or ""
120
+
121
+
122
+ async def _ask_via_httpx(prompt: str, model_name: str) -> str:
123
+ """Fallback: direct API call via httpx for models not in config."""
124
+ import httpx
125
+
126
+ api_key = _detect_api_key(model_name)
127
+ api_base = _detect_api_base(model_name)
128
+
129
+ if not api_key:
130
+ return f"(No API key found for '{model_name}')"
131
+
132
+ verify_ssl = os.environ.get("DRYDOCK_INSECURE") != "1"
133
+ async with httpx.AsyncClient(verify=verify_ssl, timeout=30.0) as client:
134
+ response = await client.post(
135
+ f"{api_base}/chat/completions",
136
+ headers={
137
+ "Authorization": f"Bearer {api_key}",
138
+ "Content-Type": "application/json",
139
+ },
140
+ json={
141
+ "model": model_name,
142
+ "messages": [{"role": "user", "content": prompt}],
143
+ "max_tokens": 500,
144
+ "temperature": 0.3,
145
+ },
146
+ )
147
+ response.raise_for_status()
148
+ return response.json()["choices"][0]["message"]["content"]
149
+
150
+
151
+ def _detect_api_key(model: str) -> str:
152
+ model_lower = model.lower()
153
+ if "gemini" in model_lower:
154
+ return os.environ.get("GEMINI_API_KEY", os.environ.get("GOOGLE_API_KEY", ""))
155
+ if "gpt" in model_lower or "o1" in model_lower or "o3" in model_lower:
156
+ return os.environ.get("OPENAI_API_KEY", "")
157
+ if "claude" in model_lower:
158
+ return os.environ.get("ANTHROPIC_API_KEY", "")
159
+ if "mistral" in model_lower or "devstral" in model_lower:
160
+ return os.environ.get("MISTRAL_API_KEY", "")
161
+ return os.environ.get("DRYDOCK_CONSULTANT_API_KEY", "")
162
+
163
+
164
+ def _detect_api_base(model: str) -> str:
165
+ model_lower = model.lower()
166
+ if "gemini" in model_lower:
167
+ return "https://generativelanguage.googleapis.com/v1beta/openai"
168
+ if "gpt" in model_lower or "o1" in model_lower or "o3" in model_lower:
169
+ return "https://api.openai.com/v1"
170
+ if "claude" in model_lower:
171
+ return "https://api.anthropic.com/v1"
172
+ if "mistral" in model_lower or "devstral" in model_lower:
173
+ return os.environ.get("MISTRAL_API_BASE", "https://api.mistral.ai/v1")
174
+ return os.environ.get("DRYDOCK_CONSULTANT_API_BASE", "http://localhost:8000/v1")
175
+
176
+
177
+ def is_consultant_available(config: object | None = None) -> bool:
178
+ """Check if a consultant model is configured."""
179
+ if os.environ.get("DRYDOCK_CONSULTANT_MODEL"):
180
+ return True
181
+ if config and getattr(config, "consultant_model", ""):
182
+ return True
183
+ return False
@@ -17,9 +17,36 @@ class GlobalPath:
17
17
 
18
18
 
19
19
  _DEFAULT_DRYDOCK_HOME = Path.home() / ".drydock"
20
- # Fall back to ~/.vibe if it exists and ~/.drydock doesn't (migration support)
21
20
  _DEFAULT_VIBE_HOME = Path.home() / ".vibe"
22
21
 
22
+ _migration_done = False
23
+
24
+
25
+ def _migrate_vibe_to_drydock() -> None:
26
+ """Auto-migrate ~/.vibe → ~/.drydock if the user hasn't migrated yet."""
27
+ global _migration_done
28
+ if _migration_done:
29
+ return
30
+ _migration_done = True
31
+
32
+ if not _DEFAULT_VIBE_HOME.exists() or _DEFAULT_DRYDOCK_HOME.exists():
33
+ return # Nothing to migrate, or already migrated
34
+
35
+ import shutil
36
+ import logging
37
+ logger = logging.getLogger(__name__)
38
+
39
+ try:
40
+ shutil.copytree(_DEFAULT_VIBE_HOME, _DEFAULT_DRYDOCK_HOME)
41
+ logger.info("Migrated ~/.vibe → ~/.drydock")
42
+ # Leave a note in the old directory
43
+ (_DEFAULT_VIBE_HOME / "MIGRATED.txt").write_text(
44
+ "This config has been migrated to ~/.drydock/\n"
45
+ "You can safely delete this .vibe directory.\n"
46
+ )
47
+ except (OSError, PermissionError) as e:
48
+ logger.warning("Could not migrate ~/.vibe → ~/.drydock: %s", e)
49
+
23
50
 
24
51
  def _get_vibe_home() -> Path:
25
52
  # Check env vars: DRYDOCK_HOME takes priority, then VIBE_HOME for compat
@@ -27,11 +54,12 @@ def _get_vibe_home() -> Path:
27
54
  return Path(drydock_home).expanduser().resolve()
28
55
  if vibe_home := os.getenv("VIBE_HOME"):
29
56
  return Path(vibe_home).expanduser().resolve()
30
- # Default: use ~/.drydock, fall back to ~/.vibe if it exists
57
+
58
+ # Auto-migrate ~/.vibe → ~/.drydock on first run
59
+ _migrate_vibe_to_drydock()
60
+
31
61
  if _DEFAULT_DRYDOCK_HOME.exists():
32
62
  return _DEFAULT_DRYDOCK_HOME
33
- if _DEFAULT_VIBE_HOME.exists():
34
- return _DEFAULT_VIBE_HOME
35
63
  return _DEFAULT_DRYDOCK_HOME
36
64
 
37
65
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "drydock-cli"
3
- version = "0.6.1"
3
+ version = "0.6.3"
4
4
  description = "Drydock — nautical CLI coding agent"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -402,12 +402,12 @@ class TestCircuitBreaker:
402
402
 
403
403
  tc = SimpleNamespace(tool_name="bash", raw_arguments='{"command": "ls -ltr"}')
404
404
 
405
- assert asyncio.run(al._circuit_breaker_check(tc)) is None
405
+ assert al._circuit_breaker_check(tc) is None
406
406
  al._circuit_breaker_record(tc, "file1.py\nfile2.py")
407
- assert asyncio.run(al._circuit_breaker_check(tc)) is None
407
+ assert al._circuit_breaker_check(tc) is None
408
408
  al._circuit_breaker_record(tc, "file1.py\nfile2.py")
409
409
 
410
- result = asyncio.run(al._circuit_breaker_check(tc))
410
+ result = al._circuit_breaker_check(tc)
411
411
  assert result is not None
412
412
  assert "CIRCUIT BREAKER" in result
413
413
 
@@ -426,8 +426,8 @@ class TestCircuitBreaker:
426
426
 
427
427
  al._circuit_breaker_record(tc1, "result1")
428
428
  al._circuit_breaker_record(tc1, "result1")
429
- assert asyncio.run(al._circuit_breaker_check(tc1)) is not None
430
- assert asyncio.run(al._circuit_breaker_check(tc2)) is None
429
+ assert al._circuit_breaker_check(tc1) is not None
430
+ assert al._circuit_breaker_check(tc2) is None
431
431
 
432
432
 
433
433
  # ============================================================================
@@ -1,141 +0,0 @@
1
- """Consultant agent — asks a smarter model for single-turn advice.
2
-
3
- The consultant is a READ-ONLY advisor:
4
- - The local model stays in control of ALL tool calls
5
- - The consultant NEVER calls tools, writes files, or runs commands
6
- - It only receives a question and returns reasoning/advice
7
- - Used when the local model is stuck, uncertain, or looping
8
-
9
- Usage from agent_loop:
10
- advice = await ask_consultant("I found 3 files that match. Which one likely contains the bug?")
11
-
12
- The consultant model is configured via:
13
- - CLI: drydock --consultant gemini-2.5-pro
14
- - Env: DRYDOCK_CONSULTANT_MODEL=gemini-2.5-pro
15
- """
16
-
17
- from __future__ import annotations
18
-
19
- import logging
20
- import os
21
- from typing import Any
22
-
23
- import httpx
24
-
25
- logger = logging.getLogger(__name__)
26
-
27
-
28
- async def ask_consultant(
29
- question: str,
30
- context: str = "",
31
- model: str | None = None,
32
- api_key: str | None = None,
33
- api_base: str | None = None,
34
- ) -> str:
35
- """Ask the consultant model a question and get text advice back.
36
-
37
- Parameters
38
- ----------
39
- question : str
40
- The specific question to ask.
41
- context : str
42
- Optional context (e.g., file contents, error messages).
43
- model : str
44
- Model name. Defaults to DRYDOCK_CONSULTANT_MODEL env var.
45
- api_key : str
46
- API key. Auto-detected from common env vars if not provided.
47
- api_base : str
48
- API base URL. Auto-detected based on model name if not provided.
49
-
50
- Returns
51
- -------
52
- str
53
- The consultant's advice text, or an error message.
54
- """
55
- model = model or os.environ.get("DRYDOCK_CONSULTANT_MODEL", "")
56
- if not model:
57
- return ""
58
-
59
- # Auto-detect API key and base URL from model name
60
- api_key = api_key or _detect_api_key(model)
61
- api_base = api_base or _detect_api_base(model)
62
-
63
- if not api_key:
64
- logger.warning("No API key found for consultant model '%s'", model)
65
- return ""
66
-
67
- prompt = f"""You are a senior software engineering consultant. A junior AI coding agent is asking for your advice.
68
- Give concise, actionable guidance. Do NOT provide code — just tell them WHAT to do and WHERE to look.
69
-
70
- QUESTION:
71
- {question}
72
- """
73
- if context:
74
- prompt += f"\nCONTEXT:\n{context[:2000]}\n"
75
-
76
- try:
77
- # Use OpenAI-compatible API (works with Gemini, OpenAI, Mistral, local models)
78
- verify_ssl = os.environ.get("DRYDOCK_INSECURE") != "1"
79
- async with httpx.AsyncClient(verify=verify_ssl, timeout=30.0) as client:
80
- response = await client.post(
81
- f"{api_base}/chat/completions",
82
- headers={
83
- "Authorization": f"Bearer {api_key}",
84
- "Content-Type": "application/json",
85
- },
86
- json={
87
- "model": model,
88
- "messages": [{"role": "user", "content": prompt}],
89
- "max_tokens": 500,
90
- "temperature": 0.3,
91
- # NO tools — consultant is read-only
92
- },
93
- )
94
- response.raise_for_status()
95
- data = response.json()
96
- advice = data["choices"][0]["message"]["content"]
97
- logger.info("Consultant (%s) responded: %s", model, advice[:100])
98
- return advice
99
-
100
- except Exception as e:
101
- logger.warning("Consultant call failed: %s", e)
102
- return f"(Consultant unavailable: {e})"
103
-
104
-
105
- def _detect_api_key(model: str) -> str:
106
- """Auto-detect API key from environment based on model name."""
107
- model_lower = model.lower()
108
-
109
- if "gemini" in model_lower:
110
- return os.environ.get("GEMINI_API_KEY", os.environ.get("GOOGLE_API_KEY", ""))
111
- if "gpt" in model_lower or "o1" in model_lower or "o3" in model_lower:
112
- return os.environ.get("OPENAI_API_KEY", "")
113
- if "claude" in model_lower:
114
- return os.environ.get("ANTHROPIC_API_KEY", "")
115
- if "mistral" in model_lower or "devstral" in model_lower:
116
- return os.environ.get("MISTRAL_API_KEY", "")
117
-
118
- # Generic fallback
119
- return os.environ.get("DRYDOCK_CONSULTANT_API_KEY", "")
120
-
121
-
122
- def _detect_api_base(model: str) -> str:
123
- """Auto-detect API base URL from model name."""
124
- model_lower = model.lower()
125
-
126
- if "gemini" in model_lower:
127
- return "https://generativelanguage.googleapis.com/v1beta/openai"
128
- if "gpt" in model_lower or "o1" in model_lower or "o3" in model_lower:
129
- return "https://api.openai.com/v1"
130
- if "claude" in model_lower:
131
- return "https://api.anthropic.com/v1"
132
- if "mistral" in model_lower or "devstral" in model_lower:
133
- return os.environ.get("MISTRAL_API_BASE", "https://api.mistral.ai/v1")
134
-
135
- # Try local vLLM
136
- return os.environ.get("DRYDOCK_CONSULTANT_API_BASE", "http://localhost:8000/v1")
137
-
138
-
139
- def is_consultant_available() -> bool:
140
- """Check if a consultant model is configured."""
141
- return bool(os.environ.get("DRYDOCK_CONSULTANT_MODEL"))
File without changes
File without changes
File without changes
File without changes