Documentation
¶
Index ¶
- Constants
- type BandwidthExceeded
- type Client
- func (c *Client) HasPTYSession(sessionID string) bool
- func (c *Client) RegisterPTYSession(ctx context.Context, sessionID string) (write PTYWriteFunc, input <-chan []byte, cleanup func())
- func (c *Client) Run(ctx context.Context) error
- func (c *Client) SendReclaim(ctx context.Context, sessionID, agent, cwd string) error
- type DirEntry
- type Envelope
- type ErrorMsg
- type PTYAttach
- type PTYAttentionAck
- type PTYDetach
- type PTYExited
- type PTYHandler
- type PTYInput
- type PTYKill
- type PTYOutput
- type PTYReclaim
- type PTYResize
- type PTYStart
- type PTYStarted
- type PTYWriteFunc
- type PasskeyChallenge
- type PasskeyResponse
- type RegisteredMsg
- type RelayRestart
- type SessionInfo
- type SessionsList
- type SessionsSync
- type TunnelHandler
- type TunnelRequest
- type TunnelResponse
- type TunnelStream
- type WingHeartbeat
- type WingProject
- type WingRegister
Constants ¶
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" // 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
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
Pinned bool
PinnedCount 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
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.
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 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
PTYAttentionAck acknowledges a notification was seen by the browser.
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 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
}
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 ¶
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 ¶
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
}
SessionInfo describes one active session on a wing.
type SessionsList ¶ added in v0.7.32
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)
}
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 WingHeartbeat ¶
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"`
Pinned bool `json:"pinned"` // explicit pinned flag from wing.yaml
PinnedCount int `json:"pinned_count,omitempty"` // number of pinned keys
}
WingRegister is sent by the wing on connect.