ipc

package
v1.45.3 Latest Latest
Warning

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

Go to latest
Published: Jul 31, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// Lifecycle
	MsgAttach    = "attach"
	MsgDetach    = "detach"
	MsgShutdown  = "shutdown"
	MsgHeartbeat = "heartbeat"

	// Session control (Client -> Daemon)
	MsgCreatePane   = "create_pane"
	MsgDestroyPane  = "destroy_pane"
	MsgResizePane   = "resize_pane"
	MsgUpdatePane   = "update_pane"
	MsgUpdateLayout = "update_layout"

	// Tab control (Client -> Daemon)
	MsgCreateTab  = "create_tab"
	MsgDestroyTab = "destroy_tab"
	MsgSwitchTab  = "switch_tab"
	MsgUpdateTab  = "update_tab"
	MsgReorderTab = "reorder_tab"

	// I/O (bidirectional)
	MsgPaneInput  = "pane_input"
	MsgPaneOutput = "pane_output"

	// State sync (Daemon -> Client)
	MsgWorkspaceState = "workspace_state"
	MsgStateUpdate    = "state_update"

	// Plugin (Daemon -> Client)
	MsgPluginError = "plugin_error"

	// Plugin management (Client -> Daemon)
	MsgReloadPlugins = "reload_plugins"

	// MCP request-response (Client -> Daemon -> Client)
	MsgListPanesReq       = "list_panes_req"
	MsgListPanesResp      = "list_panes_resp"
	MsgReadPaneOutputReq  = "read_pane_output_req"
	MsgReadPaneOutputResp = "read_pane_output_resp"
	MsgPaneStatusReq      = "pane_status_req"
	MsgPaneStatusResp     = "pane_status_resp"
	MsgCreatePaneReq      = "create_pane_req"
	MsgCreatePaneResp     = "create_pane_resp"
	MsgRestartPaneReq     = "restart_pane_req"
	MsgRestartPaneResp    = "restart_pane_resp"
	MsgScreenshotPaneReq  = "screenshot_pane_req"
	MsgScreenshotPaneResp = "screenshot_pane_resp"
	MsgSwitchTabReq       = "switch_tab_req"
	MsgSwitchTabResp      = "switch_tab_resp"
	MsgListTabsReq        = "list_tabs_req"
	MsgListTabsResp       = "list_tabs_resp"
	MsgDestroyPaneReq     = "destroy_pane_req"
	MsgDestroyPaneResp    = "destroy_pane_resp"
	MsgSetActivePane      = "set_active_pane" // broadcast to TUI
	MsgCloseTUI           = "close_tui"       // broadcast to TUI
	MsgHighlightPane      = "highlight_pane"  // broadcast to TUI (MCP interaction indicator)

	// Notification center (M12)
	MsgPaneEvent              = "pane_event"               // broadcast to TUI
	MsgDismissEvent           = "dismiss_event"            // client → daemon
	MsgGetNotificationsReq    = "get_notifications_req"    // MCP request
	MsgGetNotificationsResp   = "get_notifications_resp"   // MCP response
	MsgWatchNotificationsReq  = "watch_notifications_req"  // MCP request (blocking)
	MsgWatchNotificationsResp = "watch_notifications_resp" // MCP response

	// Version negotiation — TUI asks daemon for its version string before
	// attaching so mismatches can be surfaced as a blocking dialog or an
	// auto-restart prompt. A daemon built before this pair existed will
	// silently drop MsgVersionReq; the client handles the timeout.
	MsgVersionReq  = "version_req"  // client → daemon (empty payload)
	MsgVersionResp = "version_resp" // daemon → client (VersionRespPayload)

	// Memory reporting
	MsgMemoryReportReq  = "memory_report_req"
	MsgMemoryReportResp = "memory_report_resp"

	// Pane input history
	MsgPaneHistoryReq       = "pane_history_req"
	MsgPaneHistoryResp      = "pane_history_resp"
	MsgPaneHistoryEntryReq  = "pane_history_entry_req"
	MsgPaneHistoryEntryResp = "pane_history_entry_resp"

	// Pane content search (M11 command palette)
	MsgPaneSearchReq  = "pane_search_req"
	MsgPaneSearchResp = "pane_search_resp"

	// Claude Code session discovery (pane setup dialog "resume" picker)
	MsgClaudeSessionsReq       = "claude_sessions_req"
	MsgClaudeSessionsResp      = "claude_sessions_resp"
	MsgClaudeSessionDetailReq  = "claude_session_detail_req"
	MsgClaudeSessionDetailResp = "claude_session_detail_resp"

	// Auto-update (TUI ⇄ daemon)
	MsgStageUpdateReq  = "stage_update_req"  // TUI → daemon (empty payload)
	MsgStageUpdateResp = "stage_update_resp" // daemon → TUI (unicast)
)

Message type constants

View Source
const ContextTokensCompacting int64 = -1

ContextTokensCompacting is the sentinel value for a pane's context-token count while a Claude compaction is in flight. The true post-compaction size is not knowable at PostCompact time — the compaction summary is written to the transcript as system/user entries with no assistant usage, so a read there would return the (now-stale) pre-compaction count. The daemon stores this sentinel on PostCompact and the TUI renders "<model> · compacting" until the next completed turn's Stop reports the real reduced size. It travels as the context_tokens value in both the hook-event data path and the workspace snapshot; the display convention lives in tui.modelStatusSegment.

Variables

View Source
var ErrConnClosed = errors.New("ipc: conn closed")

ErrConnClosed is returned by SendBlocking when the conn closes (locally, via the overflow path, or by the peer) while waiting for queue space.

View Source
var ErrSendCanceled = errors.New("ipc: blocking send canceled")

ErrSendCanceled is returned by SendBlocking when the caller's cancel channel fires while waiting for queue space.

View Source
var ErrSendOverflow = errors.New("ipc: send buffer overflow (slow client)")

ErrSendOverflow is returned by Conn.Send when the per-conn send buffer is full. The connection has been scheduled for close; future Sends short- circuit with the same error.

Functions

func EncodeFrame added in v1.18.6

func EncodeFrame(msg *Message) ([]byte, error)

EncodeFrame marshals msg into a single length-prefixed wire frame in one allocation. Shared by WriteMessage and the per-conn send queues — replaces the marshal → bytes.Buffer → clone chain that copied every broadcast frame up to four times.

func WriteMessage

func WriteMessage(w io.Writer, msg *Message) error

WriteMessage writes a length-prefixed JSON message to w. Format: [4 bytes uint32 big-endian length][JSON payload]

Types

type AttachPayload

type AttachPayload struct {
	Cols int    `json:"cols"`
	Rows int    `json:"rows"`
	CWD  string `json:"cwd,omitempty"`
}

type ClaudeSessionDetailReqPayload added in v1.42.0

type ClaudeSessionDetailReqPayload struct {
	CWD       string `json:"cwd"`
	SessionID string `json:"session_id"`
}

ClaudeSessionDetailReqPayload asks for the deep read of ONE session — the listing head-reads every transcript in a directory, so this is issued per user request (the picker's info key), never per listing.

type ClaudeSessionDetailRespPayload added in v1.42.0

type ClaudeSessionDetailRespPayload struct {
	CWD         string `json:"cwd"`
	SessionID   string `json:"session_id"`
	FirstPrompt string `json:"first_prompt,omitempty"`
	LastPrompt  string `json:"last_prompt,omitempty"`
	UserPrompts int    `json:"user_prompts,omitempty"`
	StartedMs   int64  `json:"started_ms,omitempty"`
	ModifiedMs  int64  `json:"modified_ms,omitempty"`
	SizeBytes   int64  `json:"size_bytes,omitempty"`
	Error       string `json:"error,omitempty"`
}

ClaudeSessionDetailRespPayload answers with one session's summary. CWD and SessionID echo the request VERBATIM for the same staleness contract ClaudeSessionsRespPayload documents — here the pair is what identifies which highlighted row the answer belongs to, since the user can keep moving the cursor while the read is in flight.

StartedMs is 0 when no opening entry carried a timestamp. Prompts are multi-line: they render as paragraphs, not rows. UserPrompts counts only what the user typed — see claudesessions.Detail for why no assistant-side count is reported.

type ClaudeSessionInfo added in v1.42.0

type ClaudeSessionInfo struct {
	ID          string `json:"id"`
	Title       string `json:"title"`
	ModifiedMs  int64  `json:"modified_ms"`
	InUsePaneID string `json:"in_use_pane_id,omitempty"`
}

ClaudeSessionInfo is one resumable session. InUsePaneID identifies the live pane already attached to this session (empty when free) — two claude processes on one transcript would fight over it, so the TUI renders those rows blocked. Like PaneSearchHit, only the id travels: the TUI already holds tab/pane metadata and resolves the display label itself.

type ClaudeSessionsReqPayload added in v1.42.0

type ClaudeSessionsReqPayload struct {
	CWD string `json:"cwd"`
}

ClaudeSessionsReqPayload asks the daemon to enumerate the Claude Code sessions recorded for CWD. CWD is the directory currently highlighted in the pane setup dialog — not yet committed, which is why the response echoes it back for staleness comparison.

type ClaudeSessionsRespPayload added in v1.42.0

type ClaudeSessionsRespPayload struct {
	CWD       string              `json:"cwd"`
	Sessions  []ClaudeSessionInfo `json:"sessions"`
	Truncated bool                `json:"truncated,omitempty"`
	Error     string              `json:"error,omitempty"`
}

ClaudeSessionsRespPayload carries one directory's sessions, newest first. CWD echoes the request VERBATIM (never cleaned or resolved — the TUI compares it against its own value to drop responses that arrived after the user moved to a different directory; any daemon-side normalization would make a legitimate request look permanently stale). Truncated is set when the directory held more sessions than the discovery cap returns.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client connects to the daemon over a Unix socket.

func NewClient

func NewClient(socketPath string) (*Client, error)

func NewClientWithDialer added in v1.43.0

func NewClientWithDialer(ctx context.Context, dial DialFunc) (*Client, error)

NewClientWithDialer builds a Client over whatever connection dial returns. NewClient remains the Unix-socket convenience wrapper used by every local call site.

func (*Client) Close

func (c *Client) Close() error

func (*Client) Receive

func (c *Client) Receive() (*Message, error)

func (*Client) Send

func (c *Client) Send(msg *Message) error

func (*Client) SetReadDeadline added in v1.8.0

func (c *Client) SetReadDeadline(t time.Time) error

SetReadDeadline installs a read deadline on the underlying socket. Pass the zero time to disable it. Used by the pre-attach version handshake to cap how long we wait for MsgVersionResp from daemons that may predate the version-negotiation protocol.

type Conn

type Conn struct {
	// contains filtered or unexported fields
}

Conn wraps a net.Conn with message framing.

Sends are non-blocking: each Conn owns TWO 64-slot queues and a dedicated goroutine that drains them into the underlying socket. The critical queue carries must-deliver frames (state, responses, ghost replay, lifecycle); the droppable queue carries live PTY output broadcasts. The send loop drains critical first (priority) so an output flood can never starve state. A slow or wedged peer drains its own queues; if the CRITICAL queue overflows the offending conn is closed in the background and Send returns ErrSendOverflow. If the DROPPABLE queue overflows the frame is dropped (cosmetic — the next output frame supersedes it) and the conn survives. Other connections are never affected by one client's slowness — closing the wedge-incident class where a single stuck TUI or MCP bridge stalled the daemon's broadcast for every other client, AND the busy-but-alive class where an output storm force-closed a TUI mid-restore.

func (*Conn) Close

func (c *Conn) Close() error

Close shuts down the conn. Idempotent — safe to call concurrently from any goroutine. Any frames still queued in critCh or outCh at close time are intentionally discarded: by the time Close is called we are either tearing down an overflowed (already broken) peer or shutting down the server entirely, and in both cases delivery guarantees no longer apply.

func (*Conn) Dropped added in v1.17.0

func (c *Conn) Dropped() uint64

Dropped returns the number of droppable (live-output) frames discarded because this conn's output queue was full. Test/metrics observability.

func (*Conn) Receive

func (c *Conn) Receive() (*Message, error)

Receive reads the next message from the connection. Callers must ensure a single reader at a time per conn — daemon: handleConn's goroutine; client: the version handshake, then the receive loop, sequentially — so br needs no locking.

func (*Conn) Send

func (c *Conn) Send(msg *Message) error

Send marshals msg into the wire frame and queues it for transmission. Returns ErrSendOverflow when the per-conn buffer is full — the conn has been scheduled for async close at that point.

The closed/overflow short-circuit here is the fast path: it skips the JSON marshal entirely for a known-dead conn. The actual race-safe check happens inside sendFrame next to the channel send — do not remove either one.

func (*Conn) SendBlocking added in v1.18.1

func (c *Conn) SendBlocking(msg *Message, cancel <-chan struct{}) error

SendBlocking queues a must-deliver frame, waiting for the critical queue to drain below sendHeadroom instead of tripping the slow-client overflow close. For unicast bulk transfers (ghost replay, event replay during attach) that run on the sender's own goroutine: backpressure slows only this client's replay, while a genuinely wedged peer is still bounded by sendLoop's writeDeadline (deadline trips → conn closes → done fires → this returns). cancel (typically the daemon shutdown channel) may be nil.

Without this, a freshly attached TUI busy applying workspace state was force-closed whenever replay volume exceeded sendBufSize frames — two full 256 KB ghost buffers were enough — locking the client out on every attach.

type CreatePanePayload

type CreatePanePayload struct {
	TabID         string   `json:"tab_id"`
	CWD           string   `json:"cwd"`
	Type          string   `json:"type,omitempty"`
	InstanceName  string   `json:"instance_name,omitempty"`
	InstanceArgs  []string `json:"instance_args,omitempty"`
	ReplacePaneID string   `json:"replace_pane_id,omitempty"`
	// Overlay marks the pane as a TUI overlay (lazygit toggle view): it
	// never enters the layout tree, is muted at creation, and is excluded
	// from disk snapshots (ephemeral — gone on daemon restart).
	// Trust: any IPC client can set this field; the daemon honors it under
	// the same socket trust model as every other field (the MCP bridge
	// deliberately does not expose it).
	Overlay bool `json:"overlay,omitempty"`
	// ResumeSessionID resumes an existing Claude Code session instead of
	// starting a fresh one: the daemon spawns `claude --resume <id>` in place
	// of the preassign_id strategy's `--session-id <new-uuid>`. Empty (the
	// default) preserves the fresh-session behavior.
	//
	// Trust: like Overlay, any IPC client can set this. The daemon validates
	// it against the canonical UUID shape before it reaches argv, and also
	// refuses a session a live pane already holds — two claude processes on
	// one transcript overwrite each other's history. Either rejection falls
	// back to a fresh session rather than failing the spawn. The MCP bridge
	// deliberately does not expose this field.
	ResumeSessionID string `json:"resume_session_id,omitempty"`
}

type CreatePaneReqPayload

type CreatePaneReqPayload struct {
	TabID        string   `json:"tab_id,omitempty"`
	CWD          string   `json:"cwd,omitempty"`
	Type         string   `json:"type,omitempty"`
	InstanceName string   `json:"instance_name,omitempty"`
	InstanceArgs []string `json:"instance_args,omitempty"`
}

type CreatePaneRespPayload

type CreatePaneRespPayload struct {
	PaneID string `json:"pane_id"`
	TabID  string `json:"tab_id"`
}

type CreateTabPayload

type CreateTabPayload struct {
	Name string `json:"name"`
}

type DestroyPanePayload

type DestroyPanePayload struct {
	PaneID string `json:"pane_id"`
}

type DestroyPaneReqPayload

type DestroyPaneReqPayload struct {
	PaneID string `json:"pane_id"`
}

type DestroyPaneRespPayload

type DestroyPaneRespPayload struct {
	Success bool `json:"success"`
}

type DestroyTabPayload

type DestroyTabPayload struct {
	TabID string `json:"tab_id"`
}

type DialFunc added in v1.43.0

type DialFunc func(ctx context.Context) (net.Conn, error)

DialFunc establishes one transport-level connection to a daemon. It is the seam that lets a Client run over something other than a Unix socket (an SSH channel today, a TLS connection later) without the protocol layer knowing.

CONTRACT: ctx bounds the dial only. Once a DialFunc returns a net.Conn, that conn owns any underlying process or socket and releases it on Close — cancelling ctx afterwards must not disturb a live connection. Reconnect loops depend on this: they dial under a per-attempt timeout with a deferred cancel, and would otherwise destroy each session as they created it.

type DismissEventPayload

type DismissEventPayload struct {
	EventID string `json:"event_id"` // empty = dismiss all
}

type GetNotificationsRespPayload

type GetNotificationsRespPayload struct {
	Events []PaneEventPayload `json:"events"`
}

type HighlightPanePayload

type HighlightPanePayload struct {
	PaneID string `json:"pane_id"`
}

type HistoryEntryMeta added in v1.30.0

type HistoryEntryMeta struct {
	TsMs    int64  `json:"ts_ms"`
	Preview string `json:"preview"`
}

HistoryEntryMeta is one list row: a stable id (TsMs) and a single-line preview. The list renders exactly one row per entry, so the preview is flattened daemon-side (panehistory.PreviewLine) rather than shipped as the prompt's separate lines — the wire carries what is displayed, nothing more.

type ListPanesRespPayload

type ListPanesRespPayload struct {
	Panes []PaneInfo `json:"panes"`
}

type ListTabsRespPayload

type ListTabsRespPayload struct {
	Tabs []TabInfo `json:"tabs"`
}

type MemoryReportReqPayload added in v1.9.0

type MemoryReportReqPayload struct{}

type MemoryReportRespPayload added in v1.9.0

type MemoryReportRespPayload struct {
	SnapshotAt int64         `json:"snapshot_at"` // Unix nanoseconds
	Panes      []PaneMemInfo `json:"panes"`
	Total      uint64        `json:"total"`
	// Tabs is the same view that MsgListTabsResp would return at the moment
	// the daemon assembled this response. Embedded here so MCP
	// `get_memory_report` does not need a second round-trip to enrich tab
	// IDs with names. Note: the per-pane memory numbers come from the
	// memreport collector's last tick (up to 5 s old), while Tabs is taken
	// fresh — the two halves are captured close-in-time on the daemon side
	// but are not guaranteed to be drawn from the exact same instant.
	Tabs []TabInfo `json:"tabs,omitempty"`
}

type Message

type Message struct {
	Type    string          `json:"type"`
	ID      string          `json:"id,omitempty"` // request-response correlation (MCP bridge)
	Payload json.RawMessage `json:"payload,omitempty"`
}

Message is the wire format for IPC communication.

func NewMessage

func NewMessage(typ string, payload any) (*Message, error)

NewMessage creates a Message with a typed payload.

func ReadMessage

func ReadMessage(r io.Reader) (*Message, error)

ReadMessage reads a length-prefixed JSON message from r.

func (*Message) DecodePayload

func (m *Message) DecodePayload(target any) error

DecodePayload unmarshals the message payload into the given target.

type MessageHandler

type MessageHandler func(conn *Conn, msg *Message)

MessageHandler is called for each incoming message on a connection.

type PaneEventPayload

type PaneEventPayload struct {
	ID        string            `json:"id"`
	PaneID    string            `json:"pane_id"`
	TabID     string            `json:"tab_id"`
	PaneName  string            `json:"pane_name"`
	Type      string            `json:"type"`
	Title     string            `json:"title"`
	Message   string            `json:"message,omitempty"`
	Severity  string            `json:"severity"`
	Timestamp int64             `json:"timestamp"`
	Data      map[string]string `json:"data,omitempty"`
}

type PaneHistoryEntryReqPayload added in v1.30.0

type PaneHistoryEntryReqPayload struct {
	PaneID string `json:"pane_id"`
	TsMs   int64  `json:"ts_ms"`
}

PaneHistoryEntryReqPayload requests one entry's full text by its TsMs id.

type PaneHistoryEntryRespPayload added in v1.30.0

type PaneHistoryEntryRespPayload struct {
	PaneID string `json:"pane_id"`
	TsMs   int64  `json:"ts_ms"`
	Text   string `json:"text"`
	Found  bool   `json:"found"`
}

PaneHistoryEntryRespPayload carries one entry's full text (Found=false if the id no longer exists, e.g. compacted away between list and fetch).

type PaneHistoryReqPayload added in v1.30.0

type PaneHistoryReqPayload struct {
	PaneID string `json:"pane_id"`
}

PaneHistoryReqPayload requests the input-history preview list for one pane.

type PaneHistoryRespPayload added in v1.30.0

type PaneHistoryRespPayload struct {
	PaneID  string             `json:"pane_id"`
	Entries []HistoryEntryMeta `json:"entries"`
}

PaneHistoryRespPayload carries the preview list, newest first.

type PaneInfo

type PaneInfo struct {
	ID           string `json:"id"`
	TabID        string `json:"tab_id"`
	TabName      string `json:"tab_name"`
	Name         string `json:"name"`
	Type         string `json:"type"`
	CWD          string `json:"cwd"`
	Running      bool   `json:"running"`
	Pending      bool   `json:"pending,omitempty"`
	InstanceName string `json:"instance_name,omitempty"`
}

type PaneInputPayload

type PaneInputPayload struct {
	PaneID string `json:"pane_id"`
	Data   []byte `json:"data"`
}

type PaneMemInfo added in v1.9.0

type PaneMemInfo struct {
	PaneID      string `json:"pane_id"`
	TabID       string `json:"tab_id"`
	GoHeapBytes uint64 `json:"go_heap_bytes"`
	PTYRSSBytes uint64 `json:"pty_rss_bytes"`
	TotalBytes  uint64 `json:"total_bytes"`
}

PaneMemInfo is the wire form of a single pane's daemon-side memory. TUI-local memory is not part of the wire format — the TUI merges its own values at render time.

type PaneOutputPayload

type PaneOutputPayload struct {
	PaneID string `json:"pane_id"`
	Data   []byte `json:"data"`
	Ghost  bool   `json:"ghost,omitempty"`
}

type PaneSearchHit added in v1.40.0

type PaneSearchHit struct {
	PaneID    string `json:"pane_id"`
	Matches   int    `json:"matches"`
	Excerpt   string `json:"excerpt"`
	Truncated bool   `json:"truncated,omitempty"`
}

PaneSearchHit is one matching pane. The TUI resolves the display label itself from PaneID (it already holds tab/pane metadata), so the daemon returns only the id, the total match count, a single preview line, and whether THIS pane's count was capped (the per-hit flag is what the "capped" label renders from — the payload-level Truncated is only a "some pane was capped" summary).

type PaneSearchReqPayload added in v1.40.0

type PaneSearchReqPayload struct {
	Query string `json:"query"`
}

PaneSearchReqPayload asks the daemon to scan every pane's scrollback for a literal, case-insensitive substring. Query is the palette query verbatim — content search runs inline with the command filter, so there is no sigil to strip; the daemon trims it only for matching and echoes it back unchanged.

type PaneSearchRespPayload added in v1.40.0

type PaneSearchRespPayload struct {
	Query     string          `json:"query"`
	Hits      []PaneSearchHit `json:"hits"`
	Truncated bool            `json:"truncated,omitempty"`
}

PaneSearchRespPayload carries the hits for one search. Query echoes the request term VERBATIM (never trimmed — the TUI compares it against its own untrimmed term to drop responses that arrived after the user typed more). Truncated is set when any pane hit the per-pane match cap.

type PaneStatusReqPayload

type PaneStatusReqPayload struct {
	PaneID string `json:"pane_id"`
}

type PaneStatusRespPayload

type PaneStatusRespPayload struct {
	PaneID   string `json:"pane_id"`
	Running  bool   `json:"running"`
	Pending  bool   `json:"pending,omitempty"`
	ExitCode *int   `json:"exit_code,omitempty"`
	Type     string `json:"type"`
	CWD      string `json:"cwd"`
	Name     string `json:"name"`
}

type PluginErrorPayload

type PluginErrorPayload struct {
	PaneID  string `json:"pane_id"`
	Title   string `json:"title"`
	Message string `json:"message"`
}

type ReadPaneOutputReqPayload

type ReadPaneOutputReqPayload struct {
	PaneID    string `json:"pane_id"`
	LastLines int    `json:"last_lines"`
}

type ReadPaneOutputRespPayload

type ReadPaneOutputRespPayload struct {
	PaneID string `json:"pane_id"`
	Text   string `json:"text"`
	Lines  int    `json:"lines"`
}

type ReorderTabPayload added in v1.15.0

type ReorderTabPayload struct {
	TabID    string `json:"tab_id"`
	NewIndex int    `json:"new_index"`
}

ReorderTabPayload moves an existing tab to a new ordinal position. NewIndex is clamped to the daemon-side tab list bounds, so a stale TUI does not have to track creation/destruction races to send a safe value.

type ResizePanePayload

type ResizePanePayload struct {
	PaneID string `json:"pane_id"`
	Rows   uint16 `json:"rows"`
	Cols   uint16 `json:"cols"`
}

type RestartPaneReqPayload

type RestartPaneReqPayload struct {
	PaneID string `json:"pane_id"`
}

type RestartPaneRespPayload

type RestartPaneRespPayload struct {
	PaneID  string `json:"pane_id"`
	Success bool   `json:"success"`
}

type ScreenshotPaneReqPayload

type ScreenshotPaneReqPayload struct {
	PaneID string `json:"pane_id"`
	Width  int    `json:"width,omitempty"`
	Height int    `json:"height,omitempty"`
}

type ScreenshotPaneRespPayload

type ScreenshotPaneRespPayload struct {
	PaneID  string `json:"pane_id"`
	Text    string `json:"text"`
	CursorX int    `json:"cursor_x"`
	CursorY int    `json:"cursor_y"`
}

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server listens for client connections over a Unix socket.

func NewServer

func NewServer(socketPath string, handler MessageHandler, onDisconnect func(*Conn)) *Server

func (*Server) Broadcast

func (s *Server) Broadcast(msg *Message)

Broadcast sends a message to all connected clients without blocking on any individual conn. Marshals the wire frame once and shares the bytes across all per-conn send queues. Live PTY output (MsgPaneOutput) is enqueued as droppable — a slow conn sheds it without being closed. All other message types are critical: a slow or wedged conn that overflows its critical queue is dropped from the fan-out (logged once, per CAS-guarded enqueue) without affecting the others.

func (*Server) ConnCount added in v1.16.0

func (s *Server) ConnCount() int

ConnCount returns the number of currently-connected clients. Test-friendly alternative to the existing log-line scraping pattern; used to wait for connect/disconnect events without time-based sleeps.

func (*Server) Start

func (s *Server) Start() error

func (*Server) Stop

func (s *Server) Stop() error

Stop closes the listener and all active connections. Frames queued in any conn's send buffer at the moment of Stop are discarded — Daemon.Stop's shutdown sequence does not rely on a final IPC broadcast reaching clients (the final-snapshot durability lives in the on-disk workspace.json path, not in the wire).

type SetActivePanePayload

type SetActivePanePayload struct {
	PaneID string `json:"pane_id"`
}

type StageUpdateRespPayload added in v1.37.0

type StageUpdateRespPayload struct {
	Success bool   `json:"success"`
	Version string `json:"version,omitempty"`
	Error   string `json:"error,omitempty"`
}

StageUpdateRespPayload answers MsgStageUpdateReq (About → Update now with nothing staged yet).

type SwitchTabPayload

type SwitchTabPayload struct {
	TabID string `json:"tab_id"`
}

type SwitchTabReqPayload

type SwitchTabReqPayload struct {
	TabID string `json:"tab_id"`
}

type SwitchTabRespPayload

type SwitchTabRespPayload struct {
	TabID string `json:"tab_id"`
}

type TabInfo

type TabInfo struct {
	ID        string `json:"id"`
	Name      string `json:"name"`
	Color     string `json:"color,omitempty"`
	PaneCount int    `json:"pane_count"`
	Active    bool   `json:"active"`
}

type UpdateInfo added in v1.37.0

type UpdateInfo struct {
	LatestVersion   string `json:"latest_version"`
	ReleaseURL      string `json:"release_url,omitempty"`
	StagedVersion   string `json:"staged_version,omitempty"` // set once fully staged
	InstallWritable bool   `json:"install_writable"`
}

UpdateInfo rides the workspace_state broadcast under the "update" key when a newer release than the running daemon's version is known. Omitted entirely when up to date; old clients ignore the extra key.

type UpdateLayoutPayload

type UpdateLayoutPayload struct {
	TabID  string          `json:"tab_id"`
	Layout json.RawMessage `json:"layout"`
}

type UpdatePanePayload

type UpdatePanePayload struct {
	PaneID string `json:"pane_id"`
	Name   string `json:"name,omitempty"`
	CWD    string `json:"cwd,omitempty"`
	// Muted is a pointer so an unset field (nil) is distinguishable from an
	// explicit false. Callers updating only Name or CWD pass nil and the
	// daemon leaves the pane's mute state untouched.
	Muted *bool `json:"muted,omitempty"`
	// Eager is a pointer for the same nil-vs-false tri-state reason as Muted.
	Eager *bool `json:"eager,omitempty"`
}

type UpdateTabPayload

type UpdateTabPayload struct {
	TabID string `json:"tab_id"`
	Name  string `json:"name,omitempty"`
	Color string `json:"color,omitempty"`
	// ClearColor disambiguates an empty Color: "" alone means "no change"
	// (e.g. a rename of an uncolored tab), ClearColor=true means "reset to
	// the default color" (the tab-color cycle wrapping past the last color).
	ClearColor bool `json:"clear_color,omitempty"`
}

type VersionRespPayload added in v1.8.0

type VersionRespPayload struct {
	Version string `json:"version"`
}

VersionRespPayload carries the daemon's version string. MsgVersionReq has no payload — the request is just "what version are you running?".

type WatchNotificationsReqPayload

type WatchNotificationsReqPayload struct {
	PaneIDs   []string `json:"pane_ids,omitempty"`
	TimeoutMs int      `json:"timeout_ms"`
	// SinceTimestamp closes the race between "kick off a task" and "start
	// watching" — events fired during that window would otherwise be lost.
	// When set (Unix ms), the daemon first scans the existing event queue
	// for any matching event whose timestamp is strictly greater, returning
	// the oldest such event immediately. Only if the queue holds no
	// qualifying event does it register a blocking watcher. Agents should
	// pass the timestamp of the last event they handled.
	SinceTimestamp int64 `json:"since_timestamp,omitempty"`
}

type WatchNotificationsRespPayload

type WatchNotificationsRespPayload struct {
	Event   *PaneEventPayload `json:"event,omitempty"`
	Timeout bool              `json:"timeout"`
}

Jump to

Keyboard shortcuts

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