cliwrap

package
v0.4.6 Latest Latest
Warning

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

Go to latest
Published: May 12, 2026 License: Apache-2.0 Imports: 21 Imported by: 0

Documentation

Overview

Package cliwrap re-exports the canonical types from internal/cwtypes via Go type aliases, so the public API surface is unchanged.

Index

Constants

View Source
const (
	RestartNever     = cwtypes.RestartNever
	RestartOnFailure = cwtypes.RestartOnFailure
	RestartAlways    = cwtypes.RestartAlways

	ExceedWarn     = cwtypes.ExceedWarn
	ExceedThrottle = cwtypes.ExceedThrottle
	ExceedKill     = cwtypes.ExceedKill

	StdinNone    = cwtypes.StdinNone
	StdinPipe    = cwtypes.StdinPipe
	StdinInherit = cwtypes.StdinInherit

	StatePending    = cwtypes.StatePending
	StateStarting   = cwtypes.StateStarting
	StateRunning    = cwtypes.StateRunning
	StateStopping   = cwtypes.StateStopping
	StateStopped    = cwtypes.StateStopped
	StateCrashed    = cwtypes.StateCrashed
	StateRestarting = cwtypes.StateRestarting
	StateFailed     = cwtypes.StateFailed
)

Re-exported constants.

View Source
const DefaultLogRingBufferBytes = 1 << 20 // 1 MiB

DefaultLogRingBufferBytes is the per-(process, stream) log ring buffer capacity used when neither WithLogRingBufferBytes nor the YAML `log.ring_buffer_bytes` key is set.

Variables

View Source
var (
	ErrProcessNotFound         = errors.New("cliwrap: process not found")
	ErrProcessAlreadyExists    = errors.New("cliwrap: process already exists")
	ErrProcessNotRunning       = errors.New("cliwrap: process not running")
	ErrProcessAlreadyRunning   = errors.New("cliwrap: process already running")
	ErrManagerShuttingDown     = errors.New("cliwrap: manager is shutting down")
	ErrManagerClosed           = errors.New("cliwrap: manager is closed")
	ErrSandboxProviderNotFound = errors.New("cliwrap: sandbox provider not registered")
	ErrAgentSpawnFailed        = errors.New("cliwrap: failed to spawn agent")
	ErrHandshakeTimeout        = errors.New("cliwrap: handshake timeout")
	ErrStopTimeout             = errors.New("cliwrap: stop timeout")

	// ErrInvalidSpec is re-exported from cwtypes so that
	// SpecValidationError.Is(ErrInvalidSpec) works across both packages.
	ErrInvalidSpec = cwtypes.ErrInvalidSpec

	// PTY-related errors.
	// ErrPTYUnsupportedByAgent is re-exported from cwtypes so that
	// errors.Is checks work across both packages.
	ErrPTYUnsupportedByAgent = cwtypes.ErrPTYUnsupportedByAgent
	ErrPTYNotConfigured      = errors.New("cliwrap: PTY operations require Spec.PTY to be set")

	// ErrSessionNotFound is returned by Reattach when the session ID has
	// no metadata directory under WithPersistentDir.
	ErrSessionNotFound = errors.New("cliwrap: persistent session not found")

	// ErrSessionAlreadyExists is returned by Spawn (Persistent=true) when
	// a session with the same ID already exists in WithPersistentDir.
	// The user must terminate or rm the existing session first; cli-wrapper
	// does not auto-clean stale dirs.
	ErrSessionAlreadyExists = errors.New("cliwrap: persistent session already exists")

	// ErrAgentDead is returned by Reattach when the pid file points to a
	// dead PID, OR when the agent's MsgHello.startedAt does not match the
	// recorded meta.json startedAt (PID rollover defense).
	ErrAgentDead = errors.New("cliwrap: persistent agent is no longer alive")

	// ErrAlreadyAttached is returned by Reattach when another host is
	// currently connected to the session.
	ErrAlreadyAttached = errors.New("cliwrap: persistent session already attached by another host")

	// ErrIncompatibleAgent is returned by Reattach when the agent's
	// capability version does not match the host's expectations.
	ErrIncompatibleAgent = errors.New("cliwrap: incompatible agent version")

	// ErrPersistenceUnsupportedByAgent is returned at Start time when the
	// caller passes Persistent=true but the agent did not advertise the
	// "persistence" capability.
	ErrPersistenceUnsupportedByAgent = errors.New("cliwrap: agent does not support persistent sessions")
)

Sentinel errors.

View Source
var ApplyPTYDefaults = cwtypes.ApplyPTYDefaults

ApplyPTYDefaults re-exports cwtypes.ApplyPTYDefaults so callers need only import pkg/cliwrap.

Functions

This section is empty.

Types

type ExceedAction

type ExceedAction = cwtypes.ExceedAction

Type aliases — these are transparent to callers. Users continue to write cliwrap.State, cliwrap.Spec, etc.

type LogChunk added in v0.2.0

type LogChunk = cwtypes.LogChunk

LogChunk is an alias for cwtypes.LogChunk, re-exported so public callers of pkg/cliwrap see a cliwrap.LogChunk type while the canonical definition lives in the leaf cwtypes package (which internal/mgmt can import without creating a cycle).

type LogOptions

type LogOptions = cwtypes.LogOptions

Type aliases — these are transparent to callers. Users continue to write cliwrap.State, cliwrap.Spec, etc.

type Manager

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

Manager is the top-level library entry point.

func NewManager

func NewManager(opts ...ManagerOption) (*Manager, error)

NewManager constructs a Manager with the given options.

func (*Manager) ChildPIDs

func (m *Manager) ChildPIDs() map[string]int

ChildPIDs returns a snapshot of running (process ID -> child PID) pairs. Processes that are not in StateRunning are omitted.

func (*Manager) Events

func (m *Manager) Events() event.Bus

Events returns the Manager's event bus. Subscribers receive lifecycle, log, and reliability events. The bus is lazily created on first call.

func (*Manager) List

func (m *Manager) List() []mgmt.ListEntry

List returns a snapshot of every registered process for the mgmt API.

func (*Manager) ListPersistent added in v0.3.0

func (m *Manager) ListPersistent() ([]PersistentSessionInfo, error)

ListPersistent scans WithPersistentDir for valid sessions. Stale entries (Alive=false) are returned but not auto-cleaned; the user removes them via `cliwrap kill <id>` or `rm -rf <dir>/<id>`. Sessions are returned sorted by ID.

CW-G4 Task 13.

func (*Manager) LogsSnapshot added in v0.2.0

func (m *Manager) LogsSnapshot(id string, stream uint8) []byte

LogsSnapshot is the mgmt API entry that returns the current ring-buffer contents for a (process, stream) pair. Returns nil if no logs have been recorded for that pair yet.

func (*Manager) LogsSnapshotFiltered added in v0.3.0

func (m *Manager) LogsSnapshotFiltered(id string, stream uint8, since time.Time, lines int) []byte

LogsSnapshotFiltered returns the snapshot filtered by chunk-arrival timestamp (`since`, zero disables) and trimmed to the trailing `lines` newline-delimited lines (zero disables). When both filters are zero it is byte-equivalent to LogsSnapshot. Backs `cliwrap logs --since` and `--lines`.

func (*Manager) Reattach added in v0.3.0

func (m *Manager) Reattach(ctx context.Context, id string) (ProcessHandle, error)

Reattach connects to a previously-spawned persistent session by ID. On success, returns a ProcessHandle equivalent to one returned by Manager.Register followed by Start: WriteInput, SubscribePTYData, Signal, Resize, Status, Stop, and Close all behave identically.

SubscribePTYData on a Reattach-derived handle yields the ring buffer snapshot first (as one or more chunks in chronological order), then transitions to live PTY data.

Errors (see spec §"Error Matrix"):

  • ErrSessionNotFound: <persistentDir>/<id>/ does not exist (or sock missing)
  • ErrAgentDead: pid file points to a dead PID, or Hello.StartedAt does not match meta.json.StartedAt (PID rollover defense)
  • ErrAlreadyAttached: another host is currently connected
  • ErrIncompatibleAgent: handshake parsing failure
  • ctx.Err(): ctx canceled / deadline exceeded

CW-G4 Task 14.

func (*Manager) Register

func (m *Manager) Register(spec Spec) (ProcessHandle, error)

Register validates and registers a process spec.

func (*Manager) Shutdown

func (m *Manager) Shutdown(ctx context.Context) error

