ws

package
v0.43.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 14, 2026 License: MIT Imports: 7 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// Wing → Relay
	TypeWingRegister  = "wing.register"
	TypeWingHeartbeat = "wing.heartbeat"

	// PTY (bidirectional, already E2E encrypted)
	TypePTYStart        = "pty.start"         // browser → relay → wing
	TypePTYStarted      = "pty.started"       // wing → relay → browser
	TypePTYOutput       = "pty.output"        // wing → relay → browser
	TypePTYInput        = "pty.input"         // browser → relay → wing
	TypePTYResize       = "pty.resize"        // browser → relay → wing
	TypePTYExited       = "pty.exited"        // wing → relay → browser
	TypePTYAttach       = "pty.attach"        // browser → relay → wing (reattach)
	TypePTYKill         = "pty.kill"          // browser → relay → wing (terminate session)
	TypePTYDetach       = "pty.detach"        // browser → relay (explicit detach before disconnect)
	TypePTYAttentionAck = "pty.attention_ack" // browser → relay → wing (notification seen)

	// Encrypted tunnel (browser ↔ wing, relay is opaque forwarder)
	TypeTunnelRequest  = "tunnel.req"    // browser → relay → wing
	TypeTunnelResponse = "tunnel.res"    // wing → relay → browser
	TypeTunnelStream   = "tunnel.stream" // wing → relay → browser (streaming)

	// Wing → Relay (session reclaim after wing restart)
	TypePTYReclaim = "pty.reclaim"

	// Session sync (relay requests, wing responds; also sent on heartbeat)
	TypeSessionsList = "sessions.list" // relay → wing
	TypeSessionsSync = "sessions.sync" // wing → relay

	// Relay → Browser/Wing (bandwidth)
	TypeBandwidthExceeded = "bandwidth.exceeded"

	// Passkey challenge-response (wing ↔ browser, relay is passthrough)
	TypePasskeyChallenge = "passkey.challenge"
	TypePasskeyResponse  = "passkey.response"

	// Wing → Relay (config change)
	TypeWingConfig = "wing.config"

	// Relay → Wing (control)
	TypeRegistered   = "registered"
	TypeRelayRestart = "relay.restart" // relay → all: server shutting down, reconnect
	TypeError        = "error"
)

Message types for the relay WebSocket protocol.

Variables

This section is empty.

Functions

This section is empty.

Types

type BandwidthExceeded added in v0.23.0

type BandwidthExceeded struct {
	Type    string `json:"type"`
	Message string `json:"message"`
}

BandwidthExceeded is sent to browser/wing when monthly cap is hit.

type Client

type Client struct {
	RoostURL string // e.g. "wss://ws.wingthing.ai/ws/wing"
	Token    string // device auth token
	WingID   string
	Hostname string // display name (os.Hostname)
	Platform string // runtime.GOOS
	Version  string // build version

	Agents     []string
	Skills     []string
	Labels     []string
	Identities []string
	Projects   []WingProject
	OrgSlug    string
	RootDir    string

	Locked       bool
	AllowedCount int

	OnPTY         PTYHandler
	OnTunnel      TunnelHandler
	OnOrphanKill  func(ctx context.Context, sessionID string) // kill egg with no active goroutine
	OnReconnect   func(ctx context.Context)                   // called after re-registration with relay
	SessionLister func(ctx context.Context) []SessionInfo
	// contains filtered or unexported fields
}

Client is an outbound WebSocket client that connects a wing to the roost.

func (*Client) HasPTYSession added in v0.16.1

func (c *Client) HasPTYSession(sessionID string) bool

HasPTYSession returns true if a goroutine is already handling this session.

func (*Client) RegisterPTYSession added in v0.7.35

func (c *Client) RegisterPTYSession(ctx context.Context, sessionID string) (write PTYWriteFunc, input <-chan []byte, cleanup func())

RegisterPTYSession creates an input channel for a reclaimed session so pty.attach/input/resize/kill messages from the relay get routed to it. Returns the input channel and a write function. The caller must start a goroutine to handle the session and clean up when done.

func (*Client) Run

func (c *Client) Run(ctx context.Context) error

Run connects to the relay and processes tasks until ctx is cancelled. Automatically reconnects on disconnect with exponential backoff.

func (*Client) SendConfig added in v0.37.0

func (c *Client) SendConfig(ctx context.Context) error

SendConfig pushes the wing's current lock state to the relay.

func (*Client) SendReclaim added in v0.7.0

func (c *Client) SendReclaim(ctx context.Context, sessionID, agent, cwd string) error

SendReclaim sends a pty.reclaim message to the relay for a surviving session.

type DirEntry added in v0.6.3

type DirEntry struct {
	Name  string `json:"name"`
	IsDir bool   `json:"is_dir"`
	Path  string `json:"path"`
}

DirEntry is a single entry in a directory listing.

type Envelope

type Envelope struct {
	Type string `json:"type"`
}

Envelope wraps every WebSocket message with a type field for routing.

type ErrorMsg

type ErrorMsg struct {
	Type    string `json:"type"`
	Message string `json:"message"`
}

ErrorMsg is sent by the relay for protocol errors.

type PTYAttach

type PTYAttach struct {
	Type      string `json:"type"`
	SessionID string `json:"session_id"`
	PublicKey string `json:"public_key,omitempty"` // new browser ephemeral key
}

PTYAttach requests reattachment to an existing PTY session.

type PTYAttentionAck added in v0.12.8

type PTYAttentionAck struct {
	Type      string `json:"type"`
	SessionID string `json:"session_id"`
}

PTYAttentionAck acknowledges a notification was seen by the browser.

type PTYDetach added in v0.7.19

type PTYDetach struct {
	Type      string `json:"type"`
	SessionID string `json:"session_id"`
}

PTYDetach explicitly detaches the browser from a PTY session.

type PTYExited

type PTYExited struct {
	Type      string `json:"type"`
	SessionID string `json:"session_id"`
	ExitCode  int    `json:"exit_code"`
	Error     string `json:"error,omitempty"` // crash/error info for display
}

PTYExited tells the browser the process exited.

type PTYHandler

type PTYHandler func(ctx context.Context, start PTYStart, write PTYWriteFunc, input <-chan []byte)

PTYHandler is called when the wing receives a pty.start request. It should spawn the agent in a PTY and manage I/O. The write function sends messages back through the relay to the browser. The input channel receives raw JSON messages (pty.input and pty.resize) from the browser.

type PTYInput

type PTYInput struct {
	Type      string `json:"type"`
	SessionID string `json:"session_id"`
	Data      string `json:"data"` // base64-encoded
}

PTYInput carries keystrokes from browser to wing.

type PTYKill

type PTYKill struct {
	Type      string `json:"type"`
	SessionID string `json:"session_id"`
}

PTYKill requests termination of a PTY session.

type PTYOutput

type PTYOutput struct {
	Type       string `json:"type"`
	SessionID  string `json:"session_id"`
	Data       string `json:"data"`                 // base64-encoded
	Compressed bool   `json:"compressed,omitempty"` // gzip before encrypt
}

PTYOutput carries raw terminal bytes from wing to browser.

type PTYReclaim added in v0.7.0

type PTYReclaim struct {
	Type      string `json:"type"`
	SessionID string `json:"session_id"`
	Agent     string `json:"agent,omitempty"`
	CWD       string `json:"cwd,omitempty"`
}

PTYReclaim is sent by the wing after reconnect to reclaim a surviving egg session.

type PTYResize

type PTYResize struct {
	Type      string `json:"type"`
	SessionID string `json:"session_id"`
	Cols      int    `json:"cols"`
	Rows      int    `json:"rows"`
}

PTYResize tells the wing to resize the terminal.

type PTYStart

type PTYStart struct {
	Type                string `json:"type"`
	SessionID           string `json:"session_id"`
	Agent               string `json:"agent"` // "claude", "codex", "ollama"
	Cols                int    `json:"cols"`
	Rows                int    `json:"rows"`
	PublicKey           string `json:"public_key,omitempty"`            // browser's ephemeral X25519 (base64)
	CWD                 string `json:"cwd,omitempty"`                   // working directory for the agent
	WingID              string `json:"wing_id,omitempty"`               // target wing (picks first if empty)
	PasskeyCredentialID string `json:"passkey_credential_id,omitempty"` // base64url credential ID
	AuthToken           string `json:"auth_token,omitempty"`            // cached passkey auth token
	UserID              string `json:"user_id,omitempty"`               // relay-injected creator user ID
}

PTYStart requests a new interactive terminal session on the wing.

type PTYStarted

type PTYStarted struct {
	Type      string `json:"type"`
	SessionID string `json:"session_id"`
	Agent     string `json:"agent"`
	PublicKey string `json:"public_key,omitempty"` // wing's X25519 (base64)
	CWD       string `json:"cwd,omitempty"`        // resolved working directory
	AuthToken string `json:"auth_token,omitempty"` // passkey auth token
}

PTYStarted confirms the PTY session is running.

type PTYWriteFunc

type PTYWriteFunc func(v any) error

PTYWriteFunc sends a message back to the relay over the wing's WebSocket.

type PasskeyChallenge added in v0.34.0

type PasskeyChallenge struct {
	Type      string `json:"type"`
	SessionID string `json:"session_id"`
	Challenge string `json:"challenge"` // base64url random 32 bytes
}

PasskeyChallenge is sent from wing to browser requesting passkey verification.

type PasskeyResponse added in v0.34.0

type PasskeyResponse struct {
	Type              string `json:"type"`
	SessionID         string `json:"session_id"`
	CredentialID      string `json:"credential_id"`      // base64url
	AuthenticatorData string `json:"authenticator_data"` // base64
	ClientDataJSON    string `json:"client_data_json"`   // base64
	Signature         string `json:"signature"`          // base64 (ASN.1 DER)
}

