drydock-cli 2.7.8__tar.gz → 2.7.22__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 (677) hide show
  1. drydock_cli-2.7.22/.auto_release.lock +1 -0
  2. drydock_cli-2.7.22/.claude/scheduled_tasks.lock +1 -0
  3. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/PKG-INFO +1 -1
  4. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/admiral/detectors.py +28 -10
  5. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/admiral/detectors_proposed.py +9 -2
  6. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/agent_loop.py +62 -9
  7. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/llm/format.py +185 -4
  8. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/bash.py +65 -8
  9. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/read_file.py +74 -15
  10. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/search_replace.py +212 -42
  11. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/write_file.py +30 -0
  12. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/pyproject.toml +1 -1
  13. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/resume.md +13 -2
  14. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/auto_release.sh +26 -6
  15. drydock_cli-2.7.22/scripts/autonomous_review.sh +97 -0
  16. drydock_cli-2.7.22/scripts/autonomous_review_prompt.md +101 -0
  17. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/llm_balancer.py +5 -1
  18. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/stress_babysitter.sh +1 -2
  19. drydock_cli-2.7.22/tests/core/test_circuit_breaker_count_escalation.py +93 -0
  20. drydock_cli-2.7.22/tests/core/test_circuit_breaker_readonly_threshold.py +93 -0
  21. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_admiral_proposed.py +19 -0
  22. drydock_cli-2.7.22/tests/test_admiral_struggle_dedup.py +99 -0
  23. drydock_cli-2.7.22/tests/test_hallucinated_tool_suppression.py +87 -0
  24. drydock_cli-2.7.22/tests/test_read_file_not_found_listing.py +70 -0
  25. drydock_cli-2.7.22/tests/test_truncated_arg_path_hint.py +124 -0
  26. drydock_cli-2.7.22/tests/test_truncated_search_replace_escalation.py +76 -0
  27. drydock_cli-2.7.22/tests/test_truncated_write_escalation.py +104 -0
  28. drydock_cli-2.7.22/tests/test_write_file_missing_path.py +75 -0
  29. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/tools/test_bash.py +42 -10
  30. drydock_cli-2.7.22/tests/tools/test_read_file_dedup_reembed.py +136 -0
  31. drydock_cli-2.7.22/tests/tools/test_read_file_directory.py +65 -0
  32. drydock_cli-2.7.22/tests/tools/test_read_file_limit_truncation.py +76 -0
  33. drydock_cli-2.7.22/tests/tools/test_search_replace_dir_path.py +114 -0
  34. drydock_cli-2.7.22/tests/tools/test_search_replace_empty_content.py +90 -0
  35. drydock_cli-2.7.22/tests/tools/test_search_replace_hard_stop.py +136 -0
  36. drydock_cli-2.7.22/tests/tools/test_search_replace_no_op_loop_breaker.py +139 -0
  37. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/tools/test_search_replace_refused_loop_breaker.py +34 -33
  38. drydock_cli-2.7.22/tests/tools/test_write_file_dedup_missing_imports.py +103 -0
  39. drydock_cli-2.7.22/tests/tools/test_write_file_missing_path_hint.py +78 -0
  40. drydock_cli-2.7.22/trip_log.md +772 -0
  41. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/uv.lock +1 -1
  42. drydock_cli-2.7.8/.auto_release.lock +0 -1
  43. drydock_cli-2.7.8/.claude/scheduled_tasks.lock +0 -1
  44. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/.github/CODEOWNERS +0 -0
  45. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/.github/DISCUSSION_TEMPLATE/ideas.yml +0 -0
  46. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
  47. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  48. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/.github/workflows/build-and-upload.yml +0 -0
  49. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/.github/workflows/ci.yml +0 -0
  50. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/.github/workflows/issue-labeler.yml +0 -0
  51. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/.github/workflows/release.yml +0 -0
  52. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/.gitignore +0 -0
  53. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/.pre-commit-config.yaml +0 -0
  54. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/.python-version +0 -0
  55. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/.typos.toml +0 -0
  56. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/.vscode/extensions.json +0 -0
  57. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/.vscode/launch.json +0 -0
  58. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/.vscode/settings.json +0 -0
  59. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/AGENTS.md +0 -0
  60. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/Admiral.md +0 -0
  61. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/BASELINE_412.md +0 -0
  62. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/CHANGELOG.md +0 -0
  63. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/CLAUDE.md +0 -0
  64. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/CONTRIBUTING.md +0 -0
  65. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/DEPLOYMENT.md +0 -0
  66. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/Drydock_rebrand.md +0 -0
  67. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/LICENSE +0 -0
  68. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/MODEL_SHORTCOMINGS.md +0 -0
  69. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/NOTICE +0 -0
  70. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/OVERNIGHT_PROGRESS.md +0 -0
  71. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/OVERNIGHT_REPORT_2026_04_13.md +0 -0
  72. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/PRD.md +0 -0
  73. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/README.md +0 -0
  74. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/action.yml +0 -0
  75. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/baseline_history/README.md +0 -0
  76. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/baseline_history/results1.tsv +0 -0
  77. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/baseline_history/results13.tsv +0 -0
  78. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/baseline_history/results14.tsv +0 -0
  79. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/baseline_history/results15.tsv +0 -0
  80. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/baseline_history/results16.tsv +0 -0
  81. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/baseline_history/results17.tsv +0 -0
  82. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/baseline_history/results18.tsv +0 -0
  83. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/baseline_history/results19.tsv +0 -0
  84. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/baseline_history/results2.tsv +0 -0
  85. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/baseline_history/results20.tsv +0 -0
  86. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/baseline_history/results3.tsv +0 -0
  87. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/baseline_history/results4.tsv +0 -0
  88. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/baseline_history/results5.tsv +0 -0
  89. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/baseline_history/results6.tsv +0 -0
  90. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/baseline_history/results7.tsv +0 -0
  91. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/baseline_history/results8.tsv +0 -0
  92. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/baseline_history/results9.tsv +0 -0
  93. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/baseline_history/results_evolved_v1.tsv +0 -0
  94. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/distribution/zed/LICENSE +0 -0
  95. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/distribution/zed/extension.toml +0 -0
  96. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/distribution/zed/icons/mistral_vibe.svg +0 -0
  97. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/docs/README.md +0 -0
  98. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/docs/acp-setup.md +0 -0
  99. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/docs/proxy-setup.md +0 -0
  100. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/__init__.py +0 -0
  101. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/acp/__init__.py +0 -0
  102. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/acp/acp_agent_loop.py +0 -0
  103. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/acp/acp_logger.py +0 -0
  104. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/acp/entrypoint.py +0 -0
  105. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/acp/tools/__init__.py +0 -0
  106. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/acp/tools/base.py +0 -0
  107. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/acp/tools/builtins/bash.py +0 -0
  108. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/acp/tools/builtins/read_file.py +0 -0
  109. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/acp/tools/builtins/search_replace.py +0 -0
  110. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/acp/tools/builtins/todo.py +0 -0
  111. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/acp/tools/builtins/write_file.py +0 -0
  112. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/acp/tools/session_update.py +0 -0
  113. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/acp/utils.py +0 -0
  114. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/admiral/__init__.py +0 -0
  115. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/admiral/history.py +0 -0
  116. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/admiral/interventions.py +0 -0
  117. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/admiral/llm_analyzer.py +0 -0
  118. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/admiral/metrics.py +0 -0
  119. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/admiral/opus_escalator.py +0 -0
  120. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/admiral/persistence.py +0 -0
  121. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/admiral/policy.py +0 -0
  122. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/admiral/proposer.py +0 -0
  123. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/admiral/stager.py +0 -0
  124. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/admiral/task_classifier.py +0 -0
  125. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/admiral/tuning.py +0 -0
  126. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/admiral/validator.py +0 -0
  127. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/admiral/worker.py +0 -0
  128. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/__init__.py +0 -0
  129. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/autocompletion/__init__.py +0 -0
  130. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/autocompletion/base.py +0 -0
  131. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/autocompletion/path_completion.py +0 -0
  132. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/autocompletion/slash_command.py +0 -0
  133. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/cli.py +0 -0
  134. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/clipboard.py +0 -0
  135. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/commands.py +0 -0
  136. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/entrypoint.py +0 -0
  137. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/history_manager.py +0 -0
  138. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/plan_offer/adapters/http_whoami_gateway.py +0 -0
  139. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/plan_offer/decide_plan_offer.py +0 -0
  140. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/plan_offer/ports/whoami_gateway.py +0 -0
  141. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/terminal_setup.py +0 -0
  142. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/__init__.py +0 -0
  143. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/ansi_markdown.py +0 -0
  144. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/app.py +0 -0
  145. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/app.tcss +0 -0
  146. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/external_editor.py +0 -0
  147. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/handlers/__init__.py +0 -0
  148. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/handlers/event_handler.py +0 -0
  149. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/notifications/__init__.py +0 -0
  150. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/notifications/adapters/__init__.py +0 -0
  151. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/notifications/adapters/textual_notification_adapter.py +0 -0
  152. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/notifications/ports/__init__.py +0 -0
  153. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/notifications/ports/notification_port.py +0 -0
  154. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/__init__.py +0 -0
  155. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/approval_app.py +0 -0
  156. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/banner/banner.py +0 -0
  157. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/banner/petit_chat.py +0 -0
  158. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/braille_renderer.py +0 -0
  159. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/chat_input/__init__.py +0 -0
  160. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/chat_input/body.py +0 -0
  161. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/chat_input/completion_manager.py +0 -0
  162. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/chat_input/completion_popup.py +0 -0
  163. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/chat_input/container.py +0 -0
  164. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/chat_input/text_area.py +0 -0
  165. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/checkpoint_picker.py +0 -0
  166. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/compact.py +0 -0
  167. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/config_app.py +0 -0
  168. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/context_progress.py +0 -0
  169. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/load_more.py +0 -0
  170. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/loading.py +0 -0
  171. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/messages.py +0 -0
  172. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/no_markup_static.py +0 -0
  173. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/path_display.py +0 -0
  174. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/proxy_setup_app.py +0 -0
  175. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/question_app.py +0 -0
  176. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/session_picker.py +0 -0
  177. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/spinner.py +0 -0
  178. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/status_message.py +0 -0
  179. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/teleport_message.py +0 -0
  180. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/tool_widgets.py +0 -0
  181. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/tools.py +0 -0
  182. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/widgets/vscode_compat.py +0 -0
  183. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/windowing/__init__.py +0 -0
  184. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/windowing/history.py +0 -0
  185. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/windowing/history_windowing.py +0 -0
  186. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/textual_ui/windowing/state.py +0 -0
  187. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/update_notifier/__init__.py +0 -0
  188. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/update_notifier/adapters/filesystem_update_cache_repository.py +0 -0
  189. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/update_notifier/adapters/github_update_gateway.py +0 -0
  190. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/update_notifier/adapters/pypi_update_gateway.py +0 -0
  191. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/update_notifier/ports/update_cache_repository.py +0 -0
  192. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/update_notifier/ports/update_gateway.py +0 -0
  193. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/update_notifier/update.py +0 -0
  194. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/cli/update_notifier/whats_new.py +0 -0
  195. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/__init__.py +0 -0
  196. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/agents/__init__.py +0 -0
  197. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/agents/manager.py +0 -0
  198. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/agents/models.py +0 -0
  199. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/auth/__init__.py +0 -0
  200. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/auth/crypto.py +0 -0
  201. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/auth/github.py +0 -0
  202. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/autocompletion/__init__.py +0 -0
  203. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/autocompletion/completers.py +0 -0
  204. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/autocompletion/file_indexer/__init__.py +0 -0
  205. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/autocompletion/file_indexer/ignore_rules.py +0 -0
  206. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/autocompletion/file_indexer/indexer.py +0 -0
  207. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/autocompletion/file_indexer/store.py +0 -0
  208. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/autocompletion/file_indexer/watcher.py +0 -0
  209. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/autocompletion/fuzzy.py +0 -0
  210. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/autocompletion/path_prompt.py +0 -0
  211. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/autocompletion/path_prompt_adapter.py +0 -0
  212. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/build_orchestrator.py +0 -0
  213. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/checkpoint.py +0 -0
  214. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/config/__init__.py +0 -0
  215. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/config/_settings.py +0 -0
  216. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/config/doctor.py +0 -0
  217. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/config/harness_files/__init__.py +0 -0
  218. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/config/harness_files/_harness_manager.py +0 -0
  219. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/config/harness_files/_paths.py +0 -0
  220. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/consultant.py +0 -0
  221. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/drydock_states.py +0 -0
  222. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/hooks.py +0 -0
  223. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/llm/__init__.py +0 -0
  224. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/llm/backend/anthropic.py +0 -0
  225. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/llm/backend/base.py +0 -0
  226. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/llm/backend/factory.py +0 -0
  227. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/llm/backend/generic.py +0 -0
  228. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/llm/backend/mistral.py +0 -0
  229. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/llm/backend/reasoning_adapter.py +0 -0
  230. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/llm/backend/vertex.py +0 -0
  231. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/llm/exceptions.py +0 -0
  232. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/llm/message_utils.py +0 -0
  233. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/llm/types.py +0 -0
  234. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/logger.py +0 -0
  235. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/middleware.py +0 -0
  236. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/output_formatters.py +0 -0
  237. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/paths/__init__.py +0 -0
  238. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/paths/_drydock_home.py +0 -0
  239. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/paths/_local_config_walk.py +0 -0
  240. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/paths/conventions.py +0 -0
  241. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/plan_session.py +0 -0
  242. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/plugins.py +0 -0
  243. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/programmatic.py +0 -0
  244. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/prompts/__init__.py +0 -0
  245. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/prompts/builder.md +0 -0
  246. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/prompts/cli.md +0 -0
  247. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/prompts/compact.md +0 -0
  248. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/prompts/dangerous_directory.md +0 -0
  249. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/prompts/diagnostic.md +0 -0
  250. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/prompts/explore.md +0 -0
  251. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/prompts/gemma4.md +0 -0
  252. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/prompts/planner.md +0 -0
  253. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/prompts/project_context.md +0 -0
  254. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/prompts/tests.md +0 -0
  255. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/proxy_setup.py +0 -0
  256. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/session/agent_memory.py +0 -0
  257. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/session/checkpoints.py +0 -0
  258. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/session/session_loader.py +0 -0
  259. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/session/session_logger.py +0 -0
  260. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/session/session_migration.py +0 -0
  261. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/session/state_file.py +0 -0
  262. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/session_checker.py +0 -0
  263. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/skills/__init__.py +0 -0
  264. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/skills/manager.py +0 -0
  265. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/skills/models.py +0 -0
  266. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/skills/parser.py +0 -0
  267. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/slug.py +0 -0
  268. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/system_prompt.py +0 -0
  269. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/telemetry/__init__.py +0 -0
  270. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/telemetry/send.py +0 -0
  271. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/teleport/errors.py +0 -0
  272. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/teleport/git.py +0 -0
  273. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/teleport/nuage.py +0 -0
  274. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/teleport/teleport.py +0 -0
  275. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/teleport/types.py +0 -0
  276. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/base.py +0 -0
  277. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/_task_manager.py +0 -0
  278. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/ask_user_question.py +0 -0
  279. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/cron.py +0 -0
  280. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/exit_plan_mode.py +0 -0
  281. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/glob_tool.py +0 -0
  282. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/grep.py +0 -0
  283. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/invoke_skill.py +0 -0
  284. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/lsp.py +0 -0
  285. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/mcp_resources.py +0 -0
  286. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/notebook_edit.py +0 -0
  287. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/powershell.py +0 -0
  288. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/prompts/__init__.py +0 -0
  289. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/prompts/ask_user_question.md +0 -0
  290. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/prompts/bash.md +0 -0
  291. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/prompts/cron.md +0 -0
  292. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/prompts/glob.md +0 -0
  293. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/prompts/grep.md +0 -0
  294. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/prompts/invoke_skill.md +0 -0
  295. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/prompts/lsp.md +0 -0
  296. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/prompts/mcp_resources.md +0 -0
  297. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/prompts/notebook_edit.md +0 -0
  298. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/prompts/powershell.md +0 -0
  299. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/prompts/read_file.md +0 -0
  300. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/prompts/search_replace.md +0 -0
  301. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/prompts/swe_bench.md +0 -0
  302. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/prompts/task.md +0 -0
  303. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/prompts/task_manager.md +0 -0
  304. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/prompts/todo.md +0 -0
  305. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/prompts/tool_search.md +0 -0
  306. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/prompts/webfetch.md +0 -0
  307. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/prompts/websearch.md +0 -0
  308. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/prompts/worktree.md +0 -0
  309. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/prompts/write_file.md +0 -0
  310. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/task.py +0 -0
  311. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/todo.py +0 -0
  312. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/tool_search.py +0 -0
  313. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/webfetch.py +0 -0
  314. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/websearch.py +0 -0
  315. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/builtins/worktree.py +0 -0
  316. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/injection_guard.py +0 -0
  317. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/manager.py +0 -0
  318. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/mcp/__init__.py +0 -0
  319. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/mcp/registry.py +0 -0
  320. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/mcp/tools.py +0 -0
  321. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/mcp_sampling.py +0 -0
  322. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/ui.py +0 -0
  323. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/tools/utils.py +0 -0
  324. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/trusted_folders.py +0 -0
  325. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/types.py +0 -0
  326. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/core/utils.py +0 -0
  327. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/setup/onboarding/__init__.py +0 -0
  328. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/setup/onboarding/base.py +0 -0
  329. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/setup/onboarding/onboarding.tcss +0 -0
  330. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/setup/onboarding/screens/__init__.py +0 -0
  331. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/setup/onboarding/screens/api_key.py +0 -0
  332. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/setup/onboarding/screens/choice.py +0 -0
  333. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/setup/onboarding/screens/local_model.py +0 -0
  334. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/setup/onboarding/screens/welcome.py +0 -0
  335. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/setup/trusted_folders/trust_folder_dialog.py +0 -0
  336. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/setup/trusted_folders/trust_folder_dialog.tcss +0 -0
  337. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/__init__.py +0 -0
  338. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/api-design/SKILL.md +0 -0
  339. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/audit-tests/SKILL.md +0 -0
  340. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/batch/SKILL.md +0 -0
  341. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/commit-code/SKILL.md +0 -0
  342. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/context-summary/SKILL.md +0 -0
  343. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/create-presentation/SKILL.md +0 -0
  344. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/deep-research/SKILL.md +0 -0
  345. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/deploy/SKILL.md +0 -0
  346. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/diff-review/SKILL.md +0 -0
  347. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/doc-gen/SKILL.md +0 -0
  348. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/explain-code/SKILL.md +0 -0
  349. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/explore-code/SKILL.md +0 -0
  350. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/fix-issue/SKILL.md +0 -0
  351. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/git-ops/SKILL.md +0 -0
  352. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/init-project/SKILL.md +0 -0
  353. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/investigate/SKILL.md +0 -0
  354. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/loop/SKILL.md +0 -0
  355. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/migrate/SKILL.md +0 -0
  356. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/perf-analyze/SKILL.md +0 -0
  357. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/plan-impl/SKILL.md +0 -0
  358. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/pr-review/SKILL.md +0 -0
  359. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/refactor/SKILL.md +0 -0
  360. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/regex-help/SKILL.md +0 -0
  361. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/review/SKILL.md +0 -0
  362. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/security-review/SKILL.md +0 -0
  363. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/ship/SKILL.md +0 -0
  364. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/simplify/SKILL.md +0 -0
  365. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/strong-tests/SKILL.md +0 -0
  366. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/skills/test-verify/SKILL.md +0 -0
  367. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock/whats_new.md +0 -0
  368. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock-acp.spec +0 -0
  369. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/drydock_terms.md +0 -0
  370. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/flake.lock +0 -0
  371. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/flake.nix +0 -0
  372. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/nohup.out +0 -0
  373. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/research/README.md +0 -0
  374. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/research/config_base.toml +0 -0
  375. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/research/config_best.toml +0 -0
  376. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/research/domain_spec.md +0 -0
  377. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/research/experimenter.py +0 -0
  378. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/research/kernel.py +0 -0
  379. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/research/mini_prd.md +0 -0
  380. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/research/mini_prompts.txt +0 -0
  381. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/research/proposer.py +0 -0
  382. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/research/results.tsv +0 -0
  383. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/README.md +0 -0
  384. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/admiral_probe.py +0 -0
  385. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/audit_sampler.py +0 -0
  386. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/auto_generate_tests.py +0 -0
  387. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/auto_test_loop.sh +0 -0
  388. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/backup.sh +0 -0
  389. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/bump_version.py +0 -0
  390. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/comprehensive_loop.py +0 -0
  391. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/deploy_to_github.sh +0 -0
  392. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/discover_cli_tools.sh +0 -0
  393. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/evolve_tests.py +0 -0
  394. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/gen_2000_prompts.py +0 -0
  395. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/install.sh +0 -0
  396. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/mega_loop.py +0 -0
  397. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/meta_ralph_loop.py +0 -0
  398. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/monitor_swebench.sh +0 -0
  399. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/monitor_test_battery.sh +0 -0
  400. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/notify_release.py +0 -0
  401. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/oss_task_harness.py +0 -0
  402. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/overnight_agents_test.sh +0 -0
  403. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/poll_issues.sh +0 -0
  404. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/port_task.py +0 -0
  405. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/prepare_release.py +0 -0
  406. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/publish_to_pypi.sh +0 -0
  407. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/ralph_loop.py +0 -0
  408. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/research_babysitter.sh +0 -0
  409. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/session_loop_audit.py +0 -0
  410. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/shakedown.py +0 -0
  411. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/shakedown_interactive.py +0 -0
  412. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/shakedown_regression.sh +0 -0
  413. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/shakedown_suite.sh +0 -0
  414. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/shakedown_variance.sh +0 -0
  415. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/stress_prompts_50.txt +0 -0
  416. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/stress_prompts_realuser.txt +0 -0
  417. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/stress_prompts_tool_agent.txt +0 -0
  418. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/stress_prompts_tool_agent_2000.txt +0 -0
  419. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/stress_shakedown.py +0 -0
  420. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/stress_telegram_status.py +0 -0
  421. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/stress_watcher.py +0 -0
  422. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/telegram_bot.py +0 -0
  423. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/test_bank.sh +0 -0
  424. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/test_full.sh +0 -0
  425. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/test_smoke.sh +0 -0
  426. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/test_tui_path.py +0 -0
  427. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/tui_test.py +0 -0
  428. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/scripts/vllm_failover.sh +0 -0
  429. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/test/project/dummy +0 -0
  430. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/__init__.py +0 -0
  431. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/acp/conftest.py +0 -0
  432. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/acp/test_acp.py +0 -0
  433. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/acp/test_agent_thought.py +0 -0
  434. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/acp/test_bash.py +0 -0
  435. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/acp/test_compact_session_updates.py +0 -0
  436. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/acp/test_content.py +0 -0
  437. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/acp/test_initialize.py +0 -0
  438. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/acp/test_list_sessions.py +0 -0
  439. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/acp/test_load_session.py +0 -0
  440. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/acp/test_multi_session.py +0 -0
  441. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/acp/test_new_session.py +0 -0
  442. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/acp/test_proxy_setup_acp.py +0 -0
  443. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/acp/test_read_file.py +0 -0
  444. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/acp/test_search_replace.py +0 -0
  445. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/acp/test_set_config_option.py +0 -0
  446. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/acp/test_set_mode.py +0 -0
  447. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/acp/test_set_model.py +0 -0
  448. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/acp/test_tool_call_session_update.py +0 -0
  449. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/acp/test_utils.py +0 -0
  450. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/acp/test_write_file.py +0 -0
  451. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/autocompletion/test_file_indexer.py +0 -0
  452. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/autocompletion/test_fuzzy.py +0 -0
  453. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/autocompletion/test_path_completer_fuzzy.py +0 -0
  454. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/autocompletion/test_path_completer_recursive.py +0 -0
  455. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/autocompletion/test_path_completion_controller.py +0 -0
  456. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/autocompletion/test_path_prompt_transformer.py +0 -0
  457. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/autocompletion/test_slash_command_controller.py +0 -0
  458. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/autocompletion/test_ui_chat_autocompletion.py +0 -0
  459. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/backend/__init__.py +0 -0
  460. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/backend/data/__init__.py +0 -0
  461. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/backend/data/fireworks.py +0 -0
  462. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/backend/data/mistral.py +0 -0
  463. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/backend/test_anthropic_adapter.py +0 -0
  464. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/backend/test_backend.py +0 -0
  465. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/backend/test_generic_adapter_sanitize.py +0 -0
  466. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/backend/test_reasoning_adapter.py +0 -0
  467. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/backend/test_vertex_anthropic_adapter.py +0 -0
  468. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/cli/plan_offer/adapters/fake_whoami_gateway.py +0 -0
  469. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/cli/plan_offer/test_decide_plan_offer.py +0 -0
  470. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/cli/plan_offer/test_http_whoami_gateway.py +0 -0
  471. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/cli/test_bell_notifications.py +0 -0
  472. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/cli/test_braille_renderer.py +0 -0
  473. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/cli/test_clipboard.py +0 -0
  474. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/cli/test_commands.py +0 -0
  475. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/cli/test_copy_shortcuts.py +0 -0
  476. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/cli/test_external_editor.py +0 -0
  477. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/cli/test_no_markup_static.py +0 -0
  478. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/cli/test_question_app.py +0 -0
  479. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/cli/test_spinner.py +0 -0
  480. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/cli/test_switching_mode.py +0 -0
  481. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/cli/test_ui_clipboard_notifications.py +0 -0
  482. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/cli/test_ui_session_incremental_renderer.py +0 -0
  483. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/cli/test_ui_session_resume.py +0 -0
  484. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/cli/test_ui_skill_dispatch.py +0 -0
  485. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/cli/textual_ui/__init__.py +0 -0
  486. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/cli/textual_ui/test_session_picker.py +0 -0
  487. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/conftest.py +0 -0
  488. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/core/test_agents.py +0 -0
  489. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/core/test_auth_crypto.py +0 -0
  490. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/core/test_auth_github.py +0 -0
  491. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/core/test_config_load_dotenv.py +0 -0
  492. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/core/test_config_paths.py +0 -0
  493. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/core/test_config_resolution.py +0 -0
  494. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/core/test_file_logging.py +0 -0
  495. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/core/test_plan_session.py +0 -0
  496. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/core/test_proxy_setup.py +0 -0
  497. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/core/test_slug.py +0 -0
  498. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/core/test_telemetry_send.py +0 -0
  499. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/core/test_teleport_git.py +0 -0
  500. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/core/test_teleport_nuage.py +0 -0
  501. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/core/test_teleport_service.py +0 -0
  502. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/core/test_trusted_folders.py +0 -0
  503. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/core/test_utils.py +0 -0
  504. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/e2e/common.py +0 -0
  505. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/e2e/conftest.py +0 -0
  506. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/e2e/mock_server.py +0 -0
  507. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/e2e/test_cli_tui_onboarding.py +0 -0
  508. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/e2e/test_cli_tui_streaming.py +0 -0
  509. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/e2e/test_cli_tui_tool_approval.py +0 -0
  510. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/fixtures/doc_qa_system_prd.md +0 -0
  511. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/mock/__init__.py +0 -0
  512. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/mock/mock_backend_factory.py +0 -0
  513. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/mock/mock_entrypoint.py +0 -0
  514. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/mock/utils.py +0 -0
  515. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/onboarding/test_run_onboarding.py +0 -0
  516. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/onboarding/test_ui_onboarding.py +0 -0
  517. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/session/test_session_loader.py +0 -0
  518. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/session/test_session_logger.py +0 -0
  519. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/session/test_session_migration.py +0 -0
  520. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/skills/conftest.py +0 -0
  521. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/skills/test_manager.py +0 -0
  522. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/skills/test_models.py +0 -0
  523. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/skills/test_parser.py +0 -0
  524. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_ask_user_question/test_snapshot_ask_user_question_collapsed.svg +0 -0
  525. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_ask_user_question/test_snapshot_ask_user_question_expanded.svg +0 -0
  526. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_basic_conversation/test_snapshot_shows_basic_conversation.svg +0 -0
  527. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_code_block_horizontal_scrolling/test_snapshot_allows_horizontal_scrolling_for_long_code_blocks.svg +0 -0
  528. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_empty_assistant_before_reasoning/test_snapshot_empty_assistant_removed_when_reasoning_starts.svg +0 -0
  529. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_cycle_to_accept_edits_mode.svg +0 -0
  530. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_cycle_to_auto_approve_mode.svg +0 -0
  531. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_cycle_to_plan_mode.svg +0 -0
  532. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_cycle_wraps_to_default.svg +0 -0
  533. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_modes/test_snapshot_default_mode.svg +0 -0
  534. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_parallel_tool_calls/test_snapshot_parallel_tool_calls_pending.svg +0 -0
  535. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_parallel_tool_calls/test_snapshot_parallel_tool_calls_resolved.svg +0 -0
  536. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_cancel_discards_changes.svg +0 -0
  537. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_edit_existing_values.svg +0 -0
  538. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_initial_empty.svg +0 -0
  539. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_initial_with_values.svg +0 -0
  540. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_save_error.svg +0 -0
  541. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_proxy_setup/test_snapshot_proxy_setup_save_new_values.svg +0 -0
  542. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_answer_first_advance.svg +0 -0
  543. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_first_answered_checkmark.svg +0 -0
  544. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_initial.svg +0 -0
  545. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_navigate_left_wraps.svg +0 -0
  546. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_navigate_right.svg +0 -0
  547. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_question_tab_to_second.svg +0 -0
  548. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_initial.svg +0 -0
  549. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_mixed_selection.svg +0 -0
  550. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_navigate_to_submit.svg +0 -0
  551. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_other_with_text.svg +0 -0
  552. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_toggle_first.svg +0 -0
  553. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_toggle_multiple.svg +0 -0
  554. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_multi_select_untoggle.svg +0 -0
  555. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_initial.svg +0 -0
  556. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_navigate_down.svg +0 -0
  557. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_navigate_to_other.svg +0 -0
  558. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_navigate_to_third_option.svg +0 -0
  559. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_navigate_up_wraps.svg +0 -0
  560. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_question_app/test_snapshot_question_app_other_typing.svg +0 -0
  561. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_reasoning_content/test_snapshot_buffered_reasoning_yields_before_content.svg +0 -0
  562. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_reasoning_content/test_snapshot_shows_interleaved_reasoning.svg +0 -0
  563. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_reasoning_content/test_snapshot_shows_reasoning_content.svg +0 -0
  564. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_reasoning_content/test_snapshot_shows_reasoning_content_expanded.svg +0 -0
  565. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_release_update_notification/test_snapshot_shows_release_update_notification.svg +0 -0
  566. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_session_resume/test_snapshot_shows_resumed_session_messages.svg +0 -0
  567. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_streaming_tool_call/test_snapshot_tool_call_partial.svg +0 -0
  568. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_streaming_tool_call/test_snapshot_tool_call_updated.svg +0 -0
  569. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_push_confirmation_cancel_selected.svg +0 -0
  570. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_push_confirmation_multiple_commits.svg +0 -0
  571. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_push_confirmation_single_commit.svg +0 -0
  572. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_auth_complete.svg +0 -0
  573. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_auth_required.svg +0 -0
  574. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_checking_git.svg +0 -0
  575. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_complete.svg +0 -0
  576. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_error.svg +0 -0
  577. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_pushing.svg +0 -0
  578. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_sending_token.svg +0 -0
  579. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_teleport/test_snapshot_teleport_status_starting_workflow.svg +0 -0
  580. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_whats_new/test_snapshot_shows_no_plan_message.svg +0 -0
  581. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_whats_new/test_snapshot_shows_switch_message.svg +0 -0
  582. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_whats_new/test_snapshot_shows_upgrade_message.svg +0 -0
  583. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/__snapshots__/test_ui_snapshot_whats_new/test_snapshot_shows_whats_new_message.svg +0 -0
  584. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/base_snapshot_test_app.py +0 -0
  585. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/conftest.py +0 -0
  586. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/snap_compare.py +0 -0
  587. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/test_ui_snapshot_ask_user_question.py +0 -0
  588. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/test_ui_snapshot_basic_conversation.py +0 -0
  589. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/test_ui_snapshot_code_block_horizontal_scrolling.py +0 -0
  590. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/test_ui_snapshot_empty_assistant_before_reasoning.py +0 -0
  591. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/test_ui_snapshot_modes.py +0 -0
  592. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/test_ui_snapshot_parallel_tool_calls.py +0 -0
  593. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/test_ui_snapshot_proxy_setup.py +0 -0
  594. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/test_ui_snapshot_question_app.py +0 -0
  595. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/test_ui_snapshot_reasoning_content.py +0 -0
  596. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/test_ui_snapshot_release_update_notification.py +0 -0
  597. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/test_ui_snapshot_session_resume.py +0 -0
  598. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/test_ui_snapshot_streaming_tool_call.py +0 -0
  599. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/test_ui_snapshot_teleport.py +0 -0
  600. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/snapshots/test_ui_snapshot_whats_new.py +0 -0
  601. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/stubs/fake_backend.py +0 -0
  602. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/stubs/fake_client.py +0 -0
  603. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/stubs/fake_tool.py +0 -0
  604. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_admiral.py +0 -0
  605. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_admiral_phase3.py +0 -0
  606. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_agent_auto_compact.py +0 -0
  607. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_agent_backend.py +0 -0
  608. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_agent_observer_streaming.py +0 -0
  609. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_agent_stats.py +0 -0
  610. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_agent_tasks.py +0 -0
  611. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_agent_tool_call.py +0 -0
  612. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_agents.py +0 -0
  613. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_bank_build.py +0 -0
  614. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_bank_debug.py +0 -0
  615. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_bank_multiagent.py +0 -0
  616. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_bank_prd.py +0 -0
  617. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_bank_prd_extended.py +0 -0
  618. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_bank_tools.py +0 -0
  619. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_bank_update.py +0 -0
  620. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_build_projects.py +0 -0
  621. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_checkpoint.py +0 -0
  622. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_cli_programmatic_preload.py +0 -0
  623. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_current_bugs.py +0 -0
  624. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_drydock_regression.py +0 -0
  625. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_drydock_tasks.py +0 -0
  626. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_fake_tool_call_paren_syntax.py +0 -0
  627. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_full_regression.py +0 -0
  628. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_history_manager.py +0 -0
  629. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_integration.py +0 -0
  630. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_issue_fixes.py +0 -0
  631. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_loop_detection.py +0 -0
  632. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_message_id.py +0 -0
  633. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_message_merging.py +0 -0
  634. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_middleware.py +0 -0
  635. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_multi_agent.py +0 -0
  636. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_real_failures.py +0 -0
  637. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_real_issues.py +0 -0
  638. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_real_workflow.py +0 -0
  639. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_reasoning_content.py +0 -0
  640. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_smoke.py +0 -0
  641. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_system_prompt.py +0 -0
  642. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_tagged_text.py +0 -0
  643. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_tool_args.py +0 -0
  644. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_truncate_args_valid_json.py +0 -0
  645. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_ui_external_editor.py +0 -0
  646. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_ui_input_history.py +0 -0
  647. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_user_issues.py +0 -0
  648. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_wall_of_text_rescue.py +0 -0
  649. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/test_workloads.py +0 -0
  650. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/testbank_helpers.py +0 -0
  651. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/tools/test_ask_user_question.py +0 -0
  652. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/tools/test_exit_plan_mode.py +0 -0
  653. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/tools/test_grep.py +0 -0
  654. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/tools/test_invoke_context.py +0 -0
  655. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/tools/test_manager_gemma_derived_models.py +0 -0
  656. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/tools/test_manager_get_tool_config.py +0 -0
  657. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/tools/test_mcp.py +0 -0
  658. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/tools/test_mcp_sampling.py +0 -0
  659. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/tools/test_search_replace_append_fallback.py +0 -0
  660. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/tools/test_task.py +0 -0
  661. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/tools/test_ui_bash_execution.py +0 -0
  662. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/tools/test_webfetch.py +0 -0
  663. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/tools/test_websearch.py +0 -0
  664. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/update_notifier/adapters/fake_update_cache_repository.py +0 -0
  665. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/update_notifier/adapters/fake_update_gateway.py +0 -0
  666. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/update_notifier/test_do_update.py +0 -0
  667. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/update_notifier/test_filesystem_update_cache_repository.py +0 -0
  668. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/update_notifier/test_github_update_gateway.py +0 -0
  669. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/update_notifier/test_pypi_update_gateway.py +0 -0
  670. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/update_notifier/test_ui_update_notification.py +0 -0
  671. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/update_notifier/test_update_use_case.py +0 -0
  672. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/tests/update_notifier/test_whats_new.py +0 -0
  673. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/worked_examples/README.md +0 -0
  674. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/worked_examples/cli_subcommand_dispatch.py +0 -0
  675. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/worked_examples/lookup.json +0 -0
  676. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/worked_examples/sql_parser.py +0 -0
  677. {drydock_cli-2.7.8 → drydock_cli-2.7.22}/worked_examples/tree_walking_interpreter.py +0 -0
