Add model-native workspace file operations

Remove shell-escaped file mutation from the stable workspace flow by adding explicit file and patch tools across the CLI, SDK, and MCP surfaces.

This adds workspace file list/read/write plus unified text patch application, backed by new guest and manager file primitives that stay scoped to started workspaces and /workspace only. Patch application is preflighted on the host, file writes stay text-only and bounded, and the existing diff/export/reset semantics remain intact.

The milestone also updates the 3.2.0 roadmap, public contract, docs, examples, and versioning, and includes focused coverage for the new helper module and dispatch paths.

Validation:
- uv lock
- UV_CACHE_DIR=.uv-cache make check
- UV_CACHE_DIR=.uv-cache make dist-check
- real guest-backed smoke for workspace file read, patch apply, exec, export, and delete
This commit is contained in:
Thales Maciel 2026-03-12 22:03:25 -03:00
parent dbb71a3174
commit ab02ae46c7
27 changed files with 3068 additions and 17 deletions

View file

@ -24,6 +24,12 @@ from pyro_mcp.contract import (
PUBLIC_CLI_WORKSPACE_DISK_READ_FLAGS,
PUBLIC_CLI_WORKSPACE_EXEC_FLAGS,
PUBLIC_CLI_WORKSPACE_EXPORT_FLAGS,
PUBLIC_CLI_WORKSPACE_FILE_LIST_FLAGS,
PUBLIC_CLI_WORKSPACE_FILE_READ_FLAGS,
PUBLIC_CLI_WORKSPACE_FILE_SUBCOMMANDS,
PUBLIC_CLI_WORKSPACE_FILE_WRITE_FLAGS,
PUBLIC_CLI_WORKSPACE_PATCH_APPLY_FLAGS,
PUBLIC_CLI_WORKSPACE_PATCH_SUBCOMMANDS,
PUBLIC_CLI_WORKSPACE_RESET_FLAGS,
PUBLIC_CLI_WORKSPACE_SERVICE_LIST_FLAGS,
PUBLIC_CLI_WORKSPACE_SERVICE_LOGS_FLAGS,
@ -121,6 +127,36 @@ def test_public_cli_help_lists_commands_and_run_flags() -> None:
).format_help()
for flag in PUBLIC_CLI_WORKSPACE_EXPORT_FLAGS:
assert flag in workspace_export_help_text
workspace_file_help_text = _subparser_choice(
_subparser_choice(parser, "workspace"), "file"
).format_help()
for subcommand_name in PUBLIC_CLI_WORKSPACE_FILE_SUBCOMMANDS:
assert subcommand_name in workspace_file_help_text
workspace_file_list_help_text = _subparser_choice(
_subparser_choice(_subparser_choice(parser, "workspace"), "file"), "list"
).format_help()
for flag in PUBLIC_CLI_WORKSPACE_FILE_LIST_FLAGS:
assert flag in workspace_file_list_help_text
workspace_file_read_help_text = _subparser_choice(
_subparser_choice(_subparser_choice(parser, "workspace"), "file"), "read"
).format_help()
for flag in PUBLIC_CLI_WORKSPACE_FILE_READ_FLAGS:
assert flag in workspace_file_read_help_text
workspace_file_write_help_text = _subparser_choice(
_subparser_choice(_subparser_choice(parser, "workspace"), "file"), "write"
).format_help()
for flag in PUBLIC_CLI_WORKSPACE_FILE_WRITE_FLAGS:
assert flag in workspace_file_write_help_text
workspace_patch_help_text = _subparser_choice(
_subparser_choice(parser, "workspace"), "patch"
).format_help()
for subcommand_name in PUBLIC_CLI_WORKSPACE_PATCH_SUBCOMMANDS:
assert subcommand_name in workspace_patch_help_text
workspace_patch_apply_help_text = _subparser_choice(
_subparser_choice(_subparser_choice(parser, "workspace"), "patch"), "apply"
).format_help()
for flag in PUBLIC_CLI_WORKSPACE_PATCH_APPLY_FLAGS:
assert flag in workspace_patch_apply_help_text
workspace_disk_help_text = _subparser_choice(
_subparser_choice(parser, "workspace"), "disk"
).format_help()