drydock-cli 0.7.2__tar.gz → 0.7.3__tar.gz

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