Documentation
¶
Index ¶
- Constants
- func ClosePinnedTerminalExecutable()
- func DrainTransferredPTY(ptmx *os.File, scrollback *Scrollback) error
- func PreparePinnedTerminalExecutable() error
- func ProbeTerminalAdoption() (int, bool)
- func ProcessStartTime(pid int) (int64, error)
- func RecoverTerminalSessionsAfterUpgrade(ctx context.Context, sessions []*Session) []error
- func ReleasePinnedTerminalExecutablePathForExec() error
- func RestorePinnedTerminalExecutableAfterExec() error
- func RunNativeTerminalSelfTest() (returnErr error)
- func TailFile(path string, lines int) ([]byte, error)
- func TerminalAdoptionCapacity() (int, bool)
- func TerminalBackend() string
- func ThawTerminalHelpers()
- func ValidateTransferredScrollbackFD(fd uintptr) error
- type AdoptOpts
- type Cell
- type CellStyle
- type Color
- type ColorKind
- type HelperProcessIdentity
- type ScreenCapture
- type Scrollback
- func (s *Scrollback) Close() error
- func (s *Scrollback) DuplicateFD() (int, error)
- func (s *Scrollback) Remove() error
- func (s *Scrollback) SetLogger(log *slog.Logger)
- func (s *Scrollback) Stats() (written, maxSize int64, saturated bool)
- func (s *Scrollback) Tail(lines int) ([]byte, error)
- func (s *Scrollback) TailBytes(maxBytes int64) ([]byte, error)
- func (s *Scrollback) ValidatePathIdentity() error
- func (s *Scrollback) Write(data []byte) (int, error)
- type Session
- func AdoptSession(opts AdoptOpts) (*Session, error)
- func AdoptSessionWithTerminalFactory(opts AdoptOpts, factory func(cols, rows int) (Terminal, error)) (*Session, error)
- func NewSession(opts SessionOpts) (*Session, error)
- func NewSessionWithTerminalFactory(opts SessionOpts, factory func(cols, rows int) (Terminal, error)) (*Session, error)
- func (s *Session) Attach(w io.Writer)
- func (s *Session) BytesRead() int64
- func (s *Session) Close()
- func (s *Session) CreatedAt() time.Time
- func (s *Session) Detach()
- func (s *Session) DetachWriter(w io.Writer)
- func (s *Session) Done() <-chan struct{}
- func (s *Session) DuplicateFD() (int, error)
- func (s *Session) ExitCode() int
- func (s *Session) ExitSignal() syscall.Signal
- func (s *Session) Exited() bool
- func (s *Session) Fd() uintptr
- func (s *Session) ForceKill() error
- func (s *Session) Interrupt(count int, delay time.Duration) error
- func (s *Session) Kill() error
- func (s *Session) LastOutputAt() time.Time
- func (s *Session) NotifyUserInput()
- func (s *Session) PeakRSSBytes() int64
- func (s *Session) Pgid() int
- func (s *Session) Poke()
- func (s *Session) ProcessPID() int
- func (s *Session) QuiesceIOForUpgrade(ctx context.Context) (func(), error)
- func (s *Session) RecentlyAdopted(grace time.Duration) bool
- func (s *Session) RecoverTerminalAfterUpgrade() error
- func (s *Session) RecoverTerminalAfterUpgradeContext(ctx context.Context) error
- func (s *Session) RejectAdoption(ctx context.Context) error
- func (s *Session) Resize(rows, cols uint16) error
- func (s *Session) ScreenPreview() string
- func (s *Session) ScreenSnapshot() ScreenCapture
- func (s *Session) ScrollbackFile() *Scrollback
- func (s *Session) SetInputDelay(delay time.Duration)
- func (s *Session) StartAdoptedWaiter()
- func (s *Session) WaitForUserIdle(idleTimeout, maxWait time.Duration) bool
- func (s *Session) WaitForUserIdleContext(ctx context.Context, idleTimeout, maxWait time.Duration) bool
- func (s *Session) WasAdopted() bool
- func (s *Session) WriteInput(data []byte) error
- func (s *Session) WriteInputAndSubmit(data []byte) error
- type SessionOpts
- type Terminal
- type TerminalSnapshot
Constants ¶
const ( TerminalBackendLibghosttyHelper = "libghostty-helper" )
Stable terminal-screen backend identifiers exposed through daemon diagnostics and lifecycle logs. Keep these values independent of concrete implementation type names so operators can rely on them across releases.
Variables ¶
This section is empty.
Functions ¶
func ClosePinnedTerminalExecutable ¶ added in v0.70.0
func ClosePinnedTerminalExecutable()
func DrainTransferredPTY ¶ added in v0.70.0
func DrainTransferredPTY(ptmx *os.File, scrollback *Scrollback) error
DrainTransferredPTY performs the bounded final drain for a daemon handoff rejection before the exact inherited descriptors are closed.
func PreparePinnedTerminalExecutable ¶ added in v0.70.0
func PreparePinnedTerminalExecutable() error
func ProbeTerminalAdoption ¶ added in v0.70.0
func ProcessStartTime ¶ added in v0.48.0
ProcessStartTime returns a value that uniquely identifies the process with the given PID (clock ticks since boot from /proc/[pid]/stat field 22). If the PID is recycled, the new process will have a different start time.
func RecoverTerminalSessionsAfterUpgrade ¶ added in v0.70.0
RecoverTerminalSessionsAfterUpgrade owns a concurrent recovery generation. It joins every started session operation before returning, so cancellation cannot strand helper factories or candidate terminals in detached goroutines.
func ReleasePinnedTerminalExecutablePathForExec ¶ added in v0.70.0
func ReleasePinnedTerminalExecutablePathForExec() error
func RestorePinnedTerminalExecutableAfterExec ¶ added in v0.70.0
func RestorePinnedTerminalExecutableAfterExec() error
func RunNativeTerminalSelfTest ¶ added in v0.70.0
func RunNativeTerminalSelfTest() (returnErr error)
RunNativeTerminalSelfTest exercises the native backend through the exact process-isolated path used by the daemon. Release validation invokes this on the unpacked executable so architecture, helper startup, FFI calls, terminal mutation, snapshot decoding, resize, close, and child reaping are all proven against the final bytes rather than a separate test binary.
func TailFile ¶ added in v0.64.5
TailFile returns the last `lines` lines from a scrollback file on disk without a live Scrollback. It is used to read logs for stopped sessions whose live PTY has already been torn down. A missing file is returned as an error; an existing but empty file returns (nil, nil).
func TerminalAdoptionCapacity ¶ added in v0.70.0
func TerminalBackend ¶ added in v0.70.0
func TerminalBackend() string
func ThawTerminalHelpers ¶ added in v0.70.0
func ThawTerminalHelpers()
func ValidateTransferredScrollbackFD ¶ added in v0.70.0
ValidateTransferredScrollbackFD checks a handoff descriptor without taking ownership. The daemon uses it before atomically moving the PTY/log pair out of its post-exec ownership guard.
Types ¶
type AdoptOpts ¶
type AdoptOpts struct {
ID string
Fd uintptr
ScrollbackFd uintptr
PID int
// ExpectedPIDStartTime binds adoption to the process identity captured by
// the old daemon. Zero is accepted only for a legacy helper-free manifest.
ExpectedPIDStartTime int64
LogPath string
MaxLogSize int64
// DefaultRows / DefaultCols are the geometry used when the adopted ptmx size
// can't be read. Non-positive falls back to the built-in 24x80 (the daemon
// passes the [lifecycle] default_rows/default_cols policy).
DefaultRows, DefaultCols uint16
// HydrationBytes is how much of the scrollback tail is replayed into the
// adopted session's virtual screen. Negative falls back to the built-in
// default; 0 disables hydration (the daemon passes the [lifecycle]
// scrollback_hydration_bytes policy).
HydrationBytes int
// PollTimeout / PollInterval bound the adopted-PTY babysit loop. Non-positive
// falls back to the built-in defaults (adoptedPollTimeout / one second).
PollTimeout time.Duration
PollInterval time.Duration
// Logger routes this session's diagnostics to the daemon's logger. Nil
// falls back to slog.Default().
Logger *slog.Logger
// DegradedScreen skips synchronous derived-screen construction while still
// adopting the PTY and starting raw-output drainage. Later screen access or
// output retries the ordinary backend through screenFactory.
DegradedScreen bool
// DeferWait leaves exact-child reaping dormant until StartAdoptedWaiter.
// Upgrade adoption uses this to finish all rejection-prone manager checks
// before any waiter can consume the leader status needed by cleanup.
DeferWait bool
// contains filtered or unexported fields
}
type Cell ¶ added in v0.69.0
Cell is a single rendered terminal cell. Content is the cell's grapheme cluster (a single rune most of the time, but possibly a wide character, emoji, or base+combining sequence). An empty Content marks the trailing column of a wide (double-width) cell and renders as nothing, since the wide grapheme in the preceding column already occupies the space.
type CellStyle ¶ added in v0.69.0
type CellStyle struct {
FG Color
BG Color
Bold bool
Faint bool
Italic bool
Underline bool
Blink bool
Reverse bool
Strikethrough bool
}
CellStyle is the visual style of a rendered cell, split out from Cell so the renderer can compare adjacent cells' styles with a single struct equality and only re-emit an SGR sequence when the style changes. All fields are comparable, and the zero value is the terminal's default style.
type Color ¶ added in v0.69.0
Color is a backend-neutral terminal cell color. The zero value is the terminal default color, which keeps a freshly rendered cell equal to the unstyled default (see render.go's run-length SGR suppression).
type ColorKind ¶ added in v0.69.0
type ColorKind uint8
ColorKind identifies how a Color's Value should be interpreted.
const ( // ColorDefault is the terminal's default foreground/background — the // renderer emits no explicit SGR color for it. ColorDefault ColorKind = iota // ColorIndexed is an ANSI palette index: 0-7 basic, 8-15 bright, 16-255 // the 256-color cube/greyscale. ColorIndexed // ColorRGB is a 24-bit true color packed as 0xRRGGBB in Value. ColorRGB )
type HelperProcessIdentity ¶ added in v0.70.0
HelperProcessIdentity identifies a native terminal helper across an exec. StartTime is mandatory so a non-zombie PID is never signalled after reuse.
func FreezeTerminalHelpers ¶ added in v0.70.0
func FreezeTerminalHelpers(context.Context) ([]HelperProcessIdentity, error)
FreezeTerminalHelpers is a no-op when this binary cannot launch native helpers. It shares the daemon upgrade path without exposing the backend.
type ScreenCapture ¶ added in v0.2.0
type Scrollback ¶
type Scrollback struct {
// contains filtered or unexported fields
}
Scrollback is an append-only log file. Live reads use the exact open inode; path is retained for reversible pre-exec identity validation and deletion.
func AdoptScrollback ¶ added in v0.70.0
func AdoptScrollback(fd uintptr, path string, maxSize int64) (*Scrollback, error)
AdoptScrollback takes ownership of an inherited append writer without reopening its pathname. Path identity is validated reversibly before exec; after exec the inherited inode remains authoritative if the path changes.
func NewScrollback ¶
func NewScrollback(path string, maxSize int64) (*Scrollback, error)
func (*Scrollback) Close ¶
func (s *Scrollback) Close() error
func (*Scrollback) DuplicateFD ¶ added in v0.70.0
func (s *Scrollback) DuplicateFD() (int, error)
DuplicateFD returns a close-on-exec duplicate owned by the caller.
func (*Scrollback) Remove ¶
func (s *Scrollback) Remove() error
func (*Scrollback) SetLogger ¶ added in v0.67.7
func (s *Scrollback) SetLogger(log *slog.Logger)
SetLogger routes the scrollback writer's diagnostics to the daemon's logger. The daemon never calls slog.SetDefault and runs with stderr sent to /dev/null, so without this the writer's logs would be discarded (issue #1087). A nil logger is ignored (keeps the slog.Default() fallback set at construction).
func (*Scrollback) Stats ¶ added in v0.28.0
func (s *Scrollback) Stats() (written, maxSize int64, saturated bool)
func (*Scrollback) TailBytes ¶ added in v0.6.1
func (s *Scrollback) TailBytes(maxBytes int64) ([]byte, error)
TailBytes returns up to maxBytes from the end of the scrollback file.
func (*Scrollback) ValidatePathIdentity ¶ added in v0.70.0
func (s *Scrollback) ValidatePathIdentity() error
ValidatePathIdentity proves the configured pathname still names this exact private writer. Upgrade calls it before exec, where refusal is reversible.
type Session ¶
type Session struct {
ID string
Cmd *exec.Cmd
Ptmx *os.File
Scrollback *Scrollback
// contains filtered or unexported fields
}
func AdoptSession ¶
func AdoptSessionWithTerminalFactory ¶ added in v0.70.0
func AdoptSessionWithTerminalFactory( opts AdoptOpts, factory func(cols, rows int) (Terminal, error), ) (*Session, error)
AdoptSessionWithTerminalFactory adopts a PTY with an explicitly supplied terminal factory. Production callers should use AdoptSession; this narrow seam lets package-level tests exercise adoption and recovery independently of the selected production backend.
func NewSession ¶
func NewSession(opts SessionOpts) (*Session, error)
func NewSessionWithTerminalFactory ¶ added in v0.70.0
func NewSessionWithTerminalFactory( opts SessionOpts, factory func(cols, rows int) (Terminal, error), ) (*Session, error)
NewSessionWithTerminalFactory creates a PTY session with an explicitly supplied terminal factory. Production callers should use NewSession; this narrow seam lets package-level tests exercise PTY and daemon lifecycle behavior without selecting a production terminal backend.
func (*Session) BytesRead ¶ added in v0.67.7
BytesRead returns the total number of PTY output bytes read this session lifetime. Zero on a running session that has been up for a while is the signature of a silent agent (issue #1087) — alive but rendering nothing.
func (*Session) CreatedAt ¶ added in v0.67.7
CreatedAt returns when this PTY session object was constructed (spawned or adopted). Used to age a silent session for the zero-output diagnostic.
func (*Session) DetachWriter ¶
func (*Session) DuplicateFD ¶ added in v0.70.0
DuplicateFD returns a close-on-exec duplicate of the PTY master. The duplicate is owned by the caller. Close serializes the original descriptor close with this operation, so a successful return cannot duplicate an already-closed descriptor or a descriptor number reused by another goroutine.
func (*Session) ExitSignal ¶ added in v0.51.0
func (*Session) Interrupt ¶ added in v0.66.2
Interrupt sends the interrupt byte (Ctrl-C, 0x03) to the PTY count times, pausing delay between successive sends. Some agent TUIs (notably Claude) ignore a single Ctrl-C and need two rapid presses to actually interrupt, so the count and delay are configurable per agent (see issue #620). A count below 1 sends once. The whole operation holds writeMu so the presses aren't interleaved with other input.
func (*Session) LastOutputAt ¶ added in v0.3.0
func (*Session) NotifyUserInput ¶ added in v0.52.0
func (s *Session) NotifyUserInput()
NotifyUserInput records that the attached user just typed something. Call this from the passthrough data path, not from gr type.
func (*Session) PeakRSSBytes ¶ added in v0.51.0
func (*Session) Pgid ¶ added in v0.67.8
Pgid returns the process-group id graith signals on Kill/ForceKill. For graith-spawned sessions (started with Setsid, see NewSession) the child is a session/group leader and its PGID equals its PID. For adopted sessions graith did not set Setsid, so PGID may differ from the reported pid — but Kill/ ForceKill signal -pid regardless, so this remains an honest report of "the group graith signals". Logging pid+pgid together (issue #1104) makes an OS-level signal trace (e.g. `kill -0 -<pgid>`) possible from the daemon log alone. Returns 0 when the pid is unknown.
func (*Session) Poke ¶ added in v0.16.5
func (s *Session) Poke()
Poke sends SIGWINCH to the session's process group. This interrupts blocked reads and forces TUI frameworks to re-check stdin, ensuring recently written input is consumed. The child process was started with Setsid, so its PID equals its process group ID.
func (*Session) ProcessPID ¶
func (*Session) QuiesceIOForUpgrade ¶ added in v0.70.0
QuiesceIOForUpgrade drains input and pauses the PTY reader at a lossless safe point. The returned release must be called on every path where syscall.Exec does not replace the process image.
func (*Session) RecentlyAdopted ¶ added in v0.6.1
RecentlyAdopted returns true if the session was adopted (daemon restart) within the last duration and has not yet received fresh PTY output.
func (*Session) RecoverTerminalAfterUpgrade ¶ added in v0.70.0
RecoverTerminalAfterUpgrade reconstructs a screen that failed while helper generation was frozen. Its daemon-owned retry loop yields between bounded, backed-off batches so a transient helper failure cannot leave an adopted session permanently blank.
func (*Session) RecoverTerminalAfterUpgradeContext ¶ added in v0.70.0
RecoverTerminalAfterUpgradeContext is the daemon-owned, cancellation-aware recovery path. Slow helper requests remain outside the session mutex so raw PTY drainage is never coupled to reconstruction.
func (*Session) RejectAdoption ¶ added in v0.70.0
RejectAdoption terminates an adopted exact child and waits for readLoop to finish its final PTY drain before closing either transferred descriptor. It must be called before StartAdoptedWaiter: retaining the daemon's sole waiter keeps the PID reserved between the identity check and process-group signal.
func (*Session) ScreenPreview ¶ added in v0.2.0
func (*Session) ScreenSnapshot ¶ added in v0.2.0
func (s *Session) ScreenSnapshot() ScreenCapture
func (*Session) ScrollbackFile ¶ added in v0.67.8
func (s *Session) ScrollbackFile() *Scrollback
ScrollbackFile returns the session's scrollback buffer. It exists so a SessionDriver interface can expose the scrollback via a method (interfaces can't have fields), while the exported Scrollback field stays for direct concrete use within this package.
func (*Session) SetInputDelay ¶ added in v0.69.1
SetInputDelay updates the pause WriteInputAndSubmit inserts between the typed text and the submit carriage return, so a reloaded [lifecycle] input_delay policy takes effect on a live session's next type operation without a restart (issue #1294). A non-positive delay restores the built-in typeInputDelay default, mirroring construction. The store is atomic and takes no lock, so it never blocks on (or races) an in-flight WriteInputAndSubmit: a write already past its Load runs to completion with the value it read, and the next submit observes the new delay.
func (*Session) StartAdoptedWaiter ¶ added in v0.70.0
func (s *Session) StartAdoptedWaiter()
StartAdoptedWaiter starts the adopted process waiter exactly once.
func (*Session) WaitForUserIdle ¶ added in v0.52.0
WaitForUserIdle blocks until at least idleTimeout has elapsed since the last user keystroke, or until maxWait has elapsed (whichever comes first). Returns true if the idle condition was met, false if maxWait expired.
func (*Session) WaitForUserIdleContext ¶ added in v0.70.0
func (s *Session) WaitForUserIdleContext(ctx context.Context, idleTimeout, maxWait time.Duration) bool
WaitForUserIdleContext is the daemon-owned variant used by notification tasks. Cancellation wakes the condition wait so an upgrade/shutdown can join the complete task tree rather than waiting for the two-minute idle bound.
func (*Session) WasAdopted ¶ added in v0.67.7
WasAdopted reports whether this session was adopted from a prior daemon (a daemon upgrade re-attaching to a surviving agent) rather than freshly spawned. An adopted PTY starts at zero bytes read even though the agent may have rendered before the upgrade, so the silent-session diagnostic can't treat its zero-output as "never rendered" (issue #1087).
func (*Session) WriteInput ¶
func (*Session) WriteInputAndSubmit ¶ added in v0.29.0
WriteInputAndSubmit writes text followed by a carriage return, with a brief pause between the two so that TUI frameworks treat them as separate events. The entire operation holds writeMu to prevent interleaving from other sources.
type SessionOpts ¶
type SessionOpts struct {
ID string
Command string
Args []string
Dir string
Env map[string]string
Rows, Cols uint16
LogPath string
MaxLogSize int64
// InputDelay is the pause WriteInputAndSubmit inserts between the typed text
// and the submit carriage return. Non-positive falls back to typeInputDelay,
// the built-in default (the daemon passes the [lifecycle] input_delay policy).
InputDelay time.Duration
// Logger routes this session's PTY/scrollback diagnostics to the daemon's
// logger. Nil falls back to slog.Default(). See the Session.log field.
Logger *slog.Logger
}
type Terminal ¶ added in v0.69.0
type Terminal interface {
// Write feeds raw PTY output bytes into the emulator. It never blocks on
// terminal query responses (the implementation drains them).
Write(p []byte) (int, error)
// Resize changes the screen dimensions to cols columns by rows rows.
Resize(cols, rows int) error
// Size returns the current dimensions as (columns, rows).
Size() (cols, rows int)
// Cursor returns the cursor column, row (both zero-based), and whether it
// is currently visible.
Cursor() (x, y int, visible bool)
// Cell returns the rendered cell at (x, y). Out-of-range coordinates return
// a blank cell.
Cell(x, y int) Cell
// Close releases resources held by the emulator (e.g. its response-drain
// goroutine). It is safe to call more than once.
Close() error
}
Terminal is the terminal-screen emulation surface graith needs: feed it raw PTY output with Write, then read back the rendered screen for previews and snapshots. It deliberately hides the concrete emulator (issue #1211).
Implementations are not required to be safe for concurrent use; callers serialize Write against the Size/Cursor/Cell readers (Session does this with its mutex).
type TerminalSnapshot ¶ added in v0.70.0
type TerminalSnapshot struct {
Cells []Cell
CursorX int
CursorY int
CursorVisible bool
Cols int
Rows int
}
TerminalSnapshot is one coherent read of a terminal's visible viewport. Cells are stored in row-major order and always contain Cols*Rows entries. Keeping this bulk form behind the narrow Terminal interface avoids one FFI or helper-process round trip per cell.