drydock-cli 3.0.28__tar.gz → 3.0.29__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.
- {drydock_cli-3.0.28/drydock_cli.egg-info → drydock_cli-3.0.29}/PKG-INFO +1 -1
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/drydock/__init__.py +1 -1
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/drydock/tui/app.py +17 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/drydock/tui/widgets.py +33 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29/drydock_cli.egg-info}/PKG-INFO +1 -1
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/pyproject.toml +1 -1
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/LICENSE +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/NOTICE +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/README.md +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/drydock/__main__.py +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/drydock/agent.py +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/drydock/bash_safety.py +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/drydock/cli.py +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/drydock/compaction.py +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/drydock/config.py +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/drydock/detect.py +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/drydock/guards.py +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/drydock/loop_detect.py +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/drydock/providers.py +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/drydock/tool_registry.py +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/drydock/tools/__init__.py +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/drydock/tui/__init__.py +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/drydock/tui/approval.py +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/drydock/tui/messages.py +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/drydock/tuning.py +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/drydock_cli.egg-info/SOURCES.txt +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/drydock_cli.egg-info/dependency_links.txt +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/drydock_cli.egg-info/entry_points.txt +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/drydock_cli.egg-info/requires.txt +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/drydock_cli.egg-info/top_level.txt +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/setup.cfg +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/tests/test_approval.py +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/tests/test_back_command.py +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/tests/test_bash_safety.py +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/tests/test_cli_agents.py +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/tests/test_compaction.py +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/tests/test_config.py +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/tests/test_detect.py +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/tests/test_empty_response.py +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/tests/test_first_run_setup.py +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/tests/test_guards_and_tools.py +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/tests/test_hallucinated_tools.py +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/tests/test_leaked_tool_call.py +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/tests/test_loop_detect.py +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/tests/test_plan_autocontinue.py +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/tests/test_providers_unreachable.py +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/tests/test_stop.py +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/tests/test_streaming_newlines.py +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/tests/test_subagent.py +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/tests/test_todo.py +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/tests/test_tool_arg_parsing.py +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/tests/test_tools_undo.py +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/tests/test_tui.py +0 -0
- {drydock_cli-3.0.28 → drydock_cli-3.0.29}/tests/test_tuning.py +0 -0
|
@@ -34,6 +34,7 @@ from drydock.tui.messages import (
|
|
|
34
34
|
AgentTurnDone,
|
|
35
35
|
)
|
|
36
36
|
from drydock.tui.widgets import (
|
|
37
|
+
SLASH_COMMANDS,
|
|
37
38
|
AssistantMessage,
|
|
38
39
|
ErrorMessage,
|
|
39
40
|
PromptArea,
|
|
@@ -351,6 +352,22 @@ class DrydockApp(App):
|
|
|
351
352
|
|
|
352
353
|
# ── input ─────────────────────────────────────────────────────────────
|
|
353
354
|
|
|
355
|
+
def on_text_area_changed(self, event) -> None:
|
|
356
|
+
"""As the user types a bare slash command, surface the matching commands
|
|
357
|
+
in the (idle) activity line — '/m' shows '/model'. Tab completes them."""
|
|
358
|
+
if self._busy:
|
|
359
|
+
return # #working shows live activity while a turn is running
|
|
360
|
+
try:
|
|
361
|
+
text = self.query_one("#prompt", PromptArea).text
|
|
362
|
+
except Exception: # noqa: BLE001 — widget not mounted yet
|
|
363
|
+
return
|
|
364
|
+
hint = ""
|
|
365
|
+
if text.startswith("/") and " " not in text and "\n" not in text:
|
|
366
|
+
matches = [c for c in SLASH_COMMANDS if c.startswith(text.lower())]
|
|
367
|
+
if matches:
|
|
368
|
+
hint = " " + " ".join(matches) + " · Tab to complete"
|
|
369
|
+
self.query_one("#working", Static).update(hint)
|
|
370
|
+
|
|
354
371
|
def on_prompt_area_submitted(self, event: PromptArea.Submitted) -> None:
|
|
355
372
|
text = event.text.strip()
|
|
356
373
|
prompt = self.query_one("#prompt", PromptArea)
|
|
@@ -148,6 +148,25 @@ class PromptHistory:
|
|
|
148
148
|
return self._draft
|
|
149
149
|
|
|
150
150
|
|
|
151
|
+
# The slash commands offered for completion (typing "/m" → /model). Keep in
|
|
152
|
+
# sync with app._handle_slash. Shown as a hint as the user types, and Tab
|
|
153
|
+
# completes the prefix.
|
|
154
|
+
SLASH_COMMANDS = [
|
|
155
|
+
"/help", "/model", "/cwd", "/undo", "/back", "/stop", "/status",
|
|
156
|
+
"/clear", "/quit",
|
|
157
|
+
]
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def _common_prefix(strings: list[str]) -> str:
|
|
161
|
+
if not strings:
|
|
162
|
+
return ""
|
|
163
|
+
pre = strings[0]
|
|
164
|
+
for s in strings[1:]:
|
|
165
|
+
while not s.startswith(pre):
|
|
166
|
+
pre = pre[:-1]
|
|
167
|
+
return pre
|
|
168
|
+
|
|
169
|
+
|
|
151
170
|
class PromptArea(TextArea):
|
|
152
171
|
"""Multi-line prompt box.
|
|
153
172
|
|
|
@@ -187,6 +206,20 @@ class PromptArea(TextArea):
|
|
|
187
206
|
event.prevent_default()
|
|
188
207
|
self.insert("\n")
|
|
189
208
|
return
|
|
209
|
+
if key == "tab":
|
|
210
|
+
t = self.text
|
|
211
|
+
if t.startswith("/") and " " not in t and "\n" not in t:
|
|
212
|
+
matches = [c for c in SLASH_COMMANDS if c.startswith(t.lower())]
|
|
213
|
+
if matches:
|
|
214
|
+
event.stop()
|
|
215
|
+
event.prevent_default()
|
|
216
|
+
# one match → complete it (+ space); several → common prefix.
|
|
217
|
+
self.text = (
|
|
218
|
+
matches[0] + " " if len(matches) == 1
|
|
219
|
+
else _common_prefix(matches)
|
|
220
|
+
)
|
|
221
|
+
self.move_cursor(self.document.end)
|
|
222
|
+
return
|
|
190
223
|
if key == "up" and self.cursor_at_first_line:
|
|
191
224
|
event.stop()
|
|
192
225
|
event.prevent_default()
|
|
@@ -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.
|
|
10
|
+
version = "3.0.29"
|
|
11
11
|
description = "Drydock — a local, provider-agnostic terminal coding agent for local LLMs"
|
|
12
12
|
readme = "README.md"
|
|
13
13
|
requires-python = ">=3.12"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|