Shutdown stops every process and releases resources.

func (*Manager) StatusOf

func (m *Manager) StatusOf(id string) (mgmt.ListEntry, error)

StatusOf returns the status of a specific process for the mgmt API.

func (*Manager) Stop

func (m *Manager) Stop(ctx context.Context, id string) error

Stop is the mgmt API entry that routes a stop request to the handle.

func (*Manager) WatchLogs added in v0.2.0

func (m *Manager) WatchLogs(processID string) (chunks <-chan LogChunk, unregister func())

WatchLogs registers a follow-mode subscription. The returned channel receives LogChunk values for every subsequent call to emitLogChunk whose processID matches the filter. An empty processID filter matches every process.

The caller MUST invoke the returned unregister function exactly once when done — this is typically done via defer. Failing to unregister leaks the subscription and the goroutine that reads from it.

The channel is buffered; emit-side fan-out is non-blocking, so slow consumers lose chunks rather than backpressuring the producer.

type ManagerOption

type ManagerOption func(*Manager)

ManagerOption mutates a Manager during construction.

func WithAgentOutboxCapacity added in v0.4.6

func WithAgentOutboxCapacity(n int) ManagerOption

WithAgentOutboxCapacity sets the IPC outbox slot count INSIDE the agent process. WithOutboxCapacity tunes the host's outbox (host → agent direction); this option tunes the agent's outbox (agent → host direction), where PTY output frames accumulate when the host's SubscribePTYData consumer is slow or backpressured.

Zero or negative values keep the agent's legacy default (1024). Propagated via the CLIWRAP_AGENT_OUTBOX_CAPACITY env var that the spawner sets on every spawned agent; the agent's DefaultConfig honors the variable when its value parses as a positive integer.

For interactive PTY hosts whose terminals briefly stall (window resize, paste, scrollback dump), values of 4096–16384 match the guidance for the host side.

func WithAgentPath

func WithAgentPath(path string) ManagerOption

WithAgentPath sets the absolute path to the cliwrap-agent binary.

func WithLogFileDir added in v0.3.0

func WithLogFileDir(dir string) ManagerOption

WithLogFileDir enables file-backed log persistence. Each (process, stream) pair gets its own rotated log file at `<dir>/<processID>.<stream>.log`, with `<processID>.<stream>.1.log`, `.2.log`, ... as rotated siblings. Files coexist with the in-memory ring buffer: live snapshots and `cliwrap logs` continue to read from memory; the on-disk copies survive Manager shutdown for postmortem.

Empty path disables file persistence (default). Per-rotator MaxSize and MaxFiles use FileRotator defaults (64 MiB and 7) unless overridden via WithLogFileRotation.

func WithLogFileRotation added in v0.3.0

func WithLogFileRotation(maxSize int64, maxFiles int) ManagerOption

WithLogFileRotation overrides the per-rotator size cap and retention count used by WithLogFileDir. Zero values fall back to FileRotator defaults (64 MiB, 7 files). No effect when WithLogFileDir is unset.

func WithLogRingBufferBytes added in v0.3.0

func WithLogRingBufferBytes(n int) ManagerOption

WithLogRingBufferBytes overrides the per-(process, stream) log ring buffer capacity. Smaller values reduce memory at the cost of evicting older log lines sooner. Zero or negative values fall back to DefaultLogRingBufferBytes.

func WithOutboxCapacity added in v0.4.0

func WithOutboxCapacity(n int) ManagerOption

WithOutboxCapacity overrides the IPC outbox slot count for every session created by this Manager. Zero or negative values fall back to the legacy default (1024). Larger buffers reduce overflow likelihood under bursty traffic at the cost of memory; for interactive PTY hosts values of 4096–16384 are typical.

func WithPersistentDir added in v0.3.0

func WithPersistentDir(path string) ManagerOption

WithPersistentDir overrides the directory where persistent-session metadata (sock, pid, meta.json, agent.log) is stored. Default: $HOME/.cliwrap/sessions/. The directory is created with mode 0700 lazily on first persistent Spawn; per-session subdirectories are 0700 with files 0600.

Tests should pass t.TempDir() to keep state isolated. CW-G4.

func WithRuntimeDir

func WithRuntimeDir(path string) ManagerOption

