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:
parent
f504f0a331
commit
18b8fd2a7d
20 changed files with 1429 additions and 29 deletions
|
|
@ -46,6 +46,10 @@ def test_create_server_registers_vm_tools(tmp_path: Path) -> None:
|
|||
assert "service_status" in tool_names
|
||||
assert "service_logs" in tool_names
|
||||
assert "service_stop" in tool_names
|
||||
assert "snapshot_create" in tool_names
|
||||
assert "snapshot_delete" in tool_names
|
||||
assert "snapshot_list" in tool_names
|
||||
assert "workspace_reset" in tool_names
|
||||
|
||||
|
||||
def test_vm_run_round_trip(tmp_path: Path) -> None:
|
||||
|
|
@ -234,6 +238,15 @@ def test_workspace_tools_round_trip(tmp_path: Path) -> None:
|
|||
diffed = _extract_structured(
|
||||
await server.call_tool("workspace_diff", {"workspace_id": workspace_id})
|
||||
)
|
||||
snapshot = _extract_structured(
|
||||
await server.call_tool(
|
||||
"snapshot_create",
|
||||
{"workspace_id": workspace_id, "snapshot_name": "checkpoint"},
|
||||
)
|
||||
)
|
||||
snapshots = _extract_structured(
|
||||
await server.call_tool("snapshot_list", {"workspace_id": workspace_id})
|
||||
)
|
||||
export_path = tmp_path / "exported-more.txt"
|
||||
exported = _extract_structured(
|
||||
await server.call_tool(
|
||||
|
|
@ -287,6 +300,18 @@ def test_workspace_tools_round_trip(tmp_path: Path) -> None:
|
|||
},
|
||||
)
|
||||
)
|
||||
reset = _extract_structured(
|
||||
await server.call_tool(
|
||||
"workspace_reset",
|
||||
{"workspace_id": workspace_id, "snapshot": "checkpoint"},
|
||||
)
|
||||
)
|
||||
deleted_snapshot = _extract_structured(
|
||||
await server.call_tool(
|
||||
"snapshot_delete",
|
||||
{"workspace_id": workspace_id, "snapshot_name": "checkpoint"},
|
||||
)
|
||||
)
|
||||
logs = _extract_structured(
|
||||
await server.call_tool("workspace_logs", {"workspace_id": workspace_id})
|
||||
)
|
||||
|
|
@ -298,12 +323,16 @@ def test_workspace_tools_round_trip(tmp_path: Path) -> None:
|
|||
synced,
|
||||
executed,
|
||||
diffed,
|
||||
snapshot,
|
||||
snapshots,
|
||||
exported,
|
||||
service,
|
||||
services,
|
||||
service_status,
|
||||
service_logs,
|
||||
service_stopped,
|
||||
reset,
|
||||
deleted_snapshot,
|
||||
logs,
|
||||
deleted,
|
||||
)
|
||||
|
|
@ -313,12 +342,16 @@ def test_workspace_tools_round_trip(tmp_path: Path) -> None:
|
|||
synced,
|
||||
executed,
|
||||
diffed,
|
||||
snapshot,
|
||||
snapshots,
|
||||
exported,
|
||||
service,
|
||||
services,
|
||||
service_status,
|
||||
service_logs,
|
||||
service_stopped,
|
||||
reset,
|
||||
deleted_snapshot,
|
||||
logs,
|
||||
deleted,
|
||||
) = asyncio.run(_run())
|
||||
|
|
@ -327,6 +360,11 @@ def test_workspace_tools_round_trip(tmp_path: Path) -> None:
|
|||
assert synced["workspace_sync"]["destination"] == "/workspace/subdir"
|
||||
assert executed["stdout"] == "more\n"
|
||||
assert diffed["changed"] is True
|
||||
assert snapshot["snapshot"]["snapshot_name"] == "checkpoint"
|
||||
assert [entry["snapshot_name"] for entry in snapshots["snapshots"]] == [
|
||||
"baseline",
|
||||
"checkpoint",
|
||||
]
|
||||
assert exported["artifact_type"] == "file"
|
||||
assert Path(str(exported["output_path"])).read_text(encoding="utf-8") == "more\n"
|
||||
assert service["state"] == "running"
|
||||
|
|
@ -334,5 +372,9 @@ def test_workspace_tools_round_trip(tmp_path: Path) -> None:
|
|||
assert service_status["state"] == "running"
|
||||
assert service_logs["tail_lines"] is None
|
||||
assert service_stopped["state"] == "stopped"
|
||||
assert logs["count"] == 1
|
||||
assert reset["workspace_reset"]["snapshot_name"] == "checkpoint"
|
||||
assert reset["command_count"] == 0
|
||||
assert reset["service_count"] == 0
|
||||
assert deleted_snapshot["deleted"] is True
|
||||
assert logs["count"] == 0
|
||||
assert deleted["deleted"] is True
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue