drydock-cli 3.0.16__tar.gz → 3.0.17__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.16/drydock_cli.egg-info → drydock_cli-3.0.17}/PKG-INFO +1 -1
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/drydock/__init__.py +1 -1
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/drydock/tools/__init__.py +10 -4
- {drydock_cli-3.0.16 → drydock_cli-3.0.17/drydock_cli.egg-info}/PKG-INFO +1 -1
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/drydock_cli.egg-info/SOURCES.txt +1 -0
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/pyproject.toml +1 -1
- drydock_cli-3.0.17/tests/test_todo.py +38 -0
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/LICENSE +0 -0
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/NOTICE +0 -0
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/README.md +0 -0
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/drydock/__main__.py +0 -0
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/drydock/agent.py +0 -0
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/drydock/bash_safety.py +0 -0
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/drydock/cli.py +0 -0
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/drydock/compaction.py +0 -0
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/drydock/config.py +0 -0
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/drydock/detect.py +0 -0
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/drydock/guards.py +0 -0
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/drydock/loop_detect.py +0 -0
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/drydock/providers.py +0 -0
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/drydock/tool_registry.py +0 -0
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/drydock/tui/__init__.py +0 -0
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/drydock/tui/app.py +0 -0
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/drydock/tui/approval.py +0 -0
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/drydock/tui/messages.py +0 -0
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/drydock/tui/widgets.py +0 -0
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/drydock/tuning.py +0 -0
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/drydock_cli.egg-info/dependency_links.txt +0 -0
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/drydock_cli.egg-info/entry_points.txt +0 -0
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/drydock_cli.egg-info/requires.txt +0 -0
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/drydock_cli.egg-info/top_level.txt +0 -0
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/setup.cfg +0 -0
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/tests/test_approval.py +0 -0
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/tests/test_back_command.py +0 -0
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/tests/test_bash_safety.py +0 -0
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/tests/test_compaction.py +0 -0
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/tests/test_config.py +0 -0
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/tests/test_detect.py +0 -0
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/tests/test_guards_and_tools.py +0 -0
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/tests/test_hallucinated_tools.py +0 -0
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/tests/test_leaked_tool_call.py +0 -0
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/tests/test_loop_detect.py +0 -0
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/tests/test_plan_autocontinue.py +0 -0
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/tests/test_providers_unreachable.py +0 -0
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/tests/test_subagent.py +0 -0
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/tests/test_tools_undo.py +0 -0
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/tests/test_tui.py +0 -0
- {drydock_cli-3.0.16 → drydock_cli-3.0.17}/tests/test_tuning.py +0 -0
|
@@ -496,10 +496,16 @@ _TODO_DONE = {"x", "X", "✓"}
|
|
|
496
496
|
_TODO_DOING = {"~", "-", "/", "*"}
|
|
497
497
|
|
|
498
498
|
|
|
499
|
-
def parse_todo(tasks
|
|
500
|
-
"""Parse a
|
|
501
|
-
|
|
502
|
-
|
|
499
|
+
def parse_todo(tasks) -> list[tuple[str, str]]:
|
|
500
|
+
"""Parse a checklist into (text, status) pairs. Each non-empty line is one
|
|
501
|
+
task, optionally prefixed with [x] done / [~] in_progress / [ ] pending.
|
|
502
|
+
Deliberately forgiving: a bare line counts as pending, and `tasks` may be a
|
|
503
|
+
newline-joined string OR a list of lines (the model sometimes sends a JSON
|
|
504
|
+
array instead of one string — handle both rather than crash the TUI)."""
|
|
505
|
+
if isinstance(tasks, (list, tuple)):
|
|
506
|
+
tasks = "\n".join(str(t) for t in tasks)
|
|
507
|
+
elif tasks is not None and not isinstance(tasks, str):
|
|
508
|
+
tasks = str(tasks)
|
|
503
509
|
out: list[tuple[str, str]] = []
|
|
504
510
|
for raw in (tasks or "").splitlines():
|
|
505
511
|
line = raw.strip().lstrip("-*•").strip()
|
|
@@ -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.17"
|
|
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"
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""Tests for the `todo` checklist tool and its forgiving parser."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from drydock.tools import parse_todo, tool_todo
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def test_parse_todo_basic_statuses():
|
|
8
|
+
items = parse_todo("[x] done one\n[~] doing two\n[ ] pending three")
|
|
9
|
+
assert items == [
|
|
10
|
+
("done one", "done"),
|
|
11
|
+
("doing two", "in_progress"),
|
|
12
|
+
("pending three", "pending"),
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def test_parse_todo_accepts_list_input():
|
|
17
|
+
# The model sometimes sends a JSON array instead of one newline string —
|
|
18
|
+
# this must NOT crash (it took down the whole TUI before).
|
|
19
|
+
items = parse_todo([
|
|
20
|
+
"[~] Explore existing tests and run them",
|
|
21
|
+
"[ ] Add edge-case tests",
|
|
22
|
+
"[ ] Verify all tests pass",
|
|
23
|
+
])
|
|
24
|
+
assert [s for _, s in items] == ["in_progress", "pending", "pending"]
|
|
25
|
+
assert items[0][0] == "Explore existing tests and run them"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def test_parse_todo_none_and_empty():
|
|
29
|
+
assert parse_todo(None) == []
|
|
30
|
+
assert parse_todo("") == []
|
|
31
|
+
assert parse_todo([]) == []
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def test_tool_todo_accepts_list(tmp_path):
|
|
35
|
+
cfg: dict = {}
|
|
36
|
+
out = tool_todo({"tasks": ["[ ] a", "[x] b"]}, cfg)
|
|
37
|
+
assert "2 tasks" in out and "1 done" in out
|
|
38
|
+
assert len(cfg["_todo"]) == 2
|
|
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
|