mirror of
https://github.com/vercel-labs/agent-desktop.git
synced 2026-11-15 14:18:12 +08:00
* feat: add the install and sandbox commands An agent had no way to give itself an isolated desktop; setting one up was a manual job. Adds `agent-desktop install` and `agent-desktop sandbox` (create, start, stop, status, list, rm, exec) on a small provider contract, with plain errors and the guest's own output passed through `exec`. * fix: pass a guest exit status of 125 through sandbox exec A guest program can exit 125 itself, and exec reported that as a provider failure. Status 125 now counts as a provider failure only when the provider printed its failure object; otherwise the guest output and status pass through. * fix: give a sandbox record with an unknown provider a recovery that works sandbox list told the user to run sandbox rm for a record naming a provider this build does not know, but that command failed on the same unknown provider, and --provider was refused as a mismatch. Such a record now reports its own error, points at --provider, and is recoverable with a known provider the same way a malformed record is. * refactor: move install under the sandbox command install only ever builds or reports sandbox providers, so it now lives at `agent-desktop sandbox install [provider]` beside the other sandbox actions. The top-level install command is gone, which takes the published command count from 62 to 61. Behavior and output are unchanged. * refactor: name the macOS sandbox provider macos in tests and examples The provider is being renamed from macos-vm to macos, so the examples, test strings and the planted architecture-check paths use the new name. * test: give the slow trace capture test the full action budget A 500 ms wall-clock budget ran out on a slow Windows runner before the action dispatched. The test still fails if capture is not capped, because an uncapped capture sleeps for the whole budget. * fix: report a sandbox directory without a record as broken, and settle sandbox exec errors A sandbox directory whose record file is missing was listed as broken, but rm, status, start, stop and exec answered SANDBOX_NOT_FOUND. They now return INVALID_ARGS with the --provider recovery command, as the docs say. Errors from sandbox exec skipped the delivery settling every other command gets, so an invalid name reported retry unknown. They now go through the same settling. * fix: close four sandbox gaps in record identity, removal, mcp globals and exec output - A record whose name differs from its directory is refused as malformed, so list and status never run a provider against another sandbox's path. - Removing a sandbox whose provider already deleted the directory succeeds instead of ending in SANDBOX_NOT_FOUND. - The MCP server drops a server global that conflicts with one the guest sets, so --wait-for-gone on the server no longer breaks a guest --wait-for. - The docs state the 8 MiB limit on each sandbox exec output stream. * fix: recover an oversized sandbox record and return plain guest output over mcp - A record file above the size limit returned INTERNAL from every verb and could not be removed. It is now a malformed record, so sandbox rm --provider clears it. - The MCP sandbox exec tool returned an error for guest output that is not JSON, such as --help. It now returns that text with the guest's status. - The docs say sandbox exec passes neither stderr nor stdin. * fix: keep the record of an unanswered create and stop the provider when the command is cancelled - A create that timed out, or whose provider ended without a readable reply, dropped its record when the sandbox directory held nothing else. Delivery is unknown there, so the record now stays and the sandbox still lists and can be removed. A create the provider refuses still leaves no record. - A terminating signal during a provider call killed agent-desktop and left the provider script and its children running. The sandbox path now forwards SIGHUP, SIGINT and SIGTERM to the provider's process group. It is installed only there, so the FFI library never replaces a host's handlers. * fix: kill a provider that ignores SIGTERM on cancel, and drop a create record only on a refusal - The signal handler sent SIGTERM to the provider's group and ended the host at once, so a provider or guest that ignores SIGTERM kept running. It now waits up to two seconds for the group to exit, then sends SIGKILL. - A create reply that was ok:true but incomplete, or ok:false with data.changed:true, still dropped the record. The record is now dropped only for a complete failure reply that does not report a change, or an unavailable provider. * fix: drop a create record only when the provider never ran, and reap the provider on cancel - A create whose provider ran but printed too much output still dropped its record. The record is now dropped after a run error only when nothing was delivered: the script could not start, or the platform has no sandbox support. - The cancel handler waited its full two-second grace even after the provider exited, because the exited provider was never reaped. It now reaps it while it waits. * fix: cut the sandbox recovery paths that kept breaking, and serialize changes to one sandbox Most review findings on this command came from three places: the `--provider` recovery for broken records, the per-case broken-record errors, and the MCP code that pushed server globals into `sandbox exec`. This removes them instead of adding more guards. - A sandbox whose record is missing, malformed, unreadable or names a provider this build lacks is `broken` to every command, with one error that names the directory to delete. `rm --provider` is gone. - `create` no longer takes over a directory that already holds files. - `create`, `start`, `stop` and `rm` hold a per-sandbox lock while the provider works; a second one fails at once with nothing delivered. - `sandbox list` passes on a failed status check's own suggestion instead of always advising `rm`. - A refused create that drops its record reports `not_delivered`. - `sandbox exec`: a guest killed by a signal reports 128 + signal, a guest envelope with exit 125 passes through, and errors before the provider runs are `not_delivered`. - MCP no longer passes server globals to `sandbox exec`; the guest command carries its own. - Help, skill and JSON contract no longer name a provider this PR does not ship. Tests that restated clap or serde, covered a removed staging step, or repeated one path were dropped. Net: about 750 fewer lines. * fix: refuse an option-shaped sandbox name over mcp, and document that the host session never reaches the guest An MCP sandbox exec call whose name started with '-' was parsed as a host flag, so '--help' returned the host's help as if the guest printed it. The session and agent-id environment variables were silently ignored by sandbox exec; the contract and skill now say so. * feat: let sandbox start show the sandbox in a window and take provider options `sandbox start <name> --window` asks the provider to show the sandbox's desktop on the host instead of running it headless, and `--set key=value` passes the provider an option for that start, the same way `create` does. The flag reaches the provider as the `window=on` setting. * fix(mcp): take sandbox exec output as the guest's, not as an envelope The MCP call layer decided what a child's stdout meant by trying to parse it, so a guest that printed nothing and exited 0 came back as an error and guest JSON came back as the host envelope. Each tool now declares its output kind once: envelope tools are parsed, and sandbox exec hands back its child's own bytes with its exit status, empty output included. A host failure still arrives as its envelope text, marked as an error. Verified over stdio against the built binary with a stub provider: silent guest output, guest JSON, a non-zero guest status, a host SANDBOX_NOT_FOUND envelope, and an ordinary tool envelope.