workspace

package
v0.74.1 Latest Latest
Warning

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

Go to latest
Published: Feb 19, 2026 License: MIT Imports: 45 Imported by: 0

Documentation

Overview

Package workspace manages git worktrees and tmux sessions for parallel development workflows, with AI agent orchestration, PR fetching, and interactive shell access.

Index

Constants

This section is empty.

Variables

View Source
var AgentCommands = map[AgentType]string{
	AgentClaude:   "claude",
	AgentCodex:    "codex",
	AgentAider:    "aider",
	AgentGemini:   "gemini",
	AgentCursor:   "cursor-agent",
	AgentOpenCode: "opencode",
	AgentPi:       "pi",
}

AgentCommands maps agent types to their CLI commands.

View Source
var AgentDisplayNames = map[AgentType]string{
	AgentNone:     "None (attach only)",
	AgentClaude:   "Claude Code",
	AgentCodex:    "Codex CLI",
	AgentGemini:   "Gemini CLI",
	AgentCursor:   "Cursor Agent",
	AgentOpenCode: "OpenCode",
	AgentPi:       "Pi Agent",
	AgentShell:    "Project Shell",
}

AgentDisplayNames provides human-readable names for agent types.

AgentTypeOrder defines the order of agents in selection UI.

View Source
var DefaultEnvOverrides = map[string]string{

	"GOWORK": "off",

	"GOFLAGS": "",

	"NODE_OPTIONS": "",
	"NODE_PATH":    "",

	"PYTHONPATH":  "",
	"VIRTUAL_ENV": "",
}

DefaultEnvOverrides contains environment variables to clear/override for worktree isolation. These prevent common issues when running commands in worktrees.

ShellAgentOrder defines agent order for shell creation (None first as default). td-a902fe: shells default to no agent, so "None" is first.

View Source
var SkipPermissionsFlags = map[AgentType]string{
	AgentClaude:   "--dangerously-skip-permissions",
	AgentCodex:    "--dangerously-bypass-approvals-and-sandbox",
	AgentAider:    "--yes",
	AgentGemini:   "--yolo",
	AgentCursor:   "-f",
	AgentOpenCode: "",
	AgentPi:       "",
}

SkipPermissionsFlags maps agent types to their skip-permissions CLI flags.

Functions

func ApplyEnvOverrides

func ApplyEnvOverrides(baseEnv []string, overrides map[string]string) []string

ApplyEnvOverrides applies overrides to an existing environment slice. Returns a new slice with overrides applied.

func BuildEnvOverrides

func BuildEnvOverrides(mainRepoPath string) map[string]string

BuildEnvOverrides returns the combined environment overrides for a worktree. User overrides from .worktree-env take precedence over defaults.

func EnsureDefaultPrompts

func EnsureDefaultPrompts(globalConfigDir string) bool

EnsureDefaultPrompts creates the global config with default prompts if no config exists. Returns true if defaults were created.

func ExpandPromptTemplate

func ExpandPromptTemplate(body, taskID string) string

ExpandPromptTemplate expands template variables in a prompt body. - {{ticket}} expands to taskID (returns empty if taskID is empty) - {{ticket || 'default'}} expands to taskID, or 'default' if taskID is empty

func ExtractFallback

func ExtractFallback(body string) string

ExtractFallback extracts the fallback value from a prompt body. Returns the first fallback found, or empty string if none.

func GenerateExportCommands

func GenerateExportCommands(overrides map[string]string) []string

GenerateExportCommands generates shell commands to apply environment overrides. Empty values generate unset commands, non-empty generate export commands.

func GenerateSingleEnvCommand

func GenerateSingleEnvCommand(overrides map[string]string) string

GenerateSingleEnvCommand returns a single shell command that applies all env overrides. This is less noisy than sending multiple commands individually.

func HasTicketPlaceholder

func HasTicketPlaceholder(body string) bool

HasTicketPlaceholder returns true if the body contains {{ticket}} or {{ticket || '...'}}

func MapKeyToTmux

func MapKeyToTmux(msg tea.KeyMsg) (key string, useLiteral bool)

MapKeyToTmux is a wrapper around tty.MapKeyToTmux for backward compatibility. See tty.MapKeyToTmux for documentation.

func SanitizeBranchName

func SanitizeBranchName(name string) string

SanitizeBranchName converts a string to a valid git branch name. The output should always pass ValidateBranchName.

func ValidateBranchName

func ValidateBranchName(name string) (bool, []string, string)

ValidateBranchName validates a git branch name and returns validation state. Returns: (valid, errors, sanitized suggestion) Based on git-check-ref-format rules.

func WriteDefaultPromptsToConfig

func WriteDefaultPromptsToConfig(globalConfigDir string) bool

WriteDefaultPromptsToConfig merges default prompts into the global config. If config.json exists, it preserves other fields and adds/replaces the prompts key. If config.json does not exist, it creates one with default prompts. Returns true on success.

Types

type Agent

type Agent struct {
	Type        AgentType // claude, codex, aider, gemini
	TmuxSession string    // tmux session name
	TmuxPane    string    // Pane identifier (e.g., "%12" - globally unique)
	PID         int       // Process ID (if available)
	StartedAt   time.Time
	LastOutput  time.Time     // Last time output was detected
	OutputBuf   *OutputBuffer // Last N lines of output
	Status      AgentStatus
	WaitingFor  string // Prompt text if waiting

	// Runaway detection fields (td-018f25)
	// Track recent poll times to detect continuous output that would cause CPU spikes.
	RecentPollTimes    []time.Time // Last N poll times for runaway detection
	PollsThrottled     bool        // True if this agent is throttled due to continuous output
	UnchangedPollCount int         // Consecutive unchanged polls (for throttle reset)
}

Agent represents an AI coding agent process.

func (*Agent) CheckRunaway

func (a *Agent) CheckRunaway() bool

CheckRunaway checks if this agent should be throttled (td-018f25). Returns true and sets PollsThrottled if runaway condition is detected.

func (*Agent) RecordPollTime

func (a *Agent) RecordPollTime()

RecordPollTime records a poll time for runaway detection (td-018f25). Should be called when an AgentOutputMsg (content changed) is received.

func (*Agent) RecordUnchangedPoll

func (a *Agent) RecordUnchangedPoll()

RecordUnchangedPoll records an unchanged poll for throttle reset (td-018f25). Should be called when an AgentPollUnchangedMsg is received.

type AgentOutputMsg

type AgentOutputMsg struct {
	WorkspaceName string
	Output        string
	Status        WorktreeStatus
	WaitingFor    string
	// Cursor position captured atomically with output (only set in interactive mode)
	CursorRow     int
	CursorCol     int
	CursorVisible bool
	HasCursor     bool // True if cursor position was captured
	PaneHeight    int  // Tmux pane height for cursor offset calculation
	PaneWidth     int  // Tmux pane width for display alignment
}

AgentOutputMsg delivers new agent output.

type AgentPollUnchangedMsg

type AgentPollUnchangedMsg struct {
	WorkspaceName string
	CurrentStatus WorktreeStatus // Status including session file re-check
	WaitingFor    string         // Prompt text if waiting
	// Cursor position captured atomically (even when content unchanged)
	CursorRow     int
	CursorCol     int
	CursorVisible bool
	HasCursor     bool
	PaneHeight    int // Tmux pane height for cursor offset calculation
	PaneWidth     int // Tmux pane width for display alignment
}

AgentPollUnchangedMsg signals content unchanged, schedule next poll.

type AgentStartedMsg

type AgentStartedMsg struct {
	Epoch         uint64 // Epoch when request was issued (for stale detection)
	WorkspaceName string
	SessionName   string
	PaneID        string // tmux pane ID (e.g., "%12") for interactive mode
	AgentType     AgentType
	Reconnected   bool // True if we reconnected to an existing session
	Err           error
}

AgentStartedMsg signals an agent has been started in a worktree.

func (AgentStartedMsg) GetEpoch

func (m AgentStartedMsg) GetEpoch() uint64

GetEpoch implements plugin.EpochMessage.

type AgentStatus

type AgentStatus int

AgentStatus represents the current status of an agent.

const (
	AgentStatusIdle AgentStatus = iota
	AgentStatusRunning
	AgentStatusWaiting
	AgentStatusDone
	AgentStatusError
)

type AgentStoppedMsg

type AgentStoppedMsg struct {
	WorkspaceName string
	Err           error
}

AgentStoppedMsg signals an agent has stopped.

type AgentType

type AgentType string

AgentType represents the type of AI coding agent.

const (
	AgentNone     AgentType = ""         // No agent (attach only)
	AgentClaude   AgentType = "claude"   // Claude Code
	AgentCodex    AgentType = "codex"    // Codex CLI
	AgentAider    AgentType = "aider"    // Aider
	AgentGemini   AgentType = "gemini"   // Gemini CLI
	AgentCursor   AgentType = "cursor"   // Cursor Agent
	AgentOpenCode AgentType = "opencode" // OpenCode
	AgentPi       AgentType = "pi"       // Pi Agent
	AgentCustom   AgentType = "custom"   // Custom command
	AgentShell    AgentType = "shell"    // Project shell (not an AI agent)
)

type ApproveResultMsg

type ApproveResultMsg struct {
	WorkspaceName string
	Err           error
}

ApproveResultMsg signals the result of an approve action.

type AsyncCaptureResultMsg

type AsyncCaptureResultMsg struct {
	WorkspaceName string // Worktree this capture is for
	SessionName   string // tmux session name
	Output        string // Captured output (empty on error)
	Err           error  // Non-nil if capture failed
}

AsyncCaptureResultMsg delivers async tmux capture results. Used to avoid blocking the UI thread on tmux subprocess calls (td-c2961e).

type AsyncShellCaptureResultMsg

type AsyncShellCaptureResultMsg struct {
	TmuxName string // Shell session tmux name
	Output   string // Captured output (empty on error)
	Err      error  // Non-nil if capture failed
}

AsyncShellCaptureResultMsg delivers async shell capture results.

type BranchListMsg

type BranchListMsg struct {
	Branches []string
	Err      error
}

BranchListMsg delivers available branches.

type CheckPRMergedMsg

type CheckPRMergedMsg struct {
	WorkspaceName string
	Merged        bool
	Err           error
}

CheckPRMergedMsg signals the result of checking if a PR was merged.

type CleanupDoneMsg

type CleanupDoneMsg struct {
	WorkspaceName string
	Results       *CleanupResults
}

CleanupDoneMsg signals that cleanup operations completed.

type CleanupResults

type CleanupResults struct {
	LocalWorktreeDeleted bool
	LocalBranchDeleted   bool
	RemoteBranchDeleted  bool
	PullAttempted        bool
	PullSuccess          bool
	PullError            error
	Errors               []string

	// Error detail expansion state (for UX improvements)
	ShowErrorDetails bool   // Toggle for expanded error view
	PullErrorSummary string // Concise 1-line summary
	PullErrorFull    string // Full git output for details view
	BranchDiverged   bool   // Enables rebase/merge resolution actions
	BaseBranch       string // Branch name for resolution commands
}

CleanupResults holds the results of cleanup operations for display in summary.

type CommitStatusInfo

type CommitStatusInfo struct {
	Hash    string // Short commit hash
	Subject string // Commit subject line
	Pushed  bool   // Is commit pushed to remote?
	Merged  bool   // Is commit merged to base branch?
}

CommitStatusInfo holds commit information with merge/push status.

type CommitStatusLoadedMsg

type CommitStatusLoadedMsg struct {
	Epoch         uint64 // Epoch when request was issued (for stale detection)
	WorkspaceName string
	Commits       []CommitStatusInfo
	Err           error
}

CommitStatusLoadedMsg delivers commit status info for the diff view header.

func (CommitStatusLoadedMsg) GetEpoch

func (m CommitStatusLoadedMsg) GetEpoch() uint64

GetEpoch implements plugin.EpochMessage.

type Conflict

type Conflict struct {
	Worktrees []string // Names of worktrees with conflicting changes
	Files     []string // List of conflicting files
}

Conflict represents a file conflict between worktrees.

type ConflictsDetectedMsg

type ConflictsDetectedMsg struct {
	Conflicts []Conflict
	Err       error
}

ConflictsDetectedMsg signals that conflicts have been detected.

type CreateDoneMsg

type CreateDoneMsg struct {
	Worktree  *Worktree
	AgentType AgentType // Agent selected at creation
	SkipPerms bool      // Whether to skip permissions
	Prompt    *Prompt   // Selected prompt template (nil if none)
	Err       error
}

CreateDoneMsg signals worktree creation completed.

type CreateWorktreeMsg

type CreateWorktreeMsg struct {
	Name       string
	BaseBranch string
	TaskID     string
}

CreateWorktreeMsg requests worktree creation.

type DeleteDoneMsg

type DeleteDoneMsg struct {
	Name     string
	Err      error
	Warnings []string // Non-fatal warnings (e.g., branch deletion failures)
}

DeleteDoneMsg signals worktree deletion completed.

type DeleteWorktreeMsg

type DeleteWorktreeMsg struct {
	Name  string
	Force bool
}

DeleteWorktreeMsg requests worktree deletion.

type DiffErrorMsg

type DiffErrorMsg struct {
	WorkspaceName string
	Err           error
}

DiffErrorMsg signals diff loading failed.

type DiffLoadedMsg

type DiffLoadedMsg struct {
	Epoch         uint64 // Epoch when request was issued (for stale detection)
	WorkspaceName string
	Content       string
	Raw           string
}

DiffLoadedMsg delivers diff content for a worktree.

func (DiffLoadedMsg) GetEpoch

func (m DiffLoadedMsg) GetEpoch() uint64

GetEpoch implements plugin.EpochMessage.

type DiffViewMode

type DiffViewMode int

DiffViewMode specifies the diff rendering mode.

const (
	DiffViewUnified    DiffViewMode = iota // Line-by-line unified view
	DiffViewSideBySide                     // Side-by-side split view
)

type DirectMergeDoneMsg

type DirectMergeDoneMsg struct {
	WorkspaceName string
	BaseBranch    string
	Err           error
}

DirectMergeDoneMsg signals that direct merge completed.

type FetchPRDoneMsg

type FetchPRDoneMsg struct {
	Worktree     *Worktree
	AlreadyLocal bool   // branch already existed locally
	Branch       string // for finding existing worktree when Worktree is nil
	Err          error
}

FetchPRDoneMsg signals that a PR branch was fetched and worktree created.

type FetchPRListMsg

type FetchPRListMsg struct {
	PRs []PRListItem
	Err error
}

FetchPRListMsg delivers the list of open PRs from gh CLI.

type FocusPane

type FocusPane int

FocusPane represents which pane is active in the split view.

const (
	PaneSidebar FocusPane = iota // Worktree list
	PanePreview                  // Preview pane (output/diff/task)
)

type GitStats

type GitStats struct {
	Additions    int
	Deletions    int
	FilesChanged int
	Ahead        int // Commits ahead of base branch
	Behind       int // Commits behind base branch
}

GitStats holds file change statistics.

type InteractivePasteResultMsg

type InteractivePasteResultMsg struct {
	Err         error
	Empty       bool
	SessionDead bool
}

InteractivePasteResultMsg reports clipboard paste results for interactive mode.

type InteractiveSessionDeadMsg

type InteractiveSessionDeadMsg struct{}

InteractiveSessionDeadMsg indicates the tmux session has ended. Sent when send-keys or capture fails with a session/pane not found error.

type InteractiveState

type InteractiveState struct {
	// Active indicates whether interactive mode is currently active.
	Active bool

	// TargetPane is the tmux pane ID (e.g., "%12") receiving input.
	TargetPane string

	// TargetSession is the tmux session name for the active pane.
	TargetSession string

	// LastKeyTime tracks when the last key was sent for polling decay.
	LastKeyTime time.Time

	// EscapePressed tracks if a single Escape was recently pressed
	// (for double-escape exit detection with 150ms delay).
	EscapePressed bool

	// EscapeTime is when the first Escape was pressed.
	EscapeTime time.Time

	// CursorRow and CursorCol track the cached cursor position for overlay rendering.
	// Updated asynchronously via cursorPositionMsg from poll handler (td-648af4).
	CursorRow int
	CursorCol int

	// CursorVisible indicates if the cursor should be rendered.
	// Updated asynchronously via cursorPositionMsg from poll handler (td-648af4).
	CursorVisible bool

	// PaneHeight tracks the tmux pane height for cursor offset calculation.
	// Used to adjust cursor_y when display height differs from pane height.
	PaneHeight int

	// PaneWidth tracks the tmux pane width for display width alignment.
	PaneWidth int

	// VisibleStart and VisibleEnd track the buffer line range currently visible.
	// Used for interactive selection mapping.
	VisibleStart int
	VisibleEnd   int

	// ContentRowOffset is the number of preview content rows before output lines.
	// Used to map mouse coordinates to buffer lines.
	ContentRowOffset int

	// BracketedPasteEnabled tracks whether the target app has enabled
	// bracketed paste mode (ESC[?2004h). Updated from captured output.
	BracketedPasteEnabled bool

	// MouseReportingEnabled tracks whether the target app has enabled
	// mouse reporting (1000/1002/1003/1006/1015). Updated from captured output.
	MouseReportingEnabled bool

	// EscapeTimerPending tracks if an escape timer is already in flight.
	// Prevents duplicate timers from accumulating (td-83dc22).
	EscapeTimerPending bool

	// LastResizeAt tracks the last time we attempted to resize the tmux pane.
	LastResizeAt time.Time
}

InteractiveState tracks state for interactive mode (tmux input passthrough). Feature-gated behind tmux_interactive_input feature flag.

type LocalBranchesMsg

type LocalBranchesMsg struct {
	Branches []string
	Err      error
}

LocalBranchesMsg returns available local branches for target selection.

type MergeCommitDoneMsg

type MergeCommitDoneMsg struct {
	WorkspaceName string
	CommitHash    string
	Err           error
}

MergeCommitDoneMsg signals that the commit before merge completed.

type MergeCommitState

type MergeCommitState struct {
	Worktree       *Worktree
	StagedCount    int
	ModifiedCount  int
	UntrackedCount int
	CommitMessage  string
	Error          string
}

MergeCommitState holds state for the commit-before-merge modal.

type MergeResolutionMsg

type MergeResolutionMsg struct {
	WorkspaceName string
	Branch        string
	Success       bool
	Err           error
}

MergeResolutionMsg signals result of merge resolution attempt.

type MergeStepCompleteMsg

type MergeStepCompleteMsg struct {
	WorkspaceName   string
	Step            MergeWorkflowStep
	Data            string // Step-specific data (e.g., PR URL)
	Err             error
	ExistingPRFound bool // True if PR already existed (vs newly created)
}

MergeStepCompleteMsg signals a merge workflow step completed.

type MergeWorkflowState

type MergeWorkflowState struct {
	Worktree         *Worktree
	Step             MergeWorkflowStep
	DiffSummary      string
	PRTitle          string
	PRBody           string
	PRURL            string
	ExistingPR       bool // True if using an existing PR (vs newly created)
	Error            error
	ErrorTitle       string                       // Short title for error display (e.g. "Direct Merge Failed")
	ErrorDetail      string                       // Full error text for display and clipboard copy
	ErrorFromStep    MergeWorkflowStep            // Which step produced the error
	StepStatus       map[MergeWorkflowStep]string // "pending", "running", "done", "error", "skipped"
	DeleteAfterMerge bool                         // true = delete worktree after merge (default)

	// Target branch selection
	TargetBranch       string   // Resolved target branch for merge/PR
	TargetBranchOption int      // Selected index in branch list
	TargetBranches     []string // Available branches for selection

	// Merge method selection
	UseDirectMerge    bool // true = direct merge to base, false = PR workflow
	MergeMethodOption int  // 0 = Create PR (default), 1 = Direct merge

	// Post-merge confirmation options
	DeleteLocalWorktree bool   // Checkbox: delete local worktree (default: true)
	DeleteLocalBranch   bool   // Checkbox: delete local branch (default: true)
	DeleteRemoteBranch  bool   // Checkbox: delete remote branch (default: false)
	PullAfterMerge      bool   // Checkbox: pull changes to current branch after merge
	CurrentBranch       string // Branch user was on before merge (for pull)
	ConfirmationFocus   int    // 0-3=checkboxes, 4=confirm btn, 5=skip btn
	ConfirmationHover   int    // Mouse hover state

	// Cleanup results for summary display
	CleanupResults    *CleanupResults
	PendingCleanupOps int // Counter for parallel cleanup operations in flight
}

MergeWorkflowState holds the state for the merge workflow modal.

type MergeWorkflowStep

type MergeWorkflowStep int

MergeWorkflowStep represents the current step in the merge workflow.

const (
	MergeStepReviewDiff   MergeWorkflowStep = iota
	MergeStepTargetBranch                   // Choose target branch for merge/PR
	MergeStepMergeMethod                    // Choose: PR workflow or direct merge
	MergeStepPush
	MergeStepCreatePR
	MergeStepWaitingMerge
	MergeStepDirectMerge           // Performing direct merge (no PR)
	MergeStepPostMergeConfirmation // User confirms cleanup options after PR merge
	MergeStepCleanup
	MergeStepDone
	MergeStepError // Error display step (strategy-agnostic)
)

func (MergeWorkflowStep) String

func (s MergeWorkflowStep) String() string

String returns a display name for the merge step.

type OpenCreateModalWithTaskMsg

type OpenCreateModalWithTaskMsg struct {
	TaskID    string
	TaskTitle string
}

OpenCreateModalWithTaskMsg opens create modal pre-filled with task data. Sent from td-monitor plugin when user presses send-to-worktree hotkey.

type OutputBuffer

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

OutputBuffer is a thread-safe bounded buffer for agent output. Uses SHA256 hashing to detect content changes and avoid duplicate processing.

func NewOutputBuffer

func NewOutputBuffer(capacity int) *OutputBuffer

NewOutputBuffer creates a new output buffer with the given capacity.

func (*OutputBuffer) Clear

func (b *OutputBuffer) Clear()

Clear removes all lines from the buffer.

func (*OutputBuffer) Len

func (b *OutputBuffer) Len() int

Len returns the number of lines in the buffer.

func (*OutputBuffer) LineCount

func (b *OutputBuffer) LineCount() int

LineCount returns the number of lines without copying.

func (*OutputBuffer) Lines

func (b *OutputBuffer) Lines() []string

Lines returns a copy of all lines in the buffer.

func (*OutputBuffer) LinesRange

func (b *OutputBuffer) LinesRange(start, end int) []string

LinesRange returns a copy of lines in the specified range [start, end). This is more efficient than Lines() when only a portion is needed.

func (*OutputBuffer) String

func (b *OutputBuffer) String() string

String returns the buffer contents as a single string.

func (*OutputBuffer) Update

func (b *OutputBuffer) Update(content string) bool

Update replaces buffer content if it has changed (detected via SHA256 hash). Returns true if content was updated, false if content was unchanged.

func (*OutputBuffer) Write

func (b *OutputBuffer) Write(content string)

Write replaces content in the buffer (for backward compatibility). Prefer Update() for change detection.

type PRListItem

type PRListItem struct {
	Number    int      `json:"number"`
	Title     string   `json:"title"`
	Branch    string   `json:"headRefName"`
	Author    prAuthor `json:"author"`
	URL       string   `json:"url"`
	CreatedAt string   `json:"createdAt"`
	IsDraft   bool     `json:"isDraft"`
}

PRListItem represents an open pull request for the fetch modal.

type Plugin

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

Plugin implements the worktree manager plugin.

func New

func New() *Plugin

New creates a new worktree manager plugin.

func (*Plugin) Approve

func (p *Plugin) Approve(wt *Worktree) tea.Cmd

Approve sends "y" to approve a pending prompt.

func (*Plugin) ApproveAll

func (p *Plugin) ApproveAll() tea.Cmd

ApproveAll approves all worktrees with pending prompts.

func (*Plugin) AttachToSession

func (p *Plugin) AttachToSession(wt *Worktree) tea.Cmd

AttachToSession attaches to a tmux session using tea.ExecProcess.

func (*Plugin) AttachToWorktreeDir

func (p *Plugin) AttachToWorktreeDir(wt *Worktree) tea.Cmd

AttachToWorktreeDir creates a tmux session in the worktree directory and attaches to it.

func (*Plugin) Cleanup

func (p *Plugin) Cleanup(removeSessions bool) error

Cleanup cleans up tmux sessions, optionally removing them.

func (*Plugin) CleanupOrphanedSessions

func (p *Plugin) CleanupOrphanedSessions() error

CleanupOrphanedSessions removes sessions that no longer have worktrees.

func (*Plugin) Commands

func (p *Plugin) Commands() []plugin.Command

Commands returns the available commands.

func (*Plugin) ConsumesTextInput

func (p *Plugin) ConsumesTextInput() bool

ConsumesTextInput reports whether the workspace plugin is currently in a mode that expects typed text input.

func (*Plugin) FocusContext

func (p *Plugin) FocusContext() string

FocusContext returns the current focus context for keybinding dispatch.

func (*Plugin) ID

func (p *Plugin) ID() string

ID returns the plugin identifier.

func (*Plugin) Icon

func (p *Plugin) Icon() string

Icon returns the plugin icon.

func (*Plugin) Init

func (p *Plugin) Init(ctx *plugin.Context) error

Init initializes the plugin with context.

func (*Plugin) IsFocused

func (p *Plugin) IsFocused() bool

IsFocused returns whether the plugin is focused.

func (*Plugin) Name

func (p *Plugin) Name() string

Name returns the plugin display name.

func (*Plugin) Reject

func (p *Plugin) Reject(wt *Worktree) tea.Cmd

Reject sends "n" to reject a pending prompt.

func (*Plugin) SendText

func (p *Plugin) SendText(wt *Worktree, text string) tea.Cmd

SendText sends arbitrary text to an agent.

func (*Plugin) SetFocused

func (p *Plugin) SetFocused(f bool)

SetFocused sets the focus state.

func (*Plugin) Start

func (p *Plugin) Start() tea.Cmd

Start begins async operations.

func (*Plugin) StartAgent

func (p *Plugin) StartAgent(wt *Worktree, agentType AgentType) tea.Cmd

StartAgent creates a tmux session and starts an agent for a worktree. If a session already exists, it reconnects to it instead of failing.

func (*Plugin) StartAgentWithOptions

func (p *Plugin) StartAgentWithOptions(wt *Worktree, agentType AgentType, skipPerms bool, prompt *Prompt) tea.Cmd

StartAgentWithOptions creates a tmux session and starts an agent with options. If a session already exists, it reconnects to it instead of failing.

func (*Plugin) Stop

func (p *Plugin) Stop()

Stop cleans up plugin resources.

func (*Plugin) StopAgent

func (p *Plugin) StopAgent(wt *Worktree) tea.Cmd

StopAgent stops an agent running in a worktree.

func (*Plugin) Update

func (p *Plugin) Update(msg tea.Msg) (plugin.Plugin, tea.Cmd)

Update handles messages.

func (*Plugin) View

func (p *Plugin) View(width, height int) string

View renders the plugin UI.

type PreviewTab

type PreviewTab int

PreviewTab represents the active tab in the preview pane.

const (
	PreviewTabOutput PreviewTab = iota // Agent output
	PreviewTabDiff                     // Git diff
	PreviewTabTask                     // TD task info
)

type Prompt

type Prompt struct {
	Name       string     `json:"name"`
	TicketMode TicketMode `json:"ticketMode"`
	Body       string     `json:"body"`
	Source     string     `json:"-"` // "global" or "project" (set at load time)
}

Prompt represents a configurable prompt template.

func DefaultPrompts

func DefaultPrompts() []Prompt

DefaultPrompts returns the built-in default prompts. These serve as examples users can modify.

func LoadPrompts

func LoadPrompts(globalConfigDir, projectDir string) []Prompt

LoadPrompts loads and merges prompts from global and project config directories. Project prompts override global prompts with the same name. If no config exists, creates global config with default prompts. Returns sorted list by name.

type PromptCancelledMsg

type PromptCancelledMsg struct{}

PromptCancelledMsg is sent when the picker is cancelled.

type PromptInstallDefaultsMsg

type PromptInstallDefaultsMsg struct{}

PromptInstallDefaultsMsg is sent when user requests installing default prompts.

type PromptPicker

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

PromptPicker is a modal for selecting a prompt template.

func NewPromptPicker

func NewPromptPicker(prompts []Prompt, width, height int) *PromptPicker

NewPromptPicker creates a new prompt picker.

func (*PromptPicker) ClearHover

func (pp *PromptPicker) ClearHover()

ClearHover clears the hover state.

func (*PromptPicker) FocusFilter

func (pp *PromptPicker) FocusFilter()

FocusFilter focuses the filter input field.

func (*PromptPicker) SetHover

func (pp *PromptPicker) SetHover(idx int)

SetHover sets the hover index for visual feedback.

func (*PromptPicker) Update

func (pp *PromptPicker) Update(msg tea.Msg) (*PromptPicker, tea.Cmd)

Update handles input for the prompt picker.

func (*PromptPicker) View

func (pp *PromptPicker) View() string

View renders the prompt picker modal.

type PromptSelectedMsg

type PromptSelectedMsg struct {
	Prompt *Prompt // nil means "none" was selected
}

PromptSelectedMsg is sent when a prompt is selected.

type PullAfterMergeMsg

type PullAfterMergeMsg struct {
	WorkspaceName string
	Branch        string
	Success       bool
	Err           error
}

PullAfterMergeMsg signals that pull after merge completed.

type PushDoneMsg

type PushDoneMsg struct {
	WorkspaceName string
	Err           error
}

PushDoneMsg signals push operation completed.

type PushMsg

type PushMsg struct {
	WorkspaceName string
	Force         bool
	SetUpstream   bool
}

PushMsg requests pushing a worktree branch.

type RebaseResolutionMsg

type RebaseResolutionMsg struct {
	WorkspaceName string
	Branch        string
	Success       bool
	Err           error
}

RebaseResolutionMsg signals result of rebase resolution attempt.

type RefreshDoneMsg

type RefreshDoneMsg struct {
	Epoch     uint64 // Epoch when request was issued (for stale detection)
	Worktrees []*Worktree
	Err       error
}

RefreshDoneMsg signals that refresh has completed.

func (RefreshDoneMsg) GetEpoch

func (m RefreshDoneMsg) GetEpoch() uint64

GetEpoch implements plugin.EpochMessage.

type RefreshMsg

type RefreshMsg struct{}

RefreshMsg triggers a worktree list refresh.

type RejectResultMsg

type RejectResultMsg struct {
	WorkspaceName string
	Err           error
}

RejectResultMsg signals the result of a reject action.

type RemoteBranchDeleteMsg

type RemoteBranchDeleteMsg struct {
	WorkspaceName string
	BranchName    string
	Err           error
}

RemoteBranchDeleteMsg signals the result of deleting a remote branch.

type RemoteCheckDoneMsg

type RemoteCheckDoneMsg struct {
	WorkspaceName string
	Branch        string
	Exists        bool
}

RemoteCheckDoneMsg signals remote branch existence check completed.

type RenameShellDoneMsg

type RenameShellDoneMsg struct {
	TmuxName string // Session name (stable identifier)
	NewName  string // New display name
	Err      error  // Non-nil if rename failed
}

RenameShellDoneMsg signals shell rename operation completed

type ResumeConversationMsg

type ResumeConversationMsg struct {
	SessionID string // Adapter session ID for resume command
	AdapterID string // Adapter type (claude-code, codex, etc.)
	ResumeCmd string // Full resume command (e.g., "claude --resume xyz")
	Type      string // "shell" or "worktree"
	// Worktree-specific fields (only used when Type == "worktree")
	WorktreeName string    // Branch name for new worktree
	BaseBranch   string    // Base branch to create from
	AgentType    AgentType // Agent to start (matches adapter or user selection)
	SkipPerms    bool      // Whether to auto-approve agent actions
}

ResumeConversationMsg requests resuming a conversation in a new shell or worktree. Sent from conversations plugin when user presses O key.

type SendTextResultMsg

type SendTextResultMsg struct {
	WorkspaceName string
	Text          string
	Err           error
}

SendTextResultMsg signals the result of sending text to an agent.

type SetupConfig

type SetupConfig struct {
	CopyEnv        bool     // Whether to copy env files (default: true)
	EnvFiles       []string // List of env files to copy
	SymlinkDirs    []string // Directories to symlink (default: empty, opt-in)
	RunSetupScript bool     // Whether to run .worktree-setup.sh (default: true)
}

SetupConfig holds worktree setup configuration.

func DefaultSetupConfig

func DefaultSetupConfig() *SetupConfig

DefaultSetupConfig returns the default setup configuration.

type ShellAgentErrorMsg

type ShellAgentErrorMsg struct {
	TmuxName string // Shell's tmux session name
	Err      error  // Error that occurred
}

ShellAgentErrorMsg signals agent failed to start in a shell session. td-21a2d8: Sent when agent command fails to execute.

type ShellAgentStartedMsg

type ShellAgentStartedMsg struct {
	TmuxName  string    // Shell's tmux session name
	AgentType AgentType // Agent type that was started
	SkipPerms bool      // Whether skip permissions was enabled
}

ShellAgentStartedMsg signals agent was started in a shell session. td-21a2d8: Sent after agent command is sent to tmux.

type ShellCreatedMsg

type ShellCreatedMsg struct {
	SessionName string    // tmux session name
	DisplayName string    // Display name (e.g., "Shell 1")
	PaneID      string    // tmux pane ID (e.g., "%12") for interactive mode
	Err         error     // Non-nil if creation failed
	AgentType   AgentType // td-16b2b5: Agent to start (AgentNone if plain shell)
	SkipPerms   bool      // td-16b2b5: Whether to skip permissions for agent
}

ShellCreatedMsg signals shell session was created

type ShellDefinition

type ShellDefinition struct {
	TmuxName    string    `json:"tmuxName"`
	DisplayName string    `json:"displayName"`
	CreatedAt   time.Time `json:"createdAt"`
	AgentType   string    `json:"agentType,omitempty"`
	SkipPerms   bool      `json:"skipPerms,omitempty"`
}

ShellDefinition contains all info needed to recreate a shell session.

type ShellDetachedMsg

type ShellDetachedMsg struct {
	Err error
}

ShellDetachedMsg signals user detached from shell session

type ShellKilledMsg

type ShellKilledMsg struct {
	SessionName string // tmux session name that was killed
}

ShellKilledMsg signals shell session was terminated

type ShellManifest

type ShellManifest struct {
	Version int               `json:"version"`
	Shells  []ShellDefinition `json:"shells"`
	// contains filtered or unexported fields
}

ShellManifest stores persistent shell definitions for cross-instance sync and reboot survival. Stored in {project}/.sidecar/shells.json.

func LoadShellManifest

func LoadShellManifest(path string) (*ShellManifest, error)

LoadShellManifest loads the shell manifest from disk. Returns an empty manifest (not error) if file doesn't exist or is corrupted.

func (*ShellManifest) AddShell

func (m *ShellManifest) AddShell(def ShellDefinition) error

AddShell adds a shell definition and saves.

func (*ShellManifest) FindShell

func (m *ShellManifest) FindShell(tmuxName string) *ShellDefinition

FindShell returns a shell definition by tmuxName, or nil if not found.

func (*ShellManifest) Path

func (m *ShellManifest) Path() string

Path returns the manifest file path.

func (*ShellManifest) RemoveShell

func (m *ShellManifest) RemoveShell(tmuxName string) error

RemoveShell removes a shell by tmuxName and saves.

func (*ShellManifest) Save

func (m *ShellManifest) Save() error

Save writes the manifest to disk atomically with file locking.

func (*ShellManifest) UpdateShell

func (m *ShellManifest) UpdateShell(def ShellDefinition) error

UpdateShell updates an existing shell definition and saves.

type ShellManifestChangedMsg

type ShellManifestChangedMsg struct{}

ShellManifestChangedMsg is emitted when the manifest file changes. This can be triggered by another sidecar instance modifying the manifest.

type ShellOutputMsg

type ShellOutputMsg struct {
	TmuxName string // Session name (stable identifier)
	Output   string
	Changed  bool
	// Cursor position captured atomically with output (only set in interactive mode)
	CursorRow     int
	CursorCol     int
	CursorVisible bool
	HasCursor     bool // True if cursor position was captured
	PaneHeight    int  // Tmux pane height for cursor offset calculation
	PaneWidth     int  // Tmux pane width for display alignment
}

ShellOutputMsg signals shell output was captured (for polling)

type ShellSession

type ShellSession struct {
	Name        string // Display name (e.g., "Shell 1")
	TmuxName    string // tmux session name (e.g., "sidecar-sh-project-1")
	Agent       *Agent // Reuses Agent struct for tmux state
	CreatedAt   time.Time
	ChosenAgent AgentType // td-317b64: Agent type selected at creation (AgentNone for plain shell)
	SkipPerms   bool      // td-317b64: Whether skip permissions was enabled
	IsOrphaned  bool      // td-f88fdd: True if manifest entry exists but tmux session is gone
}

ShellSession represents a tmux shell session (not tied to a git worktree).

type ShellSessionDeadMsg

type ShellSessionDeadMsg struct {
	TmuxName string // Session name for cleanup (stable identifier)
}

ShellSessionDeadMsg signals shell session was externally terminated (e.g., user typed 'exit' in the shell)

type ShellWatcher

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

ShellWatcher monitors the shell manifest file for changes. When changes are detected, it emits ShellManifestChangedMsg for cross-instance sync.

func NewShellWatcher

func NewShellWatcher(manifestPath string) (*ShellWatcher, error)

NewShellWatcher creates a watcher for the shell manifest file.

func (*ShellWatcher) Start

func (w *ShellWatcher) Start() <-chan tea.Msg

Start begins watching and returns a channel for receiving messages. The channel emits ShellManifestChangedMsg when the manifest changes.

func (*ShellWatcher) Stop

func (w *ShellWatcher) Stop()

Stop stops the watcher and closes channels.

type StatsErrorMsg

type StatsErrorMsg struct {
	WorkspaceName string
	Err           error
}

StatsErrorMsg signals stats loading failed.

