drydock-cli 3.0.91__tar.gz → 3.0.93__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 (108) hide show
  1. {drydock_cli-3.0.91/drydock_cli.egg-info → drydock_cli-3.0.93}/PKG-INFO +5 -2
  2. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/README.md +4 -1
  3. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/drydock/tools/__init__.py +7 -1
  4. {drydock_cli-3.0.91 → drydock_cli-3.0.93/drydock_cli.egg-info}/PKG-INFO +5 -2
  5. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/drydock_cli.egg-info/SOURCES.txt +2 -0
  6. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/pyproject.toml +1 -1
  7. drydock_cli-3.0.93/tests/test_bash_binary_output.py +33 -0
  8. drydock_cli-3.0.93/tests/test_graphify_example.py +36 -0
  9. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/LICENSE +0 -0
  10. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/NOTICE +0 -0
  11. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/drydock/__init__.py +0 -0
  12. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/drydock/__main__.py +0 -0
  13. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/drydock/advisor.py +0 -0
  14. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/drydock/agent.py +0 -0
  15. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/drydock/bash_safety.py +0 -0
  16. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/drydock/builtin_skills/__init__.py +0 -0
  17. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/drydock/builtin_skills/rmf-categorize.md +0 -0
  18. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/drydock/builtin_skills/rmf-control.md +0 -0
  19. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/drydock/builtin_skills/rmf-poam.md +0 -0
  20. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/drydock/builtin_skills/rmf-review.md +0 -0
  21. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/drydock/builtin_skills/stig-assess.md +0 -0
  22. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/drydock/builtin_skills/stig-remediate.md +0 -0
  23. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/drydock/cci.py +0 -0
  24. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/drydock/cli.py +0 -0
  25. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/drydock/compaction.py +0 -0
  26. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/drydock/config.py +0 -0
  27. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/drydock/detect.py +0 -0
  28. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/drydock/extract.py +0 -0
  29. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/drydock/gittools.py +0 -0
  30. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/drydock/graphrag.py +0 -0
  31. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/drydock/guards.py +0 -0
  32. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/drydock/loop_detect.py +0 -0
  33. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/drydock/mcp.py +0 -0
  34. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/drydock/poam.py +0 -0
  35. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/drydock/providers.py +0 -0
  36. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/drydock/rmf.py +0 -0
  37. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/drydock/rmf_graph.py +0 -0
  38. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/drydock/skills.py +0 -0
  39. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/drydock/stig.py +0 -0
  40. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/drydock/tool_registry.py +0 -0
  41. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/drydock/tui/__init__.py +0 -0
  42. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/drydock/tui/app.py +0 -0
  43. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/drydock/tui/approval.py +0 -0
  44. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/drydock/tui/messages.py +0 -0
  45. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/drydock/tui/widgets.py +0 -0
  46. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/drydock/tuning.py +0 -0
  47. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/drydock/web.py +0 -0
  48. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/drydock_cli.egg-info/dependency_links.txt +0 -0
  49. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/drydock_cli.egg-info/entry_points.txt +0 -0
  50. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/drydock_cli.egg-info/requires.txt +0 -0
  51. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/drydock_cli.egg-info/top_level.txt +0 -0
  52. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/setup.cfg +0 -0
  53. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_advisor.py +0 -0
  54. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_approval.py +0 -0
  55. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_back_command.py +0 -0
  56. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_bash_background.py +0 -0
  57. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_bash_output_bounding.py +0 -0
  58. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_bash_process_group.py +0 -0
  59. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_bash_safety.py +0 -0
  60. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_bash_shell.py +0 -0
  61. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_bash_stdin.py +0 -0
  62. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_bash_timeout_network.py +0 -0
  63. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_cci.py +0 -0
  64. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_cli_agents.py +0 -0
  65. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_compact_command.py +0 -0
  66. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_compaction.py +0 -0
  67. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_config.py +0 -0
  68. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_config_migration.py +0 -0
  69. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_context_limit_config.py +0 -0
  70. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_detect.py +0 -0
  71. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_dispatch.py +0 -0
  72. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_e2e_connected.py +0 -0
  73. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_empty_response.py +0 -0
  74. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_extract.py +0 -0
  75. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_failure_loop.py +0 -0
  76. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_first_run_setup.py +0 -0
  77. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_gittools.py +0 -0
  78. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_graphrag.py +0 -0
  79. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_guards_and_tools.py +0 -0
  80. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_hallucinated_tools.py +0 -0
  81. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_leaked_tool_call.py +0 -0
  82. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_loop_detect.py +0 -0
  83. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_mcp.py +0 -0
  84. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_oneshot_unreachable.py +0 -0
  85. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_plan_autocontinue.py +0 -0
  86. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_poam.py +0 -0
  87. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_providers_unreachable.py +0 -0
  88. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_read_index.py +0 -0
  89. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_rmf.py +0 -0
  90. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_rmf_graph.py +0 -0
  91. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_rmf_stig_graph.py +0 -0
  92. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_runaway_repetition.py +0 -0
  93. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_server_probe.py +0 -0
  94. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_skills.py +0 -0
  95. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_stig.py +0 -0
  96. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_stop.py +0 -0
  97. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_streaming_newlines.py +0 -0
  98. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_subagent.py +0 -0
  99. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_system_prompt_help.py +0 -0
  100. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_todo.py +0 -0
  101. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_tool_arg_parsing.py +0 -0
  102. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_tools_undo.py +0 -0
  103. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_tui.py +0 -0
  104. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_tuning.py +0 -0
  105. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_viewimage.py +0 -0
  106. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_vision_input.py +0 -0
  107. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/tests/test_web_tools.py +0 -0
  108. {drydock_cli-3.0.91 → drydock_cli-3.0.93}/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.91
3
+ Version: 3.0.93
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
@@ -77,7 +77,10 @@ A full agentic CLI harness — every tool below is clean-room and dependency-fre
77
77
  calls the `Consult` tool for a second opinion when stuck, and you can `/ask
78
78
  <question>` directly. Opt-in, user-configured — no extra dependency.
79
79
  - **MCP** — connect to Model Context Protocol servers (`~/.drydock/mcp.json`);
80
- their tools appear as `mcp__<server>__<tool>`. List them with `/mcp`.
80
+ their tools appear as `mcp__<server>__<tool>`. List them with `/mcp`. Works with
81
+ third-party servers out of the box — e.g. [Graphify](https://github.com/safishamsi/graphify)
82
+ for a queryable code knowledge graph: see [docs/graphify.md](docs/graphify.md)
83
+ and the copy-paste [example config](examples/mcp/graphify.json).
81
84
  - **Skills** — reusable `/<name>` commands authored as markdown in
82
85
  `~/.drydock/skills/` (or `<project>/.drydock/skills/`); `$ARGS` substitution.
83
86
  - **Loops** — `/loop <count> <prompt>` runs a prompt iteratively (Esc stops).
@@ -53,7 +53,10 @@ A full agentic CLI harness — every tool below is clean-room and dependency-fre
53
53
  calls the `Consult` tool for a second opinion when stuck, and you can `/ask
54
54
  <question>` directly. Opt-in, user-configured — no extra dependency.
55
55
  - **MCP** — connect to Model Context Protocol servers (`~/.drydock/mcp.json`);
56
- their tools appear as `mcp__<server>__<tool>`. List them with `/mcp`.
56
+ their tools appear as `mcp__<server>__<tool>`. List them with `/mcp`. Works with
57
+ third-party servers out of the box — e.g. [Graphify](https://github.com/safishamsi/graphify)
58
+ for a queryable code knowledge graph: see [docs/graphify.md](docs/graphify.md)
59
+ and the copy-paste [example config](examples/mcp/graphify.json).
57
60
  - **Skills** — reusable `/<name>` commands authored as markdown in
58
61
  `~/.drydock/skills/` (or `<project>/.drydock/skills/`); `$ARGS` substitution.
59
62
  - **Loops** — `/loop <count> <prompt>` runs a prompt iteratively (Esc stops).
@@ -942,7 +942,13 @@ def tool_bash(params: dict, config: dict) -> str:
942
942
  # explicitly via a pipe/redirect (echo x | cmd, cmd < file), which
943
943
  # overrides this.
944
944
  stdin=subprocess.DEVNULL,
945
- text=True, cwd=config.get("cwd"), start_new_session=True,
945
+ # errors="replace" so BINARY / non-UTF8 output (cat a binary, a tool
946
+ # emitting raw bytes, gzip to stdout) decodes to replacement chars
947
+ # instead of raising UnicodeDecodeError inside the reader thread —
948
+ # which killed the thread and handed the agent "(no output)", losing
949
+ # even the text parts of mixed output.
950
+ text=True, encoding="utf-8", errors="replace",
951
+ cwd=config.get("cwd"), start_new_session=True,
946
952
  )
947
953
  config.setdefault("_abort", {})["proc"] = proc
948
954
  # Read output in a daemon thread with a HARD byte cap, so memory can't
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: drydock-cli
3
- Version: 3.0.91
3
+ Version: 3.0.93
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
@@ -77,7 +77,10 @@ A full agentic CLI harness — every tool below is clean-room and dependency-fre
77
77
  calls the `Consult` tool for a second opinion when stuck, and you can `/ask
78
78
  <question>` directly. Opt-in, user-configured — no extra dependency.
79
79
  - **MCP** — connect to Model Context Protocol servers (`~/.drydock/mcp.json`);
80
- their tools appear as `mcp__<server>__<tool>`. List them with `/mcp`.
80
+ their tools appear as `mcp__<server>__<tool>`. List them with `/mcp`. Works with
81
+ third-party servers out of the box — e.g. [Graphify](https://github.com/safishamsi/graphify)
82
+ for a queryable code knowledge graph: see [docs/graphify.md](docs/graphify.md)
83
+ and the copy-paste [example config](examples/mcp/graphify.json).
81
84
  - **Skills** — reusable `/<name>` commands authored as markdown in
82
85
  `~/.drydock/skills/` (or `<project>/.drydock/skills/`); `$ARGS` substitution.
83
86
  - **Loops** — `/loop <count> <prompt>` runs a prompt iteratively (Esc stops).
@@ -50,6 +50,7 @@ tests/test_advisor.py
50
50
  tests/test_approval.py
51
51
  tests/test_back_command.py
52
52
  tests/test_bash_background.py
53
+ tests/test_bash_binary_output.py
53
54
  tests/test_bash_output_bounding.py
54
55
  tests/test_bash_process_group.py
55
56
  tests/test_bash_safety.py
@@ -71,6 +72,7 @@ tests/test_extract.py
71
72
  tests/test_failure_loop.py
72
73
  tests/test_first_run_setup.py
73
74
  tests/test_gittools.py
75
+ tests/test_graphify_example.py
74
76
  tests/test_graphrag.py
75
77
  tests/test_guards_and_tools.py
76
78
  tests/test_hallucinated_tools.py
@@ -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.91"
10
+ version = "3.0.93"
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,33 @@
1
+ """tool_bash must not choke on binary / non-UTF8 stdout. text=True with the
2
+ default (strict) decode raised UnicodeDecodeError INSIDE the reader thread — the
3
+ thread died and the agent got "(no output)", losing even the text parts of mixed
4
+ output. errors="replace" keeps it non-crashing and preserves the text. Found by
5
+ probing the binary-output I/O path directly."""
6
+ from __future__ import annotations
7
+
8
+ from drydock.tools import tool_bash
9
+
10
+
11
+ def _run(cmd):
12
+ return tool_bash({"command": cmd, "timeout": 8}, {"cwd": "/tmp"})
13
+
14
+
15
+ def test_invalid_utf8_does_not_crash_and_keeps_text():
16
+ out = _run(r"printf '\xff\xfe hello'")
17
+ assert "hello" in out and "(no output)" not in out
18
+
19
+
20
+ def test_mixed_text_and_binary_preserves_text():
21
+ # the readable lines must survive even though raw bytes sit between them
22
+ out = _run(r"echo START; printf '\xc0\xc1\xff'; echo END")
23
+ assert "START" in out and "END" in out
24
+
25
+
26
+ def test_binary_file_head_returns_something():
27
+ out = _run("head -c 80 /bin/ls")
28
+ assert out.strip() and "(no output)" not in out and "EXCEPTION" not in out
29
+
30
+
31
+ def test_plain_text_unaffected():
32
+ out = _run("echo hello && echo world")
33
+ assert "hello" in out and "world" in out
@@ -0,0 +1,36 @@
1
+ """The bundled Graphify MCP example (docs/graphify.md + examples/mcp/graphify.json)
2
+ must stay valid + in the shape drydock's MCP loader expects, so the copy-paste
3
+ recipe never rots."""
4
+ from __future__ import annotations
5
+
6
+ import json
7
+ from pathlib import Path
8
+
9
+ _ROOT = Path(__file__).resolve().parent.parent
10
+ _EXAMPLE = _ROOT / "examples" / "mcp" / "graphify.json"
11
+ _DOC = _ROOT / "docs" / "graphify.md"
12
+
13
+
14
+ def test_example_is_valid_json_with_mcpservers_shape():
15
+ cfg = json.loads(_EXAMPLE.read_text())
16
+ assert "mcpServers" in cfg and "graphify" in cfg["mcpServers"]
17
+ srv = cfg["mcpServers"]["graphify"]
18
+ assert srv["command"] == "graphify-mcp"
19
+ assert "--transport" in srv["args"] and "stdio" in srv["args"]
20
+ # the same shape drydock/mcp.py consumes: command + args list
21
+ assert isinstance(srv["args"], list)
22
+
23
+
24
+ def test_example_matches_drydock_mcp_loader_shape():
25
+ """Instantiating an MCPServer from the example must not raise (parses the
26
+ command/args the way connect_all does), without starting it."""
27
+ from drydock.mcp import MCPServer
28
+ cfg = json.loads(_EXAMPLE.read_text())["mcpServers"]["graphify"]
29
+ srv = MCPServer("graphify", cfg["command"], cfg["args"], cfg.get("env"))
30
+ assert srv.command == "graphify-mcp" and srv.args[0] == "--transport"
31
+
32
+
33
+ def test_doc_exists_and_links_example():
34
+ text = _DOC.read_text()
35
+ assert "graphify-mcp" in text and "OPENAI_BASE_URL" in text
36
+ assert "examples/mcp/graphify.json" in text
File without changes
File without changes
File without changes