Add workspace snapshots and full reset

Implement the 2.8.0 workspace milestone with named snapshots and full-sandbox reset across the CLI, Python SDK, and MCP server.

Persist the immutable baseline plus named snapshot archives under each workspace, add workspace reset metadata, and make reset recreate the sandbox while clearing command history, shells, and services without changing the workspace identity or diff baseline.

Refresh the 2.8.0 docs, roadmap, and Python example around reset-over-repair, then validate with uv lock, UV_CACHE_DIR=.uv-cache make check, UV_CACHE_DIR=.uv-cache make dist-check, and a real guest-backed create/snapshot/reset/diff smoke test outside the sandbox.
This commit is contained in:
Thales Maciel 2026-03-12 12:41:11 -03:00
parent f504f0a331
commit 18b8fd2a7d
20 changed files with 1429 additions and 29 deletions

View file

@ -146,6 +146,23 @@ class Pyro:
def diff_workspace(self, workspace_id: str) -> dict[str, Any]:
return self._manager.diff_workspace(workspace_id)
def create_snapshot(self, workspace_id: str, snapshot_name: str) -> dict[str, Any]:
return self._manager.create_snapshot(workspace_id, snapshot_name)
def list_snapshots(self, workspace_id: str) -> dict[str, Any]:
return self._manager.list_snapshots(workspace_id)
def delete_snapshot(self, workspace_id: str, snapshot_name: str) -> dict[str, Any]:
return self._manager.delete_snapshot(workspace_id, snapshot_name)
def reset_workspace(
self,
workspace_id: str,
*,
snapshot: str = "baseline",
) -> dict[str, Any]:
return self._manager.reset_workspace(workspace_id, snapshot=snapshot)
def open_shell(
self,
workspace_id: str,
@ -444,6 +461,29 @@ class Pyro:
"""Compare `/workspace` to the immutable create-time baseline."""
return self.diff_workspace(workspace_id)
@server.tool()
async def snapshot_create(workspace_id: str, snapshot_name: str) -> dict[str, Any]:
"""Create one named workspace snapshot from the current `/workspace` tree."""
return self.create_snapshot(workspace_id, snapshot_name)
@server.tool()
async def snapshot_list(workspace_id: str) -> dict[str, Any]:
"""List the baseline plus named snapshots for one workspace."""
return self.list_snapshots(workspace_id)
@server.tool()
async def snapshot_delete(workspace_id: str, snapshot_name: str) -> dict[str, Any]:
"""Delete one named snapshot from a workspace."""
return self.delete_snapshot(workspace_id, snapshot_name)
@server.tool()
async def workspace_reset(
workspace_id: str,
snapshot: str = "baseline",
) -> dict[str, Any]:
"""Recreate a workspace and restore `/workspace` from baseline or one named snapshot."""
return self.reset_workspace(workspace_id, snapshot=snapshot)
@server.tool()
async def shell_open(
workspace_id: str,