Classifies every running child as idle/working/thinking/permission/error using one of three pluggable strategies (output_activity, osc_title_stability, osc_title_status) plus optional regex promoters applied to the tail of recent output. State and last-match reason are exposed via MCP on ProcessInfo and get_process_status. Per-preset configuration lives on a new preset.IdleDetection block with bundled defaults for the first-party claude/codex/opencode presets. OSC title plumbing is exposed as Emulator.Title(), polled from the session pump after each emulator write so title-change activity feeds into the classifier without an extra cgo callback. The MCP timer surface expands to match Solo: timer_set, timer_fire_when_idle_any/all, timer_cancel, timer_pause, timer_resume, timer_list. timer_wait is now a thin wrapper that shares the same manager so it shows up in timer_list while pending. Timer bodies are delivered to the owner process through the existing InjectAsOrchestrator path. Top-level (non-agent) callers can attach timers to a specific process via owner_process_id; omitting it grants universal cancel/pause/resume/list privileges. The sidebar gains a state glyph per process row and appends a nearest-timer indicator when one is pending or paused. Tests: idle_test.go covers the classify() pure function across the three strategies and regex promotion; timers_test.go covers the manager. Harness scenarios cover output_activity, osc_title_stability, osc_title_status, and regex promotion, plus timer_set delivery, cancel, pause/resume, idle_any-on-transition, idle_all-pending, and idle_all-already-satisfied. A new wait_until_mcp harness step type polls an MCP method until an assertion holds.
83 lines
3.0 KiB
Go
83 lines
3.0 KiB
Go
// Package vt wraps a headless virtual terminal emulator behind a small
|
|
// Go interface. The intent is that all cgo to libghostty-vt is confined
|
|
// to the GhosttyEmulator implementation in this package.
|
|
package vt
|
|
|
|
// Screen identifies which buffer is currently displayed.
|
|
type Screen uint8
|
|
|
|
const (
|
|
ScreenPrimary Screen = iota
|
|
ScreenAlternate
|
|
)
|
|
|
|
// CursorState is a snapshot of cursor position and visibility.
|
|
type CursorState struct {
|
|
Col, Row uint16
|
|
Visible bool
|
|
}
|
|
|
|
// Emulator is the headless VT used by the daemon (and by the milestone-1 spike).
|
|
//
|
|
// Implementations are not required to be safe for concurrent use. The spike
|
|
// CLI funnels all calls through a single goroutine.
|
|
type Emulator interface {
|
|
// Write feeds bytes from the PTY master into the emulator. It returns
|
|
// the number of bytes consumed (always len(p) on success).
|
|
Write(p []byte) (int, error)
|
|
|
|
// Resize updates the emulator's cell grid. The caller is responsible
|
|
// for issuing TIOCSWINSZ on the PTY itself.
|
|
Resize(cols, rows uint16) error
|
|
|
|
// PlainText returns the active screen rendered as plain text, with
|
|
// soft-wrapped lines unwrapped and trailing whitespace trimmed.
|
|
PlainText() (string, error)
|
|
|
|
// ScreenText returns the active screen as fixed screen rows. Unlike
|
|
// PlainText, this preserves row boundaries so a host UI can repaint
|
|
// into a clipped viewport.
|
|
ScreenText() (string, error)
|
|
|
|
// SerializeVT returns the active screen as a VT byte sequence that, when
|
|
// written to a fresh terminal, reproduces the visible state (colours,
|
|
// styles, cursor, hyperlinks, etc.). Used as the daemon's "catch-up
|
|
// frame" for newly-attached clients.
|
|
SerializeVT() ([]byte, error)
|
|
|
|
// StyledScreenVT returns the active screen's visible cell grid as VT
|
|
// bytes with SGR styling and child-space cursor movement, but without
|
|
// terminal modes, scroll regions, tabstops, or formatter cursor side
|
|
// effects.
|
|
StyledScreenVT() ([]byte, error)
|
|
|
|
// Cursor returns cursor position and visibility on the active screen.
|
|
Cursor() (CursorState, error)
|
|
|
|
// ActiveScreen reports whether we are on the primary or alternate buffer.
|
|
ActiveScreen() (Screen, error)
|
|
|
|
// Title returns the most recently set window title (OSC 0/2). Returns
|
|
// an empty string if no title has been set. Used by idle detection
|
|
// for the osc_title_stability and osc_title_status strategies.
|
|
Title() (string, error)
|
|
|
|
// ScrollViewportTop moves the viewport to the top of the scrollback.
|
|
ScrollViewportTop() error
|
|
|
|
// ScrollViewportBottom moves the viewport back to the active area.
|
|
ScrollViewportBottom() error
|
|
|
|
// ScrollViewportDelta moves the viewport by `delta` rows (negative = up).
|
|
ScrollViewportDelta(delta int) error
|
|
|
|
// OnWritePTY registers a callback that fires when the emulator wants
|
|
// to write bytes back to the PTY master (e.g. responses to DA / DSR
|
|
// queries). The callback runs synchronously inside Write and must not
|
|
// recurse into the emulator.
|
|
OnWritePTY(fn func([]byte))
|
|
|
|
// Close releases any underlying resources.
|
|
Close() error
|
|
}
|