@@ -0,0 +1 @@
1
+ 522842
@@ -0,0 +1 @@
1
+ {"sessionId":"facd51cc-fa47-4911-afc8-14485ae9caf3","pid":711220,"acquiredAt":1775966390914}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: drydock-cli
3
- Version: 2.7.8
3
+ Version: 2.7.22
4
4
  Summary: Local-first CLI coding agent — tested with Gemma 4 26B via vLLM
5
5
  Project-URL: Homepage, https://github.com/fbobe321/drydock
6
6
  Project-URL: Repository, https://github.com/fbobe321/drydock
@@ -80,18 +80,36 @@ def detect_struggle(messages: Sequence[LLMMessage], threshold: int = 20) -> Find
80
80
  calls_since_write += 1
81
81
  if calls_since_write < threshold:
82
82
  return None
83
- hint = (
84
- "Either (a) you already have enough context commit to a plan and "
85
- "start writing code now, or (b) you're genuinely stuck stop and "
86
- "report what's blocking you to the user."
87
- )
88
- return Finding(
89
- code=f"struggle:{calls_since_write}:{last_write_tool or 'none'}",
90
- directive=(
83
+ # Stable code (no count) so DEDUP_WINDOW_SEC suppresses repeated firings.
84
+ # Previously included the count, which caused 33 identical interventions
85
+ # in a single session (each with a unique key that bypassed dedup).
86
+ code = f"struggle:{last_write_tool or 'none'}"
87
+ if calls_since_write >= 30:
88
+ if last_write_tool is None:
89
+ directive = (
90
+ f"Admiral: you have made {calls_since_write} tool calls without "
91
+ f"writing a single file. You have enough context. STOP exploring "
92
+ f"and start writing code NOW. Call `write_file` to create your "
93
+ f"first file immediately."
94
+ )
95
+ else:
96
+ directive = (
97
+ f"Admiral: you have made {calls_since_write} tool calls without "
98
+ f"writing any file — search_replace is clearly not finding the text. "
99
+ f"STOP retrying. Call `write_file` with `overwrite=True` to rewrite "
100
+ f"the target file from scratch right now."
101
+ )
102
+ else:
103
+ hint = (
104
+ "Either (a) you already have enough context — commit to a plan and "
105
+ "start writing code now, or (b) you're genuinely stuck — stop and "
106
+ "report what's blocking you to the user."
107
+ )
108
+ directive = (
91
109
  f"Admiral: you have made {calls_since_write} tool calls without "
92
110
  f"writing or editing any file. {hint}"
93
- ),
94
- )
111
+ )
112
+ return Finding(code=code, directive=directive)
95
113
 
