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
|
|
@ -22,7 +22,7 @@ Networking: tun=yes ip_forward=yes
|
|||
|
||||
```bash
|
||||
$ uvx --from pyro-mcp pyro env list
|
||||
Catalog version: 3.1.0
|
||||
Catalog version: 3.2.0
|
||||
debian:12 [installed|not installed] Debian 12 environment with Git preinstalled for common agent workflows.
|
||||
debian:12-base [installed|not installed] Minimal Debian 12 environment for shell and core Unix tooling.
|
||||
debian:12-build [installed|not installed] Debian 12 environment with Git and common build tools preinstalled.
|
||||
|
|
@ -76,6 +76,8 @@ a source checkout.
|
|||
$ uvx --from pyro-mcp pyro workspace create debian:12 --seed-path ./repo --json | tee /tmp/pyro-workspace.json
|
||||
$ export WORKSPACE_ID="$(python -c 'import json,sys; print(json.load(sys.stdin)["workspace_id"])' < /tmp/pyro-workspace.json)"
|
||||
$ uvx --from pyro-mcp pyro workspace sync push "$WORKSPACE_ID" ./changes
|
||||
$ uvx --from pyro-mcp pyro workspace file read "$WORKSPACE_ID" note.txt
|
||||
$ uvx --from pyro-mcp pyro workspace patch apply "$WORKSPACE_ID" --patch "$(cat fix.patch)"
|
||||
$ uvx --from pyro-mcp pyro workspace exec "$WORKSPACE_ID" -- cat note.txt
|
||||
$ uvx --from pyro-mcp pyro workspace snapshot create "$WORKSPACE_ID" checkpoint
|
||||
$ uvx --from pyro-mcp pyro workspace service start "$WORKSPACE_ID" web --ready-file .web-ready -- sh -lc 'touch .web-ready && while true; do sleep 60; done'
|
||||
|
|
@ -95,6 +97,10 @@ $ uvx --from pyro-mcp pyro workspace delete "$WORKSPACE_ID"
|
|||
$ uvx --from pyro-mcp pyro demo
|
||||
$ uvx --from pyro-mcp pyro workspace create debian:12 --seed-path ./repo
|
||||
$ uvx --from pyro-mcp pyro workspace sync push WORKSPACE_ID ./changes
|
||||
$ uvx --from pyro-mcp pyro workspace file list WORKSPACE_ID src --recursive
|
||||
$ uvx --from pyro-mcp pyro workspace file read WORKSPACE_ID src/app.py
|
||||
$ uvx --from pyro-mcp pyro workspace file write WORKSPACE_ID src/app.py --text 'print("hi")'
|
||||
$ uvx --from pyro-mcp pyro workspace patch apply WORKSPACE_ID --patch "$(cat fix.patch)"
|
||||
$ uvx --from pyro-mcp pyro workspace create debian:12 --network-policy egress
|
||||
$ uvx --from pyro-mcp pyro workspace create debian:12 --secret API_TOKEN=expected --secret-file PIP_TOKEN=./token.txt
|
||||
$ uvx --from pyro-mcp pyro workspace exec WORKSPACE_ID --secret-env API_TOKEN -- sh -lc 'test "$API_TOKEN" = "expected"'
|
||||
|
|
@ -128,6 +134,17 @@ Command count: 0
|
|||
$ uvx --from pyro-mcp pyro workspace sync push WORKSPACE_ID ./changes --dest src
|
||||
[workspace-sync] workspace_id=... mode=directory source=... destination=/workspace/src entry_count=... bytes_written=... execution_mode=guest_vsock
|
||||
|
||||
$ uvx --from pyro-mcp pyro workspace file list WORKSPACE_ID src --recursive
|
||||
Workspace file path: /workspace/src
|
||||
- /workspace/src/note.txt [file] bytes=...
|
||||
|
||||
$ uvx --from pyro-mcp pyro workspace file read WORKSPACE_ID src/note.txt
|
||||
hello from synced workspace
|
||||
[workspace-file-read] workspace_id=... path=/workspace/src/note.txt size_bytes=... truncated=False execution_mode=guest_vsock
|
||||
|
||||
$ uvx --from pyro-mcp pyro workspace patch apply WORKSPACE_ID --patch "$(cat fix.patch)"
|
||||
[workspace-patch] workspace_id=... total=... added=... modified=... deleted=... execution_mode=guest_vsock
|
||||
|
||||
$ uvx --from pyro-mcp pyro workspace exec WORKSPACE_ID -- cat src/note.txt
|
||||
hello from synced workspace
|
||||
[workspace-exec] workspace_id=... sequence=1 cwd=/workspace execution_mode=guest_vsock exit_code=0 duration_ms=...
|
||||
|
|
@ -231,11 +248,12 @@ State: started
|
|||
Use `--seed-path` when the workspace should start from a host directory or a local
|
||||
`.tar` / `.tar.gz` / `.tgz` archive instead of an empty `/workspace`. Use
|
||||
`pyro workspace sync push` when you need to import later host-side changes into a started
|
||||
workspace. Sync is non-atomic in `3.1.0`; if it fails partway through, prefer `pyro workspace reset`
|
||||
workspace. Sync is non-atomic in `3.2.0`; if it fails partway through, prefer `pyro workspace reset`
|
||||
to recover from `baseline` or one named snapshot. Use `pyro workspace diff` to compare the current
|
||||
`/workspace` tree to its immutable create-time baseline, `pyro workspace snapshot *` to create
|
||||
named checkpoints, and `pyro workspace export` to copy one changed file or directory back to the
|
||||
host. Use `pyro workspace exec` for one-shot commands and `pyro workspace shell *` when you
|
||||
host. Use `pyro workspace file *` and `pyro workspace patch apply` for model-native text edits,
|
||||
`pyro workspace exec` for one-shot commands, and `pyro workspace shell *` when you
|
||||
need a persistent interactive PTY session in that same workspace. Use `pyro workspace service *`
|
||||
when the workspace needs long-running background processes with typed readiness checks. Internal
|
||||
service state and logs stay outside `/workspace`, so service runtime data does not appear in
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue