terminal

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: May 17, 2026 License: MIT Imports: 32 Imported by: 0

README

deepwork-terminal

A standalone web terminal with authentication, Cloudflare tunnel support, and an embedded Vue frontend. Drop it into any Go application via a single HTTP handler.

Features

  • Full PTY terminal over WebSocket
  • Session management with reconnect support
  • Clipboard paste support
  • Settings portal (workbench API)
  • Optional Cloudflare Tunnel (auto-downloads cloudflared)
  • Embedded Vue SPA — zero static file serving required
  • Hook points for auth, session lifecycle, and shell customization

Quick Start (as a library)

go get github.com/brightman-ai/deepwork-terminal
import terminal "github.com/brightman-ai/deepwork-terminal"

srv := terminal.New(terminal.DefaultConfig())
http.Handle("/terminal/", srv.Handler())
http.ListenAndServe(":8080", nil)

Or run the CLI directly:

go run ./cmd/dw-terminal

See guide/ for full documentation.

Build from source

The frontend is pre-built and committed to the repo (internal/spa/dist/). Building the binary requires only Go — no Node.js needed:

git clone https://github.com/brightman-ai/deepwork-terminal
cd deepwork-terminal
go build -o dw-terminal ./cmd/dw-terminal/
Full build (frontend + Go)

If you modify the Vue frontend source (frontend/src/), rebuild and re-embed:

# Requires Node.js 18+ and npm
./build.sh

build.sh runs npm install + vite build, copies the output to internal/spa/dist/, then compiles the Go binary. The updated internal/spa/dist/ should be committed alongside your frontend changes so others can build without Node.js.

Headless servers: if npm install triggers a browser download (Playwright/Puppeteer postinstall), the script sets PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 automatically.

License

MIT

Documentation

Overview

Package terminal — observability declarations (BS-08 Terminal).

Package terminal — protocol.go: T5 §5 WebSocket 终端消息协议定义 (r2) BS-08 v2 消息类型:input/output/resize/ping/pong/closed

Package terminal — pty_manager.go: PTY spawn/stop/watch goroutines [T5 §4]

Package terminal — session.go: SessionV2 内存对象 [T5 §2.1] BS-08 v2: Int64 SessionID, WorkspaceID, PTY, Ring, WS 连接

Package terminal — shell_cmd.go: 跨平台 shell 命令构造辅助

Package terminal implements the BS-08 Terminal subsystem. It provides PTY management, WebSocket-based terminal I/O, and session lifecycle for browser-based terminal access. All state is held in memory (IR-03).

Index

Constants

View Source
const (
	// MsgInput 键盘输入 / 控制序列 (客户端→服务端)
	MsgInput = "input"
	// MsgResize 窗口大小变化 (客户端→服务端)
	MsgResize = "resize"
	// MsgPing 心跳 (客户端→服务端)
	MsgPing = "ping"
)
View Source
const (
	// MsgOutput PTY 输出 ANSI 透传 (服务端→客户端)
	MsgOutput = "output"
	// MsgClosed 终端关闭通知 (服务端→客户端)
	MsgClosed = "closed"
	// MsgPong 心跳响应 (服务端→客户端)
	MsgPong = "pong"
)
View Source
const (
	ClosedReasonNormal     = "normal"
	ClosedReasonCrashed    = "crashed"
	ClosedReasonStopCalled = "stop_called"
)
View Source
const (
	// AdapterStateSpawning PTY 正在启动
	AdapterStateSpawning = "spawning"
	// AdapterStateRunning PTY 运行中
	AdapterStateRunning = "running"
	// AdapterStateStopping PTY 正在停止
	AdapterStateStopping = "stopping"
	// AdapterStateStopped PTY 已停止(正常)
	AdapterStateStopped = "stopped"
	// AdapterStateFailed PTY 异常退出
	AdapterStateFailed = "failed"
)
View Source
const (
	MsgTypeResize       = "resize"
	MsgTypeHeartbeat    = "heartbeat"
	MsgTypeHeartbeatAck = "heartbeat_ack"
	MsgTypePing         = "ping"
	MsgTypePong         = "pong"
	MsgTypeAuthRefresh  = "auth_refresh"
	MsgTypeShellExit    = "shell_exit"
	MsgTypeError        = "error"
	MsgTypePreempted    = "preempted"
	MsgTypeInput        = "input"        // client → server: terminal input as text frame (WKWebView binary frame fix)
	MsgTypeTmuxNav      = "tmux_nav"     // client → server: navigate tmux windows/sessions
	MsgTypeSessionMeta  = "session_meta" // server → client: pushed once after WS handshake
	MsgTypeAgentState   = "agent_state"  // server → client: agent state push (replaces SSE)
)

Control message type constants.

View Source
const DefaultBufferCapacity = 1024 * 1024

DefaultBufferCapacity is the default size for the RingBuffer (1 MB). [Ref: T5-B3, CAP-terminal-io S4, DDC-03]

Variables

This section is empty.

Functions

func DefaultPTYFactory

func DefaultPTYFactory(opts PTYStartOptions) (*os.File, *exec.Cmd, error)

DefaultPTYFactory creates a real PTY. Tries independent process group (Setpgid) for DDC-01 SIGHUP isolation; falls back gracefully in restricted environments (containers, seccomp) where Setpgid is denied.

func DialTestWS

func DialTestWS(t *testing.T, server *httptest.Server, sessionID string, token string) *websocket.Conn

DialTestWS opens a WebSocket connection to the test server for the given session.

func NewTestCLIServer

func NewTestCLIServer(t *testing.T) (*httptest.Server, *SessionManager, *SafeWriteEnds)

NewTestCLIServer creates a test HTTP server with terminal routes (no auth). Returns the server, SessionManager, and write-end pipes for data injection.

func NewTestCLIServerWithAuth

func NewTestCLIServerWithAuth(t *testing.T, authCode string) (*httptest.Server, *SessionManager, *SafeWriteEnds)

NewTestCLIServerWithAuth creates a test server with a specific auth code. Note: in tests, requests go through httptest which connects from 127.0.0.1, so auth is bypassed automatically for localhost connections.

func WaitForBinaryContaining

func WaitForBinaryContaining(t *testing.T, ws *websocket.Conn, substr string, timeout time.Duration) []byte

WaitForBinaryContaining reads binary WS messages until one contains substr.

func WaitForPTYReady

func WaitForPTYReady(t *testing.T, sm *SessionManager, sessionID string, timeout time.Duration)

WaitForPTYReady waits for the session to appear in the SessionManager.

Types

type AgentDetectFunc

type AgentDetectFunc func(ctx context.Context, shellPID int, cwd string) (tool, status string)

AgentDetectFunc detects an AI agent running under the given shell PID. Returns (tool, status) strings; empty tool means no agent detected.

type AgentStatePushFunc

type AgentStatePushFunc func(ctx context.Context, sessionID string) (<-chan json.RawMessage, func(), error)

AgentStatePushFunc subscribes to agent state changes for a session. Returns a channel of JSON-encoded AgentIntelResponse and a cleanup function. Injected by the webui layer to avoid terminal → agent_intel import cycle.

type Config

type Config struct {
	Addr         string // listen address, e.g. ":8022" (always 0.0.0.0)
	DefaultShell string // e.g. "/bin/bash --login"
	BufferSize   int    // ring buffer size in bytes, default 1MB
	MaxSessions  int    // max concurrent sessions, default 100
	AuthCode     string // auto-generated auth code, printed to console on start
	DataDir      string // data directory for persistence
}

Config for the terminal session server.

func DefaultConfig

func DefaultConfig() Config

DefaultConfig returns sensible defaults.

type CreateOptions

type CreateOptions struct {
	Name   string
	Title  string
	Engine string
	Shell  string
	CWD    string
}

CreateOptions describes the product-level terminal session metadata and runtime options supplied by the WebUI.

type ErrorPayload

type ErrorPayload struct {
	Code    string `json:"code"`
	Message string `json:"message"`
}

ErrorPayload is the payload for an "error" control message.

type Hooks

type Hooks struct {
	OnSessionStart func(ctx context.Context, id string, meta SessionMeta) error
	OnSessionEnd   func(ctx context.Context, id string, exitCode int) error
	OnOutput       func(ctx context.Context, id string, data []byte) error
	OnCommand      func(ctx context.Context, id string, cmd string) (handled bool, err error)
	Store          SessionStore

	// AgentDetect optionally enriches session list with agent tool/status.
	// Injected by the host to avoid import cycles.
	AgentDetect AgentDetectFunc

	// AgentStatePush optionally subscribes to agent state changes for WS push.
	// Injected by the host to avoid import cycles.
	AgentStatePush AgentStatePushFunc
}

Hooks defines optional integration points for a host application. All fields are optional — nil means standalone behavior.

type HudLogRequest

type HudLogRequest struct {
	SessionID string          `json:"sessionId"`
	Timestamp string          `json:"timestamp"`
	UserAgent string          `json:"userAgent"`
	Screen    json.RawMessage `json:"screen"`
	Events    json.RawMessage `json:"events"`
	Snapshot  json.RawMessage `json:"snapshot"`
}

HudLogRequest is the request body for POST /api/cli/debug/logs. [Ref: CAP-hud-diagnostics S4]

type InProcessService

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

InProcessService wraps SessionManager and implements TerminalSessionService. All calls are in-process; no network hop occurs. SessionManager is already thread-safe via sync.Map, so InProcessService inherits that guarantee.

func NewInProcessService

func NewInProcessService(manager *SessionManager) *InProcessService

NewInProcessService creates an InProcessService backed by the given manager.

func (*InProcessService) Close

func (s *InProcessService) Close() error

Close implements TerminalSessionService.

func (*InProcessService) Create

Create implements TerminalSessionService.

func (*InProcessService) Delete

func (s *InProcessService) Delete(_ context.Context, id string) error

Delete implements TerminalSessionService.

func (*InProcessService) Get

Get implements TerminalSessionService.

func (*InProcessService) Input

func (s *InProcessService) Input(_ context.Context, id string, data []byte) error

Input implements TerminalSessionService. Writes raw bytes directly to the session's PTY file descriptor.

func (*InProcessService) List

List implements TerminalSessionService.

func (*InProcessService) PasteUpload

func (s *InProcessService) PasteUpload(_ context.Context, id string, filename string, content io.Reader, sessionCWD string) (string, error)

PasteUpload implements TerminalSessionService. Saves content to a temp directory under the session's CWD (or sessionCWD if non-empty) and returns the absolute path of the saved file. The logic mirrors clipboard_paste.go but operates on io.Reader rather than gin.Context so that it can be called without an HTTP layer.

func (*InProcessService) Resize

func (s *InProcessService) Resize(_ context.Context, id string, cols, rows int) error

Resize implements TerminalSessionService.

func (*InProcessService) TailOutput

func (s *InProcessService) TailOutput(_ context.Context, id string, lines int) ([]string, error)

TailOutput implements TerminalSessionService.

type InputPayload

type InputPayload struct {
	Data []byte `json:"data"` // raw terminal bytes (JSON base64-encoded)
}

InputPayload carries terminal input bytes as a JSON text frame. [TH-0501-m9j] WKWebView drops rapid binary WS frames; text frames are reliable.

type Option

type Option func(*Server)

Option configures a Server.

func WithAddr

func WithAddr(addr string) Option

WithAddr sets the listen address.

func WithAuthCode

func WithAuthCode(code string) Option

WithAuthCode sets the auth code (empty = no auth).

func WithConfig

func WithConfig(c Config) Option

WithConfig replaces the entire config.

func WithHooks

func WithHooks(h Hooks) Option

WithHooks sets integration hooks.

type PTYFactory

type PTYFactory func(opts PTYStartOptions) (master *os.File, cmd *exec.Cmd, err error)

PTYFactory creates a PTY-backed process. Returns the master side file descriptor, the command (may be nil for mock implementations), and an error. This abstraction allows testing without fork/exec.

type PTYStartOptions

type PTYStartOptions struct {
	Shell string
	CWD   string
}

PTYStartOptions describes how a PTY-backed process should be started.

type PreemptedPayload

type PreemptedPayload struct {
	Message string `json:"message"`
}

PreemptedPayload is the payload for a "preempted" control message.

type ResizePayload

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

ResizePayload is the payload for a "resize" control message. [Ref: T5-B3]

type RingBuffer

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

RingBuffer is a fixed-capacity circular byte buffer used to store recent terminal output for replay on WebSocket reconnection. It is safe for concurrent use. [Ref: T5-B3, CAP-terminal-io S4, DDC-03] Testability: Len() int + IsFull() bool [Ref: T6-A4.1]

func NewRingBuffer

func NewRingBuffer(capacity int) *RingBuffer

NewRingBuffer creates a RingBuffer with the given capacity. If capacity <= 0, DefaultBufferCapacity is used.

func (*RingBuffer) IsFull

func (rb *RingBuffer) IsFull() bool

IsFull returns true if the buffer has been completely filled at least once. [Ref: T6-A4.1 testability requirement]

func (*RingBuffer) Len

func (rb *RingBuffer) Len() int

Len returns the number of valid bytes currently stored. [Ref: T6-A4.1 testability requirement]

func (*RingBuffer) Read

func (rb *RingBuffer) Read() []byte

Read returns all buffered data in chronological order. If the buffer has never wrapped, returns data from the start to writePos. If wrapped, returns data from writePos to end + start to writePos.

func (*RingBuffer) ReadTail

func (rb *RingBuffer) ReadTail(n int) []byte

ReadTail returns the last n bytes from the buffer without copying the entire buffer. This minimizes mutex hold time — critical for avoiding PTY input backpressure.

func (*RingBuffer) Reset

func (rb *RingBuffer) Reset()

Reset clears the buffer.

func (*RingBuffer) Write

func (rb *RingBuffer) Write(p []byte) (int, error)

Write appends data to the ring buffer, overwriting oldest data when full (FIFO). Returns the number of bytes written (always len(p)).

type SafeWriteEnds

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

SafeWriteEnds provides thread-safe access to pipe write ends.

func (*SafeWriteEnds) CloseAt

func (s *SafeWriteEnds) CloseAt(index int)

CloseAt closes the write end at the given index.

func (*SafeWriteEnds) Get

func (s *SafeWriteEnds) Get(index int) *os.File

Get returns the write end at the given index (thread-safe).

type Server

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

Server is a complete terminal session HTTP service. Standalone: ListenAndServe() runs API + SPA. Embedded: Handler() returns API routes for a host to mount.

func NewServer

func NewServer(opts ...Option) (*Server, error)

NewServer creates a terminal session server.

func (*Server) Close

func (s *Server) Close() error

Close shuts down all sessions.

func (*Server) Handler

func (s *Server) Handler() http.Handler

Handler returns the API routes (no SPA) for embedding into a host server. Routes are relative: GET /sessions, POST /sessions, GET /sessions/{id}/ws, etc. The host uses http.StripPrefix to mount at any path prefix.

func (*Server) ListenAndServe

func (s *Server) ListenAndServe(ctx context.Context) error

ListenAndServe starts the standalone server (API + SPA). The SPA is the embedded Vue frontend (built by build.sh).

func (*Server) Port

func (s *Server) Port() int

Port returns the actual listening port (useful when Addr is ":0").

type Session

type Session struct {
	ID         string        `json:"id"`
	Name       string        `json:"name"`
	Title      string        `json:"title"`
	Engine     string        `json:"engine"`
	CWD        string        `json:"cwd"`
	ShellPath  string        `json:"-"`
	PTY        *os.File      `json:"-"`
	Cmd        *exec.Cmd     `json:"-"`
	Buffer     *RingBuffer   `json:"-"`
	Status     SessionStatus `json:"status"`
	CreatedAt  time.Time     `json:"createdAt"`
	LastActive time.Time     `json:"lastActive"`

	// TmuxDetected indicates whether the shell is running inside tmux.
	// Set after session creation by checking /proc/{pid}/environ.
	// [Ref: BUG-6, DDC-13]
	TmuxDetected bool `json:"tmuxDetected"`
	// contains filtered or unexported fields
}

Session represents a single terminal session backed by a PTY. [Ref: T5-B3]

func (*Session) Done

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

Done returns a channel that is closed when the PTY read loop exits.

func (*Session) GetExitCode

func (s *Session) GetExitCode() int

GetExitCode returns the shell exit code (thread-safe).

func (*Session) GetLastActive

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

GetLastActive returns when the session last received PTY output (thread-safe).

func (*Session) GetStatus

func (s *Session) GetStatus() SessionStatus

GetStatus returns the session status (thread-safe).

func (*Session) GetTmuxDetected

func (s *Session) GetTmuxDetected() bool

GetTmuxDetected returns whether tmux was detected (thread-safe).

func (*Session) ShellPID

func (s *Session) ShellPID() int

ShellPID returns the PID of the shell process running in the PTY.

func (*Session) TailOutput

func (s *Session) TailOutput(n int) []string

TailOutput returns the last n lines of terminal output from the RingBuffer. Used by agent intel for output analysis in direct (non-tmux) mode.

func (*Session) WorkingDir

func (s *Session) WorkingDir() string

WorkingDir returns the working directory of the session.

type SessionInfo

type SessionInfo struct {
	ID           string        `json:"id"`
	Name         string        `json:"name"`
	Title        string        `json:"title,omitempty"`
	Engine       string        `json:"engine"`
	CWD          string        `json:"cwd"`
	Status       SessionStatus `json:"status"`
	CreatedAt    string        `json:"created_at"`
	LastActive   string        `json:"last_active"`
	ShellPID     int           `json:"shell_pid,omitempty"`
	TmuxDetected bool          `json:"tmux_detected,omitempty"`
	ExitCode     int           `json:"exit_code,omitempty"`
}

SessionInfo is the service-layer representation of a terminal session. It avoids exposing the internal Session struct (with PTY, Cmd, etc.) to callers outside the package.

type SessionManager

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

SessionManager manages terminal sessions with PTY processes. All state is held in memory (IR-03: no DB, no persistence). [Ref: T5-B3, CAP-session-lifecycle S2, DDC-11]

func NewSessionManager

func NewSessionManager(bufferSize int, defaultShell string) *SessionManager

NewSessionManager creates a new SessionManager.

func NewSessionManagerWithFactory

func NewSessionManagerWithFactory(bufferSize int, defaultShell string, factory PTYFactory) *SessionManager

NewSessionManagerWithFactory creates a SessionManager with a custom PTY factory (for testing).

func (*SessionManager) ClearActiveConn

func (m *SessionManager) ClearActiveConn(sessionID string, conn *websocket.Conn)

ClearActiveConn removes the active connection entry for a session if it matches the given conn.

func (*SessionManager) CloseAll

func (m *SessionManager) CloseAll() error

CloseAll terminates all sessions. Called during server shutdown.

func (*SessionManager) Create

func (m *SessionManager) Create(name string) (*Session, error)

Create creates a new terminal session with a PTY process. [Ref: T5-B3, T5-B4.M1, CAP-session-lifecycle S2]

func (*SessionManager) CreateWithOptions

func (m *SessionManager) CreateWithOptions(opts CreateOptions) (*Session, error)

CreateWithOptions creates a new terminal session with product metadata.

func (*SessionManager) Destroy

func (m *SessionManager) Destroy(id string) error

Destroy terminates a session's PTY process and removes it from the manager. [Ref: CAP-session-lifecycle S2]

func (*SessionManager) DestroyAll

func (m *SessionManager) DestroyAll()

DestroyAll terminates all sessions. Kept for compatibility.

func (*SessionManager) Get

func (m *SessionManager) Get(id string) (*Session, error)

Get returns a session by ID or an error if not found.

func (*SessionManager) List

func (m *SessionManager) List() []*Session

List returns all sessions.

func (*SessionManager) SetActiveConn

func (m *SessionManager) SetActiveConn(sessionID string, conn *websocket.Conn, cancel context.CancelFunc)

SetActiveConn registers a new active WS connection for a session, preempting any existing one. BUG-3: Only one WS connection per session is allowed at a time.

func (*SessionManager) Subscribe

func (m *SessionManager) Subscribe(sess *Session, subID string) (<-chan []byte, func())

Subscribe adds a subscriber channel for receiving PTY output. Returns a channel and an unsubscribe function.

type SessionMeta

type SessionMeta struct {
	Shell string
	CWD   string
}

SessionMeta is passed to OnSessionStart.

type SessionMetaPayload

type SessionMetaPayload struct {
	TmuxDetected bool `json:"tmux_detected"`
}

SessionMetaPayload is pushed to the client once after the WS replay buffer is sent. The client uses TmuxDetected to decide whether to show tmux gesture hints.

type SessionSnapshot

type SessionSnapshot struct {
	ID     string
	Name   string
	Shell  string
	CWD    string
	Status string
}

SessionSnapshot is a point-in-time session state for persistence.

type SessionStatus

type SessionStatus string

SessionStatus represents the lifecycle state of a terminal session. [Ref: T5-B3, CAP-session-lifecycle S2]

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

type SessionStore

type SessionStore interface {
	SaveSession(ctx context.Context, s *SessionSnapshot) error
	ListSessions(ctx context.Context) ([]SessionSummary, error)
}

SessionStore is optional persistence. nil = in-memory only (data lost on restart).

type SessionSummary

type SessionSummary struct {
	ID     string
	Name   string
	Status string
}

SessionSummary is a brief session descriptor.

type SessionV2

type SessionV2 struct {
	SessionID   int64           // 关联 BS-03 Session.id (Int64)
	WorkspaceID int64           // 关联 BS-10 Workspace.id (Int64)
	RootDir     string          // Workspace.root_dir (PTY cwd)
	Pty         *os.File        // PTY master fd
	Cmd         *exec.Cmd       // Shell 进程
	Ring        *RingBuffer     // 环形缓冲 (一屏内容 ≈ 4KB)
	WSConn      *websocket.Conn // 当前 WebSocket 连接 (可为 nil)
	State       string          // spawning | running | stopping | stopped | failed
	// contains filtered or unexported fields
}

SessionV2 是 BS-08 v2 维护的运行时状态(内存,不持久化)。 Session 持久化由 BS-03 的 conversationDB 负责。[T5 §2.1]

func (*SessionV2) GetState

func (cs *SessionV2) GetState() string

GetState 返回当前状态(线程安全)

func (*SessionV2) Lock

func (cs *SessionV2) Lock()

Lock 加锁保护 WSConn / State 访问

func (*SessionV2) SetState

func (cs *SessionV2) SetState(s string)

SetState 设置状态(线程安全)

func (*SessionV2) SetWSConn

func (cs *SessionV2) SetWSConn(conn *websocket.Conn) bool

SetWSConn 替换 WebSocket 连接(关闭旧连接),[T5 §6.1] 返回是否关闭了旧连接

func (*SessionV2) Unlock

func (cs *SessionV2) Unlock()

Unlock 释放锁

func (*SessionV2) WriteWS

func (cs *SessionV2) WriteWS(data []byte)

WriteWS 向当前 WebSocket 发送消息(线程安全) 若无连接则静默忽略

type ShellExitPayload

type ShellExitPayload struct {
	ExitCode int `json:"exitCode"`
}

ShellExitPayload is the payload for a "shell_exit" control message.

type TermMsg

type TermMsg struct {
	Type     string `json:"type"`
	Data     string `json:"data,omitempty"`      // input / output
	Cols     int    `json:"cols,omitempty"`      // resize
	Rows     int    `json:"rows,omitempty"`      // resize
	Reason   string `json:"reason,omitempty"`    // closed
	ExitCode int    `json:"exit_code,omitempty"` // closed
}

TermMsg 是 WebSocket 文本帧的统一 JSON 格式 [T5 §5.2 §5.3]

type TerminalSessionService

type TerminalSessionService interface {
	// List returns all active sessions.
	List(ctx context.Context) ([]SessionInfo, error)

	// Create starts a new PTY-backed session with the given options.
	Create(ctx context.Context, opts CreateOptions) (*SessionInfo, error)

	// Get returns the session info for the given ID.
	// Returns an error wrapping "not found" when the session does not exist.
	Get(ctx context.Context, id string) (*SessionInfo, error)

	// Delete destroys the session identified by id, killing the PTY process.
	Delete(ctx context.Context, id string) error

	// Resize sets the terminal window size for the session.
	Resize(ctx context.Context, id string, cols, rows int) error

	// Input writes raw terminal bytes to the session PTY.
	// Used by the HTTP fallback path (WKWebView POST /sessions/:id/input).
	Input(ctx context.Context, id string, data []byte) error

	// PasteUpload saves clipboard content to a temp file under the session CWD
	// and returns the absolute path.  filename is the original filename hint;
	// content is the raw file body; sessionCWD is the working directory to use
	// (pass empty string to use the session's own CWD).
	PasteUpload(ctx context.Context, id string, filename string, content io.Reader, sessionCWD string) (string, error)

	// TailOutput returns the last n lines of terminal output for agent intel.
	TailOutput(ctx context.Context, id string, lines int) ([]string, error)

	// Close shuts down the service and destroys all sessions.
	Close() error
}

TerminalSessionService is the service-layer interface for terminal session management. Implementations: InProcessService (delegates to SessionManager directly) or a future RemoteService (proxies to a TerminalMuxHost over HTTP). The webui layer and tests depend only on this interface, enabling the underlying transport to be swapped without touching callers.

type TmuxNavPayload

type TmuxNavPayload struct {
	Action string `json:"action"` // "window_next"|"window_prev"|"session_next"|"session_prev"
}

TmuxNavPayload is the payload for a "tmux_nav" control message. The backend silently ignores the action when TmuxDetected=false.

type Tunnel

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

Tunnel manages a cloudflared quick-tunnel process.

func NewTunnel

func NewTunnel(dataDir string) *Tunnel

NewTunnel creates a tunnel manager. dataDir is where cloudflared will be cached.

func (*Tunnel) IsRunning

func (t *Tunnel) IsRunning() bool

IsRunning returns whether the tunnel is active.

func (*Tunnel) PublicURL

func (t *Tunnel) PublicURL() string

PublicURL returns the current tunnel URL.

func (*Tunnel) Start

func (t *Tunnel) Start(ctx context.Context, localAddr string) (string, error)

Start starts the tunnel, auto-downloading cloudflared if needed. Returns the public URL.

func (*Tunnel) Stop

func (t *Tunnel) Stop()

Stop stops the tunnel.

type WSControlMessage

type WSControlMessage struct {
	Type    string          `json:"type"`
	Payload json.RawMessage `json:"payload,omitempty"`
}

WSControlMessage represents a JSON control message on the WebSocket. Binary frames carry raw terminal I/O; Text/JSON frames carry control messages. [Ref: T5-B3, CAP-terminal-io S3, DDC-02]

func WaitForControlMessage

func WaitForControlMessage(t *testing.T, ws *websocket.Conn, msgType string, timeout time.Duration) WSControlMessage

WaitForControlMessage reads WS messages until a control message of the given type is found.

Directories

Path Synopsis
internal
spa

Jump to

Keyboard shortcuts

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