Add guest.session.send and vm.workspace.export RPCs

guest.session.send — write to a pipe-mode session's stdin without
holding the exclusive attach. The daemon dials a fresh SSH connection,
uploads the payload to a temp file, and cats it into the session's
named FIFO. Linux atomicity for writes ≤ PIPE_BUF covers all pi RPC
JSONL lines. Attach exclusivity is unchanged.

vm.workspace.export — pull changes from guest back to host. Runs
`git add -A && git diff --cached HEAD --binary` inside the guest via a
new RunScriptOutput helper on guest.Client (stdout-only capture,
distinct from RunScript which merges stderr). Returns a binary-safe
patch and a list of changed files. CLI writes the patch to stdout for
`| git apply` or to a file via --output.

RunScriptOutput is implemented as a direct SSH session (same pattern as
runSession) rather than going through StartCommand/StreamSession to
avoid closing the underlying Client, which is required since
ExportVMWorkspace calls it twice on the same connection.

New files: internal/daemon/workspace_test.go
This commit is contained in:
Thales Maciel 2026-04-14 15:21:50 -03:00
parent 797a9de1ce
commit 94c353f317
No known key found for this signature in database
GPG key ID: 33112E6833C34679
9 changed files with 1074 additions and 1 deletions

View file

@ -203,6 +203,29 @@ type GuestSessionAttachBeginResult struct {
StreamFormat string `json:"stream_format"`
}
type GuestSessionSendParams struct {
VMIDOrName string `json:"vm_id_or_name"`
SessionIDOrName string `json:"session_id_or_name"`
Payload []byte `json:"payload"`
}
type GuestSessionSendResult struct {
Session model.GuestSession `json:"session"`
BytesWritten int `json:"bytes_written"`
}
type WorkspaceExportParams struct {
IDOrName string `json:"id_or_name"`
GuestPath string `json:"guest_path,omitempty"`
}
type WorkspaceExportResult struct {
GuestPath string `json:"guest_path"`
Patch []byte `json:"patch"`
ChangedFiles []string `json:"changed_files"`
HasChanges bool `json:"has_changes"`
}
type VMWorkspacePrepareParams struct {
IDOrName string `json:"id_or_name"`
SourcePath string `json:"source_path"`