cage

package
v0.0.0 Latest Latest
Warning

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

Go to latest
Published: Oct 16, 2026 License: Apache-2.0 Imports: 25 Imported by: 0

Documentation

Overview

Package cage draws the CELL-655 bar: a one-line tmux status line pinned to the bottom of the terminal while devcell boots a cell and runs the agent. tmux runs on the host; devcell re-executes itself inside the tmux window, so the boot panel and the agent both render under the bar.

Left: the workspace name, then the cell name (<project>-<cellID>), each its own coloured element. Right: the status panel with clocks, joined with the theme separator. The prefix key is None, so every keystroke reaches the agent; the bar is display-only. The mouse is not captured (mouse off): selection and the wheel stay with the outer terminal or tmux.

Opt in with --experimental=ui-cage, DEVCELL_EXPERIMENTAL=ui-cage or cell experimental = ["ui-cage"] (see internal/experiments).

Index

Constants

View Source
const (
	BootUIOK          = 0   // boot finished, popup may close
	BootUIFailed      = 1   // boot failed or the writer died; user acknowledged
	BootUIUnreachable = 2   // could not connect to the event socket
	BootUIInterrupted = 130 // second Ctrl+C
)

Exit codes of RunBootUI.

View Source
const EnvActive = "DEVCELL_CAGE"

EnvActive marks the devcell process that already runs inside the cage.

Variables

This section is empty.

Functions

func Active

func Active() bool

Active reports whether this process already runs inside the cage.

func Command

func Command(confPath string, spec Spec, windowName, self string, args []string) (string, []string)

Command builds the tmux argv that runs `self args...` inside the cage. The session gets its own socket per cell so it never collides with the user's tmux server. The inner process is pinned to the same identity (workspace, cell ID) because inside tmux TMUX_PANE would say otherwise. The command is shell-joined, the form every tmux version accepts.

func ConfPath

func ConfPath(spec Spec) string

ConfPath is where the tmux config for this cell is written.

func Enabled

func Enabled(stdinTTY, stdoutTTY bool) bool

Enabled reports whether the cage can wrap this run: tmux draws the bar on the tty, so both ends must be terminals.

func PopupCommand

func PopupCommand(spec PopupSpec, pid int) (string, []string)

PopupCommand builds the tmux argv that opens the popup running boot-ui. The popup command is shell-joined; DEVCELL_BOOT_PID tells boot-ui where to forward Ctrl+C.

func PopupHeight

func PopupHeight(groups, clientRows int) int

PopupHeight is the popup height for a boot panel of groups rows: the group rows, the border and rule, and the two rows a failed boot's hold line takes, never taller than the client minus a margin. Step and warning text is drawn on the group rows, so nothing else grows below the rule.

func Run

func Run(spec Spec, agent string, args []string) error

Run writes the config, starts tmux on the host with this terminal attached and re-runs devcell (os.Args[1:] as args) inside it. It returns when the agent exits and tmux closes with it.

func RunBootUI

func RunBootUI(ctx context.Context, o BootUIOptions) int

RunBootUI connects to the boot event socket, replays the events into a BootPanel on this process's terminal and exits by the rules below:

  • finish: wait Dwell, close the socket (the ack), return BootUIOK
  • finish_error: hold the panel until a key is pressed, return BootUIFailed
  • socket EOF before finish: the writer died; show "boot aborted", hold for a key, return BootUIFailed
  • Ctrl+C: forwarded to ForwardPID, never acted on here; a second one within 2s returns BootUIInterrupted

func SocketPath

func SocketPath(cellName string) string

SocketPath is the boot event socket for a cell. Unix socket paths are capped at about 104 bytes, so it lives in the temp dir and falls back to a hashed name when the cell name is long.

func StatePath

func StatePath(workspaceHome, name string) string

StatePath is a file under the workspace's devcell state dir.

func ThemeNames

func ThemeNames() []string

ThemeNames lists the presets, sorted.

func TmuxConf

func TmuxConf(workspaceName, cellName string, theme Theme) string

TmuxConf renders the tmux configuration for the cage.

func TmuxRunner

func TmuxRunner(tmux string) func(args ...string) (string, error)

TmuxRunner runs the tmux binary for PopupPreflight.

func WriteConf

func WriteConf(spec Spec) (string, error)

WriteConf renders and writes the tmux config, returning its path.

Types

type BootUIOptions

type BootUIOptions struct {
	Socket         string        // unix socket the window process serves events on
	ForwardPID     int           // process to receive the first Ctrl+C (the booting devcell)
	Stdin          *os.File      // keyboard, for "press any key"; nil means no wait
	ConnectTimeout time.Duration // give up connecting after this; default 3s
	Dwell          time.Duration // keep the finished panel visible before closing; default 400ms
}

BootUIOptions configures RunBootUI, the renderer that runs inside the tmux popup (`devcell boot-ui <socket>`).

type Geometry

type Geometry struct{ Width, Height int }

Geometry is the popup size, from PopupPreflight.

func PopupPreflight

func PopupPreflight(run func(args ...string) (string, error), groups int) (Geometry, error)

PopupPreflight decides whether a popup can be shown: tmux 3.3 or newer (title, border and style flags) and a client large enough. run executes tmux with the given arguments and returns its stdout. groups is how many group rows the boot panel will draw (see PopupHeight).

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

Popup is one boot popup session owned by the window process.

func StartPopup

func StartPopup(spec PopupSpec) (*Popup, error)

StartPopup listens for boot-ui, redirects this process's stdio away from the tty and opens the popup. On error nothing is left redirected and the caller runs with the inline panel.

func (*Popup) BeforeAttach

func (p *Popup) BeforeAttach() error

BeforeAttach is the engine.RunOpts.BeforeAttach hook: the agent gate. It returns once the popup is gone and the tty is ours again.

func (*Popup) Finish

func (p *Popup) Finish(bootErr error) error

Finish closes the session after the engine returned. On a boot error the popup stays up until the user acknowledges it; on success everything was already torn down by BeforeAttach.

func (*Popup) NewBootView

func (p *Popup) NewBootView(groups []ux.PanelGroup) ux.BootView

NewBootView is the engine.RunOpts.NewBootView hook. Events buffer from the first call; boot-ui gets them when it connects. If no client connects within the window, the popup is abandoned and the buffered events replay into an inline panel on the restored tty.

type PopupSpec

type PopupSpec struct {
	SocketPath string   // unix socket for boot events
	LogPath    string   // where the window process's stdout/stderr go during boot
	Title      string   // popup title
	Accent     string   // tmux colour for the border
	Geometry   Geometry // from PopupPreflight
	Tmux       string   // tmux binary; default "tmux"
	Self       string   // devcell binary that runs boot-ui; default os.Executable()
	SelfArgs   []string // arguments placed before "boot-ui" (tests inject a helper)
	Env        []string // KEY=VALUE pairs for boot-ui; the popup runs from the tmux server's environment, not ours
}

PopupSpec is what StartPopup needs.

type Spec

type Spec struct {
	WorkspaceName string
	CellID        string
	CellName      string
	WorkspaceHome string // ~/.devcell/<workspace>; the config is written below it
	Theme         Theme  // from ResolveTheme; zero value means the default preset
}

Spec is what the cage needs to render its bar and find its config.

type Theme

type Theme struct {
	BarBG, BarFG             string
	WorkspaceBG, WorkspaceFG string
	CellBG, CellFG           string
	StatusBG, StatusFG       string
	Accent                   string
	Separator                string
}

Theme is the resolved colour set the cage template renders. The bar has three elements, each coloured on its own: the workspace name, the cell name and the status panel (clocks). Bar* colours fill the gap between.

func ResolveTheme

func ResolveTheme(t cfg.ThemeSection) (Theme, error)

ResolveTheme turns [theme] into a Theme: the named preset (or the default) with every non-empty override applied. Colours are checked here because tmux stops reading the config at the first bad one.

Jump to

Keyboard shortcuts

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