Documentation
¶
Index ¶
- Constants
- Variables
- func WriteMessage(w io.Writer, msg *Message) error
- type AttachPayload
- type Client
- type Conn
- type CreatePanePayload
- type CreatePaneReqPayload
- type CreatePaneRespPayload
- type CreateTabPayload
- type DestroyPanePayload
- type DestroyPaneReqPayload
- type DestroyPaneRespPayload
- type DestroyTabPayload
- type DismissEventPayload
- type GetNotificationsRespPayload
- type HighlightPanePayload
- type ListPanesRespPayload
- type ListTabsRespPayload
- type MemoryReportReqPayload
- type MemoryReportRespPayload
- type Message
- type MessageHandler
- type PaneEventPayload
- type PaneInfo
- type PaneInputPayload
- type PaneMemInfo
- type PaneOutputPayload
- type PaneStatusReqPayload
- type PaneStatusRespPayload
- type PluginErrorPayload
- type ReadPaneOutputReqPayload
- type ReadPaneOutputRespPayload
- type ReorderTabPayload
- type ResizePanePayload
- type RestartPaneReqPayload
- type RestartPaneRespPayload
- type ScreenshotPaneReqPayload
- type ScreenshotPaneRespPayload
- type Server
- type SetActivePanePayload
- type SwitchTabPayload
- type SwitchTabReqPayload
- type SwitchTabRespPayload
- type TabInfo
- type UpdateLayoutPayload
- type UpdatePanePayload
- type UpdateTabPayload
- type VersionRespPayload
- type WatchNotificationsReqPayload
- type WatchNotificationsRespPayload
Constants ¶
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" )
Message type constants
Variables ¶
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 ¶
Types ¶
type AttachPayload ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client connects to the daemon over a Unix socket.
func (*Client) SetReadDeadline ¶ added in v1.8.0
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 a 64-slot queue and a dedicated goroutine that drains the queue into the underlying socket. A slow or wedged peer drains its own queue; if the queue overflows, the offending conn is closed in the background and Send returns ErrSendOverflow. 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.
func (*Conn) Close ¶
Close shuts down the conn. Idempotent — safe to call concurrently from any goroutine. Any frames still queued in sendCh 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) Send ¶
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.
type CreatePanePayload ¶
type CreatePaneReqPayload ¶
type CreatePaneRespPayload ¶
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 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 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 ¶
NewMessage creates a Message with a typed payload.
func ReadMessage ¶
ReadMessage reads a length-prefixed JSON message from r.
func (*Message) DecodePayload ¶
DecodePayload unmarshals the message payload into the given target.
type MessageHandler ¶
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 PaneInputPayload ¶
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 PaneStatusReqPayload ¶
type PaneStatusReqPayload struct {
PaneID string `json:"pane_id"`
}
type PaneStatusRespPayload ¶
type PluginErrorPayload ¶
type ReorderTabPayload ¶ added in v1.15.0
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 RestartPaneReqPayload ¶
type RestartPaneReqPayload struct {
PaneID string `json:"pane_id"`
}
type RestartPaneRespPayload ¶
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 ¶
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. A slow or wedged conn is dropped from the fan-out (logged once, per CAS-guarded sendFrame) without affecting the others.
func (*Server) ConnCount ¶ added in v1.16.0
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) Stop ¶
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 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 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"`
}
type UpdateTabPayload ¶
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"`
}