PasskeyResponse is sent from browser to wing with the passkey assertion.

type RegisteredMsg

type RegisteredMsg struct {
	Type   string `json:"type"`
	WingID string `json:"wing_id"`
}

RegisteredMsg is the relay's acknowledgment of a successful wing registration.

type RelayRestart added in v0.23.0

type RelayRestart struct {
	Type string `json:"type"`
}

RelayRestart is sent to all connected WebSockets when the server is shutting down.

type SessionInfo added in v0.7.32

type SessionInfo struct {
	SessionID      string `json:"session_id"`
	Agent          string `json:"agent"`
	CWD            string `json:"cwd,omitempty"`
	EggConfig      string `json:"egg_config,omitempty"` // YAML config snapshot
	NeedsAttention bool   `json:"needs_attention,omitempty"`
	Audit          bool   `json:"audit,omitempty"` // true if session has audit recording
	UserID         string `json:"user_id,omitempty"`
}

SessionInfo describes one active session on a wing.

type SessionsList added in v0.7.32

type SessionsList struct {
	Type      string `json:"type"`
	RequestID string `json:"request_id"`
}

SessionsList requests the wing's current session list.

type SessionsSync added in v0.7.32

type SessionsSync struct {
	Type      string        `json:"type"`
	RequestID string        `json:"request_id,omitempty"` // set when responding to sessions.list
	Sessions  []SessionInfo `json:"sessions"`
}

SessionsSync carries the wing's current session list.

type TunnelHandler added in v0.34.0

type TunnelHandler func(ctx context.Context, req TunnelRequest, write PTYWriteFunc)

TunnelHandler is called when the wing receives an encrypted tunnel request.

type TunnelRequest added in v0.34.0

type TunnelRequest struct {
	Type          string `json:"type"`
	WingID        string `json:"wing_id"`
	RequestID     string `json:"request_id"`
	SenderPub     string `json:"sender_pub,omitempty"`      // browser X25519 identity pubkey
	Payload       string `json:"payload"`                   // base64(AES-GCM encrypted)
	SenderUserID  string `json:"sender_user_id,omitempty"`  // relay-injected user ID
	SenderOrgRole string `json:"sender_org_role,omitempty"` // relay-injected: "owner", "admin", "member", ""
	SenderEmail   string `json:"sender_email,omitempty"`    // relay-injected user email
}

TunnelRequest is an encrypted request from browser to wing via relay.

type TunnelResponse added in v0.34.0

type TunnelResponse struct {
	Type      string `json:"type"`
	RequestID string `json:"request_id"`
	Payload   string `json:"payload"` // base64(AES-GCM encrypted)
}

TunnelResponse is an encrypted response from wing to browser via relay.

type TunnelStream added in v0.34.0

type TunnelStream struct {
	Type      string `json:"type"`
	RequestID string `json:"request_id"`
	Payload   string `json:"payload"` // base64(AES-GCM encrypted)
	Done      bool   `json:"done"`
}

TunnelStream is an encrypted streaming chunk from wing to browser via relay.

type WingConfig added in v0.37.0

type WingConfig struct {
	Type         string `json:"type"`
	WingID       string `json:"wing_id"`
	Locked       bool   `json:"locked"`
	AllowedCount int    `json:"allowed_count"`
}

WingConfig is sent by the wing when lock state changes (e.g. lock/unlock, allow/revoke).

type WingHeartbeat

type WingHeartbeat struct {
	Type   string `json:"type"`
	WingID string `json:"wing_id"`
}

WingHeartbeat is sent by the wing every 30s.

type WingProject added in v0.6.0

type WingProject struct {
	Name    string `json:"name"`               // directory name (e.g. "wingthing")
	Path    string `json:"path"`               // absolute path (e.g. "/Users/ehrlich/repos/wingthing")
	ModTime int64  `json:"mod_time,omitempty"` // unix timestamp of last modification
}

WingProject is a project directory discovered on the wing.

type WingRegister

type WingRegister struct {
	Type         string        `json:"type"`
	WingID       string        `json:"wing_id"`
	Hostname     string        `json:"hostname,omitempty"`
	Platform     string        `json:"platform,omitempty"` // runtime.GOOS (e.g. "darwin", "linux")
	Version      string        `json:"version,omitempty"`  // build version (e.g. "v0.7.35")
	Agents       []string      `json:"agents"`
	Skills       []string      `json:"skills"`
	Labels       []string      `json:"labels"`
	Identities   []string      `json:"identities"`
	Projects     []WingProject `json:"projects,omitempty"`
	OrgSlug      string        `json:"org_slug,omitempty"`
	RootDir      string        `json:"root_dir,omitempty"`
	Locked       bool          `json:"locked"`                  // explicit locked flag from wing.yaml
	AllowedCount int           `json:"allowed_count,omitempty"` // number of allowed keys
}

WingRegister is sent by the wing on connect.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL