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:
parent
dbb71a3174
commit
ab02ae46c7
27 changed files with 3068 additions and 17 deletions
|
|
@ -157,6 +157,56 @@ class Pyro:
|
|||
def diff_workspace(self, workspace_id: str) -> dict[str, Any]:
|
||||
return self._manager.diff_workspace(workspace_id)
|
||||
|
||||
def list_workspace_files(
|
||||
self,
|
||||
workspace_id: str,
|
||||
*,
|
||||
path: str = "/workspace",
|
||||
recursive: bool = False,
|
||||
) -> dict[str, Any]:
|
||||
return self._manager.list_workspace_files(
|
||||
workspace_id,
|
||||
path=path,
|
||||
recursive=recursive,
|
||||
)
|
||||
|
||||
def read_workspace_file(
|
||||
self,
|
||||
workspace_id: str,
|
||||
path: str,
|
||||
*,
|
||||
max_bytes: int = 65536,
|
||||
) -> dict[str, Any]:
|
||||
return self._manager.read_workspace_file(
|
||||
workspace_id,
|
||||
path,
|
||||
max_bytes=max_bytes,
|
||||
)
|
||||
|
||||
def write_workspace_file(
|
||||
self,
|
||||
workspace_id: str,
|
||||
path: str,
|
||||
*,
|
||||
text: str,
|
||||
) -> dict[str, Any]:
|
||||
return self._manager.write_workspace_file(
|
||||
workspace_id,
|
||||
path,
|
||||
text=text,
|
||||
)
|
||||
|
||||
def apply_workspace_patch(
|
||||
self,
|
||||
workspace_id: str,
|
||||
*,
|
||||
patch: str,
|
||||
) -> dict[str, Any]:
|
||||
return self._manager.apply_workspace_patch(
|
||||
workspace_id,
|
||||
patch=patch,
|
||||
)
|
||||
|
||||
def export_workspace_disk(
|
||||
self,
|
||||
workspace_id: str,
|
||||
|
|
@ -529,6 +579,56 @@ class Pyro:
|
|||
"""Compare `/workspace` to the immutable create-time baseline."""
|
||||
return self.diff_workspace(workspace_id)
|
||||
|
||||
@server.tool()
|
||||
async def workspace_file_list(
|
||||
workspace_id: str,
|
||||
path: str = "/workspace",
|
||||
recursive: bool = False,
|
||||
) -> dict[str, Any]:
|
||||
"""List metadata for files and directories under one live workspace path."""
|
||||
return self.list_workspace_files(
|
||||
workspace_id,
|
||||
path=path,
|
||||
recursive=recursive,
|
||||
)
|
||||
|
||||
@server.tool()
|
||||
async def workspace_file_read(
|
||||
workspace_id: str,
|
||||
path: str,
|
||||
max_bytes: int = 65536,
|
||||
) -> dict[str, Any]:
|
||||
"""Read one regular text file from a live workspace path."""
|
||||
return self.read_workspace_file(
|
||||
workspace_id,
|
||||
path,
|
||||
max_bytes=max_bytes,
|
||||
)
|
||||
|
||||
@server.tool()
|
||||
async def workspace_file_write(
|
||||
workspace_id: str,
|
||||
path: str,
|
||||
text: str,
|
||||
) -> dict[str, Any]:
|
||||
"""Create or replace one regular text file under `/workspace`."""
|
||||
return self.write_workspace_file(
|
||||
workspace_id,
|
||||
path,
|
||||
text=text,
|
||||
)
|
||||
|
||||
@server.tool()
|
||||
async def workspace_patch_apply(
|
||||
workspace_id: str,
|
||||
patch: str,
|
||||
) -> dict[str, Any]:
|
||||
"""Apply a unified text patch inside one live workspace."""
|
||||
return self.apply_workspace_patch(
|
||||
workspace_id,
|
||||
patch=patch,
|
||||
)
|
||||
|
||||
@server.tool()
|
||||
async def workspace_disk_export(
|
||||
workspace_id: str,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue