drydock-cli 3.0.95__tar.gz → 3.0.96__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.95/drydock_cli.egg-info → drydock_cli-3.0.96}/PKG-INFO +1 -1
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/drydock/tools/__init__.py +17 -1
- {drydock_cli-3.0.95 → drydock_cli-3.0.96/drydock_cli.egg-info}/PKG-INFO +1 -1
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/drydock_cli.egg-info/SOURCES.txt +1 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/pyproject.toml +1 -1
- drydock_cli-3.0.96/tests/test_bash_timeout_param.py +30 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/LICENSE +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/NOTICE +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/README.md +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/drydock/__init__.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/drydock/__main__.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/drydock/advisor.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/drydock/agent.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/drydock/bash_safety.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/drydock/builtin_skills/__init__.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/drydock/builtin_skills/rmf-categorize.md +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/drydock/builtin_skills/rmf-control.md +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/drydock/builtin_skills/rmf-poam.md +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/drydock/builtin_skills/rmf-review.md +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/drydock/builtin_skills/stig-assess.md +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/drydock/builtin_skills/stig-remediate.md +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/drydock/cci.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/drydock/cli.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/drydock/compaction.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/drydock/config.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/drydock/detect.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/drydock/extract.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/drydock/gittools.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/drydock/graphrag.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/drydock/guards.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/drydock/loop_detect.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/drydock/mcp.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/drydock/poam.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/drydock/providers.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/drydock/rmf.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/drydock/rmf_graph.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/drydock/skills.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/drydock/stig.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/drydock/tool_registry.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/drydock/tui/__init__.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/drydock/tui/app.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/drydock/tui/approval.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/drydock/tui/messages.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/drydock/tui/widgets.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/drydock/tuning.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/drydock/web.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/drydock_cli.egg-info/dependency_links.txt +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/drydock_cli.egg-info/entry_points.txt +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/drydock_cli.egg-info/requires.txt +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/drydock_cli.egg-info/top_level.txt +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/setup.cfg +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_advisor.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_approval.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_back_command.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_bash_background.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_bash_binary_output.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_bash_output_bounding.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_bash_process_group.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_bash_safety.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_bash_sanitize.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_bash_shell.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_bash_stdin.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_bash_timeout_network.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_cci.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_cli_agents.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_compact_command.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_compaction.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_config.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_config_migration.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_context_limit_config.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_detect.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_dispatch.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_e2e_connected.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_empty_response.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_extract.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_failure_loop.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_first_run_setup.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_gittools.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_graphify_example.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_graphrag.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_guards_and_tools.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_hallucinated_tools.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_leaked_tool_call.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_loop_detect.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_mcp.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_oneshot_unreachable.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_plan_autocontinue.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_poam.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_providers_unreachable.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_read_index.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_rmf.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_rmf_graph.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_rmf_stig_graph.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_runaway_repetition.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_server_probe.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_skills.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_stig.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_stop.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_streaming_newlines.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_subagent.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_system_prompt_help.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_todo.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_tool_arg_parsing.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_tools_undo.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_tui.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_tuning.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_viewimage.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_vision_input.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_web_tools.py +0 -0
- {drydock_cli-3.0.95 → drydock_cli-3.0.96}/tests/test_xccdf.py +0 -0
|
@@ -22,6 +22,22 @@ from pathlib import Path
|
|
|
22
22
|
# once it's hit — bounding RAM regardless of how much it tries to produce.
|
|
23
23
|
_MAX_BASH_OUTPUT_BYTES = 256 * 1024 # 256 KB — plenty of context, safe for RAM
|
|
24
24
|
_PARTIAL_TAIL = 4000 # chars of pre-timeout output to keep (tail) in the timeout msg
|
|
25
|
+
_DEFAULT_TIMEOUT = 120
|
|
26
|
+
_MAX_TIMEOUT = 1800 # 30 min hard ceiling — a single command shouldn't hang longer
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _coerce_timeout(value) -> int:
|
|
30
|
+
"""Make the model-supplied timeout robust: local models often send it as a
|
|
31
|
+
string ("10"), and a 0/negative/absurd value would make EVERY command time
|
|
32
|
+
out instantly (or hang for hours). Coerce to int, fall back to the default on
|
|
33
|
+
junk, and clamp to (0, _MAX_TIMEOUT]."""
|
|
34
|
+
try:
|
|
35
|
+
t = int(float(value))
|
|
36
|
+
except (TypeError, ValueError):
|
|
37
|
+
return _DEFAULT_TIMEOUT
|
|
38
|
+
if t <= 0:
|
|
39
|
+
return _DEFAULT_TIMEOUT
|
|
40
|
+
return min(t, _MAX_TIMEOUT)
|
|
25
41
|
|
|
26
42
|
|
|
27
43
|
def _detect_bash() -> str | None:
|
|
@@ -916,7 +932,7 @@ def tool_bash(params: dict, config: dict) -> str:
|
|
|
916
932
|
# and crack hashes — a 30s wall killed legitimate long work before it could
|
|
917
933
|
# finish (terminal-bench: 16 tasks died at 30s on builds/training). Bounded,
|
|
918
934
|
# and the model can pass a larger `timeout` for genuinely heavy commands.
|
|
919
|
-
timeout = params.get("timeout", 120)
|
|
935
|
+
timeout = _coerce_timeout(params.get("timeout", 120))
|
|
920
936
|
reason = bash_safety.dangerous_command(cmd)
|
|
921
937
|
if reason is not None:
|
|
922
938
|
return bash_safety.refusal_message(cmd, reason)
|
|
@@ -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.96"
|
|
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"
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""The model-supplied `timeout` must be robust. Local models often send it as a
|
|
2
|
+
string ("10"); a 0/negative value made EVERY command time out instantly; an
|
|
3
|
+
absurd value could hang for hours. _coerce_timeout normalizes all of these."""
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import time
|
|
7
|
+
|
|
8
|
+
import pytest
|
|
9
|
+
|
|
10
|
+
from drydock.tools import _coerce_timeout, tool_bash
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@pytest.mark.parametrize("raw,expected", [
|
|
14
|
+
("10", 10), (30, 30), (15.7, 15), # numbers / stringified / float
|
|
15
|
+
(0, 120), (-5, 120), ("abc", 120), (None, 120), # invalid → default
|
|
16
|
+
(99999, 1800), (100000, 1800), # clamp to the 30-min ceiling
|
|
17
|
+
])
|
|
18
|
+
def test_coerce_timeout(raw, expected):
|
|
19
|
+
assert _coerce_timeout(raw) == expected
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def test_string_timeout_runs_instead_of_crashing():
|
|
23
|
+
# previously raised TypeError in the '>' comparison
|
|
24
|
+
out = tool_bash({"command": "echo hi", "timeout": "10"}, {"cwd": "/tmp"})
|
|
25
|
+
assert "hi" in out
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def test_zero_timeout_does_not_instant_timeout():
|
|
29
|
+
out = tool_bash({"command": "echo hi", "timeout": 0}, {"cwd": "/tmp"})
|
|
30
|
+
assert "hi" in out and "timed out" not in out
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|