Documentation
¶
Overview ¶
Package ghostline provides embeddable Unix pseudo-terminal sessions backed by libghostty-vt screen replays and append-only output spools. A Hub runs sessions in-process; a Server and Client expose the same Session API over a Unix socket.
Index ¶
- Constants
- Variables
- func Adopt(ctx context.Context, adminSocket string, h *Hub) (int, error)
- func Ping(socketPath string) bool
- type Checkpoint
- type Client
- func (c *Client) Check(ctx context.Context) error
- func (c *Client) Close() error
- func (c *Client) Ensure(ctx context.Context) error
- func (c *Client) List(ctx context.Context) ([]string, error)
- func (c *Client) PID() int
- func (c *Client) Session(name string) (Session, bool)
- func (c *Client) Sessions() []Session
- func (c *Client) Socket() string
- func (c *Client) Start(ctx context.Context, options SessionOptions) (Session, error)
- func (c *Client) Version(ctx context.Context) (string, error)
- type ColorQueryCallback
- type ColorQueryKind
- type ConnectOptions
- type ExitError
- type Hub
- type MetadataProvider
- type Options
- type QueryResponder
- type Server
- type Session
- type SessionMetadata
- type SessionOptions
- type Size
- type SpoolWatcher
- type Status
- type VTTerminal
- type VTTerminalOptions
- type WatchOptions
Constants ¶
const DefaultVTScrollbackMaxBytes uint64 = 2 << 20
DefaultVTScrollbackMaxBytes is the default logical scrollback budget for each embedded VT terminal. libghostty stores history in page-sized units, so the physical allocation can be somewhat larger than this value.
const ProtocolVersion = "0.6.0"
ProtocolVersion identifies the RPC protocol spoken by the server. Clients use it to detect an outdated server process during upgrades instead of failing on unknown methods.
Variables ¶
var ( ErrUnavailable = errors.New("ghostline: libghostty-vt unavailable") // ErrClosed indicates that the hub is closed. ErrClosed = errors.New("ghostline: hub closed") // ErrSessionExists indicates that the name is already taken. ErrSessionExists = errors.New("ghostline: session already exists") // ErrSessionNotFound indicates that no session has the requested name. ErrSessionNotFound = errors.New("ghostline: session not found") // ErrSessionClosed indicates that a session handle is no longer usable. ErrSessionClosed = errors.New("ghostline: session closed") // ErrInvalidSessionName indicates that a name cannot identify a spool file. ErrInvalidSessionName = errors.New("ghostline: invalid session name") )
Functions ¶
Types ¶
type Checkpoint ¶ added in v0.2.0
type Checkpoint struct {
// Replay is a full VT replay of the visible grid and scrollback.
Replay []byte
// Offset is the raw spool byte position covered by Replay.
Offset int64
}
Checkpoint is an atomic screen replay and raw output position.
type Client ¶ added in v0.2.0
type Client struct {
// contains filtered or unexported fields
}
Client proxies Hub operations to a Server over a Unix socket.
func Connect ¶ added in v0.3.0
func Connect(ctx context.Context, options ConnectOptions) (*Client, error)
Connect returns a client, spawning the server when the socket is missing. The returned client owns the spawned process; Close stops it.
func (*Client) Close ¶ added in v0.3.0
Close stops the server that this client spawned. Clients that connected to an existing server have nothing to stop.
func (*Client) Ensure ¶ added in v0.3.0
Ensure starts the server if it is missing and waits until it is ready.
func (*Client) PID ¶ added in v0.3.4
PID returns the process ID of the server spawned by this client, or zero when the client attached to an existing server.
func (*Client) Session ¶ added in v0.3.2
Session returns a handle for a session known to the server, mirroring Hub.Session. The handle is lazy; operations fail with the server's error if the session disappears.
func (*Client) Sessions ¶ added in v0.3.2
Sessions returns handles for all sessions known to the server, ordered by name, mirroring Hub.Sessions.
func (*Client) Start ¶ added in v0.2.0
Start creates a session on the server and returns its remote handle.
type ColorQueryCallback ¶ added in v0.6.2
type ColorQueryCallback func(ColorQueryKind) (color string, ok bool)
ColorQueryCallback supplies a color for an OSC 10 or OSC 11 query.
The callback should return a six-digit RGB value with an optional leading '#'. It returns false when the requested color is not available. A callback is optional; without one, unknown colors receive no reply.
type ColorQueryKind ¶ added in v0.6.2
type ColorQueryKind uint8
ColorQueryKind identifies the terminal color requested by an OSC query.
const ( // ColorQueryForeground is the default text color (OSC 10). ColorQueryForeground ColorQueryKind = 10 // ColorQueryBackground is the default background color (OSC 11). ColorQueryBackground ColorQueryKind = 11 )
type ConnectOptions ¶ added in v0.3.0
type ConnectOptions struct {
// Socket is the Unix socket path the server listens on.
Socket string
// Spawn is the command used to start the server when the socket is
// missing. Arguments may contain {socket}, replaced by Socket. Empty uses
// ["ghostline", "serve", "--socket", socket].
Spawn []string
// Env overrides the spawned server's environment.
Env []string
// ReadyTimeout bounds how long Connect waits for the socket. Zero uses 5s.
ReadyTimeout time.Duration
// Log receives the spawned server's stdout and stderr. Empty discards it.
Log io.Writer
}
ConnectOptions configures how Connect starts a missing server.
type ExitError ¶ added in v0.3.0
type ExitError struct {
// Code is the process exit status, or -1 when the process was signaled.
Code int
// Signal names the terminating signal when the process was signaled.
Signal string
// Unknown is true when a migrated child exited after its original parent
// had already gone away. In that case the new server can observe the PTY
// closing, but the operating system cannot provide the original wait
// status to a different parent process.
Unknown bool
}
ExitError describes a terminated child process.
type Hub ¶ added in v0.2.0
type Hub struct {
// contains filtered or unexported fields
}
Hub owns local pseudo-terminal sessions.
func (*Hub) Close ¶ added in v0.2.0
Close terminates every session and prevents further Start calls.
type MetadataProvider ¶ added in v0.5.0
type MetadataProvider interface {
// Metadata reports OS-level foreground process metadata when the hub was
// created with ProbeForeground enabled. When probing is disabled it
// returns zero values; otherwise it may return an error when the
// foreground process cannot be resolved.
Metadata(ctx context.Context) (SessionMetadata, error)
}
MetadataProvider is implemented by sessions that can report OS-level foreground process metadata. It is kept separate from Session so existing Session implementations and test doubles continue to compile.
type Options ¶ added in v0.2.0
type Options struct {
// OutputDir stores session spools. An empty value uses
// $HOME/.ghostline/output.
OutputDir string
// DefaultSize is used when SessionOptions.Size is zero. The default is
// 120 columns by 36 rows.
DefaultSize Size
// DefaultTerm is used for pty children whose environment has no
// non-empty TERM. An empty value defaults to xterm-256color.
DefaultTerm string
// VTScrollbackMaxBytes is the default logical scrollback budget for new
// sessions. Zero uses DefaultVTScrollbackMaxBytes.
VTScrollbackMaxBytes uint64
// ProbeForeground enables OS-level foreground process/cwd metadata.
// Disabled by default; Session.Metadata returns empty values without
// spawning any OS probes.
ProbeForeground bool
}
Options configures a Hub. Zero values select documented defaults.
type QueryResponder ¶
type QueryResponder struct {
// contains filtered or unexported fields
}
QueryResponder answers terminal capability queries while a session has no attached terminal client. TUIs such as Codex send DA/DSR/OSC/kitty keyboard queries at startup. A raw PTY has nobody to answer until a client attaches, so the application may downgrade itself (for example disabling colors). Replies are written back into the PTY as input, never into output.
func NewQueryResponder ¶
func NewQueryResponder() *QueryResponder
NewQueryResponder returns a responder initialized to a 120x36 terminal.
func NewQueryResponderWithColorQuery ¶ added in v0.6.2
func NewQueryResponderWithColorQuery(callback ColorQueryCallback) *QueryResponder
NewQueryResponderWithColorQuery returns a responder that uses callback to answer OSC 10 and OSC 11 color queries.
func (*QueryResponder) Feed ¶
func (r *QueryResponder) Feed(data []byte) [][]byte
Feed scans output bytes for complete terminal queries and returns the replies to write back into the PTY. Queries split across chunks are buffered until complete or until they prove not to be queries.
func (*QueryResponder) Resize ¶
func (r *QueryResponder) Resize(columns, rows int)
Resize updates the window size reported in XTWINOPS replies.
type Server ¶ added in v0.2.0
type Server struct {
// contains filtered or unexported fields
}
Server owns PTY sessions in a standalone process so clients can restart without ending any session. The wire protocol is one JSON object per line on a Unix socket; []byte fields use JSON base64 encoding automatically.
func (*Server) Adopt ¶ added in v0.3.4
Server.Adopt migrates sessions into this server. Call it before Serve so the target never accepts a client while its session map is being rebuilt.
type Session ¶ added in v0.2.0
type Session interface {
// Name returns the session's unique name.
Name() string
// CreatedAt returns when the child process started.
CreatedAt() time.Time
// Done is closed after the child exits and all output is consumed.
Done() <-chan struct{}
// Wait waits for the child and returns its exit error. Context
// cancellation stops waiting but does not terminate the child.
Wait(ctx context.Context) error
// Alive reports whether the session is currently running.
Alive() bool
// Status distinguishes a running session from a stopped one and reports
// the exit reason when stopped.
Status(ctx context.Context) (Status, error)
// Input writes bytes to the PTY verbatim.
Input(ctx context.Context, data []byte) error
// Resize updates the real PTY and the emulated grid.
Resize(ctx context.Context, size Size) error
// Snapshot returns a full VT replay of the visible grid and scrollback.
Snapshot(ctx context.Context) ([]byte, error)
// Checkpoint captures a replay and its exact spool boundary atomically.
Checkpoint(ctx context.Context) (Checkpoint, error)
// Recover reads the raw spool range [offset, end).
Recover(ctx context.Context, offset, end int64) ([]byte, error)
// SpoolPath returns the append-only raw output spool path.
SpoolPath() string
// SpoolSize returns the current raw output spool size.
SpoolSize(ctx context.Context) (int64, error)
// WatchOutput subscribes to raw output and starts the watcher.
WatchOutput(options WatchOptions) (*SpoolWatcher, error)
// Close terminates the session. The record stays visible until Remove.
Close() error
// Remove deletes the session record. Spool files stay on disk.
Remove() error
// TruncateSpool compacts the live spool in place.
TruncateSpool(ctx context.Context) error
// ArchiveSpool compresses the spool and prunes old archives.
ArchiveSpool(ctx context.Context) error
// RemoveSpool deletes the spool and its archives.
RemoveSpool()
}
Session is a stable handle to one session, local or remote.
type SessionMetadata ¶ added in v0.5.0
type SessionMetadata struct {
// Process is the foreground process name.
Process string `json:"process"`
// Directory is the foreground process working directory.
Directory string `json:"directory"`
}
SessionMetadata is the OS-level foreground process snapshot for one session. It is presentation metadata, not lifecycle state.
type SessionOptions ¶ added in v0.2.0
type SessionOptions struct {
// Name identifies the session and its spool file. It must be a single,
// non-empty path component.
Name string
// Directory is the child's working directory. An empty value inherits the
// embedding process's working directory.
Directory string
// Command is evaluated by "sh -lc". An empty value starts $SHELL, falling
// back to sh.
Command string
// Size is the initial grid size. A zero value uses the hub's default.
Size Size
// Environment entries use KEY=value form and override inherited values.
Environment []string
// VTScrollbackMaxBytes overrides the Hub default for this session. Zero
// inherits the Hub setting.
VTScrollbackMaxBytes uint64
}
SessionOptions configures one session.
type Size ¶ added in v0.2.0
type Size struct {
// Columns is the number of character cells per line.
Columns int
// Rows is the number of lines in the grid.
Rows int
}
Size is a terminal grid size in cells.
type SpoolWatcher ¶
type SpoolWatcher struct {
// contains filtered or unexported fields
}
SpoolWatcher reads an append-only spool from a persisted byte offset, draining to EOF whenever the file grows. The byte slice passed to onBytes is valid only for the duration of the callback; callers must copy it to retain it.
The watcher also detects in-place truncation (spool compaction). After a truncate the file size drops below the watcher offset; the watcher re-bases to offset zero and calls onRotate so the consumer can invalidate old offsets instead of silently skipping bytes.
func NewSpoolWatcher ¶
func NewSpoolWatcher(path string, offset int64, onBytes func([]byte), onRotate func(), onOverflow func()) (*SpoolWatcher, error)
NewSpoolWatcher returns a watcher positioned at offset in the file at path. The callbacks may be nil. Start begins polling.
func (*SpoolWatcher) Close ¶
func (w *SpoolWatcher) Close()
Close stops the watcher and releases its file descriptor. It is safe to call multiple times.
func (*SpoolWatcher) Offset ¶
func (w *SpoolWatcher) Offset() int64
Offset returns the next byte position the watcher will deliver.
func (*SpoolWatcher) Pause ¶
func (w *SpoolWatcher) Pause()
Pause blocks until any in-flight drain finishes, then prevents new drains. Use it while preparing a checkpoint replay so live reads cannot interleave.
func (*SpoolWatcher) Ping ¶
func (w *SpoolWatcher) Ping()
Ping asks the watcher to check for output without waiting for its next poll.
func (*SpoolWatcher) Resume ¶
func (w *SpoolWatcher) Resume()
Resume re-enables draining after Pause and asks the watcher to check immediately.
func (*SpoolWatcher) SetMaxBytes ¶
func (w *SpoolWatcher) SetMaxBytes(maxBytes int64)
SetMaxBytes configures the spool size cap before Start. When the watcher passes the cap it calls onOverflow so the consumer can compact the spool.
func (*SpoolWatcher) SkipTo ¶
func (w *SpoolWatcher) SkipTo(offset int64) error
SkipTo re-bases the watcher to a byte position covered by a snapshot. It must be called while paused and the offset must be within the current file; any unread bytes below the target were already rendered by the snapshot and must not be delivered again.
func (*SpoolWatcher) Start ¶
func (w *SpoolWatcher) Start()
Start begins watching. Repeated calls are safe and have no effect.
type Status ¶ added in v0.3.0
type Status struct {
// Alive is true while the child process is running.
Alive bool `json:"alive"`
// Exit describes the termination when Alive is false.
Exit *ExitError `json:"exit,omitempty"`
}
Status describes whether a session is running and, when stopped, why.
type VTTerminal ¶
type VTTerminal struct {
// contains filtered or unexported fields
}
VTTerminal is a libghostty-vt terminal emulator that renders raw PTY bytes into a complete screen snapshot (visible grid + scrollback) with SGR styles preserved. It is the server-side counterpart of the Ghostty client, so a replayed snapshot matches exactly what the client would have rendered.
func NewVTTerminal ¶
func NewVTTerminal(cols, rows int) (*VTTerminal, error)
NewVTTerminal creates a terminal emulator with the given grid size.
func NewVTTerminalWithOptions ¶ added in v0.6.1
func NewVTTerminalWithOptions(cols, rows int, options VTTerminalOptions) (*VTTerminal, error)
NewVTTerminalWithOptions creates a terminal emulator with the given grid size and VT configuration.
func (*VTTerminal) Close ¶
func (v *VTTerminal) Close()
Close releases the native terminal state. It must be called at most once.
func (*VTTerminal) EncodeState ¶ added in v0.3.4
func (v *VTTerminal) EncodeState() ([]byte, error)
EncodeState encodes the full emulator state (visible grid, scrollback, cursor, and terminal modes) so a session can be migrated to another server process.
func (*VTTerminal) Feed ¶
func (v *VTTerminal) Feed(data []byte)
Feed parses raw PTY bytes into the emulated terminal state.
func (*VTTerminal) Resize ¶
func (v *VTTerminal) Resize(cols, rows int)
Resize reflows the emulated terminal. The caller keeps the real PTY size in sync so snapshots are rendered at the client's dimensions.
func (*VTTerminal) RestoreState ¶ added in v0.3.4
func (v *VTTerminal) RestoreState(snapshot []byte) error
RestoreState replaces the emulated state with bytes produced by EncodeState.
func (*VTTerminal) Snapshot ¶
func (v *VTTerminal) Snapshot() ([]byte, error)
Snapshot renders the current emulated screen (visible grid + scrollback) as VT sequences that preserve colors and styles.
type VTTerminalOptions ¶ added in v0.6.1
type VTTerminalOptions struct {
// ScrollbackMaxBytes is the maximum logical scrollback allocation. Zero
// uses DefaultVTScrollbackMaxBytes.
ScrollbackMaxBytes uint64
}
VTTerminalOptions configures the embedded VT terminal.
type WatchOptions ¶ added in v0.2.0
type WatchOptions struct {
// Offset is the first spool byte to deliver.
Offset int64
// MaxBytes invokes OnOverflow after the watcher passes the limit. Zero
// uses the watcher default.
MaxBytes int64
// OnOutput receives borrowed bytes; copy them to retain after return.
OnOutput func([]byte)
// OnTruncate runs when the spool is compacted in place.
OnTruncate func()
// OnOverflow runs when Offset passes MaxBytes.
OnOverflow func()
}
WatchOptions configures an output subscription.