type StatsLoadedMsg

type StatsLoadedMsg struct {
	Epoch         uint64 // Epoch when request was issued (for stale detection)
	WorkspaceName string
	Stats         *GitStats
}

StatsLoadedMsg delivers git stats for a worktree.

func (StatsLoadedMsg) GetEpoch

func (m StatsLoadedMsg) GetEpoch() uint64

GetEpoch implements plugin.EpochMessage.

type Task

type Task struct {
	ID          string
	Title       string
	Status      string
	Description string
	EpicTitle   string // Parent epic title for search
}

Task represents a TD task for linking.

type TaskDetails

type TaskDetails struct {
	ID          string
	Title       string
	Status      string
	Priority    string
	Type        string
	Description string
	Acceptance  string
	CreatedAt   string
	UpdatedAt   string
}

TaskDetails contains full task information for preview pane.

type TaskDetailsLoadedMsg

type TaskDetailsLoadedMsg struct {
	TaskID  string
	Details *TaskDetails
	Err     error
}

TaskDetailsLoadedMsg delivers task details for the preview pane.

type TaskLinkedMsg

type TaskLinkedMsg struct {
	WorkspaceName string
	TaskID        string
	Err           error
}

TaskLinkedMsg signals a task was linked to a worktree.

type TaskSearchResultsMsg

type TaskSearchResultsMsg struct {
	Tasks []Task
	Err   error
}

TaskSearchResultsMsg delivers task search results.

type TicketMode

type TicketMode string

TicketMode defines how the task field behaves with a prompt.

const (
	TicketRequired TicketMode = "required" // Task must be selected
	TicketOptional TicketMode = "optional" // Task is optional (may have fallback)
	TicketNone     TicketMode = "none"     // Task field is hidden
)

type TmuxAttachFinishedMsg

type TmuxAttachFinishedMsg struct {
	WorkspaceName string
	Err           error
}

TmuxAttachFinishedMsg signals return from tmux attach.

type UncommittedChangesCheckMsg

type UncommittedChangesCheckMsg struct {
	WorkspaceName  string
	HasChanges     bool
	StagedCount    int
	ModifiedCount  int
	UntrackedCount int
	Err            error
}

UncommittedChangesCheckMsg signals the result of checking for uncommitted changes.

type ViewMode

type ViewMode int

ViewMode represents the current view state.

const (
	ViewModeList               ViewMode = iota // List view (default)
	ViewModeKanban                             // Kanban board view
	ViewModeCreate                             // New worktree modal
	ViewModeTaskLink                           // Task link modal (for existing worktrees)
	ViewModeMerge                              // Merge workflow modal
	ViewModeAgentChoice                        // Agent action choice modal (attach/restart)
	ViewModeConfirmDelete                      // Delete confirmation modal
	ViewModeConfirmDeleteShell                 // Shell delete confirmation modal
	ViewModeCommitForMerge                     // Commit modal before merge workflow
	ViewModePromptPicker                       // Prompt template picker modal
	ViewModeTypeSelector                       // Type selector modal (shell vs worktree)
	ViewModeRenameShell                        // Rename shell modal
	ViewModeFilePicker                         // Diff file picker modal
	ViewModeInteractive                        // Interactive mode (tmux input passthrough)
	ViewModeFetchPR                            // Fetch remote PR modal
)

type WatchEventMsg

type WatchEventMsg struct {
	Path string
}

WatchEventMsg signals a filesystem change was detected.

type WatcherErrorMsg

type WatcherErrorMsg struct {
	Err error
}

WatcherErrorMsg signals a file watcher error.

type WatcherStartedMsg

type WatcherStartedMsg struct{}

WatcherStartedMsg signals the file watcher is running.

type WorkDirDeletedMsg

type WorkDirDeletedMsg struct {
	MainWorktreePath string
}

WorkDirDeletedMsg signals that the current working directory was deleted. This happens when sidecar is running inside a worktree that gets deleted.

type Worktree

type Worktree struct {
	Name            string         // e.g., "auth-oauth-flow"
	Path            string         // Absolute path
	Branch          string         // Git branch name
	BaseBranch      string         // Branch worktree was created from
	TaskID          string         // Linked td task (e.g., "td-a1b2")
	TaskTitle       string         // Task title (used as fallback if td show fails)
	PRURL           string         // URL of open PR (if any)
	ChosenAgentType AgentType      // Agent selected at creation (persists even when agent not running)
	Agent           *Agent         // nil if no agent running
	Status          WorktreeStatus // Derived from agent state
	Stats           *GitStats      // +/- line counts
	CreatedAt       time.Time
	UpdatedAt       time.Time
	IsOrphaned      bool // True if agent file exists but tmux session is gone
	IsMain          bool // True if this is the primary/main worktree (project root)
	IsMissing       bool // True if worktree directory no longer exists (detected via os.Stat or git prunable)
}

Worktree represents a git worktree with optional agent.

type WorktreeStatus

type WorktreeStatus int

WorktreeStatus represents the current state of a worktree.

const (
	StatusPaused   WorktreeStatus = iota // No agent, worktree exists
	StatusActive                         // Agent running, recent output
	StatusThinking                       // Agent is processing/thinking
	StatusWaiting                        // Agent waiting for input
	StatusDone                           // Agent completed task
	StatusError                          // Agent crashed or errored
)

func (WorktreeStatus) Icon

func (s WorktreeStatus) Icon() string

Icon returns the status indicator icon for display.

func (WorktreeStatus) String

func (s WorktreeStatus) String() string

String returns the display string for a WorktreeStatus.

Jump to

Keyboard shortcuts

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