Add content-only workspace read modes
Make the human workspace read commands easier to use in chat transcripts and shell pipelines by adding CLI-only --content-only to workspace file read and workspace disk read. Keep JSON, SDK, and MCP behavior unchanged while fixing the default human rendering so content without a trailing newline is cleanly separated from the summary footer. Update the 3.9.0 docs and roadmap status, and add CLI regression coverage plus a real guest-backed smoke for live and stopped-disk reads.
This commit is contained in:
parent
407c805ce2
commit
22d284b1f5
13 changed files with 314 additions and 46 deletions
|
|
@ -159,6 +159,7 @@ def test_cli_subcommand_help_includes_examples_and_guidance() -> None:
|
|||
_subparser_choice(_subparser_choice(parser, "workspace"), "file"), "read"
|
||||
).format_help()
|
||||
assert "--max-bytes" in workspace_file_read_help
|
||||
assert "--content-only" in workspace_file_read_help
|
||||
|
||||
workspace_file_write_help = _subparser_choice(
|
||||
_subparser_choice(_subparser_choice(parser, "workspace"), "file"), "write"
|
||||
|
|
@ -207,6 +208,7 @@ def test_cli_subcommand_help_includes_examples_and_guidance() -> None:
|
|||
_subparser_choice(_subparser_choice(parser, "workspace"), "disk"), "read"
|
||||
).format_help()
|
||||
assert "--max-bytes" in workspace_disk_read_help
|
||||
assert "--content-only" in workspace_disk_read_help
|
||||
|
||||
workspace_diff_help = _subparser_choice(
|
||||
_subparser_choice(parser, "workspace"), "diff"
|
||||
|
|
@ -637,6 +639,32 @@ def test_cli_shortcut_flags_are_mutually_exclusive() -> None:
|
|||
]
|
||||
)
|
||||
|
||||
with pytest.raises(SystemExit):
|
||||
parser.parse_args(
|
||||
[
|
||||
"workspace",
|
||||
"file",
|
||||
"read",
|
||||
"workspace-123",
|
||||
"note.txt",
|
||||
"--json",
|
||||
"--content-only",
|
||||
]
|
||||
)
|
||||
|
||||
with pytest.raises(SystemExit):
|
||||
parser.parse_args(
|
||||
[
|
||||
"workspace",
|
||||
"disk",
|
||||
"read",
|
||||
"workspace-123",
|
||||
"note.txt",
|
||||
"--json",
|
||||
"--content-only",
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def test_cli_workspace_create_prints_json(
|
||||
monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str]
|
||||
|
|
@ -1523,6 +1551,184 @@ def test_cli_workspace_disk_commands_print_human_and_json(
|
|||
assert read_payload["content"] == "hello\n"
|
||||
|
||||
|
||||
def test_cli_workspace_file_read_human_separates_summary_from_content(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
capsys: pytest.CaptureFixture[str],
|
||||
) -> None:
|
||||
class StubPyro:
|
||||
def read_workspace_file(
|
||||
self,
|
||||
workspace_id: str,
|
||||
path: str,
|
||||
*,
|
||||
max_bytes: int,
|
||||
) -> dict[str, Any]:
|
||||
assert workspace_id == "workspace-123"
|
||||
assert path == "note.txt"
|
||||
assert max_bytes == 4096
|
||||
return {
|
||||
"workspace_id": workspace_id,
|
||||
"path": "/workspace/note.txt",
|
||||
"size_bytes": 5,
|
||||
"max_bytes": max_bytes,
|
||||
"content": "hello",
|
||||
"truncated": False,
|
||||
}
|
||||
|
||||
class StubParser:
|
||||
def parse_args(self) -> argparse.Namespace:
|
||||
return argparse.Namespace(
|
||||
command="workspace",
|
||||
workspace_command="file",
|
||||
workspace_file_command="read",
|
||||
workspace_id="workspace-123",
|
||||
path="note.txt",
|
||||
max_bytes=4096,
|
||||
content_only=False,
|
||||
json=False,
|
||||
)
|
||||
|
||||
monkeypatch.setattr(cli, "Pyro", StubPyro)
|
||||
monkeypatch.setattr(cli, "_build_parser", lambda: StubParser())
|
||||
|
||||
cli.main()
|
||||
captured = capsys.readouterr()
|
||||
assert captured.out == "hello\n"
|
||||
assert "[workspace-file-read] workspace_id=workspace-123" in captured.err
|
||||
|
||||
|
||||
def test_cli_workspace_file_read_content_only_suppresses_summary(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
capsys: pytest.CaptureFixture[str],
|
||||
) -> None:
|
||||
class StubPyro:
|
||||
def read_workspace_file(
|
||||
self,
|
||||
workspace_id: str,
|
||||
path: str,
|
||||
*,
|
||||
max_bytes: int,
|
||||
) -> dict[str, Any]:
|
||||
return {
|
||||
"workspace_id": workspace_id,
|
||||
"path": "/workspace/note.txt",
|
||||
"size_bytes": 5,
|
||||
"max_bytes": max_bytes,
|
||||
"content": "hello",
|
||||
"truncated": False,
|
||||
}
|
||||
|
||||
class StubParser:
|
||||
def parse_args(self) -> argparse.Namespace:
|
||||
return argparse.Namespace(
|
||||
command="workspace",
|
||||
workspace_command="file",
|
||||
workspace_file_command="read",
|
||||
workspace_id="workspace-123",
|
||||
path="note.txt",
|
||||
max_bytes=4096,
|
||||
content_only=True,
|
||||
json=False,
|
||||
)
|
||||
|
||||
monkeypatch.setattr(cli, "Pyro", StubPyro)
|
||||
monkeypatch.setattr(cli, "_build_parser", lambda: StubParser())
|
||||
|
||||
cli.main()
|
||||
captured = capsys.readouterr()
|
||||
assert captured.out == "hello"
|
||||
assert captured.err == ""
|
||||
|
||||
|
||||
def test_cli_workspace_disk_read_human_separates_summary_from_content(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
capsys: pytest.CaptureFixture[str],
|
||||
) -> None:
|
||||
class StubPyro:
|
||||
def read_workspace_disk(
|
||||
self,
|
||||
workspace_id: str,
|
||||
path: str,
|
||||
*,
|
||||
max_bytes: int,
|
||||
) -> dict[str, Any]:
|
||||
assert workspace_id == "workspace-123"
|
||||
assert path == "note.txt"
|
||||
assert max_bytes == 4096
|
||||
return {
|
||||
"workspace_id": workspace_id,
|
||||
"path": "/workspace/note.txt",
|
||||
"size_bytes": 5,
|
||||
"max_bytes": max_bytes,
|
||||
"content": "hello",
|
||||
"truncated": False,
|
||||
}
|
||||
|
||||
class StubParser:
|
||||
def parse_args(self) -> argparse.Namespace:
|
||||
return argparse.Namespace(
|
||||
command="workspace",
|
||||
workspace_command="disk",
|
||||
workspace_disk_command="read",
|
||||
workspace_id="workspace-123",
|
||||
path="note.txt",
|
||||
max_bytes=4096,
|
||||
content_only=False,
|
||||
json=False,
|
||||
)
|
||||
|
||||
monkeypatch.setattr(cli, "Pyro", StubPyro)
|
||||
monkeypatch.setattr(cli, "_build_parser", lambda: StubParser())
|
||||
|
||||
cli.main()
|
||||
captured = capsys.readouterr()
|
||||
assert captured.out == "hello\n"
|
||||
assert "[workspace-disk-read] workspace_id=workspace-123" in captured.err
|
||||
|
||||
|
||||
def test_cli_workspace_disk_read_content_only_suppresses_summary(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
capsys: pytest.CaptureFixture[str],
|
||||
) -> None:
|
||||
class StubPyro:
|
||||
def read_workspace_disk(
|
||||
self,
|
||||
workspace_id: str,
|
||||
path: str,
|
||||
*,
|
||||
max_bytes: int,
|
||||
) -> dict[str, Any]:
|
||||
return {
|
||||
"workspace_id": workspace_id,
|
||||
"path": "/workspace/note.txt",
|
||||
"size_bytes": 5,
|
||||
"max_bytes": max_bytes,
|
||||
"content": "hello",
|
||||
"truncated": False,
|
||||
}
|
||||
|
||||
class StubParser:
|
||||
def parse_args(self) -> argparse.Namespace:
|
||||
return argparse.Namespace(
|
||||
command="workspace",
|
||||
workspace_command="disk",
|
||||
workspace_disk_command="read",
|
||||
workspace_id="workspace-123",
|
||||
path="note.txt",
|
||||
max_bytes=4096,
|
||||
content_only=True,
|
||||
json=False,
|
||||
)
|
||||
|
||||
monkeypatch.setattr(cli, "Pyro", StubPyro)
|
||||
monkeypatch.setattr(cli, "_build_parser", lambda: StubParser())
|
||||
|
||||
cli.main()
|
||||
captured = capsys.readouterr()
|
||||
assert captured.out == "hello"
|
||||
assert captured.err == ""
|
||||
|
||||
|
||||
def test_cli_workspace_diff_prints_human_output(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
capsys: pytest.CaptureFixture[str],
|
||||
|
|
@ -2618,6 +2824,17 @@ def test_chat_host_docs_and_examples_recommend_workspace_core() -> None:
|
|||
assert "Recommended default for most chat hosts: `workspace-core`." in mcp_config
|
||||
|
||||
|
||||
def test_content_only_read_docs_are_aligned() -> None:
|
||||
readme = Path("README.md").read_text(encoding="utf-8")
|
||||
install = Path("docs/install.md").read_text(encoding="utf-8")
|
||||
first_run = Path("docs/first-run.md").read_text(encoding="utf-8")
|
||||
|
||||
assert 'workspace file read "$WORKSPACE_ID" note.txt --content-only' in readme
|
||||
assert 'workspace file read "$WORKSPACE_ID" note.txt --content-only' in install
|
||||
assert 'workspace file read "$WORKSPACE_ID" note.txt --content-only' in first_run
|
||||
assert 'workspace disk read "$WORKSPACE_ID" note.txt --content-only' in first_run
|
||||
|
||||
|
||||
def test_cli_workspace_shell_write_signal_close_json(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
capsys: pytest.CaptureFixture[str],
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue