Documentation
¶
Index ¶
- Constants
- Variables
- func BindSwitchKey(key, targetSession string) error
- func BindSwitchKeyWithAck(key, targetSession, sessionID string) error
- func CleanupOrphanedLogs() (removed int, freedBytes int64, err error)
- func ClearStatusLeft(sessionName string) error
- func ClearStatusLeftGlobal() error
- func DetectTerminal() string
- func GetAckSignalPath() (string, error)
- func GetActiveSession() (string, error)
- func GetAttachedSessions() ([]string, error)
- func InitializeStatusBarOptions() error
- func IsTmuxAvailable() error
- func ListAgentDeckSessions() ([]string, error)
- func LogDir() string
- func ReadAndClearAckSignal() string
- func RefreshExistingSessions()
- func RefreshPaneInfoCache()
- func RefreshSessionCache()
- func RefreshStatusBarImmediate() error
- func RunLogMaintenance(maxSizeMB int, maxLines int, removeOrphans bool)
- func SetPipeManager(pm *PipeManager)
- func SetStatusLeft(sessionName, text string) error
- func SetStatusLeftGlobal(text string) error
- func SpinnerRuneSet() []rune
- func StripANSI(content string) string
- func StripSpinnerRunes(s string) string
- func SupportsHyperlinks() bool
- func TruncateLargeLogFiles(maxSizeMB int, maxLines int) (truncated int, err error)
- func TruncateLogFile(logPath string, maxLines int) error
- func UnbindKey(key string) error
- type ControlPipe
- func (cp *ControlPipe) CapturePaneVia() (string, error)
- func (cp *ControlPipe) Close()
- func (cp *ControlPipe) Done() <-chan struct{}
- func (cp *ControlPipe) IsAlive() bool
- func (cp *ControlPipe) LastOutputTime() time.Time
- func (cp *ControlPipe) OutputEvents() <-chan struct{}
- func (cp *ControlPipe) SendCommand(command string) (string, error)
- type PaneInfo
- type PipeManager
- func (pm *PipeManager) CapturePane(sessionName string) (string, error)
- func (pm *PipeManager) Close()
- func (pm *PipeManager) Connect(sessionName string) error
- func (pm *PipeManager) ConnectedCount() int
- func (pm *PipeManager) Disconnect(sessionName string)
- func (pm *PipeManager) GetPipe(sessionName string) *ControlPipe
- func (pm *PipeManager) GetWindowActivity(sessionName string) (int64, error)
- func (pm *PipeManager) IsConnected(sessionName string) bool
- func (pm *PipeManager) LastOutputTime(sessionName string) time.Time
- func (pm *PipeManager) RefreshAllActivities() (map[string]int64, error)
- func (pm *PipeManager) RefreshAllPaneInfo() (map[string]PaneInfo, error)
- type PromptDetector
- type RawPatterns
- type ResolvedPatterns
- type Session
- func DiscoverAllTmuxSessions() ([]*Session, error)
- func ListAllSessions() ([]*Session, error)
- func NewSession(name, workDir string) *Session
- func ReconnectSession(tmuxName, displayName, workDir, command string) *Session
- func ReconnectSessionLazy(tmuxName, displayName, workDir, command string, previousStatus string) *Session
- func ReconnectSessionWithStatus(tmuxName, displayName, workDir, command string, previousStatus string) *Session
- func (s *Session) Acknowledge()
- func (s *Session) AcknowledgeWithSnapshot()
- func (s *Session) ApplySharedAcknowledged(ack bool)
- func (s *Session) Attach(ctx context.Context) error
- func (s *Session) AttachReadOnly(ctx context.Context) error
- func (s *Session) CaptureFullHistory() (string, error)
- func (s *Session) CapturePane() (string, error)
- func (s *Session) ConfigureStatusBar()
- func (s *Session) DetectTool() string
- func (s *Session) EnableMouseMode() error
- func (s *Session) EnsureConfigured()
- func (s *Session) Exists() bool
- func (s *Session) ForceDetectTool() string
- func (s *Session) GetCachedWindowActivity() int64
- func (s *Session) GetEnvironment(key string) (string, error)
- func (s *Session) GetLastActivityTime() time.Time
- func (s *Session) GetStatus() (string, error)
- func (s *Session) GetWaitingSince() time.Time
- func (s *Session) GetWindowActivity() (int64, error)
- func (s *Session) GetWorkDir() string
- func (s *Session) HasUpdated() (bool, error)
- func (s *Session) InvalidateEnvCache()
- func (s *Session) IsAcknowledged() bool
- func (s *Session) IsClaudeRunning() bool
- func (s *Session) IsConfigured() bool
- func (s *Session) Kill() error
- func (s *Session) LogFile() string
- func (s *Session) ResetAcknowledged()
- func (s *Session) Resize(cols, rows int) error
- func (s *Session) RespawnPane(command string) error
- func (s *Session) SendCommand(command string) error
- func (s *Session) SendCtrlC() error
- func (s *Session) SendCtrlU() error
- func (s *Session) SendEnter() error
- func (s *Session) SendKeys(keys string) error
- func (s *Session) SendKeysAndEnter(keys string) error
- func (s *Session) SendKeysChunked(content string) error
- func (s *Session) SetCustomPatterns(toolName string, busyPatterns, promptPatterns, detectPatterns []string)
- func (s *Session) SetDetectPatterns(toolName string, detectPatterns []string)
- func (s *Session) SetEnvironment(key, value string) error
- func (s *Session) SetInjectStatusLine(inject bool)
- func (s *Session) SetPatterns(p *ResolvedPatterns)
- func (s *Session) Start(command string) error
- func (s *Session) StreamOutput(ctx context.Context, w io.Writer) error
- func (s *Session) WaitForReady(timeout time.Duration) bool
- func (s *Session) WaitForShellPrompt(timeout time.Duration) bool
- type SessionState
- type SpinnerActivityTracker
- type StateTracker
- type TerminalInfo
- type TitleState
Constants ¶
const SessionPrefix = "agentdeck_"
Variables ¶
var ErrCaptureTimeout = errors.New("capture-pane timed out")
ErrCaptureTimeout is returned when CapturePane exceeds its timeout. Callers should preserve previous state rather than transitioning to error/inactive.
Functions ¶
func BindSwitchKey ¶ added in v0.8.43
BindSwitchKey binds a number key to switch to target session. Uses prefix table (default) so Ctrl+b N works. The key should be a single character like "1", "2", etc. Deprecated: Use BindSwitchKeyWithAck for notification bar integration.
func BindSwitchKeyWithAck ¶ added in v0.8.52
BindSwitchKeyWithAck binds a number key to switch to target session AND writes a signal file so agent-deck can acknowledge the session was selected. This enables proper acknowledgment when user presses Ctrl+b 1-6 shortcuts.
func CleanupOrphanedLogs ¶ added in v0.5.3
CleanupOrphanedLogs removes log files for sessions that no longer exist A log is considered orphaned if: 1. No tmux session with matching name exists 2. The log file is older than 1 hour (to avoid race conditions during session creation)
func ClearStatusLeft ¶ added in v0.8.43
ClearStatusLeft resets status-left to default for a session. Called when notifications are cleared or acknowledged.
func ClearStatusLeftGlobal ¶ added in v0.8.65
func ClearStatusLeftGlobal() error
ClearStatusLeftGlobal resets status-left to default globally.
func DetectTerminal ¶ added in v0.3.0
func DetectTerminal() string
DetectTerminal identifies the current terminal emulator from environment variables Returns terminal name: "warp", "iterm2", "kitty", "alacritty", "vscode", "windows-terminal", or "unknown"
func GetAckSignalPath ¶ added in v0.8.52
GetAckSignalPath returns the path to the acknowledgment signal file
func GetActiveSession ¶ added in v0.8.43
GetActiveSession returns the session name the user is currently attached to. Returns empty string and error if not attached to any session.
func GetAttachedSessions ¶ added in v0.8.65
GetAttachedSessions returns the names of tmux sessions that have real clients attached. Used to detect which session the user is currently viewing. Filters out control mode clients (from PipeManager) which are not real user sessions.
func InitializeStatusBarOptions ¶ added in v0.8.67
func InitializeStatusBarOptions() error
InitializeStatusBarOptions sets optimal status bar options for agent-deck. Fixes truncation by setting adequate status-left-length globally. Should be called once during startup.
func IsTmuxAvailable ¶
func IsTmuxAvailable() error
IsTmuxAvailable checks if tmux is installed and accessible Returns nil if tmux is available, otherwise returns an error with details
func ListAgentDeckSessions ¶ added in v0.8.62
ListAgentDeckSessions returns the names of all agentdeck tmux sessions. This is used to update notification bars across ALL sessions, not just those in the current profile. This ensures consistent notification bars when users switch between sessions.
func LogDir ¶ added in v0.3.0
func LogDir() string
LogDir returns the directory containing all session logs
func ReadAndClearAckSignal ¶ added in v0.8.52
func ReadAndClearAckSignal() string
ReadAndClearAckSignal reads the session ID from the signal file and deletes it. Returns empty string if no signal file exists or on error.
func RefreshExistingSessions ¶ added in v0.6.0
func RefreshExistingSessions()
RefreshExistingSessions is an alias for RefreshSessionCache for backwards compatibility
func RefreshPaneInfoCache ¶ added in v0.14.0
func RefreshPaneInfoCache()
RefreshPaneInfoCache updates the cache of pane titles and commands for all sessions. Call this ONCE per tick (from backgroundStatusUpdate), then use GetCachedPaneInfo() to read cached values. Tries PipeManager first, falls back to subprocess.
func RefreshSessionCache ¶ added in v0.6.0
func RefreshSessionCache()
RefreshSessionCache updates the cache of existing tmux sessions and their activity Call this ONCE per tick, then use Session.Exists() and Session.GetWindowActivity() which read from cache. This reduces 30+ subprocess spawns to just 1 per tick cycle.
Tries PipeManager first (zero subprocess), falls back to subprocess.
NOTE: We use window_activity (not session_activity) because window_activity updates when there's actual terminal output, while session_activity only updates on session-level events. This is critical for detecting when Claude is actively working.
func RefreshStatusBarImmediate ¶ added in v0.8.67
func RefreshStatusBarImmediate() error
RefreshStatusBarImmediate forces an immediate status bar redraw for ALL connected clients. This bypasses the status-interval timer (default 15s) for instant visual feedback. Uses -S flag which only refreshes the status line (lightweight operation ~1-2ms per client). Filters out control mode clients (from PipeManager) which don't have a visible status bar.
func RunLogMaintenance ¶ added in v0.5.3
RunLogMaintenance performs all log maintenance tasks based on settings This should be called once at startup and optionally periodically
func SetPipeManager ¶ added in v0.11.0
func SetPipeManager(pm *PipeManager)
SetPipeManager sets the global PipeManager instance (called once at startup).
func SetStatusLeft ¶ added in v0.8.43
SetStatusLeft sets the left side of tmux status bar for a session. Used by NotificationManager to display waiting session notifications.
func SetStatusLeftGlobal ¶ added in v0.8.65
SetStatusLeftGlobal sets the left side of tmux status bar globally. This is a MAJOR performance optimization: ONE tmux call instead of 100+. All agentdeck sessions inherit this global setting.
func SpinnerRuneSet ¶ added in v0.9.2
func SpinnerRuneSet() []rune
spinnerRuneSet returns the full set of spinner runes for content normalization. Includes both the "active-only" chars (used for busy detection) and the additional chars (·, ✻) that appear in done/other states but still need stripping for stable hashing.
func StripANSI ¶
StripANSI removes ANSI escape codes from content using O(n) single-pass algorithm. This is important because terminal output contains color codes.
PERFORMANCE: Uses strings.Builder with pre-allocation for O(n) time complexity. Previous implementation used string concatenation in loops which was O(n²) and caused 2-11 second UI freezes on large terminal output (Issue #39).
NOTE: We intentionally avoid regex here because complex ANSI regex patterns can cause catastrophic backtracking on malformed escape sequences.
func StripSpinnerRunes ¶ added in v0.12.3
StripSpinnerRunes removes all spinner characters in a single O(n) pass using strings.Map, replacing 16 sequential strings.ReplaceAll calls.
func SupportsHyperlinks ¶ added in v0.3.0
func SupportsHyperlinks() bool
SupportsHyperlinks returns true if the current terminal supports OSC 8 hyperlinks
func TruncateLargeLogFiles ¶ added in v0.5.3
TruncateLargeLogFiles checks all log files and truncates any that exceed maxSizeMB
func TruncateLogFile ¶ added in v0.5.3
TruncateLogFile truncates a log file to keep only the last maxLines lines This is called when a log file exceeds maxSizeBytes
func UnbindKey ¶ added in v0.8.43
UnbindKey removes a key binding and restores default behavior. After unbinding, attempts to restore the default behavior where number keys select windows. The restore is best-effort since it may fail in environments without windows (e.g., CI) and agent-deck rebinds keys every 2s anyway.
Types ¶
type ControlPipe ¶ added in v0.11.0
type ControlPipe struct {
// contains filtered or unexported fields
}
ControlPipe wraps a persistent `tmux -C attach-session -t <name>` process. It provides event-driven output detection via %output events and zero-subprocess command execution through the stdin/stdout pipe.
func NewControlPipe ¶ added in v0.11.0
func NewControlPipe(sessionName string) (*ControlPipe, error)
NewControlPipe starts a tmux control mode pipe attached to the given session. Blocks until the initial handshake completes (or 2s timeout), so the pipe is ready for SendCommand immediately after return.
func (*ControlPipe) CapturePaneVia ¶ added in v0.11.0
func (cp *ControlPipe) CapturePaneVia() (string, error)
CapturePaneVia sends capture-pane through the control mode pipe. Returns the pane content without spawning any subprocess.
func (*ControlPipe) Close ¶ added in v0.11.0
func (cp *ControlPipe) Close()
Close shuts down the control mode pipe and kills the process.
func (*ControlPipe) Done ¶ added in v0.11.0
func (cp *ControlPipe) Done() <-chan struct{}
Done returns a channel that closes when the pipe exits.
func (*ControlPipe) IsAlive ¶ added in v0.11.0
func (cp *ControlPipe) IsAlive() bool
IsAlive returns true if the control mode process is still running.
func (*ControlPipe) LastOutputTime ¶ added in v0.11.0
func (cp *ControlPipe) LastOutputTime() time.Time
LastOutputTime returns the time of the most recent %output event.
func (*ControlPipe) OutputEvents ¶ added in v0.11.0
func (cp *ControlPipe) OutputEvents() <-chan struct{}
OutputEvents returns a channel that fires when the session produces output. Multiple rapid outputs may be coalesced into fewer channel sends.
func (*ControlPipe) SendCommand ¶ added in v0.11.0
func (cp *ControlPipe) SendCommand(command string) (string, error)
SendCommand sends a command through the control mode pipe and waits for the response. Commands are serialized via cmdMu. Returns the response text or an error. Timeout is 3 seconds to match the existing CapturePane subprocess timeout.
type PaneInfo ¶ added in v0.14.0
PaneInfo holds pane title and current command for a tmux session.
func GetCachedPaneInfo ¶ added in v0.14.0
GetCachedPaneInfo returns cached pane info for a session. Returns (info, true) if found and cache is fresh, (zero, false) otherwise.
type PipeManager ¶ added in v0.11.0
type PipeManager struct {
// contains filtered or unexported fields
}
PipeManager manages ControlPipes for all active tmux sessions. It provides zero-subprocess CapturePane and event-driven output detection. Falls back to subprocess execution when pipes are unavailable.
func GetPipeManager ¶ added in v0.11.0
func GetPipeManager() *PipeManager
GetPipeManager returns the global PipeManager instance. Returns nil if not initialized (control pipes disabled or not yet started).
func NewPipeManager ¶ added in v0.11.0
func NewPipeManager(ctx context.Context, onOutput func(sessionName string)) *PipeManager
NewPipeManager creates a new PipeManager. The onOutput callback is invoked whenever a connected session produces terminal output (via %output events).
func (*PipeManager) CapturePane ¶ added in v0.11.0
func (pm *PipeManager) CapturePane(sessionName string) (string, error)
CapturePane routes capture-pane through the control mode pipe if available. Falls back to subprocess execution if the pipe is nil, dead, or errors.
func (*PipeManager) Close ¶ added in v0.11.0
func (pm *PipeManager) Close()
Close shuts down all pipes and cancels the context.
func (*PipeManager) Connect ¶ added in v0.11.0
func (pm *PipeManager) Connect(sessionName string) error
Connect creates a control mode pipe for the given tmux session. If a pipe already exists and is alive, this is a no-op. Uses reconnecting map to prevent concurrent pipe creation for the same session.
func (*PipeManager) ConnectedCount ¶ added in v0.11.0
func (pm *PipeManager) ConnectedCount() int
ConnectedCount returns the number of alive pipes.
func (*PipeManager) Disconnect ¶ added in v0.11.0
func (pm *PipeManager) Disconnect(sessionName string)
Disconnect closes and removes the pipe for the given session.
func (*PipeManager) GetPipe ¶ added in v0.11.0
func (pm *PipeManager) GetPipe(sessionName string) *ControlPipe
GetPipe returns the ControlPipe for a session, or nil if not connected.
func (*PipeManager) GetWindowActivity ¶ added in v0.11.0
func (pm *PipeManager) GetWindowActivity(sessionName string) (int64, error)
GetWindowActivity sends a display-message command through the pipe to get the window_activity timestamp. Falls back to error if pipe unavailable.
func (*PipeManager) IsConnected ¶ added in v0.11.0
func (pm *PipeManager) IsConnected(sessionName string) bool
IsConnected returns true if a session has an alive pipe.
func (*PipeManager) LastOutputTime ¶ added in v0.11.0
func (pm *PipeManager) LastOutputTime(sessionName string) time.Time
LastOutputTime returns the last output time for a session from its pipe. Returns zero time if no pipe or no output recorded.
func (*PipeManager) RefreshAllActivities ¶ added in v0.11.0
func (pm *PipeManager) RefreshAllActivities() (map[string]int64, error)
RefreshAllActivities sends a single list-windows command through any available pipe to get activity timestamps for ALL sessions. This replaces the subprocess call in RefreshSessionCache.
func (*PipeManager) RefreshAllPaneInfo ¶ added in v0.14.0
func (pm *PipeManager) RefreshAllPaneInfo() (map[string]PaneInfo, error)
RefreshAllPaneInfo sends a single list-panes command through any available pipe to get pane titles and current commands for ALL sessions. This provides the data needed for title-based state detection without subprocess spawns.
type PromptDetector ¶
type PromptDetector struct {
// contains filtered or unexported fields
}
PromptDetector checks for tool-specific prompts in terminal content Based on Claude Squad's exact implementation: https://github.com/smtg-ai/claude-squad/blob/main/session/tmux/tmux.go
func NewPromptDetector ¶
func NewPromptDetector(tool string) *PromptDetector
NewPromptDetector creates a detector for the specified tool
func (*PromptDetector) HasPrompt ¶
func (d *PromptDetector) HasPrompt(content string) bool
HasPrompt checks if the terminal content contains a prompt waiting for input These patterns are derived from Claude Squad + additional research for edge cases
type RawPatterns ¶ added in v0.9.2
type RawPatterns struct {
BusyPatterns []string // plain strings + "re:" prefixed regex
PromptPatterns []string
SpinnerChars []string
WhimsicalWords []string
}
RawPatterns holds string-form patterns before compilation. Patterns prefixed with "re:" are compiled as regex; everything else uses strings.Contains.
func DefaultRawPatterns ¶ added in v0.9.2
func DefaultRawPatterns(toolName string) *RawPatterns
DefaultRawPatterns returns the built-in detection patterns for a known tool. Returns nil for unknown tools (they have no defaults).
func MergeRawPatterns ¶ added in v0.9.2
func MergeRawPatterns(defaults, overrides, extras *RawPatterns) *RawPatterns
MergeRawPatterns merges defaults with overrides and extras.
- If overrides has a field set (non-nil slice, even if empty), it replaces the default.
- extras fields are appended to the result (after defaults or overrides).
- If defaults is nil, only overrides/extras are used.
type ResolvedPatterns ¶ added in v0.9.2
type ResolvedPatterns struct {
BusyStrings []string
BusyRegexps []*regexp.Regexp
PromptStrings []string
PromptRegexps []*regexp.Regexp
SpinnerChars []string
// Pre-built combo patterns (from WhimsicalWords + SpinnerChars)
ThinkingPattern *regexp.Regexp
ThinkingPatternEllipsis *regexp.Regexp
SpinnerActivePattern *regexp.Regexp
}
ResolvedPatterns holds the compiled, ready-to-use patterns for status detection.
func CompilePatterns ¶ added in v0.9.2
func CompilePatterns(raw *RawPatterns) (*ResolvedPatterns, error)
CompilePatterns compiles raw string patterns into ready-to-use ResolvedPatterns. Patterns prefixed with "re:" are compiled as regex. Invalid regex patterns are logged as warnings and skipped (never crash).
type Session ¶
type Session struct {
Name string
DisplayName string
WorkDir string
Command string
Created time.Time
InstanceID string // Agent-deck instance ID for hook callbacks
// OptionOverrides are user-specified tmux set-option overrides from config.
// Applied AFTER all defaults in Start(), so they take precedence.
// Keys are tmux option names, values are their settings.
// Example: {"allow-passthrough": "all", "history-limit": "50000"}
OptionOverrides map[string]string
// contains filtered or unexported fields
}
Session represents a tmux session NOTE: All mutable fields are protected by mu. The Bubble Tea event loop is single-threaded, but we use mutex protection for defensive programming and future-proofing.
func DiscoverAllTmuxSessions ¶
DiscoverAllTmuxSessions returns all tmux sessions (including non-Agent Deck ones)
func ListAllSessions ¶
ListAllSessions returns all Agent Deck tmux sessions
func NewSession ¶
NewSession creates a new Session instance with a unique name
func ReconnectSession ¶
ReconnectSession creates a Session object for an existing tmux session This is used when loading sessions from storage - it properly initializes all fields needed for status detection to work correctly
Note: This runs immediate configuration (ConfigureStatusBar). For lazy loading during TUI startup, use ReconnectSessionLazy instead.
func ReconnectSessionLazy ¶ added in v0.8.95
func ReconnectSessionLazy(tmuxName, displayName, workDir, command string, previousStatus string) *Session
ReconnectSessionLazy creates a Session object without running any tmux configuration. PERFORMANCE: This is used during TUI startup to avoid subprocess overhead. Non-essential configuration (EnableMouseMode, ConfigureStatusBar) is deferred until first user interaction via EnsureConfigured().
Use this for bulk session loading where immediate configuration is not needed. For sessions that need immediate configuration, use ReconnectSession or ReconnectSessionWithStatus.
func ReconnectSessionWithStatus ¶
func ReconnectSessionWithStatus(tmuxName, displayName, workDir, command string, previousStatus string) *Session
ReconnectSessionWithStatus creates a Session with pre-initialized state based on previous status This restores the exact status state across app restarts:
- "idle" (gray): acknowledged=true, cooldown expired
- "waiting" (yellow): acknowledged=false, cooldown expired
- "active" (green): will be recalculated based on actual content changes
func (*Session) Acknowledge ¶
func (s *Session) Acknowledge()
Acknowledge marks the session as "seen" by the user Call this when user attaches to the session
func (*Session) AcknowledgeWithSnapshot ¶
func (s *Session) AcknowledgeWithSnapshot()
AcknowledgeWithSnapshot marks the session as seen and baselines the current content hash. Called when user detaches from session.
func (*Session) ApplySharedAcknowledged ¶ added in v0.14.0
ApplySharedAcknowledged applies acknowledgment state replicated from SQLite. Unlike Acknowledge/ResetAcknowledged, this only synchronizes the ack flag and does not force an immediate status transition. GetStatus() will naturally map to waiting/idle on the next poll based on busy/prompt conditions.
func (*Session) Attach ¶
Attach attaches to the tmux session with full PTY support Ctrl+Q will detach and return to the caller
func (*Session) AttachReadOnly ¶
AttachReadOnly attaches to the session in read-only mode
func (*Session) CaptureFullHistory ¶
CaptureFullHistory captures the scrollback history (limited to last 2000 lines for performance)
func (*Session) CapturePane ¶
CapturePane captures the visible pane content. Tries control mode pipe first (zero subprocess), falls back to subprocess. Uses singleflight to deduplicate concurrent calls.
func (*Session) ConfigureStatusBar ¶ added in v0.3.0
func (s *Session) ConfigureStatusBar()
ConfigureStatusBar sets up the tmux status bar with session info Shows: notification bar on left (managed by NotificationManager), session info on right NOTE: status-left is reserved for the notification bar showing waiting sessions This function only configures status-right to avoid overwriting notification bar
func (*Session) DetectTool ¶
DetectTool detects which AI coding tool is running in the session Uses caching to avoid re-detection on every call
func (*Session) EnableMouseMode ¶
EnableMouseMode enables mouse scrolling, clipboard integration, and optimal settings Safe to call multiple times - just sets the options again
Enables: - mouse on: Mouse wheel scrolling, text selection, pane resizing - set-clipboard on: OSC 52 clipboard integration (works with modern terminals) - allow-passthrough on: OSC 8 hyperlinks, advanced escape sequences (tmux 3.2+) - history-limit 10000: Large scrollback buffer for AI agent output - escape-time 10: Fast Vim/editor responsiveness (default 500ms is too slow)
Terminal compatibility: - Warp, iTerm2, kitty, Alacritty, WezTerm: Full support (hyperlinks, clipboard, true color) - Windows Terminal, VS Code: Full support - Apple Terminal.app: Limited (no hyperlinks or clipboard)
Note: With mouse mode on, hold Shift while selecting to use native terminal selection instead of tmux's selection (useful for copying to system clipboard in some terminals)
func (*Session) EnsureConfigured ¶ added in v0.8.95
func (s *Session) EnsureConfigured()
EnsureConfigured runs deferred tmux configuration if not already done. PERFORMANCE: This should be called before attaching to a session or when the session needs full functionality (e.g., status bar, mouse mode).
Safe to call multiple times - does nothing if already configured or session doesn't exist. Thread-safe via mutex protection.
func (*Session) Exists ¶
Exists checks if the tmux session exists Uses cached session list when available (refreshed by RefreshExistingSessions) Falls back to direct tmux call if cache is stale
func (*Session) ForceDetectTool ¶
ForceDetectTool forces a re-detection of the tool, ignoring cache
func (*Session) GetCachedWindowActivity ¶ added in v0.10.6
GetCachedWindowActivity returns the cached window_activity timestamp without spawning a subprocess. Returns 0 if the cache is stale or session not found. This is used for cheap idle-session activity gating in tiered polling.
func (*Session) GetEnvironment ¶ added in v0.5.0
GetEnvironment gets an environment variable from this tmux session. Uses a 30-second cache to avoid spawning tmux show-environment subprocesses on every poll cycle. Call InvalidateEnvCache() after SetEnvironment to clear.
func (*Session) GetLastActivityTime ¶ added in v0.5.6
GetLastActivityTime returns when the session content last changed Returns zero time if no activity has been tracked
func (*Session) GetWaitingSince ¶ added in v0.8.51
GetWaitingSince returns when the session transitioned to waiting status Returns zero time if session has never been waiting
func (*Session) GetWindowActivity ¶ added in v0.3.0
GetWindowActivity returns Unix timestamp of last tmux window activity Uses cached data when available (refreshed by RefreshSessionCache) Falls back to direct tmux call if cache is stale
func (*Session) GetWorkDir ¶
GetWorkDir returns the current working directory of the tmux pane This is the live directory from the pane, not the initial WorkDir
func (*Session) HasUpdated ¶
HasUpdated checks if the pane content has changed since last check
func (*Session) InvalidateEnvCache ¶ added in v0.9.2
func (s *Session) InvalidateEnvCache()
InvalidateEnvCache clears the environment variable cache for this session. Should be called after SetEnvironment to ensure fresh reads.
func (*Session) IsAcknowledged ¶ added in v0.16.0
IsAcknowledged returns whether the session has been acknowledged by the user. Used by the hook fast path to distinguish waiting (orange) from idle (gray).
func (*Session) IsClaudeRunning ¶ added in v0.5.3
IsClaudeRunning checks if Claude appears to be running in the session Returns true if Claude indicators are found
func (*Session) IsConfigured ¶ added in v0.8.95
IsConfigured returns whether the session has been fully configured. Used for debugging and testing.
func (*Session) Kill ¶
Kill terminates the tmux session. Like RespawnPane, this captures the process tree first and ensures all processes actually die. tmux kill-session sends SIGHUP which some CLI tools (e.g. Claude Code 2.1.27+) ignore, leaving orphan processes.
func (*Session) LogFile ¶ added in v0.3.0
LogFile returns the path to this session's log file Logs are stored in ~/.agent-deck/logs/<session-name>.log
func (*Session) ResetAcknowledged ¶
func (s *Session) ResetAcknowledged()
ResetAcknowledged marks the session as needing attention Call this when a hook event indicates the agent finished (Stop, AfterAgent) This ensures the session shows yellow (waiting) instead of gray (idle)
func (*Session) RespawnPane ¶ added in v0.5.4
RespawnPane kills the current process in the pane and starts a new command. This is more reliable than sending Ctrl+C and waiting for shell prompt. The -k flag kills the current process before respawning.
IMPORTANT: After respawn, this function verifies that old processes actually died. Some CLI tools (notably Claude Code 2.1.27+) ignore SIGHUP sent by tmux respawn-pane, leaving orphan processes that consume CPU indefinitely. If old processes survive, we escalate through SIGTERM → SIGKILL.
func (*Session) SendCommand ¶ added in v0.5.1
SendCommand sends a command to the tmux session and presses Enter
func (*Session) SendCtrlC ¶ added in v0.5.1
SendCtrlC sends Ctrl+C (interrupt signal) to the tmux session
func (*Session) SendKeys ¶
SendKeys sends keys to the tmux session Uses -l flag to treat keys as literal text, preventing tmux special key interpretation
func (*Session) SendKeysAndEnter ¶ added in v0.12.2
SendKeysAndEnter sends literal text followed by Enter as two separate tmux calls with a short delay between them. The delay is necessary because tmux 3.2+ wraps send-keys -l in bracketed paste sequences (\e[200~...\e[201~). Without the delay, Enter arrives in the same PTY buffer as the paste-end marker and gets swallowed by async TUI frameworks (Ink/Node.js, curses).
func (*Session) SendKeysChunked ¶ added in v0.8.80
SendKeysChunked sends large content to the tmux session in chunks to avoid tmux/OS buffer limits. Content ≤4KB is sent directly via SendKeys. Larger content is split at newline boundaries with a short delay between chunks.
func (*Session) SetCustomPatterns ¶ added in v0.8.27
func (s *Session) SetCustomPatterns(toolName string, busyPatterns, promptPatterns, detectPatterns []string)
SetCustomPatterns sets custom patterns for generic tool support These patterns enable custom tools defined in config.toml to have proper status detection
func (*Session) SetDetectPatterns ¶ added in v0.9.2
SetDetectPatterns sets tool auto-detection patterns (separate from busy/prompt patterns).
func (*Session) SetEnvironment ¶ added in v0.5.0
SetEnvironment sets an environment variable for this tmux session
func (*Session) SetInjectStatusLine ¶ added in v0.15.0
SetInjectStatusLine controls whether ConfigureStatusBar modifies tmux settings. When set to false, the status bar is left unchanged, preserving user's tmux config.
func (*Session) SetPatterns ¶ added in v0.9.2
func (s *Session) SetPatterns(p *ResolvedPatterns)
SetPatterns sets the compiled ResolvedPatterns for configurable status detection. When set, hasBusyIndicator and normalizeContent use these instead of hardcoded values.
func (*Session) StreamOutput ¶
StreamOutput streams the session output to the provided writer
func (*Session) WaitForReady ¶ added in v0.7.0
WaitForReady polls the terminal until the agent is ready for input Ready state = NO busy indicator AND prompt visible This works for Claude ("> "), Gemini, and other agents
type SessionState ¶
type SessionState string
SessionState represents the detected state of a session
const ( StateIdle SessionState = "idle" // No activity, waiting for user StateBusy SessionState = "busy" // Actively working (output changing) StateWaiting SessionState = "waiting" // Showing a prompt, needs input )
type SpinnerActivityTracker ¶ added in v0.14.0
type SpinnerActivityTracker struct {
// contains filtered or unexported fields
}
SpinnerActivityTracker tracks when the spinner was last detected on screen. Used for the grace period between tool calls where the spinner briefly disappears.
This is intentionally simple: spinner PRESENCE from the curated char set (which excludes ✻ done marker and · non-spinner) is the reliable signal. No movement tracking needed because the char set itself distinguishes active vs done.
func NewSpinnerActivityTracker ¶ added in v0.14.0
func NewSpinnerActivityTracker() *SpinnerActivityTracker
NewSpinnerActivityTracker creates a tracker with default grace period.
func (*SpinnerActivityTracker) InGracePeriod ¶ added in v0.14.0
func (sat *SpinnerActivityTracker) InGracePeriod() bool
InGracePeriod returns true if an active spinner was visible recently. This covers the brief gap between tool calls where the spinner disappears before the next tool starts.
func (*SpinnerActivityTracker) MarkBusy ¶ added in v0.14.0
func (sat *SpinnerActivityTracker) MarkBusy()
MarkBusy records that an active spinner char is currently visible on screen.
type StateTracker ¶
type StateTracker struct {
// contains filtered or unexported fields
}
StateTracker tracks content changes for notification-style status detection
StateTracker implements a simple 3-state model:
GREEN (active) = Content changed within 2 seconds YELLOW (waiting) = Content stable, user hasn't seen it GRAY (idle) = Content stable, user has seen it
type TerminalInfo ¶ added in v0.3.0
type TerminalInfo struct {
Name string // Terminal name (warp, iterm2, kitty, alacritty, etc.)
SupportsOSC8 bool // Supports OSC 8 hyperlinks
SupportsOSC52 bool // Supports OSC 52 clipboard
SupportsTrueColor bool // Supports 24-bit color
}
TerminalInfo contains detected terminal information
func GetTerminalInfo ¶ added in v0.3.0
func GetTerminalInfo() TerminalInfo
GetTerminalInfo returns detailed terminal capabilities
type TitleState ¶ added in v0.14.0
type TitleState int
TitleState represents the state inferred from the tmux pane title. Claude Code sets pane titles via OSC escape sequences:
- Braille spinner chars (U+2800-28FF) while actively working
- Done markers (✳✻✽✶✢) when a task completes
const ( TitleStateUnknown TitleState = iota // No recognizable pattern (non-Claude tools) TitleStateWorking // Braille spinner detected = actively working TitleStateDone // Done marker detected, fall through to prompt detection )
func AnalyzePaneTitle ¶ added in v0.14.0
func AnalyzePaneTitle(title, _ string) TitleState
AnalyzePaneTitle determines session state from the pane title. Priority: Braille spinner > Done marker > Unknown.
NOTE: We intentionally do NOT use pane_current_command to detect "exited" state. Claude Code frequently spawns bash subprocesses for tool execution, and tmux reports that child process as pane_current_command. This means a waiting Claude session often shows "bash" as the command, making it indistinguishable from "Claude exited and shell is showing". The existing Exists() check handles truly dead sessions reliably.