drydock-cli 3.0.58__tar.gz → 3.0.59__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 (76) hide show
  1. {drydock_cli-3.0.58/drydock_cli.egg-info → drydock_cli-3.0.59}/PKG-INFO +1 -1
  2. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/drydock/tools/__init__.py +28 -2
  3. {drydock_cli-3.0.58 → drydock_cli-3.0.59/drydock_cli.egg-info}/PKG-INFO +1 -1
  4. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/pyproject.toml +1 -1
  5. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/tests/test_bash_output_bounding.py +12 -0
  6. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/LICENSE +0 -0
  7. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/NOTICE +0 -0
  8. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/README.md +0 -0
  9. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/drydock/__init__.py +0 -0
  10. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/drydock/__main__.py +0 -0
  11. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/drydock/agent.py +0 -0
  12. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/drydock/bash_safety.py +0 -0
  13. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/drydock/cli.py +0 -0
  14. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/drydock/compaction.py +0 -0
  15. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/drydock/config.py +0 -0
  16. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/drydock/detect.py +0 -0
  17. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/drydock/gittools.py +0 -0
  18. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/drydock/graphrag.py +0 -0
  19. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/drydock/guards.py +0 -0
  20. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/drydock/loop_detect.py +0 -0
  21. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/drydock/mcp.py +0 -0
  22. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/drydock/providers.py +0 -0
  23. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/drydock/skills.py +0 -0
  24. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/drydock/tool_registry.py +0 -0
  25. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/drydock/tui/__init__.py +0 -0
  26. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/drydock/tui/app.py +0 -0
  27. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/drydock/tui/approval.py +0 -0
  28. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/drydock/tui/messages.py +0 -0
  29. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/drydock/tui/widgets.py +0 -0
  30. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/drydock/tuning.py +0 -0
  31. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/drydock/web.py +0 -0
  32. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/drydock_cli.egg-info/SOURCES.txt +0 -0
  33. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/drydock_cli.egg-info/dependency_links.txt +0 -0
  34. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/drydock_cli.egg-info/entry_points.txt +0 -0
  35. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/drydock_cli.egg-info/requires.txt +0 -0
  36. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/drydock_cli.egg-info/top_level.txt +0 -0
  37. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/setup.cfg +0 -0
  38. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/tests/test_approval.py +0 -0
  39. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/tests/test_back_command.py +0 -0
  40. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/tests/test_bash_process_group.py +0 -0
  41. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/tests/test_bash_safety.py +0 -0
  42. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/tests/test_bash_timeout_network.py +0 -0
  43. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/tests/test_cli_agents.py +0 -0
  44. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/tests/test_compact_command.py +0 -0
  45. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/tests/test_compaction.py +0 -0
  46. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/tests/test_config.py +0 -0
  47. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/tests/test_config_migration.py +0 -0
  48. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/tests/test_context_limit_config.py +0 -0
  49. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/tests/test_detect.py +0 -0
  50. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/tests/test_dispatch.py +0 -0
  51. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/tests/test_empty_response.py +0 -0
  52. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/tests/test_failure_loop.py +0 -0
  53. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/tests/test_first_run_setup.py +0 -0
  54. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/tests/test_gittools.py +0 -0
  55. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/tests/test_graphrag.py +0 -0
  56. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/tests/test_guards_and_tools.py +0 -0
  57. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/tests/test_hallucinated_tools.py +0 -0
  58. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/tests/test_leaked_tool_call.py +0 -0
  59. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/tests/test_loop_detect.py +0 -0
  60. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/tests/test_mcp.py +0 -0
  61. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/tests/test_oneshot_unreachable.py +0 -0
  62. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/tests/test_plan_autocontinue.py +0 -0
  63. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/tests/test_providers_unreachable.py +0 -0
  64. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/tests/test_read_index.py +0 -0
  65. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/tests/test_runaway_repetition.py +0 -0
  66. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/tests/test_skills.py +0 -0
  67. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/tests/test_stop.py +0 -0
  68. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/tests/test_streaming_newlines.py +0 -0
  69. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/tests/test_subagent.py +0 -0
  70. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/tests/test_todo.py +0 -0
  71. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/tests/test_tool_arg_parsing.py +0 -0
  72. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/tests/test_tools_undo.py +0 -0
  73. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/tests/test_tui.py +0 -0
  74. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/tests/test_tuning.py +0 -0
  75. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/tests/test_vision_input.py +0 -0
  76. {drydock_cli-3.0.58 → drydock_cli-3.0.59}/tests/test_web_tools.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: drydock-cli
3
- Version: 3.0.58
3
+ Version: 3.0.59
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
@@ -22,6 +22,29 @@ 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
 
25
+
26
+ def _collapse_repeated_lines(text: str, run: int = 20) -> str:
27
+ """Collapse a run of >= `run` IDENTICAL consecutive lines into one line + a
28
+ count. Repetitive output (`yes`, a spinning progress log) tokenizes densely —
29
+ 32 KB of "y\\n" is ~24k tokens — so even after byte-capping it can eat a big
30
+ slice of the context window. Collapsing makes it cheap without losing the
31
+ signal. Non-repetitive output (a normal build log) is left untouched."""
32
+ lines = text.split("\n")
33
+ out: list[str] = []
34
+ i, n = 0, len(lines)
35
+ while i < n:
36
+ j = i
37
+ while j < n and lines[j] == lines[i]:
38
+ j += 1
39
+ count = j - i
40
+ if count >= run:
41
+ out.append(lines[i])
42
+ out.append(f"[... {count - 1} more identical lines collapsed ...]")
43
+ else:
44
+ out.extend(lines[i:j])
45
+ i = j
46
+ return "\n".join(out)
47
+
25
48
  from drydock.tool_registry import ToolDef, register
26
49
  from drydock.guards import (
27
50
  conflict_marker_refusal,
@@ -781,10 +804,13 @@ def tool_bash(params: dict, config: dict) -> str:
781
804
  msg += _OFFLINE_HINT
782
805
  return msg
783
806
  proc.wait()
784
- output = "".join(chunks)
807
+ # Collapse repetitive runs FIRST (turns 256 KB of "y\n" into ~2 lines),
808
+ # then note if we hit the byte cap. Bounds both RAM (the cap) and context
809
+ # tokens (the collapse).
810
+ output = _collapse_repeated_lines("".join(chunks))
785
811
  if capped.is_set():
786
812
  return (
787
- output[:_MAX_BASH_OUTPUT_BYTES]
813
+ output.rstrip()
788
814
  + f"\n[output truncated at {_MAX_BASH_OUTPUT_BYTES // 1024} KB — "
789
815
  "the command produced more; redirect to a file and inspect it in "
790
816
  "pieces (head/tail/grep) instead of dumping it all]"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: drydock-cli
3
- Version: 3.0.58
3
+ Version: 3.0.59
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.58"
10
+ version = "3.0.59"
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"
@@ -35,3 +35,15 @@ def test_exit_code_still_reported(tmp_path):
35
35
  cfg = {"cwd": str(tmp_path)}
36
36
  out = tool_bash({"command": "echo oops; exit 3"}, cfg)
37
37
  assert "oops" in out and "exit code: 3" in out
38
+
39
+
40
+ def test_repetitive_output_is_collapsed(tmp_path):
41
+ # PRD "protect context size": a repetitive dump must not eat the window.
42
+ out = tool_bash({"command": "yes | head -c 2000000"}, {"cwd": str(tmp_path)})
43
+ assert len(out) < 500 # ~24k chars before the collapse
44
+ assert "identical lines collapsed" in out
45
+
46
+
47
+ def test_collapse_preserves_distinct_lines(tmp_path):
48
+ out = tool_bash({"command": "printf 'a\\nb\\nc\\n'"}, {"cwd": str(tmp_path)})
49
+ assert out == "a\nb\nc" # nothing collapsed
File without changes
File without changes
File without changes
File without changes