drydock-cli 3.0.97__tar.gz → 3.0.98__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 (112) hide show
  1. {drydock_cli-3.0.97/drydock_cli.egg-info → drydock_cli-3.0.98}/PKG-INFO +1 -1
  2. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/drydock/tools/__init__.py +7 -0
  3. {drydock_cli-3.0.97 → drydock_cli-3.0.98/drydock_cli.egg-info}/PKG-INFO +1 -1
  4. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/drydock_cli.egg-info/SOURCES.txt +1 -0
  5. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/pyproject.toml +1 -1
  6. drydock_cli-3.0.98/tests/test_write_content_coerce.py +37 -0
  7. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/LICENSE +0 -0
  8. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/NOTICE +0 -0
  9. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/README.md +0 -0
  10. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/drydock/__init__.py +0 -0
  11. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/drydock/__main__.py +0 -0
  12. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/drydock/advisor.py +0 -0
  13. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/drydock/agent.py +0 -0
  14. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/drydock/bash_safety.py +0 -0
  15. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/drydock/builtin_skills/__init__.py +0 -0
  16. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/drydock/builtin_skills/rmf-categorize.md +0 -0
  17. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/drydock/builtin_skills/rmf-control.md +0 -0
  18. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/drydock/builtin_skills/rmf-poam.md +0 -0
  19. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/drydock/builtin_skills/rmf-review.md +0 -0
  20. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/drydock/builtin_skills/stig-assess.md +0 -0
  21. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/drydock/builtin_skills/stig-remediate.md +0 -0
  22. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/drydock/cci.py +0 -0
  23. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/drydock/cli.py +0 -0
  24. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/drydock/compaction.py +0 -0
  25. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/drydock/config.py +0 -0
  26. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/drydock/detect.py +0 -0
  27. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/drydock/extract.py +0 -0
  28. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/drydock/gittools.py +0 -0
  29. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/drydock/graphrag.py +0 -0
  30. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/drydock/guards.py +0 -0
  31. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/drydock/loop_detect.py +0 -0
  32. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/drydock/mcp.py +0 -0
  33. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/drydock/poam.py +0 -0
  34. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/drydock/providers.py +0 -0
  35. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/drydock/rmf.py +0 -0
  36. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/drydock/rmf_graph.py +0 -0
  37. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/drydock/skills.py +0 -0
  38. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/drydock/stig.py +0 -0
  39. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/drydock/tool_registry.py +0 -0
  40. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/drydock/tui/__init__.py +0 -0
  41. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/drydock/tui/app.py +0 -0
  42. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/drydock/tui/approval.py +0 -0
  43. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/drydock/tui/messages.py +0 -0
  44. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/drydock/tui/widgets.py +0 -0
  45. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/drydock/tuning.py +0 -0
  46. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/drydock/web.py +0 -0
  47. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/drydock_cli.egg-info/dependency_links.txt +0 -0
  48. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/drydock_cli.egg-info/entry_points.txt +0 -0
  49. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/drydock_cli.egg-info/requires.txt +0 -0
  50. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/drydock_cli.egg-info/top_level.txt +0 -0
  51. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/setup.cfg +0 -0
  52. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_advisor.py +0 -0
  53. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_approval.py +0 -0
  54. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_back_command.py +0 -0
  55. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_bash_background.py +0 -0
  56. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_bash_binary_output.py +0 -0
  57. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_bash_output_bounding.py +0 -0
  58. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_bash_process_group.py +0 -0
  59. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_bash_safety.py +0 -0
  60. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_bash_sanitize.py +0 -0
  61. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_bash_shell.py +0 -0
  62. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_bash_stdin.py +0 -0
  63. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_bash_timeout_network.py +0 -0
  64. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_bash_timeout_param.py +0 -0
  65. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_cci.py +0 -0
  66. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_cli_agents.py +0 -0
  67. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_compact_command.py +0 -0
  68. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_compaction.py +0 -0
  69. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_config.py +0 -0
  70. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_config_migration.py +0 -0
  71. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_context_limit_config.py +0 -0
  72. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_detect.py +0 -0
  73. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_dispatch.py +0 -0
  74. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_e2e_connected.py +0 -0
  75. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_empty_response.py +0 -0
  76. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_extract.py +0 -0
  77. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_failure_loop.py +0 -0
  78. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_first_run_setup.py +0 -0
  79. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_gittools.py +0 -0
  80. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_graphify_example.py +0 -0
  81. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_graphrag.py +0 -0
  82. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_grep_and_read_robust.py +0 -0
  83. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_guards_and_tools.py +0 -0
  84. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_hallucinated_tools.py +0 -0
  85. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_leaked_tool_call.py +0 -0
  86. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_loop_detect.py +0 -0
  87. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_mcp.py +0 -0
  88. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_oneshot_unreachable.py +0 -0
  89. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_plan_autocontinue.py +0 -0
  90. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_poam.py +0 -0
  91. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_providers_unreachable.py +0 -0
  92. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_read_index.py +0 -0
  93. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_rmf.py +0 -0
  94. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_rmf_graph.py +0 -0
  95. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_rmf_stig_graph.py +0 -0
  96. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_runaway_repetition.py +0 -0
  97. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_server_probe.py +0 -0
  98. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_skills.py +0 -0
  99. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_stig.py +0 -0
  100. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_stop.py +0 -0
  101. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_streaming_newlines.py +0 -0
  102. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_subagent.py +0 -0
  103. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_system_prompt_help.py +0 -0
  104. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_todo.py +0 -0
  105. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_tool_arg_parsing.py +0 -0
  106. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_tools_undo.py +0 -0
  107. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_tui.py +0 -0
  108. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_tuning.py +0 -0
  109. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_viewimage.py +0 -0
  110. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_vision_input.py +0 -0
  111. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/tests/test_web_tools.py +0 -0
  112. {drydock_cli-3.0.97 → drydock_cli-3.0.98}/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.97
3
+ Version: 3.0.98
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
@@ -671,6 +671,13 @@ def tool_write(params: dict, config: dict) -> str:
671
671
  if Path(fp).is_dir():
672
672
  return f"Error: {fp} is a directory, not a file. Pass a file path."
673
673
  content = params.get("content", "")
674
+ # Local models sometimes send content as a JSON array of lines (or a number),
675
+ # which f.write() can't take — coerce instead of crashing with a TypeError
676
+ # (tools must return errors, never raise). A list → newline-joined lines.
677
+ if isinstance(content, (list, tuple)):
678
+ content = "\n".join(str(x) for x in content)
679
+ elif not isinstance(content, str):
680
+ content = "" if content is None else str(content)
674
681
  if has_conflict_markers(content):
675
682
  return conflict_marker_refusal(fp)
676
683
  prev = _snapshot(fp)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: drydock-cli
3
- Version: 3.0.97
3
+ Version: 3.0.98
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
@@ -106,4 +106,5 @@ tests/test_tuning.py
106
106
  tests/test_viewimage.py
107
107
  tests/test_vision_input.py
108
108
  tests/test_web_tools.py
109
+ tests/test_write_content_coerce.py
109
110
  tests/test_xccdf.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.97"
10
+ version = "3.0.98"
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,37 @@
1
+ """tool_write must not raise on non-string content. Local models sometimes send
2
+ `content` as a JSON array of lines (or a number); f.write() would TypeError, and
3
+ tools must return a result, never raise. A list → newline-joined lines."""
4
+ from __future__ import annotations
5
+
6
+ from drydock.tools import tool_write
7
+
8
+
9
+ def _write(tmp_path, content):
10
+ fp = tmp_path / "out.txt"
11
+ out = tool_write({"file_path": str(fp), "content": content}, {"cwd": str(tmp_path)})
12
+ return out, fp.read_text()
13
+
14
+
15
+ def test_list_content_joined(tmp_path):
16
+ out, text = _write(tmp_path, ["line1", "line2", "line3"])
17
+ assert "Error" not in out and text == "line1\nline2\nline3"
18
+
19
+
20
+ def test_int_content_stringified(tmp_path):
21
+ out, text = _write(tmp_path, 42)
22
+ assert "Error" not in out and text == "42"
23
+
24
+
25
+ def test_none_content_empty(tmp_path):
26
+ out, text = _write(tmp_path, None)
27
+ assert "Error" not in out and text == ""
28
+
29
+
30
+ def test_normal_string_unchanged(tmp_path):
31
+ out, text = _write(tmp_path, "hello\nworld")
32
+ assert text == "hello\nworld"
33
+
34
+
35
+ def test_list_of_numbers(tmp_path):
36
+ out, text = _write(tmp_path, [1, 2, 3])
37
+ assert text == "1\n2\n3"
File without changes
File without changes
File without changes
File without changes