96
114
 
97
115
  def run_all(messages: Sequence[LLMMessage]) -> list[Finding]:
@@ -43,11 +43,18 @@ def _tool_result_errored(m: LLMMessage) -> bool:
43
43
  """Heuristic: does this tool-role message look like a failure?
44
44
 
45
45
  Conservative — we only want high-precision firing on actual errors.
46
- Scanned the first 800 chars of the result content.
46
+ Scanned the first 200 chars of the result content (tightened from 800
47
+ to avoid false positives when matched file content contains words like
48
+ "error" or "failed" — grep results starting with "matches:" are always
49
+ successful).
47
50
  """
48
51
  if m.role is not Role.tool:
49
52
  return False
50
- content = str(getattr(m, "content", "") or "")[:800].lower()
53
+ raw = str(getattr(m, "content", "") or "")
54
+ # Successful grep results start with "matches:" — never treat as error.
55
+ if raw.lstrip().startswith("matches:"):
56
+ return False
57
+ content = raw[:200].lower()
51
58
  return any(marker in content for marker in _TOOL_ERROR_MARKERS)
52
59
 
53
60
 
@@ -1131,10 +1131,12 @@ class AgentLoop:
1131
1131
  token-level sampling bumps don't help when the model picks
1132
1132
  the SAME serialized args every time.
1133
1133
 
1134
- Conservative thresholds only fires on truly pathological
1135
- repeat counts that would never be a "valid retry":
1134
+ Thresholds tuned for 45-prompt session windows (stress sessions
1135
+ reset every 45 prompts — a threshold of 12 never fires in practice
1136
+ because the model loops 4-8 times then moves on; admiral advisories
1137
+ fire at 3 but the model ignores them):
1136
1138
  search_replace, write_file, bash: after 8 identical calls
1137
- read_file, grep, glob, ls: after 12 identical calls
1139
+ read_file, grep, glob, ls: after 5 identical calls
1138
1140
  """
1139
1141
  args_str = json.dumps(tool_call.args_dict, sort_keys=True, default=str)
1140
1142
  sig = hashlib.sha256(
@@ -1143,9 +1145,13 @@ class AgentLoop:
1143
1145
  count, last_result = self._tool_call_history.get(sig, (0, ""))
1144
1146
  tool_name = tool_call.tool_name
1145
1147
  is_readonly = tool_name in ("grep", "read_file", "glob", "ls")
1146
- threshold = 12 if is_readonly else 8
1148
+ threshold = 5 if is_readonly else 8
1147
1149
  if count < threshold:
1148
1150
  return None
1151
+ # Increment so the count escalates on every repeated fire, giving the
1152
+ # model a growing signal that nothing has changed. Preserve last_result
1153
+ # so the message always shows the real bash/tool output, not a prior NOTE.
1154
+ self._tool_call_history[sig] = (count + 1, last_result)
1149
1155
  return (
1150
1156
  f"NOTE: this exact call to `{tool_name}` has been made "
1151
1157
  f"{count} times this session with identical arguments. "
@@ -1505,9 +1511,23 @@ class AgentLoop:
1505
1511
  self.stats.tool_calls_failed += 1
1506
1512
  self._handle_tool_response(tool_call, error_msg, "failure", decision)
1507
1513
 
1514
+ def _silence_suppressed_failures(self, suppressed: list) -> None:
1515
+ """Add tool result messages for hallucinated tools without TUI events.
1516
+
1517
+ Keeps message history well-formed (assistant tool_call → tool result)
1518
+ while hiding the error from the TUI to avoid confusing the user.
1519
+ """
1520
+ for failed in suppressed:
1521
+ error_msg = f"<{TOOL_ERROR_TAG}>{failed.tool_name}: {failed.error}</{TOOL_ERROR_TAG}>"
1522
+ self.messages.append(
1523
+ self.format_handler.create_failed_tool_response_message(failed, error_msg)
1524
+ )
1525
+ self.stats.tool_calls_failed += 1
1526
+
1508
1527
  async def _handle_tool_calls(
1509
1528
  self, resolved: ResolvedMessage
1510
1529
  ) -> AsyncGenerator[ToolCallEvent | ToolResultEvent | ToolStreamEvent | AssistantEvent]:
1530
+ self._silence_suppressed_failures(resolved.suppressed_failures)
1511
1531
  async for event in self._emit_failed_tool_events(resolved.failed_calls):
1512
1532
  yield event
1513
1533
  for tool_call in resolved.tool_calls:
@@ -1703,10 +1723,10 @@ class AgentLoop:
1703
1723
  Runs every turn but is a no-op when nothing exceeds the caps.
1704
1724
  Truncation is in-place and idempotent.
1705
1725
  """
1706
- KEEP_RECENT = 6 # last N tool messages stay full
1707
- SOFT_CAP_BYTES = 800 # tool result longer than this gets shrunk
1708
- HEAD_BYTES = 400 # bytes kept from the head
1709
- TAIL_BYTES = 100 # bytes kept from the tail
1726
+ KEEP_RECENT = 4 # last N tool messages stay full
1727
+ SOFT_CAP_BYTES = 500 # tool result longer than this gets shrunk
1728
+ HEAD_BYTES = 200 # bytes kept from the head
1729
+ TAIL_BYTES = 60 # bytes kept from the tail
1710
1730
 
1711
1731
  if len(self.messages) < KEEP_RECENT + 4:
1712
1732
  return
@@ -2334,7 +2354,16 @@ class AgentLoop:
2334
2354
  if replace_last_tool:
2335
2355
  msg.content = f"[SYSTEM: {text}]"
2336
2356
  else:
2337
- msg.content = (msg.content or "") + f"\n\n[SYSTEM: {text}]"
2357
+ content = msg.content or ""
2358
+ # Cap at 2 accumulated system notes per message; replace the
2359
+ # last one when the limit is exceeded so repeated admiral
2360
+ # interventions don't unboundedly bloat the context.
2361
+ _SYS_PREFIX = "\n\n[SYSTEM: "
2362
+ if content.count(_SYS_PREFIX) >= 2:
2363
+ last_idx = content.rfind(_SYS_PREFIX)
2364
+ msg.content = content[:last_idx] + _SYS_PREFIX + text + "]"
2365
+ else:
2366
+ msg.content = content + _SYS_PREFIX + text + "]"
2338
2367
  return
2339
2368
 
2340
2369
  # Second try: append to last user message
@@ -2370,6 +2399,30 @@ class AgentLoop:
2370
2399
  if len(recent_sr) >= 2 and recent_sr[0] == recent_sr[1]:
2371
2400
  return "WARNING|search_replace"
2372
2401
 
2402
+ # Early check: write_file with _truncated args twice in a row for the
2403
+ # same path. format.py already embeds the file content in the error,
2404
+ # but Gemma 4 ignores the advisory and retries identically. Mute
2405
+ # write_file for 1 turn so the model must use read_file or
2406
+ # search_replace instead — same pattern as the search_replace check.
2407
+ recent_wf_truncated: list[str] = []
2408
+ for msg in reversed(self.messages[-20:]):
2409
+ if msg.role == Role.assistant and msg.tool_calls:
2410
+ for tc in msg.tool_calls:
2411
+ if tc.function and tc.function.name == "write_file":
2412
+ try:
2413
+ args = json.loads(tc.function.arguments or "{}")
2414
+ if args.get("_truncated"):
2415
+ p = (args.get("file_path") or args.get("path") or "")
2416
+ recent_wf_truncated.append(p)
2417
+ except (json.JSONDecodeError, AttributeError):
2418
+ pass
2419
+ if len(recent_wf_truncated) >= 2:
2420
+ break
2421
+ if (len(recent_wf_truncated) >= 2
2422
+ and recent_wf_truncated[0] == recent_wf_truncated[1]):
2423
+ self._hot_tool_path = ("write_file", recent_wf_truncated[0])
2424
+ return "FORCE_STOP"
2425
+
2373
2426
  sigs: list[str] = []
2374
2427
  tool_names: list[str] = []
2375
2428
  lookback = 0
@@ -3,6 +3,7 @@ from __future__ import annotations
3
3
  import json
4
4
  import logging
5
5
  import re as _re
6
+ from pathlib import Path
6
7
  from typing import TYPE_CHECKING, Any
7
8
 
8
9
  from pydantic import BaseModel, ConfigDict, Field, ValidationError
@@ -165,9 +166,17 @@ class ResolvedMessage(BaseModel):
165
166
  model_config = ConfigDict(frozen=True)
166
167
  tool_calls: list[ResolvedToolCall]
167
168
  failed_calls: list[FailedToolCall] = Field(default_factory=list)
169
+ # Hallucinated tools: need a tool result in message history (to keep the
170
+ # conversation well-formed) but should NOT be shown as errors in the TUI.
171
+ suppressed_failures: list[FailedToolCall] = Field(default_factory=list)
168
172
 
169
173
 
170
174
  class APIToolFormatHandler:
175
+ def __init__(self) -> None:
176
+ # Track per-path truncated-history write_file retries so we can
177
+ # escalate on 2nd+ identical failures (model ignores advisory-only msgs).
178
+ self._truncated_hit_count: dict[str, int] = {}
179
+
171
180
  @property
172
181
  def name(self) -> str:
173
182
  return "api"
@@ -346,12 +355,25 @@ class APIToolFormatHandler:
346
355
  "list_mcp_resources", "list_resources", "search_resources",
347
356
  }
348
357
 
358
+ suppressed_failures = []
349
359
  for parsed_call in parsed.tool_calls:
350
360
  tool_class = active_tools.get(parsed_call.tool_name)
351
361
  if not tool_class:
352
- # Silently drop known hallucinated tools instead of
353
- # showing an error in the TUI
362
+ # Hallucinated tools: add a tool result to keep the message
363
+ # history well-formed (prevents empty_after_tool loops) but
364
+ # route to suppressed_failures so the TUI doesn't show an error.
354
365
  if parsed_call.tool_name in _IGNORE_TOOLS:
366
+ suppressed_failures.append(
367
+ FailedToolCall(
368
+ tool_name=parsed_call.tool_name,
369
+ call_id=parsed_call.call_id,
370
+ error=(
371
+ f"'{parsed_call.tool_name}' is not available. "
372
+ f"Use only tools from your tool list: "
373
+ f"{', '.join(sorted(active_tools.keys())[:8])}."
374
+ ),
375
+ )
376
+ )
355
377
  continue
356
378
  failed_calls.append(
357
379
  FailedToolCall(
@@ -367,6 +389,102 @@ class APIToolFormatHandler:
367
389
  continue
368
390
 
369
391
  args_model, _ = tool_class._get_tool_args_results()
392
+
393
+ # Detect when model copied truncated-history args (our truncation
394
+ # code replaces large tool-call args with {_truncated, _original_bytes,
395
+ # path}). Return a clear advisory instead of a pydantic traceback so
396
+ # the model re-does the call with real arguments rather than retrying
397
+ # the truncated form.
398
+ if (isinstance(parsed_call.raw_args, dict)
399
+ and parsed_call.raw_args.get("_truncated")):
400
+ path_hint = (parsed_call.raw_args.get("path")
401
+ or parsed_call.raw_args.get("file_path")
402
+ or "")
403
+ # Track retry count per path to escalate on 2nd+ offense.
404
+ hit_key = path_hint or "<unknown>"
405
+ hit_count = self._truncated_hit_count.get(hit_key, 0) + 1
406
+ self._truncated_hit_count[hit_key] = hit_count
407
+ escalate = hit_count >= 2
408
+
409
+ # Auto-embed the current file content so the model can
410
+ # rewrite immediately without an extra read_file round-trip.
411
+ file_embed = ""
412
+ if path_hint:
413
+ try:
414
+ p = Path(path_hint)
415
+ if p.exists() and p.is_file():
416
+ raw = p.read_text(errors="replace")
417
+ lines = raw.splitlines()
418
+ max_lines = 120
419
+ if len(lines) <= max_lines:
420
+ file_embed = (
421
+ f"\n\nCurrent file content of `{path_hint}`:\n"
422
+ f"```\n{raw}\n```\n"
423
+ f"Rewrite it now using write_file with the correct content."
424
+ )
425
+ else:
426
+ snippet = "\n".join(lines[:max_lines])
427
+ file_embed = (
428
+ f"\n\nCurrent file content of `{path_hint}` "
429
+ f"(first {max_lines} of {len(lines)} lines):\n"
430
+ f"```\n{snippet}\n```\n"
431
+ f"Use read_file to see the rest, then rewrite with write_file."
432
+ )
433
+ except Exception:
434
+ pass
435
+ if not file_embed and path_hint:
436
+ file_embed = f" Re-read `{path_hint}` with read_file first."
437
+
438
+ if escalate:
439
+ # Model is stuck in a truncated-template retry loop.
440
+ # Show project files and give a concrete directive.
441
+ try:
442
+ py_files = sorted(
443
+ str(p2.relative_to(Path.cwd()))
444
+ for p2 in Path.cwd().rglob("*.py")
445
+ if "__pycache__" not in str(p2) and ".git" not in str(p2)
446
+ )[:20]
447
+ dir_listing = "\n".join(f" {f}" for f in py_files)
448
+ except Exception:
449
+ dir_listing = " (could not list files)"
450
+ tool_name_hint = parsed_call.tool_name
451
+ if tool_name_hint == "search_replace":
452
+ recovery_hint = (
453
+ f"Use read_file on '{path_hint}' to see its current content, "
454
+ f"then call search_replace with fresh <<<<<<< SEARCH / ======= / "
455
+ f">>>>>>> REPLACE markers copied from the actual file text."
456
+ )
457
+ else:
458
+ recovery_hint = (
459
+ f"Use read_file on the target file, then call write_file "
460
+ f"with fully typed content, OR use search_replace to make "
461
+ f"targeted edits without rewriting the whole file."
462
+ )
463
+ escalation_suffix = (
464
+ f"\n\n[REPEATED FAILURE #{hit_count}: your {tool_name_hint} call "
465
+ f"keeps using a stale truncated template for '{path_hint}'. "
466
+ f"You MUST NOT copy args from history. "
467
+ f"Current .py files in project:\n{dir_listing}\n"
468
+ f"{recovery_hint}]"
469
+ )
470
+ else:
471
+ escalation_suffix = ""
472
+
473
+ failed_calls.append(
474
+ FailedToolCall(
475
+ tool_name=parsed_call.tool_name,
476
+ call_id=parsed_call.call_id,
477
+ error=(
478
+ f"your call used a "
479
+ f"truncated history entry as a template (it contained "
480
+ f"'_truncated'/'_original_bytes' instead of real "
481
+ f"arguments).{file_embed} Provide the full required "
482
+ f"arguments.{escalation_suffix}"
483
+ ),
484
+ )
485
+ )
486
+ continue
487
+
370
488
  try:
371
489
  validated_args = args_model.model_validate(parsed_call.raw_args)
372
490
  resolved_calls.append(
@@ -378,15 +496,78 @@ class APIToolFormatHandler:
378
496
  )
379
497
  )
380
498
  except ValidationError as e:
499
+ error_str = str(e)
500
+ if (
501
+ parsed_call.tool_name == "write_file"
502
+ and "path" in error_str
503
+ and "Field required" in error_str
504
+ ):
505
+ # Try to infer path from the first comment line of content.
506
+ # Gemma 4 frequently calls write_file(content="...") without path.
507
+ content_val = parsed_call.raw_args.get("content", "")
508
+ inferred_path: str | None = None
509
+ if content_val:
510
+ for _line in content_val.splitlines()[:5]:
511
+ _line = _line.strip()
512
+ _m = _re.match(
513
+ r'^#\s+([\w./+-]+\.(?:py|js|ts|json|yaml|yml|toml|md|txt|sh|cfg|ini))\s*$',
514
+ _line,
515
+ )
516
+ if _m:
517
+ inferred_path = _m.group(1)
518
+ break
519
+ if inferred_path:
520
+ try:
521
+ _new_args = dict(parsed_call.raw_args)
522
+ _new_args["path"] = inferred_path
523
+ validated_args = args_model.model_validate(_new_args)
524
+ resolved_calls.append(
525
+ ResolvedToolCall(
526
+ tool_name=parsed_call.tool_name,
527
+ tool_class=tool_class,
528
+ validated_args=validated_args,
529
+ call_id=parsed_call.call_id,
530
+ )
531
+ )
532
+ continue
533
+ except ValidationError:
534
+ pass
535
+ # List project .py files as hints so the model can pick the right one
536
+ _candidates: list[str] = []
537
+ try:
538
+ _candidates = [
539
+ str(p.relative_to(Path.cwd()))
540
+ for p in sorted(Path.cwd().rglob("*.py"))
541
+ if "__pycache__" not in str(p) and ".git" not in str(p)
542
+ ][:12]
543
+ except Exception:
544
+ pass
545
+ _hint = (
546
+ f"Project .py files: {', '.join(_candidates)}"
547
+ if _candidates
548
+ else "Use read_file or glob to list available files."
549
+ )
550
+ error_msg = (
551
+ "missing required `path` parameter. "
552
+ "You must pass BOTH `path` AND `content` as separate arguments: "
553
+ 'write_file(path="pkg/file.py", content="..."). '
554
+ f"Do NOT omit `path`. {_hint}"
555
+ )
556
+ else:
557
+ error_msg = f"Invalid arguments: {e}"
381
558
  failed_calls.append(
382
559
  FailedToolCall(
383
560
  tool_name=parsed_call.tool_name,
384
561
  call_id=parsed_call.call_id,
385
- error=f"Invalid arguments: {e}",
562
+ error=error_msg,
386
563
  )
387
564
  )
388
565
 
389
- return ResolvedMessage(tool_calls=resolved_calls, failed_calls=failed_calls)
566
+ return ResolvedMessage(
567
+ tool_calls=resolved_calls,
568
+ failed_calls=failed_calls,
569
+ suppressed_failures=suppressed_failures,
570
+ )
390
571
 
391
572
  def create_tool_response_message(
392
573
  self, tool_call: ResolvedToolCall, result_text: str
@@ -404,13 +404,38 @@ class Bash(
404
404
  self, *, command: str, stdout: str, stderr: str, returncode: int
405
405
  ) -> BashResult:
406
406
  if returncode != 0:
407
- error_msg = f"Command failed: {command!r}\n"
408
- error_msg += f"Return code: {returncode}"
409
- if stderr:
410
- error_msg += f"\nStderr: {stderr}"
411
- if stdout:
412
- error_msg += f"\nStdout: {stdout}"
413
- raise ToolError(error_msg.strip())
407
+ # ADVISORY ONLY never raise ToolError for non-zero exit codes.
408
+ # Raising blocks the model: it gets <tool_error> with no useful
409
+ # output, doesn't know if exit 1 means "no matches" (grep) or a
410
+ # real failure, and retries identically. Same pattern as the
411
+ # timeout handler above. Include a clear exit-code annotation so
412
+ # the model can reason about what happened.
413
+ # See feedback_no_tool_errors_for_loop_detection.md.
414
+ annotation = f"[Exit code {returncode}]"
415
+ if returncode < 0:
416
+ # Negative returncode means killed by a Unix signal.
417
+ try:
418
+ sig_name = signal.Signals(-returncode).name
419
+ except ValueError:
420
+ sig_name = f"signal {-returncode}"
421
+ annotation += (
422
+ f" — process killed by {sig_name}."
423
+ " If this command starts a server or long-running process,"
424
+ " background it with `command &` and verify ports with `ss -tlnp`."
425
+ )
426
+ elif not stdout and not stderr:
427
+ annotation += " (no output)"
428
+ if returncode == 1:
429
+ annotation += (
430
+ " — for grep/find, exit code 1 means no matches found"
431
+ )
432
+ annotated_stdout = (stdout + "\n" + annotation).strip() if stdout else annotation
433
+ return BashResult(
434
+ command=command,
435
+ stdout=annotated_stdout,
436
+ stderr=stderr,
437
+ returncode=returncode,
438
+ )
414
439
 
415
440
  return BashResult(
416
441
  command=command, stdout=stdout, stderr=stderr, returncode=returncode
@@ -445,7 +470,39 @@ class Bash(
445
470
  )
446
471
  except TimeoutError:
447
472
  await _kill_process_tree(proc)
448
- raise self._build_timeout_error(args.command, timeout)
473
+ # ADVISORY ONLY — never raise ToolError on timeout; raising
474
+ # causes the model to retry the exact same command (loop).
475
+ # Track repeat timeouts per command and escalate the hint.
476
+ # See feedback_no_tool_errors_for_loop_detection.md.
477
+ timeout_state = self.state.__dict__.setdefault(
478
+ "_bash_timeout_history", {}
479
+ )
480
+ count = timeout_state.get(args.command, 0) + 1
481
+ timeout_state[args.command] = count
482
+ if count == 1:
483
+ hint = (
484
+ "The command was killed. If it starts a server or "
485
+ "long-running process, background it with `command &` "
486
+ "instead of running it in the foreground."
487
+ )
488
+ else:
489
+ hint = (
490
+ f"[TIMEOUT #{count}] You have timed out {count}x on "
491
+ f"this exact command. Running it again will produce the "
492
+ f"same result. STOP retrying. Background servers with "
493
+ f"`&`, check existing listeners with `ss -tlnp`, or fix "
494
+ f"the underlying cause before re-running."
495
+ )
496
+ yield BashResult(
497
+ command=args.command,
498
+ stdout=(
499
+ f"Command timed out after {timeout}s: {args.command!r}\n"
500
+ f"{hint}"
501
+ ),
502
+ stderr="",
503
+ returncode=124,
504
+ )
505
+ return
449
506
 
450
507
  encoding = _get_subprocess_encoding()
451
508
  stdout = (
@@ -45,7 +45,7 @@ class ReadFileResult(BaseModel):
45
45
  content: str
46
46
  lines_read: int
47
47
  was_truncated: bool = Field(
48
- description="True if the reading was stopped due to the max_read_bytes limit."
48
+ description="True if the reading was stopped due to the line limit or max_read_bytes limit."
49
49
  )
50
50
 
51
51
 
@@ -111,25 +111,48 @@ class ReadFile(
111
111
  and prior.get("offset") == args.offset
112
112
  and prior.get("limit") == args.limit
113
113
  ):
114
+ # Re-embed the cached content so the model has it even if the
115
+ # earlier tool_result was truncated by _truncate_old_tool_results.
116
+ # Pointing at a stale/truncated prior result causes re-read loops.
117
+ cached_content = prior.get("content", "")
118
+ prior_lines = prior.get("lines_read", 0)
119
+ dedup_count = prior.get("dedup_count", 0)
120
+ if dedup_count == 0:
121
+ header = "[Unchanged since last read — content re-embedded]\n"
122
+ else:
123
+ header = (
124
+ f"[REPEATED READ #{dedup_count + 1}: file has not changed across your last "
125
+ f"{dedup_count + 1} reads with these exact arguments. "
126
+ f"Reading again will produce this same result. "
127
+ f"To make progress: write or edit a file, use offset= to read a different section, "
128
+ f"or move on to the next task.]\n"
129
+ )
130
+ if read_state is not None:
131
+ read_state[path_key] = {**prior, "dedup_count": dedup_count + 1}
114
132
  yield ReadFileResult(
115
133
  path=path_key,
116
- content=(
117
- "<system-reminder>\n"
118
- f"File unchanged since your earlier read this session "
119
- f"({file_path.name}, mtime unchanged, same offset/limit). "
120
- "Use the content from the earlier Read tool_result — "
121
- "do NOT re-read. If you need to take action, call "
122
- "search_replace or write_file on what you already have.\n"
123
- "</system-reminder>"
124
- ),
125
- lines_read=0,
126
- was_truncated=True,
134
+ content=f"{header}{cached_content}",
135
+ lines_read=prior_lines,
136
+ was_truncated=prior.get("was_truncated", False),
127
137
  )
128
138
  return
129
139
 
130
140
  read_result = await self._read_file(args, file_path)
131
141
  content = "".join(read_result.lines)
132
142
 
143
+ # When stopped by the line limit (not byte limit), append a hint so
144
+ # the model knows to paginate with offset= instead of re-reading.
145
+ if (
146
+ read_result.was_truncated
147
+ and args.limit is not None
148
+ and len(read_result.lines) == args.limit
149
+ ):
150
+ next_offset = args.offset + args.limit
151
+ content += (
152
+ f"\n[lines {args.offset + 1}–{next_offset} shown; "
153
+ f"use offset={next_offset} to read more]"
154
+ )
155
+
133
156
  # Record read state so Write/Edit can enforce Read-before-Write
134
157
  # and so future re-reads can dedup against this one.
135
158
  if read_state is not None:
@@ -138,6 +161,8 @@ class ReadFile(
138
161
  "timestamp": current_mtime,
139
162
  "offset": args.offset,
140
163
  "limit": args.limit,
164
+ "lines_read": len(read_result.lines),
165
+ "was_truncated": read_result.was_truncated,
141
166
  }
142
167
 
143
168
  yield ReadFileResult(
@@ -195,6 +220,7 @@ class ReadFile(
195
220
  continue
196
221
 
197
222
  if args.limit is not None and len(lines_to_return) >= args.limit:
223
+ was_truncated = True
198
224
  break
199
225
 
200
226
  line_bytes = len(line.encode("utf-8"))
@@ -237,12 +263,45 @@ class ReadFile(
237
263
  f"Security error: Cannot read path '{file_path}' outside of the project directory '{Path.cwd()}'."
238
264
  )
239
265
  except FileNotFoundError:
240
- raise ToolError(f"File not found at: {file_path}")
266
+ raise ToolError(self._not_found_msg(file_path))
241
267
 
242
268
  if not resolved_path.exists():
243
- raise ToolError(f"File not found at: {file_path}")
269
+ raise ToolError(self._not_found_msg(file_path))
244
270
  if resolved_path.is_dir():
245
- raise ToolError(f"Path is a directory, not a file: {file_path}")
271
+ raise ToolError(self._is_dir_msg(file_path, resolved_path))
272
+
273
+ @staticmethod
274
+ def _not_found_msg(file_path: Path) -> str:
275
+ """Return 'File not found' error with parent directory listing for context."""
276
+ parent = file_path.parent if file_path.parent != file_path else Path(".")
277
+ try:
278
+ entries = sorted(p.name for p in parent.iterdir())
279
+ if entries:
280
+ listing = "\n".join(f" {e}" for e in entries[:30])
281
+ suffix = f"\n ... ({len(entries) - 30} more)" if len(entries) > 30 else ""
282
+ return (
283
+ f"File not found at: {file_path}\n"
284
+ f"Contents of {parent}/:\n{listing}{suffix}"
285
+ )
286
+ except (PermissionError, OSError):
287
+ pass
288
+ return f"File not found at: {file_path}"
289
+
290
+ @staticmethod
291
+ def _is_dir_msg(file_path: Path, resolved_path: Path) -> str:
292
+ """Return 'is a directory' error with directory listing so model can pick a file."""
293
+ try:
294
+ entries = sorted(p.name for p in resolved_path.iterdir())
295
+ if entries:
296
+ listing = "\n".join(f" {e}" for e in entries[:30])
297
+ suffix = f"\n ... ({len(entries) - 30} more)" if len(entries) > 30 else ""
298
+ return (
299
+ f"Path is a directory, not a file: {file_path}\n"
300
+ f"Contents of {file_path}/:\n{listing}{suffix}"
301
+ )
302
+ except (PermissionError, OSError):
303
+ pass
304
+ return f"Path is a directory, not a file: {file_path}"
246
305
 
247
306
  @classmethod
248
307
  def format_call_display(cls, args: ReadFileArgs) -> ToolCallDisplay: