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.
53 lines
2.5 KiB
Python
53 lines
2.5 KiB
Python
from __future__ import annotations
|
|
|
|
import tempfile
|
|
from pathlib import Path
|
|
|
|
from pyro_mcp import Pyro
|
|
|
|
|
|
def main() -> None:
|
|
pyro = Pyro()
|
|
with (
|
|
tempfile.TemporaryDirectory(prefix="pyro-workspace-seed-") as seed_dir,
|
|
tempfile.TemporaryDirectory(prefix="pyro-workspace-sync-") as sync_dir,
|
|
tempfile.TemporaryDirectory(prefix="pyro-workspace-export-") as export_dir,
|
|
):
|
|
Path(seed_dir, "note.txt").write_text("hello from seed\n", encoding="utf-8")
|
|
Path(sync_dir, "note.txt").write_text("hello from sync\n", encoding="utf-8")
|
|
created = pyro.create_workspace(environment="debian:12", seed_path=seed_dir)
|
|
workspace_id = str(created["workspace_id"])
|
|
try:
|
|
pyro.push_workspace_sync(workspace_id, sync_dir)
|
|
result = pyro.exec_workspace(workspace_id, command="cat note.txt")
|
|
print(result["stdout"], end="")
|
|
diff_result = pyro.diff_workspace(workspace_id)
|
|
print(f"changed={diff_result['changed']} total={diff_result['summary']['total']}")
|
|
snapshot = pyro.create_snapshot(workspace_id, "checkpoint")
|
|
print(snapshot["snapshot"]["snapshot_name"])
|
|
exported_path = Path(export_dir, "note.txt")
|
|
pyro.export_workspace(workspace_id, "note.txt", output_path=exported_path)
|
|
print(exported_path.read_text(encoding="utf-8"), end="")
|
|
pyro.start_service(
|
|
workspace_id,
|
|
"web",
|
|
command="touch .web-ready && while true; do sleep 60; done",
|
|
readiness={"type": "file", "path": ".web-ready"},
|
|
)
|
|
services = pyro.list_services(workspace_id)
|
|
print(f"services={services['count']} running={services['running_count']}")
|
|
service_status = pyro.status_service(workspace_id, "web")
|
|
print(f"service_state={service_status['state']} ready_at={service_status['ready_at']}")
|
|
service_logs = pyro.logs_service(workspace_id, "web", tail_lines=20)
|
|
print(f"service_stdout_len={len(service_logs['stdout'])}")
|
|
pyro.stop_service(workspace_id, "web")
|
|
reset = pyro.reset_workspace(workspace_id, snapshot="checkpoint")
|
|
print(f"reset_count={reset['reset_count']}")
|
|
logs = pyro.logs_workspace(workspace_id)
|
|
print(f"workspace_id={workspace_id} command_count={logs['count']}")
|
|
finally:
|
|
pyro.delete_workspace(workspace_id)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|