sessionhost

package
v0.13.30 Latest Latest
Warning

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

Go to latest
Published: Jul 6, 2026 License: Apache-2.0 Imports: 10 Imported by: 0

Documentation

Overview

Package sessionhost implements daemon-owned, detachable PTY sessions (the "session-host" flavor described in docs/superpowers/specs/2026-07-03-remote-ssh-design.md §1-2). Unlike a classic `agnt run` session, the PTY child here is spawned and owned by the daemon process itself, so it survives the attaching client disconnecting (SSH drop, terminal close, laptop sleep).

Concurrency mirrors the ProcessManager conventions used elsewhere in this codebase: a sync.Map registry, atomic state fields, and a single mutex reserved for the PTY resize/primary-attach arbitration that cannot be made lock-free without losing correctness.

Index

Constants

View Source
const DefaultScrollback = 1024 * 1024

DefaultScrollback is the default per-session ring buffer capacity (1MB), per spec §1.4. Sized 4x the existing 256KB MaxOutputBuffer default because a session-host ring holds multiplexed interactive output (agent + human + tool output), not one process's stdout/stderr.

Variables

This section is empty.

Functions

This section is empty.

Types

type CreateConfig

type CreateConfig struct {
	Name        string
	ProjectPath string
	Command     string
	Args        []string
	Cols        int
	Rows        int
	Env         map[string]string
	// ScrollbackSize overrides DefaultScrollback; <=0 uses the default.
	ScrollbackSize int
}

CreateConfig configures a new session-host session. Mirrors SessionHostCreateConfig in the design spec.

type ExitData

type ExitData struct {
	Code int `json:"code"`
}

ExitData is the payload of an "exit" frame.

type Frame

type Frame struct {
	Type string          `json:"type"`
	Data json.RawMessage `json:"data,omitempty"`
}

Frame is the wire envelope for SESSION-HOST ATTACH, one JSON object per WriteChunk/inbound line, discriminated by Type. See spec §1.3.

type Registry

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

Registry is a lock-free (sync.Map-backed) collection of session-host sessions, mirroring ProcessManager's registry conventions.

func NewRegistry

func NewRegistry() *Registry

NewRegistry creates an empty session-host registry.

func (*Registry) Add

func (r *Registry) Add(s *Session)

Add registers a newly created session.

func (*Registry) Count

func (r *Registry) Count() int

Count returns the number of sessions currently registered.

func (*Registry) Get

func (r *Registry) Get(id string) (*Session, bool)

Get looks up a session by id.

func (*Registry) List

func (r *Registry) List(projectPath string, global bool) []*Session

List returns all sessions, optionally filtered by project path (empty projectPath or global=true returns everything).

func (*Registry) Remove

func (r *Registry) Remove(id string)

Remove deletes a session from the registry (does not close/kill it — callers do that first).

type ReplayMarkerData

type ReplayMarkerData struct {
	Truncated bool `json:"truncated"`
}

ReplayMarkerData is the payload of the one-time "replay-marker" frame.

type ResizeData

type ResizeData struct {
	Cols int `json:"cols"`
	Rows int `json:"rows"`
}

ResizeData is the payload of a "resize" frame.

type Session

type Session struct {
	ID          string
	Name        string
	ProjectPath string
	Command     string
	Args        []string
	StartedAt   time.Time

	// SessionPGID is the PTY child's own pgid (== PID, since creack/pty's
	// pty.Start sets Setsid on the child). Same containment invariant as
	// classic sessions, captured directly instead of over the wire — see
	// spec §2.2 invariant 9.
	SessionPGID int
	// contains filtered or unexported fields
}

Session is a single daemon-owned PTY child plus its scrollback ring and attached-client fan-out set.

func Create

func Create(cfg CreateConfig) (*Session, error)

Create spawns a new daemon-owned PTY child and starts its output-broadcast reader. The returned Session is already registered for output capture but has zero attached clients until Attach is called.

func (*Session) Attach

func (s *Session) Attach(bufferedFrames int) (ch <-chan []byte, attachID string, isPrimary bool)

Attach registers a new subscriber and returns:

  • a channel of already-framed JSON payloads to write to the connection (starts with one replay-marker frame, then the full scrollback as one stdout frame, then live frames — spec §1.4 invariant 6),
  • the attach id (used by Detach/SendInput to identify this attach),
  • whether this attach is primary (first attach, or promoted after the prior primary detached — spec §1.3 invariant 3).

The caller must range over the returned channel until it closes (Detach) or the session exits.

func (*Session) AttachedCount

func (s *Session) AttachedCount() int

AttachedCount returns the number of currently attached clients, for `agnt session list` / `SESSION-HOST LIST` display.

func (*Session) Close

func (s *Session) Close() error

Close closes the PTY fd (does not itself kill the child — callers that want the containment guarantee use platform.KillSessionPGID with s.SessionPGID, mirroring killSessionPGID for classic sessions).

func (*Session) Detach

func (s *Session) Detach(attachID string)

Detach removes an attach's subscription. If it was primary, the primary slot is cleared so a future attach may claim it (spec §1.3 invariant 4 — detach never touches the PTY child).

func (*Session) Done

func (s *Session) Done() <-chan struct{}

Done returns a channel that closes when the PTY child exits.

func (*Session) ExitCode

func (s *Session) ExitCode() int

ExitCode returns the child's exit code, or -1 if still running.

func (*Session) IsPrimary

func (s *Session) IsPrimary(attachID string) bool

IsPrimary reports whether attachID currently holds the primary (write) slot.

func (*Session) LastAttached

func (s *Session) LastAttached() time.Time

LastAttached returns the timestamp of the most recent Attach call, or the zero time if never attached.

func (*Session) Resize

func (s *Session) Resize(cols, rows int) error

Resize changes the PTY window size for all current attaches (spec §1.3 invariant 8 — no partial re-render, client owns redraw).

func (*Session) Status

func (s *Session) Status() Status

Status returns the current lifecycle status.

func (*Session) WriteStdin

func (s *Session) WriteStdin(data []byte) error

WriteStdin writes raw bytes to the PTY child's stdin. Callers must check IsPrimary first — non-primary stdin is rejected at the protocol layer (spec §1.3 invariant 3), not here.

type Status

type Status string

Status is the lifecycle state of a session-host session.

const (
	StatusRunning Status = "running"
	StatusExited  Status = "exited"
)

Jump to

Keyboard shortcuts

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