drydock-cli 0.5.2__tar.gz → 0.6.1__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 (454) hide show
  1. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/PKG-INFO +1 -1
  2. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/PRD.md +26 -4
  3. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/entrypoint.py +25 -0
  4. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/loading.py +9 -0
  5. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/agent_loop.py +78 -0
  6. drydock_cli-0.6.1/drydock/core/consultant.py +141 -0
  7. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/bash.py +17 -3
  8. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/pyproject.toml +1 -1
  9. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/test_drydock_tasks.py +79 -0
  10. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/.github/CODEOWNERS +0 -0
  11. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/.github/DISCUSSION_TEMPLATE/ideas.yml +0 -0
  12. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
  13. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  14. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/.github/workflows/build-and-upload.yml +0 -0
  15. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/.github/workflows/ci.yml +0 -0
  16. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/.github/workflows/issue-labeler.yml +0 -0
  17. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/.github/workflows/release.yml +0 -0
  18. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/.gitignore +0 -0
  19. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/.pre-commit-config.yaml +0 -0
  20. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/.python-version +0 -0
  21. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/.typos.toml +0 -0
  22. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/.vscode/extensions.json +0 -0
  23. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/.vscode/launch.json +0 -0
  24. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/.vscode/settings.json +0 -0
  25. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/AGENTS.md +0 -0
  26. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/CHANGELOG.md +0 -0
  27. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/CLAUDE.md +0 -0
  28. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/CONTRIBUTING.md +0 -0
  29. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/Drydock_rebrand.md +0 -0
  30. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/LICENSE +0 -0
  31. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/NOTICE +0 -0
  32. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/README.md +0 -0
  33. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/action.yml +0 -0
  34. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/distribution/zed/LICENSE +0 -0
  35. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/distribution/zed/extension.toml +0 -0
  36. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/distribution/zed/icons/mistral_vibe.svg +0 -0
  37. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/docs/README.md +0 -0
  38. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/docs/acp-setup.md +0 -0
  39. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/docs/proxy-setup.md +0 -0
  40. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/__init__.py +0 -0
  41. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/acp/__init__.py +0 -0
  42. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/acp/acp_agent_loop.py +0 -0
  43. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/acp/acp_logger.py +0 -0
  44. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/acp/entrypoint.py +0 -0
  45. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/acp/tools/__init__.py +0 -0
  46. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/acp/tools/base.py +0 -0
  47. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/acp/tools/builtins/bash.py +0 -0
  48. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/acp/tools/builtins/read_file.py +0 -0
  49. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/acp/tools/builtins/search_replace.py +0 -0
  50. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/acp/tools/builtins/todo.py +0 -0
  51. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/acp/tools/builtins/write_file.py +0 -0
  52. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/acp/tools/session_update.py +0 -0
  53. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/acp/utils.py +0 -0
  54. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/__init__.py +0 -0
  55. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/autocompletion/__init__.py +0 -0
  56. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/autocompletion/base.py +0 -0
  57. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/autocompletion/path_completion.py +0 -0
  58. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/autocompletion/slash_command.py +0 -0
  59. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/cli.py +0 -0
  60. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/clipboard.py +0 -0
  61. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/commands.py +0 -0
  62. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/history_manager.py +0 -0
  63. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/plan_offer/adapters/http_whoami_gateway.py +0 -0
  64. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/plan_offer/decide_plan_offer.py +0 -0
  65. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/plan_offer/ports/whoami_gateway.py +0 -0
  66. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/terminal_setup.py +0 -0
  67. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/__init__.py +0 -0
  68. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/ansi_markdown.py +0 -0
  69. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/app.py +0 -0
  70. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/app.tcss +0 -0
  71. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/external_editor.py +0 -0
  72. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/handlers/__init__.py +0 -0
  73. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/handlers/event_handler.py +0 -0
  74. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/notifications/__init__.py +0 -0
  75. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/notifications/adapters/__init__.py +0 -0
  76. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/notifications/adapters/textual_notification_adapter.py +0 -0
  77. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/notifications/ports/__init__.py +0 -0
  78. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/notifications/ports/notification_port.py +0 -0
  79. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/__init__.py +0 -0
  80. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/approval_app.py +0 -0
  81. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/banner/banner.py +0 -0
  82. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/banner/petit_chat.py +0 -0
  83. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/braille_renderer.py +0 -0
  84. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/chat_input/__init__.py +0 -0
  85. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/chat_input/body.py +0 -0
  86. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/chat_input/completion_manager.py +0 -0
  87. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/chat_input/completion_popup.py +0 -0
  88. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/chat_input/container.py +0 -0
  89. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/chat_input/text_area.py +0 -0
  90. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/compact.py +0 -0
  91. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/config_app.py +0 -0
  92. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/context_progress.py +0 -0
  93. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/load_more.py +0 -0
  94. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/messages.py +0 -0
  95. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/no_markup_static.py +0 -0
  96. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/path_display.py +0 -0
  97. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/proxy_setup_app.py +0 -0
  98. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/question_app.py +0 -0
  99. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/session_picker.py +0 -0
  100. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/spinner.py +0 -0
  101. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/status_message.py +0 -0
  102. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/teleport_message.py +0 -0
  103. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/tool_widgets.py +0 -0
  104. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/tools.py +0 -0
  105. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/widgets/vscode_compat.py +0 -0
  106. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/windowing/__init__.py +0 -0
  107. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/windowing/history.py +0 -0
  108. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/windowing/history_windowing.py +0 -0
  109. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/textual_ui/windowing/state.py +0 -0
  110. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/update_notifier/__init__.py +0 -0
  111. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/update_notifier/adapters/filesystem_update_cache_repository.py +0 -0
  112. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/update_notifier/adapters/github_update_gateway.py +0 -0
  113. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/update_notifier/adapters/pypi_update_gateway.py +0 -0
  114. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/update_notifier/ports/update_cache_repository.py +0 -0
  115. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/update_notifier/ports/update_gateway.py +0 -0
  116. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/update_notifier/update.py +0 -0
  117. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/cli/update_notifier/whats_new.py +0 -0
  118. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/__init__.py +0 -0
  119. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/agents/__init__.py +0 -0
  120. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/agents/manager.py +0 -0
  121. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/agents/models.py +0 -0
  122. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/auth/__init__.py +0 -0
  123. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/auth/crypto.py +0 -0
  124. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/auth/github.py +0 -0
  125. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/autocompletion/__init__.py +0 -0
  126. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/autocompletion/completers.py +0 -0
  127. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/autocompletion/file_indexer/__init__.py +0 -0
  128. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/autocompletion/file_indexer/ignore_rules.py +0 -0
  129. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/autocompletion/file_indexer/indexer.py +0 -0
  130. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/autocompletion/file_indexer/store.py +0 -0
  131. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/autocompletion/file_indexer/watcher.py +0 -0
  132. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/autocompletion/fuzzy.py +0 -0
  133. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/autocompletion/path_prompt.py +0 -0
  134. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/autocompletion/path_prompt_adapter.py +0 -0
  135. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/config/__init__.py +0 -0
  136. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/config/_settings.py +0 -0
  137. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/config/harness_files/__init__.py +0 -0
  138. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/config/harness_files/_harness_manager.py +0 -0
  139. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/config/harness_files/_paths.py +0 -0
  140. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/drydock_states.py +0 -0
  141. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/llm/__init__.py +0 -0
  142. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/llm/backend/anthropic.py +0 -0
  143. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/llm/backend/base.py +0 -0
  144. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/llm/backend/factory.py +0 -0
  145. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/llm/backend/generic.py +0 -0
  146. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/llm/backend/mistral.py +0 -0
  147. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/llm/backend/reasoning_adapter.py +0 -0
  148. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/llm/backend/vertex.py +0 -0
  149. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/llm/exceptions.py +0 -0
  150. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/llm/format.py +0 -0
  151. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/llm/message_utils.py +0 -0
  152. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/llm/types.py +0 -0
  153. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/logger.py +0 -0
  154. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/middleware.py +0 -0
  155. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/output_formatters.py +0 -0
  156. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/paths/__init__.py +0 -0
  157. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/paths/_local_config_walk.py +0 -0
  158. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/paths/_vibe_home.py +0 -0
  159. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/paths/conventions.py +0 -0
  160. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/plan_session.py +0 -0
  161. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/programmatic.py +0 -0
  162. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/prompts/__init__.py +0 -0
  163. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/prompts/cli.md +0 -0
  164. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/prompts/compact.md +0 -0
  165. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/prompts/dangerous_directory.md +0 -0
  166. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/prompts/diagnostic.md +0 -0
  167. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/prompts/explore.md +0 -0
  168. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/prompts/planner.md +0 -0
  169. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/prompts/project_context.md +0 -0
  170. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/prompts/tests.md +0 -0
  171. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/proxy_setup.py +0 -0
  172. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/session/session_loader.py +0 -0
  173. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/session/session_logger.py +0 -0
  174. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/session/session_migration.py +0 -0
  175. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/session/state_file.py +0 -0
  176. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/skills/__init__.py +0 -0
  177. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/skills/manager.py +0 -0
  178. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/skills/models.py +0 -0
  179. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/skills/parser.py +0 -0
  180. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/slug.py +0 -0
  181. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/system_prompt.py +0 -0
  182. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/telemetry/__init__.py +0 -0
  183. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/telemetry/send.py +0 -0
  184. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/teleport/errors.py +0 -0
  185. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/teleport/git.py +0 -0
  186. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/teleport/nuage.py +0 -0
  187. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/teleport/teleport.py +0 -0
  188. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/teleport/types.py +0 -0
  189. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/base.py +0 -0
  190. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/ask_user_question.py +0 -0
  191. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/exit_plan_mode.py +0 -0
  192. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/grep.py +0 -0
  193. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/prompts/__init__.py +0 -0
  194. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/prompts/ask_user_question.md +0 -0
  195. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/prompts/bash.md +0 -0
  196. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/prompts/grep.md +0 -0
  197. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/prompts/read_file.md +0 -0
  198. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/prompts/search_replace.md +0 -0
  199. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/prompts/swe_bench.md +0 -0
  200. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/prompts/task.md +0 -0
  201. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/prompts/todo.md +0 -0
  202. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/prompts/webfetch.md +0 -0
  203. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/prompts/websearch.md +0 -0
  204. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/prompts/write_file.md +0 -0
  205. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/read_file.py +0 -0
  206. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/search_replace.py +0 -0
  207. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/task.py +0 -0
  208. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/todo.py +0 -0
  209. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/webfetch.py +0 -0
  210. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/websearch.py +0 -0
  211. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/builtins/write_file.py +0 -0
  212. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/injection_guard.py +0 -0
  213. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/manager.py +0 -0
  214. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/mcp/__init__.py +0 -0
  215. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/mcp/registry.py +0 -0
  216. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/mcp/tools.py +0 -0
  217. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/mcp_sampling.py +0 -0
  218. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/ui.py +0 -0
  219. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/tools/utils.py +0 -0
  220. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/trusted_folders.py +0 -0
  221. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/types.py +0 -0
  222. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/core/utils.py +0 -0
  223. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/setup/onboarding/__init__.py +0 -0
  224. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/setup/onboarding/base.py +0 -0
  225. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/setup/onboarding/onboarding.tcss +0 -0
  226. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/setup/onboarding/screens/__init__.py +0 -0
  227. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/setup/onboarding/screens/api_key.py +0 -0
  228. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/setup/onboarding/screens/welcome.py +0 -0
  229. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/setup/trusted_folders/trust_folder_dialog.py +0 -0
  230. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/setup/trusted_folders/trust_folder_dialog.tcss +0 -0
  231. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/skills/__init__.py +0 -0
  232. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/skills/create-presentation/SKILL.md +0 -0
  233. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock/whats_new.md +0 -0
  234. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock-acp.spec +0 -0
  235. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/drydock_terms.md +0 -0
  236. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/flake.lock +0 -0
  237. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/flake.nix +0 -0
  238. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/scripts/README.md +0 -0
  239. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/scripts/bump_version.py +0 -0
  240. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/scripts/deploy_to_github.sh +0 -0
  241. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/scripts/install.sh +0 -0
  242. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/scripts/prepare_release.py +0 -0
  243. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/scripts/publish_to_pypi.sh +0 -0
  244. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/__init__.py +0 -0
  245. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/acp/conftest.py +0 -0
  246. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/acp/test_acp.py +0 -0
  247. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/acp/test_agent_thought.py +0 -0
  248. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/acp/test_bash.py +0 -0
  249. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/acp/test_compact_session_updates.py +0 -0
  250. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/acp/test_content.py +0 -0
  251. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/acp/test_initialize.py +0 -0
  252. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/acp/test_list_sessions.py +0 -0
  253. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/acp/test_load_session.py +0 -0
  254. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/acp/test_multi_session.py +0 -0
  255. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/acp/test_new_session.py +0 -0
  256. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/acp/test_proxy_setup_acp.py +0 -0
  257. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/acp/test_read_file.py +0 -0
  258. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/acp/test_search_replace.py +0 -0
  259. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/acp/test_set_config_option.py +0 -0
  260. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/acp/test_set_mode.py +0 -0
  261. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/acp/test_set_model.py +0 -0
  262. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/acp/test_tool_call_session_update.py +0 -0
  263. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/acp/test_utils.py +0 -0
  264. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/acp/test_write_file.py +0 -0
  265. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/autocompletion/test_file_indexer.py +0 -0
  266. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/autocompletion/test_fuzzy.py +0 -0
  267. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/autocompletion/test_path_completer_fuzzy.py +0 -0
  268. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/autocompletion/test_path_completer_recursive.py +0 -0
  269. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/autocompletion/test_path_completion_controller.py +0 -0
  270. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/autocompletion/test_path_prompt_transformer.py +0 -0
  271. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/autocompletion/test_slash_command_controller.py +0 -0
  272. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/autocompletion/test_ui_chat_autocompletion.py +0 -0
  273. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/backend/__init__.py +0 -0
  274. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/backend/data/__init__.py +0 -0
  275. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/backend/data/fireworks.py +0 -0
  276. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/backend/data/mistral.py +0 -0
  277. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/backend/test_anthropic_adapter.py +0 -0
  278. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/backend/test_backend.py +0 -0
  279. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/backend/test_reasoning_adapter.py +0 -0
  280. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/backend/test_vertex_anthropic_adapter.py +0 -0
  281. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/cli/plan_offer/adapters/fake_whoami_gateway.py +0 -0
  282. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/cli/plan_offer/test_decide_plan_offer.py +0 -0
  283. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/cli/plan_offer/test_http_whoami_gateway.py +0 -0
  284. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/cli/test_bell_notifications.py +0 -0
  285. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/cli/test_braille_renderer.py +0 -0
  286. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/cli/test_clipboard.py +0 -0
  287. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/cli/test_commands.py +0 -0
  288. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/cli/test_copy_shortcuts.py +0 -0
  289. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/cli/test_external_editor.py +0 -0
  290. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/cli/test_no_markup_static.py +0 -0
  291. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/cli/test_question_app.py +0 -0
  292. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/cli/test_spinner.py +0 -0
  293. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/cli/test_switching_mode.py +0 -0
  294. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/cli/test_ui_clipboard_notifications.py +0 -0
  295. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/cli/test_ui_session_incremental_renderer.py +0 -0
  296. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/cli/test_ui_session_resume.py +0 -0
  297. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/cli/test_ui_skill_dispatch.py +0 -0
  298. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/cli/textual_ui/__init__.py +0 -0
  299. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/cli/textual_ui/test_session_picker.py +0 -0
  300. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/conftest.py +0 -0
  301. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/core/test_agents.py +0 -0
  302. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/core/test_auth_crypto.py +0 -0
  303. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/core/test_auth_github.py +0 -0
  304. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/core/test_config_load_dotenv.py +0 -0
  305. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/core/test_config_paths.py +0 -0
  306. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/core/test_config_resolution.py +0 -0
  307. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/core/test_file_logging.py +0 -0
  308. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/core/test_plan_session.py +0 -0
  309. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/core/test_proxy_setup.py +0 -0
  310. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/core/test_slug.py +0 -0
  311. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/core/test_telemetry_send.py +0 -0
  312. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/core/test_teleport_git.py +0 -0
  313. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/core/test_teleport_nuage.py +0 -0
  314. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/core/test_teleport_service.py +0 -0
  315. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/core/test_trusted_folders.py +0 -0
  316. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/core/test_utils.py +0 -0
  317. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/e2e/common.py +0 -0
  318. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/e2e/conftest.py +0 -0
  319. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/e2e/mock_server.py +0 -0
  320. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/e2e/test_cli_tui_onboarding.py +0 -0
  321. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/e2e/test_cli_tui_streaming.py +0 -0
  322. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/e2e/test_cli_tui_tool_approval.py +0 -0
  323. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/mock/__init__.py +0 -0
  324. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/mock/mock_backend_factory.py +0 -0
  325. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/mock/mock_entrypoint.py +0 -0
  326. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/mock/utils.py +0 -0
  327. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/onboarding/test_run_onboarding.py +0 -0
  328. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/onboarding/test_ui_onboarding.py +0 -0
  329. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/session/test_session_loader.py +0 -0
  330. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/session/test_session_logger.py +0 -0
  331. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/session/test_session_migration.py +0 -0
  332. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/skills/conftest.py +0 -0
  333. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/skills/test_manager.py +0 -0
  334. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/skills/test_models.py +0 -0
  335. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/skills/test_parser.py +0 -0
  336. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_ask_user_question/test_snapshot_ask_user_question_collapsed.svg +0 -0
  337. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_ask_user_question/test_snapshot_ask_user_question_expanded.svg +0 -0
  338. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_basic_conversation/test_snapshot_shows_basic_conversation.svg +0 -0
  339. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_code_block_horizontal_scrolling/test_snapshot_allows_horizontal_scrolling_for_long_code_blocks.svg +0 -0
  340. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_empty_assistant_before_reasoning/test_snapshot_empty_assistant_removed_when_reasoning_starts.svg +0 -0
  341. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_cycle_to_accept_edits_mode.svg +0 -0
  342. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_cycle_to_auto_approve_mode.svg +0 -0
  343. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_cycle_to_plan_mode.svg +0 -0
  344. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_cycle_wraps_to_default.svg +0 -0
  345. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_default_mode.svg +0 -0
  346. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_parallel_tool_calls/test_snapshot_parallel_tool_calls_pending.svg +0 -0
  347. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_parallel_tool_calls/test_snapshot_parallel_tool_calls_resolved.svg +0 -0
  348. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_cancel_discards_changes.svg +0 -0
  349. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_edit_existing_values.svg +0 -0
  350. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_initial_empty.svg +0 -0
  351. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_initial_with_values.svg +0 -0
  352. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_save_error.svg +0 -0
  353. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_save_new_values.svg +0 -0
  354. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_answer_first_advance.svg +0 -0
  355. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_first_answered_checkmark.svg +0 -0
  356. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_initial.svg +0 -0
  357. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_navigate_left_wraps.svg +0 -0
  358. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_navigate_right.svg +0 -0
  359. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_tab_to_second.svg +0 -0
  360. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_initial.svg +0 -0
  361. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_mixed_selection.svg +0 -0
  362. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_navigate_to_submit.svg +0 -0
  363. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_other_with_text.svg +0 -0
  364. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_toggle_first.svg +0 -0
  365. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_toggle_multiple.svg +0 -0
  366. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_untoggle.svg +0 -0
  367. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_initial.svg +0 -0
  368. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_navigate_down.svg +0 -0
  369. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_navigate_to_other.svg +0 -0
  370. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_navigate_to_third_option.svg +0 -0
  371. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_navigate_up_wraps.svg +0 -0
  372. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_other_typing.svg +0 -0
  373. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_reasoning_content/test_snapshot_buffered_reasoning_yields_before_content.svg +0 -0
  374. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_reasoning_content/test_snapshot_shows_interleaved_reasoning.svg +0 -0
  375. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_reasoning_content/test_snapshot_shows_reasoning_content.svg +0 -0
  376. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_reasoning_content/test_snapshot_shows_reasoning_content_expanded.svg +0 -0
  377. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_release_update_notification/test_snapshot_shows_release_update_notification.svg +0 -0
  378. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_session_resume/test_snapshot_shows_resumed_session_messages.svg +0 -0
  379. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_streaming_tool_call/test_snapshot_tool_call_partial.svg +0 -0
  380. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_streaming_tool_call/test_snapshot_tool_call_updated.svg +0 -0
  381. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_push_confirmation_cancel_selected.svg +0 -0
  382. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_push_confirmation_multiple_commits.svg +0 -0
  383. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_push_confirmation_single_commit.svg +0 -0
  384. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_auth_complete.svg +0 -0
  385. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_auth_required.svg +0 -0
  386. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_checking_git.svg +0 -0
  387. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_complete.svg +0 -0
  388. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_error.svg +0 -0
  389. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_pushing.svg +0 -0
  390. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_sending_token.svg +0 -0
  391. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_starting_workflow.svg +0 -0
  392. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_whats_new/test_snapshot_shows_no_plan_message.svg +0 -0
  393. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_whats_new/test_snapshot_shows_switch_message.svg +0 -0
  394. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_whats_new/test_snapshot_shows_upgrade_message.svg +0 -0
  395. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/__snapshots__/test_ui_snapshot_whats_new/test_snapshot_shows_whats_new_message.svg +0 -0
  396. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/base_snapshot_test_app.py +0 -0
  397. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/conftest.py +0 -0
  398. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/snap_compare.py +0 -0
  399. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/test_ui_snapshot_ask_user_question.py +0 -0
  400. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/test_ui_snapshot_basic_conversation.py +0 -0
  401. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/test_ui_snapshot_code_block_horizontal_scrolling.py +0 -0
  402. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/test_ui_snapshot_empty_assistant_before_reasoning.py +0 -0
  403. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/test_ui_snapshot_modes.py +0 -0
  404. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/test_ui_snapshot_parallel_tool_calls.py +0 -0
  405. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/test_ui_snapshot_proxy_setup.py +0 -0
  406. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/test_ui_snapshot_question_app.py +0 -0
  407. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/test_ui_snapshot_reasoning_content.py +0 -0
  408. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/test_ui_snapshot_release_update_notification.py +0 -0
  409. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/test_ui_snapshot_session_resume.py +0 -0
  410. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/test_ui_snapshot_streaming_tool_call.py +0 -0
  411. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/test_ui_snapshot_teleport.py +0 -0
  412. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/snapshots/test_ui_snapshot_whats_new.py +0 -0
  413. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/stubs/fake_backend.py +0 -0
  414. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/stubs/fake_client.py +0 -0
  415. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/stubs/fake_tool.py +0 -0
  416. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/test_agent_auto_compact.py +0 -0
  417. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/test_agent_backend.py +0 -0
  418. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/test_agent_observer_streaming.py +0 -0
  419. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/test_agent_stats.py +0 -0
  420. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/test_agent_tool_call.py +0 -0
  421. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/test_agents.py +0 -0
  422. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/test_cli_programmatic_preload.py +0 -0
  423. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/test_drydock_regression.py +0 -0
  424. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/test_history_manager.py +0 -0
  425. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/test_message_id.py +0 -0
  426. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/test_message_merging.py +0 -0
  427. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/test_middleware.py +0 -0
  428. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/test_reasoning_content.py +0 -0
  429. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/test_system_prompt.py +0 -0
  430. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/test_tagged_text.py +0 -0
  431. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/test_ui_external_editor.py +0 -0
  432. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/test_ui_input_history.py +0 -0
  433. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/tools/test_ask_user_question.py +0 -0
  434. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/tools/test_bash.py +0 -0
  435. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/tools/test_exit_plan_mode.py +0 -0
  436. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/tools/test_grep.py +0 -0
  437. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/tools/test_invoke_context.py +0 -0
  438. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/tools/test_manager_get_tool_config.py +0 -0
  439. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/tools/test_mcp.py +0 -0
  440. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/tools/test_mcp_sampling.py +0 -0
  441. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/tools/test_task.py +0 -0
  442. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/tools/test_ui_bash_execution.py +0 -0
  443. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/tools/test_webfetch.py +0 -0
  444. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/tools/test_websearch.py +0 -0
  445. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/update_notifier/adapters/fake_update_cache_repository.py +0 -0
  446. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/update_notifier/adapters/fake_update_gateway.py +0 -0
  447. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/update_notifier/test_do_update.py +0 -0
  448. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/update_notifier/test_filesystem_update_cache_repository.py +0 -0
  449. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/update_notifier/test_github_update_gateway.py +0 -0
  450. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/update_notifier/test_pypi_update_gateway.py +0 -0
  451. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/update_notifier/test_ui_update_notification.py +0 -0
  452. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/update_notifier/test_update_use_case.py +0 -0
  453. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/tests/update_notifier/test_whats_new.py +0 -0
  454. {drydock_cli-0.5.2 → drydock_cli-0.6.1}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: drydock-cli
3
- Version: 0.5.2
3
+ Version: 0.6.1
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
@@ -153,10 +153,32 @@ User-reported issues from real usage testing, all fixed:
153
153
 
154
154
  ### Phase 5b: Testing & CI (Mar 24)
155
155
 
156
- - **64 regression tests** in 2 test files (0.12s total runtime)
157
- - **Tests gate all deploys** — deploy_to_github.sh and publish_to_pypi.sh abort on failure
158
- - **Continuous SWE-bench loop** — 320/500 tasks tested, 45.3% pass rate, auto-restarts on reboot
159
- - **PyPI published** — drydock-cli v0.4.1
156
+ - **76 regression tests** gating all deploys
157
+ - **Continuous SWE-bench loop** — 500/500 tasks tested, 49.0% pass rate (+9.4% from baseline)
158
+ - **vibe/ drydock/** package rename (908 imports updated)
159
+ - **PyPI published** — drydock-cli v0.5.2
160
+
161
+ ### Phase 6: GSD Integration & Performance (Mar 25)
162
+
163
+ GSD-inspired features (from [get-shit-done](https://github.com/gsd-build/get-shit-done)):
164
+
165
+ | Feature | Details |
166
+ |---------|---------|
167
+ | Tiered context warnings | 4 levels at 50/65/75/85% usage, debounced every 5 calls |
168
+ | Prompt injection guard | Detects role overrides, invisible Unicode, hidden instructions in file writes |
169
+ | Structured state file | `.drydock/state.md` persists task, files, decisions across sessions |
170
+ | Deviation handling rules | Auto-fix bugs/imports, ask user for architecture/scope decisions |
171
+
172
+ Performance and loop fixes:
173
+
174
+ | Fix | Details |
175
+ |-----|---------|
176
+ | Circuit breaker | Blocks exact same tool call after 2 attempts, returns cached result |
177
+ | Thinking flicker fix | Status words change every 4s, not every token |
178
+ | Conda env protection | Preserves user's active conda environment in subprocesses |
179
+ | `--insecure` / `-k` flag | Disables SSL verification for corporate proxy environments |
180
+ | `--consultant MODEL` flag | Allows calling a smarter model for single-turn advice when stuck |
181
+ | 81 regression tests | Circuit breaker, injection guard, state file, context tiers all tested |
160
182
 
161
183
  ---
162
184
 
@@ -90,6 +90,19 @@ def parse_arguments() -> argparse.Namespace:
90
90
  help="Skip all tool permission checks. Equivalent to --agent auto-approve. "
91
91
  "Use with caution — tools will execute without confirmation.",
92
92
  )
93
+ parser.add_argument(
94
+ "-k", "--insecure",
95
+ action="store_true",
96
+ help="Disable SSL certificate verification for web searches and API calls. "
97
+ "Useful behind corporate proxies with self-signed certificates.",
98
+ )
99
+ parser.add_argument(
100
+ "--consultant",
101
+ metavar="MODEL",
102
+ help="Enable consultant mode: when the agent is uncertain or stuck in a loop, "
103
+ "it can call a more capable model (e.g., 'gemini-2.5-pro') for single-turn advice. "
104
+ "The consultant is NOT used for tool calls, only reasoning.",
105
+ )
93
106
 
94
107
  # Feature flag for teleport, not exposed to the user yet
95
108
  parser.add_argument("--teleport", action="store_true", help=argparse.SUPPRESS)
@@ -160,6 +173,18 @@ def main() -> None:
160
173
  if args.dangerously_skip_permissions:
161
174
  args.agent = BuiltinAgentName.AUTO_APPROVE
162
175
 
176
+ # --insecure → disable SSL verification globally
177
+ if args.insecure:
178
+ os.environ["DRYDOCK_INSECURE"] = "1"
179
+ os.environ["CURL_CA_BUNDLE"] = ""
180
+ os.environ["REQUESTS_CA_BUNDLE"] = ""
181
+ import ssl
182
+ ssl._create_default_https_context = ssl._create_unverified_context
183
+
184
+ # --consultant → store for agent loop to use
185
+ if args.consultant:
186
+ os.environ["DRYDOCK_CONSULTANT_MODEL"] = args.consultant
187
+
163
188
  is_interactive = args.prompt is None
164
189
  if is_interactive:
165
190
  check_and_resolve_trusted_folder()
@@ -64,6 +64,9 @@ class LoadingWidget(SpinnerMixin, Static):
64
64
  "Stocking the galley",
65
65
  ]
66
66
 
67
+ # Minimum seconds between status word changes (prevents flicker)
68
+ _STATUS_CHANGE_INTERVAL = 4.0
69
+
67
70
  def __init__(self, status: str | None = None) -> None:
68
71
  super().__init__(classes="loading-widget")
69
72
  self.init_spinner()
@@ -77,6 +80,7 @@ class LoadingWidget(SpinnerMixin, Static):
77
80
  self._last_elapsed: int = -1
78
81
  self._paused_total: float = 0.0
79
82
  self._pause_start: float | None = None
83
+ self._last_status_change: float = 0.0
80
84
 
81
85
  def _get_easter_egg(self) -> str | None:
82
86
  EASTER_EGG_PROBABILITY = 0.10
@@ -111,6 +115,11 @@ class LoadingWidget(SpinnerMixin, Static):
111
115
  self._pause_start = None
112
116
 
113
117
  def set_status(self, status: str) -> None:
118
+ # Throttle status word changes to prevent flicker
119
+ now = time()
120
+ if now - self._last_status_change < self._STATUS_CHANGE_INTERVAL:
121
+ return # Too soon — keep current word
122
+ self._last_status_change = now
114
123
  self.status = self._apply_easter_egg(status)
115
124
  self._update_animation()
116
125
 
@@ -188,6 +188,10 @@ class AgentLoop:
188
188
  self.middleware_pipeline = MiddlewarePipeline()
189
189
  self._setup_middleware()
190
190
 
191
+ # Circuit breaker: track tool call signatures to prevent exact repeats
192
+ # Key: hash(tool_name + args), Value: (count, last_result_snippet)
193
+ self._tool_call_history: dict[str, tuple[int, str]] = {}
194
+
191
195
  system_prompt = get_universal_system_prompt(
192
196
  self.tool_manager, self.config, self.skill_manager, self.agent_manager
193
197
  )
@@ -831,9 +835,81 @@ class AgentLoop:
831
835
  )
832
836
  )
833
837
 
838
+ def _get_attempted_summary(self) -> str:
839
+ """Build a summary of what the agent has already tried."""
840
+ if not self._tool_call_history:
841
+ return ""
842
+ attempts = []
843
+ for sig, (count, result) in self._tool_call_history.items():
844
+ if count >= 2:
845
+ attempts.append(f" - Ran {count}x, result: {result[:80]}")
846
+ if attempts:
847
+ return "ALREADY ATTEMPTED (do NOT repeat):\n" + "\n".join(attempts[:10])
848
+ return ""
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."""
853
+ sig = hashlib.md5(
854
+ f"{tool_call.tool_name}:{tool_call.raw_arguments}".encode()
855
+ ).hexdigest()
856
+
857
+ count, last_result = self._tool_call_history.get(sig, (0, ""))
858
+ if count >= 2:
859
+ attempted = self._get_attempted_summary()
860
+ msg = (
861
+ f"CIRCUIT BREAKER: You already ran `{tool_call.tool_name}` with these "
862
+ f"exact arguments {count} times and got the same result each time.\n\n"
863
+ f"Previous result: {last_result[:200]}\n\n"
864
+ f"{attempted}\n\n"
865
+ f"STOP repeating. You MUST try something DIFFERENT:\n"
866
+ f"- Different arguments or search terms\n"
867
+ f"- A completely different tool\n"
868
+ f"- Ask the user for clarification"
869
+ )
870
+
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)
887
+
888
+ return msg
889
+ return None
890
+
891
+ def _circuit_breaker_record(self, tool_call: ResolvedToolCall, result_text: str) -> None:
892
+ """Record a tool call execution for circuit breaker tracking."""
893
+ sig = hashlib.md5(
894
+ f"{tool_call.tool_name}:{tool_call.raw_arguments}".encode()
895
+ ).hexdigest()
896
+ count, _ = self._tool_call_history.get(sig, (0, ""))
897
+ self._tool_call_history[sig] = (count + 1, result_text[:500])
898
+
834
899
  async def _process_one_tool_call(
835
900
  self, tool_call: ResolvedToolCall
836
901
  ) -> AsyncGenerator[ToolResultEvent | ToolStreamEvent]:
902
+ # Circuit breaker: block exact duplicate calls after 2 attempts
903
+ if blocked := await self._circuit_breaker_check(tool_call):
904
+ yield ToolResultEvent(
905
+ tool_name=tool_call.tool_name,
906
+ tool_class=tool_call.tool_class,
907
+ error=blocked,
908
+ tool_call_id=tool_call.call_id,
909
+ )
910
+ self._handle_tool_response(tool_call, blocked, "failure")
911
+ return
912
+
837
913
  try:
838
914
  tool_instance = self.tool_manager.get(tool_call.tool_name)
839
915
  except Exception as exc:
@@ -902,6 +978,8 @@ class AgentLoop:
902
978
 
903
979
  result_dict = result_model.model_dump()
904
980
  text = "\n".join(f"{k}: {v}" for k, v in result_dict.items())
981
+ # Record for circuit breaker
982
+ self._circuit_breaker_record(tool_call, text)
905
983
  self._handle_tool_response(
906
984
  tool_call, text, "success", decision, result_dict
907
985
  )
@@ -0,0 +1,141 @@
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"))
@@ -110,11 +110,25 @@ def _get_base_env() -> dict[str, str]:
110
110
 
111
111
  # Enable conda in non-interactive shells by setting BASH_ENV
112
112
  # to source conda's setup script. Without this, `conda activate`
113
- # fails because it's a shell function defined in .bashrc (which
114
- # isn't sourced for non-interactive shell commands).
113
+ # fails because it's a shell function defined in .bashrc.
114
+ #
115
+ # IMPORTANT: We also preserve the user's active conda env to avoid
116
+ # interfering with other environments and losing their aliases.
115
117
  conda_sh = _get_conda_setup_script()
116
118
  if conda_sh:
117
- base_env["BASH_ENV"] = conda_sh
119
+ # Create a wrapper that sources conda.sh then re-activates the user's env
120
+ active_env = os.environ.get("CONDA_DEFAULT_ENV", "")
121
+ if active_env and active_env != "base":
122
+ # Write a temp script that initializes conda AND activates the user's env
123
+ import tempfile
124
+ wrapper = tempfile.NamedTemporaryFile(
125
+ mode="w", suffix=".sh", delete=False, prefix="drydock_conda_"
126
+ )
127
+ wrapper.write(f'source "{conda_sh}"\nconda activate "{active_env}" 2>/dev/null\n')
128
+ wrapper.close()
129
+ base_env["BASH_ENV"] = wrapper.name
130
+ else:
131
+ base_env["BASH_ENV"] = conda_sh
118
132
 
119
133
  return base_env
120
134
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "drydock-cli"
3
- version = "0.5.2"
3
+ version = "0.6.1"
4
4
  description = "Drydock — nautical CLI coding agent"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -16,6 +16,7 @@ These catch the issues users find when actually using the application:
16
16
  from __future__ import annotations
17
17
 
18
18
  from pathlib import Path
19
+ from unittest.mock import patch
19
20
 
20
21
  import pytest
21
22
 
@@ -382,6 +383,84 @@ class TestDeviationHandling:
382
383
  assert "Auto-fix" in content or "Auto-resolve" in content
383
384
 
384
385
 
386
+ # ============================================================================
387
+ # Circuit Breaker
388
+ # ============================================================================
389
+
390
+ class TestCircuitBreaker:
391
+ """Prevents exact duplicate tool calls."""
392
+
393
+ def test_circuit_breaker_blocks_after_2(self):
394
+ import asyncio
395
+ from drydock.core.agent_loop import AgentLoop
396
+ from drydock.core.types import MessageList
397
+ from types import SimpleNamespace
398
+
399
+ al = object.__new__(AgentLoop)
400
+ al.messages = MessageList()
401
+ al._tool_call_history = {}
402
+
403
+ tc = SimpleNamespace(tool_name="bash", raw_arguments='{"command": "ls -ltr"}')
404
+
405
+ assert asyncio.run(al._circuit_breaker_check(tc)) is None
406
+ al._circuit_breaker_record(tc, "file1.py\nfile2.py")
407
+ assert asyncio.run(al._circuit_breaker_check(tc)) is None
408
+ al._circuit_breaker_record(tc, "file1.py\nfile2.py")
409
+
410
+ result = asyncio.run(al._circuit_breaker_check(tc))
411
+ assert result is not None
412
+ assert "CIRCUIT BREAKER" in result
413
+
414
+ def test_different_args_not_blocked(self):
415
+ import asyncio
416
+ from drydock.core.agent_loop import AgentLoop
417
+ from drydock.core.types import MessageList
418
+ from types import SimpleNamespace
419
+
420
+ al = object.__new__(AgentLoop)
421
+ al.messages = MessageList()
422
+ al._tool_call_history = {}
423
+
424
+ tc1 = SimpleNamespace(tool_name="bash", raw_arguments='{"command": "ls -ltr"}')
425
+ tc2 = SimpleNamespace(tool_name="bash", raw_arguments='{"command": "ls -la"}')
426
+
427
+ al._circuit_breaker_record(tc1, "result1")
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
431
+
432
+
433
+ # ============================================================================
434
+ # Insecure Flag
435
+ # ============================================================================
436
+
437
+ class TestInsecureFlag:
438
+ def test_insecure_flag_exists(self):
439
+ from drydock.cli.entrypoint import parse_arguments
440
+ import sys
441
+ with patch.object(sys, "argv", ["drydock", "-k", "-p", "test"]):
442
+ args = parse_arguments()
443
+ assert args.insecure is True
444
+
445
+ def test_consultant_flag_exists(self):
446
+ from drydock.cli.entrypoint import parse_arguments
447
+ import sys
448
+ with patch.object(sys, "argv", ["drydock", "--consultant", "gemini-2.5-pro", "-p", "test"]):
449
+ args = parse_arguments()
450
+ assert args.consultant == "gemini-2.5-pro"
451
+
452
+
453
+ # ============================================================================
454
+ # Thinking Flicker Throttle
455
+ # ============================================================================
456
+
457
+ class TestThinkingThrottle:
458
+ def test_status_change_interval_exists(self):
459
+ from drydock.cli.textual_ui.widgets.loading import LoadingWidget
460
+ assert hasattr(LoadingWidget, "_STATUS_CHANGE_INTERVAL")
461
+ assert LoadingWidget._STATUS_CHANGE_INTERVAL >= 3.0
462
+
463
+
385
464
  class TestEasterEggs:
386
465
  """Easter eggs are nautical, not French."""
387
466
 
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes