drydock-cli 3.0.109__tar.gz → 3.0.111__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 (121) hide show
  1. {drydock_cli-3.0.109/drydock_cli.egg-info → drydock_cli-3.0.111}/PKG-INFO +1 -1
  2. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/drydock/cli.py +2 -1
  3. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/drydock/tools/__init__.py +27 -3
  4. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/drydock/tui/app.py +28 -1
  5. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/drydock/tui/widgets.py +1 -1
  6. {drydock_cli-3.0.109 → drydock_cli-3.0.111/drydock_cli.egg-info}/PKG-INFO +1 -1
  7. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/pyproject.toml +1 -1
  8. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_windows_shell.py +23 -0
  9. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/LICENSE +0 -0
  10. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/NOTICE +0 -0
  11. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/README.md +0 -0
  12. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/drydock/__init__.py +0 -0
  13. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/drydock/__main__.py +0 -0
  14. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/drydock/advisor.py +0 -0
  15. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/drydock/agent.py +0 -0
  16. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/drydock/bash_safety.py +0 -0
  17. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/drydock/builtin_skills/__init__.py +0 -0
  18. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/drydock/builtin_skills/rmf-categorize.md +0 -0
  19. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/drydock/builtin_skills/rmf-control.md +0 -0
  20. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/drydock/builtin_skills/rmf-poam.md +0 -0
  21. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/drydock/builtin_skills/rmf-review.md +0 -0
  22. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/drydock/builtin_skills/stig-assess.md +0 -0
  23. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/drydock/builtin_skills/stig-remediate.md +0 -0
  24. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/drydock/cci.py +0 -0
  25. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/drydock/compaction.py +0 -0
  26. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/drydock/config.py +0 -0
  27. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/drydock/detect.py +0 -0
  28. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/drydock/extract.py +0 -0
  29. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/drydock/gittools.py +0 -0
  30. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/drydock/graphrag.py +0 -0
  31. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/drydock/guards.py +0 -0
  32. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/drydock/loop_detect.py +0 -0
  33. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/drydock/mcp.py +0 -0
  34. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/drydock/poam.py +0 -0
  35. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/drydock/providers.py +0 -0
  36. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/drydock/rmf.py +0 -0
  37. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/drydock/rmf_graph.py +0 -0
  38. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/drydock/skills.py +0 -0
  39. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/drydock/stig.py +0 -0
  40. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/drydock/tool_registry.py +0 -0
  41. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/drydock/tui/__init__.py +0 -0
  42. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/drydock/tui/approval.py +0 -0
  43. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/drydock/tui/messages.py +0 -0
  44. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/drydock/tuning.py +0 -0
  45. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/drydock/web.py +0 -0
  46. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/drydock_cli.egg-info/SOURCES.txt +0 -0
  47. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/drydock_cli.egg-info/dependency_links.txt +0 -0
  48. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/drydock_cli.egg-info/entry_points.txt +0 -0
  49. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/drydock_cli.egg-info/requires.txt +0 -0
  50. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/drydock_cli.egg-info/top_level.txt +0 -0
  51. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/setup.cfg +0 -0
  52. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_advisor.py +0 -0
  53. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_approval.py +0 -0
  54. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_back_command.py +0 -0
  55. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_bash_background.py +0 -0
  56. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_bash_binary_output.py +0 -0
  57. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_bash_crossplatform.py +0 -0
  58. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_bash_output_bounding.py +0 -0
  59. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_bash_process_group.py +0 -0
  60. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_bash_safety.py +0 -0
  61. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_bash_sanitize.py +0 -0
  62. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_bash_shell.py +0 -0
  63. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_bash_stdin.py +0 -0
  64. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_bash_stop_partial.py +0 -0
  65. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_bash_timeout_network.py +0 -0
  66. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_bash_timeout_param.py +0 -0
  67. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_cci.py +0 -0
  68. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_cli_agents.py +0 -0
  69. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_compact_command.py +0 -0
  70. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_compaction.py +0 -0
  71. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_config.py +0 -0
  72. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_config_migration.py +0 -0
  73. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_context_limit_config.py +0 -0
  74. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_detect.py +0 -0
  75. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_dispatch.py +0 -0
  76. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_e2e_connected.py +0 -0
  77. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_edit_replace_all.py +0 -0
  78. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_empty_response.py +0 -0
  79. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_extract.py +0 -0
  80. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_failure_loop.py +0 -0
  81. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_first_run_setup.py +0 -0
  82. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_gittools.py +0 -0
  83. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_glob_edit_edges.py +0 -0
  84. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_graphify_example.py +0 -0
  85. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_graphrag.py +0 -0
  86. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_grep_and_read_robust.py +0 -0
  87. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_guards_and_tools.py +0 -0
  88. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_hallucinated_tools.py +0 -0
  89. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_leaked_tool_call.py +0 -0
  90. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_loop_detect.py +0 -0
  91. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_mcp.py +0 -0
  92. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_oneshot_unreachable.py +0 -0
  93. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_overthink_interrupt.py +0 -0
  94. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_plan_autocontinue.py +0 -0
  95. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_poam.py +0 -0
  96. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_providers_unreachable.py +0 -0
  97. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_read_index.py +0 -0
  98. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_rmf.py +0 -0
  99. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_rmf_graph.py +0 -0
  100. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_rmf_stig_graph.py +0 -0
  101. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_runaway_repetition.py +0 -0
  102. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_server_probe.py +0 -0
  103. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_skills.py +0 -0
  104. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_stall_retry.py +0 -0
  105. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_stig.py +0 -0
  106. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_stop.py +0 -0
  107. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_streaming_newlines.py +0 -0
  108. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_subagent.py +0 -0
  109. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_system_prompt_help.py +0 -0
  110. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_todo.py +0 -0
  111. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_tool_arg_coercion.py +0 -0
  112. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_tool_arg_coercion_more.py +0 -0
  113. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_tool_arg_parsing.py +0 -0
  114. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_tools_undo.py +0 -0
  115. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_tui.py +0 -0
  116. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_tuning.py +0 -0
  117. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_viewimage.py +0 -0
  118. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_vision_input.py +0 -0
  119. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_web_tools.py +0 -0
  120. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_write_content_coerce.py +0 -0
  121. {drydock_cli-3.0.109 → drydock_cli-3.0.111}/tests/test_xccdf.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: drydock-cli
3
- Version: 3.0.109
3
+ Version: 3.0.111
4
4
  Summary: Drydock — a local, provider-agnostic terminal coding agent for local LLMs
5
5
  Author: Frank Bobe III
6
6
  License-Expression: Apache-2.0
@@ -130,7 +130,8 @@ def run_oneshot(prompt: str, config: dict) -> None:
130
130
  # under -p) shows WHAT each tool did, not just its name. Without
131
131
  # this, a timed-out run is an opaque wall of "[Bash]" with no way
132
132
  # to tell a genuine 100-command exploration from a tight loop.
133
- print(f" [{event.name}] {_summarize(event.inputs)}",
133
+ from drydock.tools import tool_display_name
134
+ print(f" [{tool_display_name(event.name)}] {_summarize(event.inputs)}",
134
135
  file=sys.stderr, flush=True)
135
136
  elif isinstance(event, ToolEnd):
136
137
  # One-line outcome so failures/repeats are visible in the trace.
@@ -93,9 +93,19 @@ def _detect_bash() -> str | None:
93
93
  return None
94
94
 
95
95
 
96
- # Windows even if a non-native Python (rare) reports a posix os.name — sys.platform
97
- # is the reliable signal on CPython.
98
- _IS_WINDOWS = os.name == "nt" or sys.platform.startswith("win")
96
+ def _is_windows_env(os_name: str, platform: str, environ) -> bool:
97
+ """Treat as Windows if ANY signal says so — native CPython (os.name 'nt' /
98
+ sys.platform 'win32') AND odd Pythons run from Git-Bash/MSYS/Cygwin (which
99
+ report posix but where Windows always exports WINDIR/SystemRoot). WSL (real
100
+ Linux) does not set WINDIR, so it correctly stays POSIX/bash."""
101
+ return (
102
+ os_name == "nt"
103
+ or platform in ("win32", "cygwin", "msys")
104
+ or bool(environ.get("WINDIR") or environ.get("SystemRoot"))
105
+ )
106
+
107
+
108
+ _IS_WINDOWS = _is_windows_env(os.name, sys.platform, os.environ)
99
109
 
100
110
 
101
111
  def _detect_shell() -> tuple[str, str]:
@@ -135,6 +145,20 @@ _SHELL_KIND, _SHELL_PATH = _detect_shell()
135
145
  _BASH_SHELL = _detect_bash()
136
146
 
137
147
 
148
+ def shell_display_name() -> str:
149
+ """Human label for the shell the Bash tool actually runs commands in — so the
150
+ TUI can show 'PowerShell'/'cmd' on Windows instead of the schema name 'Bash'."""
151
+ return {"powershell": "PowerShell", "cmd": "cmd",
152
+ "bash": "Bash", "sh": "sh"}.get(_SHELL_KIND, "Bash")
153
+
154
+
155
+ def tool_display_name(name: str) -> str:
156
+ """Map a tool's schema name to its display label. The `Bash` tool (the name
157
+ the model calls) is shown as the actual shell — so on Windows a user sees
158
+ 'PowerShell', not 'Bash'."""
159
+ return shell_display_name() if name == "Bash" else name
160
+
161
+
138
162
  # ANSI escape sequences (CSI colour/cursor, OSC title, and lone two-char escapes).
139
163
  # Some tools emit these even to a pipe (--color=always, forced-colour test runners),
140
164
  # and they're pure display control — noise that wastes the model's tokens.
@@ -501,6 +501,8 @@ class DrydockApp(App):
501
501
  self._cmd_compact()
502
502
  elif cmd == "/context":
503
503
  self._cmd_context(arg)
504
+ elif cmd == "/shell":
505
+ self._cmd_shell()
504
506
  elif cmd == "/advisor":
505
507
  self._cmd_advisor(arg)
506
508
  elif cmd == "/ask":
@@ -807,6 +809,30 @@ class DrydockApp(App):
807
809
  else:
808
810
  self._begin(prompt)
809
811
 
812
+ def _cmd_shell(self) -> None:
813
+ """Show exactly which shell the Bash tool runs commands through, plus the
814
+ platform signals — so a 'still using bash on Windows' report is instantly
815
+ diagnosable. (The tool is NAMED 'Bash' on every OS; on Windows it actually
816
+ invokes PowerShell/cmd underneath.)"""
817
+ import os as _os
818
+ import sys as _sys
819
+
820
+ from drydock import tools
821
+ kind, path = tools._detect_shell()
822
+ lines = [
823
+ f"The Bash tool runs your commands through: {kind.upper()}",
824
+ f" shell path : {path}",
825
+ f" os.name={_os.name} sys.platform={_sys.platform} detected_windows={tools._IS_WINDOWS}",
826
+ f" DRYDOCK_SHELL env = {_os.environ.get('DRYDOCK_SHELL') or '(unset)'}",
827
+ f" bash on system = {tools._detect_bash() or '(none)'}",
828
+ ]
829
+ if kind == "bash" and tools._IS_WINDOWS:
830
+ lines.append(" ⚠ on Windows but using bash — set $env:DRYDOCK_SHELL=\"powershell\" and restart.")
831
+ elif kind == "powershell":
832
+ lines.append(" ✓ using PowerShell (the 'Bash' label is just the tool's name).")
833
+ lines.append(" Force a shell any time: set env DRYDOCK_SHELL to powershell / cmd / bash.")
834
+ self._info("\n".join(lines))
835
+
810
836
  def _cmd_context(self, arg: str) -> None:
811
837
  """View or change the context-window budget (tokens) — the cap that drives
812
838
  the ctx gauge + auto-compaction. `/context` shows it + its source; `/context
@@ -1188,7 +1214,8 @@ class DrydockApp(App):
1188
1214
  self._render_todo(m.inputs.get("tasks", ""))
1189
1215
  self._last_card = None # tool_end is a no-op for the checklist
1190
1216
  return
1191
- card = ToolCard(m.name, summarize_inputs(m.inputs))
1217
+ from drydock.tools import tool_display_name
1218
+ card = ToolCard(tool_display_name(m.name), summarize_inputs(m.inputs))
1192
1219
  self._last_card = card
1193
1220
  self._mount(card)
1194
1221
 
@@ -153,7 +153,7 @@ class PromptHistory:
153
153
  # completes the prefix.
154
154
  SLASH_COMMANDS = [
155
155
  "/help", "/model", "/cwd", "/undo", "/back", "/stop", "/status",
156
- "/compact", "/context", "/advisor", "/ask", "/ask!", "/graphrag", "/skills",
156
+ "/compact", "/context", "/shell", "/advisor", "/ask", "/ask!", "/graphrag", "/skills",
157
157
  "/loop", "/mcp", "/rmf", "/stig",
158
158
  "/clear", "/quit",
159
159
  ]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: drydock-cli
3
- Version: 3.0.109
3
+ Version: 3.0.111
4
4
  Summary: Drydock — a local, provider-agnostic terminal coding agent for local LLMs
5
5
  Author: Frank Bobe III
6
6
  License-Expression: Apache-2.0
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
7
7
  # PyPI distribution name is drydock-cli (the established install name, continued
8
8
  # from the retired v2 fork); the import package + CLI command stay `drydock`.
9
9
  name = "drydock-cli"
10
- version = "3.0.109"
10
+ version = "3.0.111"
11
11
  description = "Drydock — a local, provider-agnostic terminal coding agent for local LLMs"
12
12
  readme = "README.md"
13
13
  requires-python = ">=3.11"
@@ -77,3 +77,26 @@ def test_env_override_forces_cmd():
77
77
  def test_env_override_forces_bash():
78
78
  with mock.patch.dict("os.environ", {"DRYDOCK_SHELL": "bash"}):
79
79
  assert T._detect_shell()[0] in ("bash", "sh")
80
+
81
+
82
+ def test_is_windows_detection_signals():
83
+ from drydock.tools import _is_windows_env
84
+ # native Windows
85
+ assert _is_windows_env("nt", "win32", {})
86
+ # MSYS/Git-Bash Python: posix os.name but WINDIR set
87
+ assert _is_windows_env("posix", "msys", {"WINDIR": r"C:\Windows"})
88
+ # Cygwin
89
+ assert _is_windows_env("posix", "cygwin", {})
90
+ # SystemRoot fallback
91
+ assert _is_windows_env("posix", "linux", {"SystemRoot": r"C:\Windows"})
92
+ # real Linux / WSL (no Windows env)
93
+ assert not _is_windows_env("posix", "linux", {})
94
+ assert not _is_windows_env("posix", "linux", {"HOME": "/home/x"})
95
+
96
+
97
+ def test_tool_display_name_maps_bash_to_shell():
98
+ from unittest import mock
99
+ for kind, expect in [("powershell", "PowerShell"), ("cmd", "cmd"), ("bash", "Bash"), ("sh", "sh")]:
100
+ with mock.patch.object(T, "_SHELL_KIND", kind):
101
+ assert T.tool_display_name("Bash") == expect
102
+ assert T.tool_display_name("Read") == "Read" # other tools unchanged
File without changes
File without changes
File without changes
File without changes