Add guest sessions and agent VM defaults

Add daemon-backed workspace and guest-session primitives so host
orchestrators can prepare /root/repo, launch long-lived guest commands,
and attach to pipe-mode sessions over the local stdio mux bridge.

Persist richer session metadata and launch diagnostics, preflight guest
cwd/command requirements, make pipe-mode attach rehydratable from guest
state after daemon restart, and allow submodules when workspace prepare
runs in full_copy mode.

At the same time, stop vm run from auto-attaching opencode, make it
print next-step commands instead, and make glibc guest images more
agent-ready by installing node, opencode, claude, and pi while syncing
opencode/claude/pi auth files into work disks on VM start.

Validation:
- GOCACHE=/tmp/banger-gocache go test ./...
- make build
- banger vm workspace prepare --help
- banger vm session --help
- banger vm session start --help
- banger vm session attach --help
This commit is contained in:
Thales Maciel 2026-04-12 23:48:42 -03:00
parent 497e6dca3d
commit 37c4c091ec
No known key found for this signature in database
GPG key ID: 33112E6833C34679
18 changed files with 3212 additions and 405 deletions

View file

@ -34,6 +34,23 @@ const (
VMStateError VMState = "error"
)
type GuestSessionStatus string
const (
GuestSessionStatusStarting GuestSessionStatus = "starting"
GuestSessionStatusRunning GuestSessionStatus = "running"
GuestSessionStatusExited GuestSessionStatus = "exited"
GuestSessionStatusFailed GuestSessionStatus = "failed"
GuestSessionStatusStopping GuestSessionStatus = "stopping"
)
type GuestSessionStdinMode string
const (
GuestSessionStdinClosed GuestSessionStdinMode = "closed"
GuestSessionStdinPipe GuestSessionStdinMode = "pipe"
)
type DaemonConfig struct {
LogLevel string
WebListenAddr string
@ -148,6 +165,60 @@ type ImageBuildRequest struct {
Docker bool
}
type GuestSession struct {
ID string `json:"id"`
VMID string `json:"vm_id"`
Name string `json:"name"`
Backend string `json:"backend"`
AttachBackend string `json:"attach_backend,omitempty"`
AttachMode string `json:"attach_mode,omitempty"`
Command string `json:"command"`
Args []string `json:"args,omitempty"`
CWD string `json:"cwd,omitempty"`
Env map[string]string `json:"env,omitempty"`
StdinMode GuestSessionStdinMode `json:"stdin_mode,omitempty"`
Status GuestSessionStatus `json:"status"`
ExitCode *int `json:"exit_code,omitempty"`
GuestPID int `json:"guest_pid,omitempty"`
GuestStateDir string `json:"guest_state_dir,omitempty"`
StdoutLogPath string `json:"stdout_log_path,omitempty"`
StderrLogPath string `json:"stderr_log_path,omitempty"`
Tags map[string]string `json:"tags,omitempty"`
LastError string `json:"last_error,omitempty"`
Attachable bool `json:"attachable"`
Reattachable bool `json:"reattachable"`
LaunchStage string `json:"launch_stage,omitempty"`
LaunchMessage string `json:"launch_message,omitempty"`
LaunchRawLog string `json:"launch_raw_log,omitempty"`
CreatedAt time.Time `json:"created_at"`
StartedAt time.Time `json:"started_at,omitempty"`
UpdatedAt time.Time `json:"updated_at"`
EndedAt time.Time `json:"ended_at,omitempty"`
}
type WorkspacePrepareMode string
const (
WorkspacePrepareModeShallowOverlay WorkspacePrepareMode = "shallow_overlay"
WorkspacePrepareModeFullCopy WorkspacePrepareMode = "full_copy"
WorkspacePrepareModeMetadataOnly WorkspacePrepareMode = "metadata_only"
)
type WorkspacePrepareResult struct {
VMID string `json:"vm_id"`
SourcePath string `json:"source_path"`
RepoRoot string `json:"repo_root"`
RepoName string `json:"repo_name"`
GuestPath string `json:"guest_path"`
Mode WorkspacePrepareMode `json:"mode"`
ReadOnly bool `json:"readonly"`
HeadCommit string `json:"head_commit,omitempty"`
CurrentBranch string `json:"current_branch,omitempty"`
BranchName string `json:"branch_name,omitempty"`
BaseCommit string `json:"base_commit,omitempty"`
PreparedAt time.Time `json:"prepared_at"`
}
func Now() time.Time {
return time.Now().UTC().Truncate(time.Second)
}