WithRuntimeDir sets the directory for per-process state (WAL, logs).

func WithoutWAL added in v0.4.0

func WithoutWAL() ManagerOption

WithoutWAL disables the disk-backed write-ahead log on the outgoing IPC direction for every session created by this Manager. When set, outbox overflow drops messages instead of fsync-spilling to disk — the host trades the legacy "messages are never lost" guarantee for predictable per-keystroke latency under load.

Recommended for interactive PTY hosts where dropped input is recovered by user retry. Not recommended for batch / persistent / replay-critical workloads.

type PTYConfig added in v0.3.0

type PTYConfig = cwtypes.PTYConfig

Type aliases — these are transparent to callers. Users continue to write cliwrap.State, cliwrap.Spec, etc.

type PTYData added in v0.3.0

type PTYData = controller.PTYData

PTYData carries one chunk of PTY output delivered to a SubscribePTYData caller.

type PersistentSessionInfo added in v0.3.0

type PersistentSessionInfo struct {
	// ID is the session identifier (matches Spec.ID).
	ID string

	// Spec is the original cwtypes.Spec recorded at agent startup.
	Spec cwtypes.Spec

	// AgentPID is the agent process PID at startup. May be stale; use
	// Alive to interpret.
	AgentPID int

	// StartedAt is the agent's startup time (UTC nanoseconds).
	StartedAt time.Time

	// Alive is true iff kill -0 AgentPID succeeds. Best-effort: under
	// PID rollover, this can be a false positive — the actual Reattach
	// performs an additional StartedAt comparison via MsgHello.
	Alive bool

	// Attached is true iff the .attached flag file exists in the session
	// directory (best-effort indicator that another host is currently
	// connected). The actual Reattach attempt is the source of truth.
	Attached bool
}

PersistentSessionInfo summarizes a persistent session discovered on disk.

CW-G4 §"Public API surface".

type ProcessHandle

type ProcessHandle interface {
	ID() string
	Spec() Spec
	Status() Status
	Start(ctx context.Context) error
	Stop(ctx context.Context) error
	Close(ctx context.Context) error

	// WriteInput forwards b as PTY stdin to the running child.
	// Returns ErrPTYNotConfigured if Spec.PTY is nil.
	WriteInput(ctx context.Context, b []byte) error

	// Resize sends a TIOCSWINSZ to the running PTY child.
	// Returns ErrPTYNotConfigured if Spec.PTY is nil.
	Resize(ctx context.Context, cols, rows uint16) error

	// Signal delivers sig to the foreground process group of the PTY child.
	// Returns ErrPTYNotConfigured if Spec.PTY is nil.
	Signal(ctx context.Context, sig syscall.Signal) error

	// SubscribePTYData registers a receiver for PTY output frames.
	// If Spec.PTY is nil the returned channel is immediately closed.
	// The caller MUST invoke the returned unsubscribe function exactly once.
	SubscribePTYData() (<-chan PTYData, func())

	// OnStateChange registers cb to be called every time the underlying
	// controller transitions to a new state (StateStarting →
	// StateRunning → StateStopping/Stopped/Crashed/...). The callback
	// fires only on actual transitions; same-value re-stores are
	// filtered out. Pass nil to disable. Replacing an existing callback
	// is supported and atomic with respect to in-flight transitions.
	//
	// The callback may be registered before or after Start; in the
	// pre-Start case it is buffered until Start wires it onto the
	// controller, so even the StateStarting → StateRunning transition
	// is observable.
	//
	// The callback runs on whichever goroutine triggered the transition
	// (typically the IPC dispatch loop or the Start/Stop call itself),
	// so it MUST NOT block. Hosts that need to do heavy work should
	// hand off to a separate goroutine.
	//
	// The Status passed to the callback reflects the freshly-updated
	// state at call time; ChildPID is the value at that instant.
	OnStateChange(cb func(Status))
}

ProcessHandle is the user-facing handle to a managed process.

type ResourceLimits

type ResourceLimits = cwtypes.ResourceLimits

Type aliases — these are transparent to callers. Users continue to write cliwrap.State, cliwrap.Spec, etc.

type RestartPolicy

type RestartPolicy = cwtypes.RestartPolicy

Type aliases — these are transparent to callers. Users continue to write cliwrap.State, cliwrap.Spec, etc.

type SandboxSpec

type SandboxSpec = cwtypes.SandboxSpec

Type aliases — these are transparent to callers. Users continue to write cliwrap.State, cliwrap.Spec, etc.

type Spec

type Spec = cwtypes.Spec

Type aliases — these are transparent to callers. Users continue to write cliwrap.State, cliwrap.Spec, etc.

type SpecBuilder

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

SpecBuilder is a fluent constructor for Spec. Errors surface only from Build.

func NewSpec

func NewSpec(id, cmd string, args ...string) *SpecBuilder

NewSpec starts a new SpecBuilder for the given ID, command, and arguments.

func (*SpecBuilder) Build

func (b *SpecBuilder) Build() (Spec, error)

Build validates and returns the Spec.

func (*SpecBuilder) Persistent added in v0.3.0

func (b *SpecBuilder) Persistent() *SpecBuilder

Persistent marks the session as CW-G4 persistent: agent + child outlive the host process and are reattachable via Manager.Reattach.

func (*SpecBuilder) WithEnv

func (b *SpecBuilder) WithEnv(k, v string) *SpecBuilder

WithEnv sets a single environment variable.

func (*SpecBuilder) WithLogOptions

func (b *SpecBuilder) WithLogOptions(o LogOptions) *SpecBuilder

WithLogOptions attaches log storage options.

func (*SpecBuilder) WithMaxRestarts

func (b *SpecBuilder) WithMaxRestarts(n int) *SpecBuilder

WithMaxRestarts limits how many restarts will be attempted.

func (*SpecBuilder) WithPTY added in v0.3.0

func (b *SpecBuilder) WithPTY(cfg *PTYConfig) *SpecBuilder

WithPTY attaches a PTY configuration. If cfg is nil the field is cleared. Call ApplyPTYDefaults on the returned Spec (or let Controller.Start do it) to fill in zero-valued cols/rows.

func (*SpecBuilder) WithResourceLimits

func (b *SpecBuilder) WithResourceLimits(l ResourceLimits) *SpecBuilder

WithResourceLimits attaches resource caps.

func (*SpecBuilder) WithRestart

func (b *SpecBuilder) WithRestart(p RestartPolicy) *SpecBuilder

WithRestart sets the restart policy.

func (*SpecBuilder) WithRestartBackoff

func (b *SpecBuilder) WithRestartBackoff(d time.Duration) *SpecBuilder

WithRestartBackoff sets the initial backoff delay between restarts.

func (*SpecBuilder) WithRingBufferSize added in v0.3.0

func (b *SpecBuilder) WithRingBufferSize(n int) *SpecBuilder

WithRingBufferSize sets the in-memory PTY ring buffer size (bytes) used for redraw on reattach. Only meaningful when Persistent=true. Default (0) means 256 KiB at agent startup. CW-G4.

func (*SpecBuilder) WithSandbox

func (b *SpecBuilder) WithSandbox(s *SandboxSpec) *SpecBuilder

WithSandbox attaches a sandbox spec.

func (*SpecBuilder) WithStdin

func (b *SpecBuilder) WithStdin(m StdinMode) *SpecBuilder

WithStdin selects how the child's stdin is wired.

func (*SpecBuilder) WithStopTimeout

func (b *SpecBuilder) WithStopTimeout(d time.Duration) *SpecBuilder

WithStopTimeout sets the SIGTERM → SIGKILL grace period.

func (*SpecBuilder) WithWorkDir

func (b *SpecBuilder) WithWorkDir(path string) *SpecBuilder

WithWorkDir sets the working directory for the child process.

type SpecValidationError

type SpecValidationError = cwtypes.SpecValidationError

Type aliases — these are transparent to callers. Users continue to write cliwrap.State, cliwrap.Spec, etc.

type State

type State = cwtypes.State

Type aliases — these are transparent to callers. Users continue to write cliwrap.State, cliwrap.Spec, etc.

type Status

type Status = cwtypes.Status

Type aliases — these are transparent to callers. Users continue to write cliwrap.State, cliwrap.Spec, etc.

type StdinMode

type StdinMode = cwtypes.StdinMode

Type aliases — these are transparent to callers. Users continue to write cliwrap.State, cliwrap.Spec, etc.

Jump to

Keyboard shortcuts

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