session

package
v1.35.0 Latest Latest
Warning

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

Go to latest
Published: Jul 6, 2026 License: AGPL-3.0 Imports: 86 Imported by: 0

Documentation

Index

Constants

View Source
const (
	SessionRoleWork   = "work"
	SessionRoleTriage = "triage"
	SessionRoleReview = "review"
)

Session role constants.

View Source
const (
	TriggeredByUser   = "user"
	TriggeredBySystem = "system"
)

TriggeredBy values for BacklogStatusEvent records.

View Source
const (
	ReviewVerdictPass         = "PASS"
	ReviewVerdictFail         = "FAIL"
	ReviewVerdictPartial      = "PARTIAL"
	ReviewVerdictUnverifiable = "UNVERIFIABLE"
)

Review verdict outcome constants.

View Source
const (
	PauseReasonManual         = "manual"
	PauseReasonAutoInactivity = "auto:inactivity"
	PauseReasonAutoLimit      = "auto:session_limit"
	PauseReasonAutoResource   = "auto:resource"
)

SessionType indicates the type of session workflow to use Pause reason constants. Use these instead of bare string literals.

View Source
const (
	// SessionTypeDirectory creates a simple directory session without git worktree
	SessionTypeDirectory = config.SessionTypeDirectory
	// SessionTypeNewWorktree creates a new git worktree for the session
	SessionTypeNewWorktree = config.SessionTypeNewWorktree
	// SessionTypeExistingWorktree uses an existing git worktree
	SessionTypeExistingWorktree = config.SessionTypeExistingWorktree
	// SessionTypeNewProject creates a new directory, initializes a git repo with an
	// initial commit, and opens the session. The directory need not exist beforehand.
	SessionTypeNewProject = config.SessionTypeNewProject
	// SessionTypeOneOff generates a fresh temporary directory under one_off_base_dir.
	SessionTypeOneOff = config.SessionTypeOneOff
)
View Source
const (
	ReasonApprovalPending    = queue.ReasonApprovalPending
	ReasonInputRequired      = queue.ReasonInputRequired
	ReasonErrorState         = queue.ReasonErrorState
	ReasonTestsFailing       = queue.ReasonTestsFailing
	ReasonIdleTimeout        = queue.ReasonIdleTimeout
	ReasonTaskComplete       = queue.ReasonTaskComplete
	ReasonUncommittedChanges = queue.ReasonUncommittedChanges
	ReasonIdle               = queue.ReasonIdle
	ReasonStale              = queue.ReasonStale
	ReasonWaitingForUser     = queue.ReasonWaitingForUser
)
View Source
const (
	PriorityUrgent = queue.PriorityUrgent
	PriorityHigh   = queue.PriorityHigh
	PriorityMedium = queue.PriorityMedium
	PriorityLow    = queue.PriorityLow
)
View Source
const (
	GoalStatusIdle    = "idle"
	GoalStatusWorking = "working"
	GoalStatusBlocked = "blocked"
	GoalStatusDone    = "done"

	TaskStatusPending    = "pending"
	TaskStatusInProgress = "in_progress"
	TaskStatusDone       = "done"
	TaskStatusBlocked    = "blocked"
)

Goal and task status constants.

View Source
const (
	MinTitleLength = 1
	MaxTitleLength = 32
)

Title validation constants

View Source
const DefaultBacklogPriority = 3

DefaultBacklogPriority is the default priority assigned to new backlog items when no priority is specified. Lower values indicate higher priority.

View Source
const (
	// DefaultBufferSize is 10MB of in-memory buffer
	DefaultBufferSize = 10 * 1024 * 1024
)
View Source
const MaxTagCount = 100

MaxTagCount is the maximum number of tags allowed per session.

View Source
const MaxTagLength = 50

MaxTagLength is the maximum allowed length for a single tag.

Variables

View Source
var (
	ErrACRequired            = errors.New("acceptance criteria required before marking ready")
	ErrPlanRequired          = errors.New("plan must be approved or skip_planning must be true before spawning work session")
	ErrPlanArtifactsRequired = errors.New("plan artifacts path is required when planning is not skipped")
	ErrVerdictRequired       = errors.New("PASS verdict or manual override required before marking done")
)

Sentinel errors for transition guards.

View Source
var (
	ErrInvalidTitleLength = errors.New("title must be 1-32 characters")
	ErrInvalidTitleChars  = errors.New("title contains invalid characters")
	ErrDuplicateTitle     = errors.New("a session with this title already exists")
	ErrCannotRestart      = errors.New("session cannot be restarted in current state")
)

Title validation errors

View Source
var ContextCloudSession = ContextOptions{
	LoadCloud:    true,
	LoadActivity: true,
	LoadUI:       true,
	LoadTags:     true,
}

ContextCloudSession loads contexts for cloud/API sessions. Optimized for remote sessions that don't have local git/filesystem context. Memory usage: ~1-2 KB per session

View Source
var ContextDetailView = ContextOptions{
	LoadGit:           true,
	LoadFilesystem:    true,
	LoadTerminal:      true,
	LoadUI:            true,
	LoadActivity:      true,
	LoadWorktree:      true,
	LoadDiffStats:     true,
	LoadTags:          true,
	LoadClaudeSession: true,
}

ContextDetailView loads most contexts for detail panel. Comprehensive data for session detail views, excluding heavy diff content. Memory usage: ~10-20 KB per session

View Source
var ContextForReviewQueue = ContextOptions{
	LoadGit:       true,
	LoadActivity:  true,
	LoadWorktree:  true,
	LoadDiffStats: true,
	LoadTags:      true,
}

ContextForReviewQueue loads data needed for review queue operations. Focused on git context and change indicators. Memory usage: ~3-5 KB per session

View Source
var ContextForSearch = ContextOptions{
	LoadGit:      true,
	LoadTags:     true,
	LoadActivity: true,
}

ContextForSearch loads contexts needed for search operations. Includes tags and basic metadata for efficient filtering. Memory usage: ~1-2 KB per session

View Source
var ContextFull = ContextOptions{
	LoadGit:           true,
	LoadFilesystem:    true,
	LoadTerminal:      true,
	LoadUI:            true,
	LoadActivity:      true,
	LoadCloud:         true,
	LoadWorktree:      true,
	LoadDiffStats:     true,
	LoadDiffContent:   true,
	LoadTags:          true,
	LoadClaudeSession: true,
}

ContextFull loads all contexts and child data (expensive). Complete data including full diff content. Use sparingly. Memory usage: Can be 1-25 MB per session depending on diff size

View Source
var ContextMinimal = ContextOptions{}

ContextMinimal loads only core session data with no contexts. Use this for basic operations that only need session metadata. Memory usage: ~500 bytes per session

View Source
var ContextTerminalView = ContextOptions{
	LoadTerminal:  true,
	LoadGit:       true,
	LoadUI:        true,
	LoadActivity:  true,
	LoadDiffStats: true,
}

ContextTerminalView loads contexts needed for terminal preview. Includes terminal output and git diffs for preview panes. Memory usage: ~5-10 KB per session (varies with terminal output size)

View Source
var ContextUIView = ContextOptions{
	LoadUI:       true,
	LoadActivity: true,
	LoadGit:      true,
	LoadTags:     true,
}

ContextUIView loads contexts needed for list/card display. Optimized for responsive UI rendering with essential context only. Memory usage: ~2-3 KB per session

View Source
var DefaultRepoPathManager = NewRepoPathManager()

DefaultRepoPathManager is the default instance used for GitHub URL resolution.

View Source
var DeterminePriority = queue.DeterminePriority

DeterminePriority re-export

View Source
var ErrConflict = errors.New("conflict")

ErrConflict is returned when an operation would violate a uniqueness constraint.

View Source
var ErrInstanceDataNotFound = errors.New("instance data not found")

ErrInstanceDataNotFound is returned by FindInstanceDataByID when no match exists.

View Source
var ErrNotFound = errors.New("not found")

ErrNotFound is returned when a requested entity does not exist.

View Source
var ErrPreconditionFailed = errors.New("precondition failed: concurrent modification detected")

ErrPreconditionFailed is returned when an optimistic-locking precondition check fails.

View Source
var ErrSessionAlreadyRegistered = errors.New("session: already registered")

ErrSessionAlreadyRegistered is returned by Register when a LiveInstance for the given ID is already present in the registry (duplicate-ID collision guard).

View Source
var ErrSessionNotFound = errors.New("session: not found in storage")

ErrSessionNotFound is returned by Acquire when the sessionID is not known to Storage.

View Source
var ErrShellStopped = errors.New("shell is stopped")

ErrShellStopped is returned when an operation is attempted on a shell that has been stopped.

View Source
var ErrSubscriberFull = errors.New("PTYSubscriber: internal buffer exceeded capacity limit")

ErrSubscriberFull is returned by PTYSubscriber.Push when the internal buffer has exceeded its capacity limit. The caller should close the subscriber.

View Source
var LoadDiffOnly = LoadOptions{
	LoadWorktree:    true,
	LoadDiffStats:   true,
	LoadDiffContent: true,
}

LoadDiffOnly loads only diff-related data, useful for preview panes.

Deprecated: For new code, use ContextTerminalView.WithDiffContent() with GetSession/ListSessions.

View Source
var LoadForReviewQueue = LoadOptions{
	LoadWorktree:      true,
	LoadDiffStats:     true,
	LoadDiffContent:   false,
	LoadTags:          true,
	LoadClaudeSession: false,
}

LoadForReviewQueue loads data needed for review queue operations.

Deprecated: For new code, use ContextForReviewQueue with GetSession/ListSessions.

View Source
var LoadFull = LoadOptions{
	LoadWorktree:      true,
	LoadDiffStats:     true,
	LoadDiffContent:   true,
	LoadTags:          true,
	LoadClaudeSession: true,
}

LoadFull loads all available data including full diff content. Use this for detail views where you need complete information. Memory usage: Can be 1-25 MB per session depending on diff size

Deprecated: For new code, use ContextFull with GetSession/ListSessions.

View Source
var LoadMinimal = LoadOptions{}

LoadMinimal loads only the core session fields without any child data. Use this when you only need session metadata (title, path, status, etc.)

Deprecated: For new code, use ContextMinimal with GetSession/ListSessions.

View Source
var LoadSummary = LoadOptions{
	LoadWorktree:      true,
	LoadDiffStats:     true,
	LoadDiffContent:   false,
	LoadTags:          true,
	LoadClaudeSession: true,
}

LoadSummary loads lightweight child data suitable for list views. This includes everything except the heavy diff content. Memory usage: ~1-2 KB per session

Deprecated: For new code, use ContextUIView with GetSession/ListSessions.

Functions

func AggregateOutcome added in v1.35.0

func AggregateOutcome(verdicts []CriterionVerdict) string

AggregateOutcome computes the overall outcome from a slice of CriterionVerdicts. Priority (highest to lowest): FAIL > PARTIAL > UNVERIFIABLE > PASS. Returns PASS only if every verdict is PASS.

func BuildHeadlessReviewPrompt added in v1.35.0

func BuildHeadlessReviewPrompt(item *ent.BacklogItem, acSnapshot []AcCriterion, diff string, diffTruncated bool) string

BuildHeadlessReviewPrompt constructs a review prompt for headless calls. Unlike BuildReviewPrompt, it asks for JSON output instead of tool invocation because headless claude -p subprocesses do not have tool access.

func BuildHeadlessTriagePrompt added in v1.35.0

func BuildHeadlessTriagePrompt(item *BacklogItemData, artifactAbsPath string) string

BuildHeadlessTriagePrompt constructs the JSON-output triage prompt for a backlog item. artifactAbsPath is the absolute path where the LLM should write planning files.

func BuildReviewPrompt added in v1.35.0

func BuildReviewPrompt(item *ent.BacklogItem, acSnapshot []AcCriterion, diff string, diffTruncated bool, itemSessionID string) string

BuildReviewPrompt constructs the initial prompt for a review gate session.

func BuildSessionInitialPrompt added in v1.35.0

func BuildSessionInitialPrompt(item *ent.BacklogItem, priorSessions []*ent.ItemSession) string

BuildSessionInitialPrompt renders the full context prompt for an agent session.

func BuildTokenBudgetedPrompt added in v1.35.0

func BuildTokenBudgetedPrompt(item *ent.BacklogItem, priorSessions []*ent.ItemSession) string

BuildTokenBudgetedPrompt wraps BuildSessionInitialPrompt with token budget enforcement. It estimates tokens as len(output)/4, and reduces content in two passes if over 4000.

func CanTransition

func CanTransition(from, to Status) bool

CanTransition returns true if transitioning from -> to is a valid state transition.

func CanTransitionBacklog added in v1.35.0

func CanTransitionBacklog(from, to BacklogStatus) bool

CanTransitionBacklog reports whether a transition from one backlog status to another is permitted.

func ClaudeProjectDirName added in v1.12.0

func ClaudeProjectDirName(projectPath string) string

ClaudeProjectDirName returns the directory name Claude uses for a given absolute project path. Claude encodes the path by replacing every non-alphanumeric character with '-'. This includes '/', '.', '_', and any other non-word characters. Example: "/Users/alice/myproject" → "-Users-alice-myproject" Example: "/Users/alice/.hidden/my_project" → "-Users-alice--hidden-my-project"

func CleanupBacklogContextFile added in v1.35.0

func CleanupBacklogContextFile(worktreePath string) error

CleanupBacklogContextFile removes .backlog-context.md from the worktree root. Logs but does not fail if the file is absent.

func CleanupSlashCommands added in v1.35.0

func CleanupSlashCommands(worktreePath string) error

CleanupSlashCommands removes the backlog slash command directory. Logs but does not return an error if the directory is absent.

func CreateFullSyncDeltaFromRawContent

func CreateFullSyncDeltaFromRawContent(rawContent string, cursorRow, cursorCol, rows, cols int) *sessionv1.TerminalData

CreateFullSyncDeltaFromRawContent creates a full-sync delta from raw tmux content. This is used when sending initial pane content to clients over WebSocket. The raw content is processed into a proper delta to avoid xterm.js parsing errors.

func DecryptToken added in v1.35.0

func DecryptToken(key []byte, ciphertext string) (string, error)

DecryptToken decrypts a base64-encoded ciphertext (nonce prepended) using AES-256-GCM.

func EncodeTasks added in v1.35.0

func EncodeTasks(tasks []TaskNode) (string, error)

EncodeTasks serializes a task tree to a JSON string.

func EncryptToken added in v1.35.0

func EncryptToken(key []byte, plaintext string) (string, error)

EncryptToken encrypts plaintext using AES-256-GCM with the given 32-byte key. Returns base64-encoded ciphertext (nonce prepended).

func EnsureDirectorySessionPath added in v1.35.0

func EnsureDirectorySessionPath(path string) error

EnsureDirectorySessionPath creates and git-inits path if it does not already exist — the same directory-creation step SessionTypeDirectory takes when CreateIfMissing is set. Callers that need path to exist before spawning a directory session (e.g. to write files into the worktree ahead of the claude process starting) should call this first so the spawn's own CreateIfMissing check finds the directory already present and correctly git-initialized, rather than skipping git-init because the path merely exists.

func ExtractPRURL added in v1.35.0

func ExtractPRURL(sessionOutput string) string

ExtractPRURL scans the last 200 lines of sessionOutput for a GitHub PR URL.

func FindConversationFilePath added in v1.35.0

func FindConversationFilePath(sessionID string) (string, error)

FindConversationFilePath is the exported wrapper for findConversationFilePath. It searches ~/.claude/projects/ for the JSONL file containing sessionID.

func FindInstanceByHistoryPath added in v1.35.0

func FindInstanceByHistoryPath(instances []*Instance, filePath string) (string, bool)

FindInstanceByHistoryPath returns the title of the session whose JSONL history file matches filePath. Returns ("", false) if not found. HistoryFilePath is a public field set by HistoryLinker; safe to read here since this runs on each HistoryLinker callback, which is the same goroutine that sets the field.

func ForkClaudeConversation

func ForkClaudeConversation(srcConvPath string, lineCount uint64, dstDir string) (string, error)

ForkClaudeConversation copies the first lineCount non-empty lines from srcConvPath into a new JSONL file named {newUUID}.jsonl inside dstDir. The new UUID is returned so the caller can set it as the forked session's ResumeId.

If lineCount is 0 an empty file is created and the new UUID is still returned. If lineCount exceeds the number of lines in the source all lines are copied without error. If srcConvPath does not exist an error is returned.

func GetGitDiff added in v1.35.0

func GetGitDiff(ctx context.Context, worktreePath string, baseSHA string) (diff string, truncated bool, err error)

GetGitDiff returns the diff of changes in worktreePath relative to baseSHA (or HEAD~1 if baseSHA is empty). If the diff exceeds MaxDiffSizeReview bytes it is truncated and truncated=true is returned.

func GetMainRepoPath

func GetMainRepoPath(path string) (string, error)

GetMainRepoPath uses git rev-parse --git-common-dir to get the main repo path. This is more reliable than parsing the .git file.

func InstanceInfoSlice added in v1.35.0

func InstanceInfoSlice(instances []*Instance) []artifacts.InstanceInfo

InstanceInfoSlice converts a slice of live Instances to the lightweight InstanceInfo type used by ArtifactExtractor.SeedOffsets.

func IsGitHubURL

func IsGitHubURL(input string) bool

IsGitHubURL returns true if the input looks like a GitHub URL or shorthand.

func IsValidTaskStatus added in v1.35.0

func IsValidTaskStatus(s string) bool

IsValidTaskStatus returns true if s is a recognized task status value.

func PortSessionHistory added in v1.35.0

func PortSessionHistory(ctx context.Context, oldProgram, newProgram string, i *Instance) error

PortSessionHistory translates and syncs history between Claude Code and Antigravity CLI.

func ReconcileOrphanedTmuxSessions added in v1.35.0

func ReconcileOrphanedTmuxSessions(instances []*Instance)

ReconcileOrphanedTmuxSessions kills staplersquad_ tmux sessions that have no corresponding record in the current workspace DB.

Orphans accumulate when DeleteSession removes the DB record but the server is restarted before (or while) the live in-memory instance is available — leaving the Claude process running inside a tmux pane with no owner. This sweep is called once during server startup, after all DB sessions have been loaded and re-adopted (steps 6/6b of BuildRuntimeDeps), so there is no risk of killing a session that is mid-adoption.

Identification strategy (two-tier):

  1. Tmux session has STAPLER_SESSION_UUID env var → compare against known UUIDs.
  2. No env var (pre-UUID sessions) → compare the tmux session name against known sanitized titles. If neither matches, the session is an orphan.

The staplersquad_keepalive sentinel is always preserved — it keeps the tmux server alive between sessions and is never tracked in the DB.

func RegisterBackendProvider added in v1.35.0

func RegisterBackendProvider(backend ProcessManagerBackend)

RegisterBackendProvider sets the backend used by NewProcessManager. Call once at startup, before any session is created.

func ResolveSessionPath added in v1.35.0

func ResolveSessionPath(path string) (string, error)

ResolveSessionPath expands a leading "~" to the current user's home directory and converts the result to an absolute path — the same resolution NewInstance applies to InstanceOptions.Path. Callers that need to act on a session's worktree path *before* calling NewInstance (e.g. writing files into it ahead of spawn) must resolve through this function first, or they risk operating on a different path than the one the spawned Instance actually uses.

func RollbackMigration

func RollbackMigration(backupPath, sqlitePath string) error

RollbackMigration restores the JSON backup and removes the SQLite database

func RunPreGateSecurityCheck added in v1.35.0

func RunPreGateSecurityCheck(diff string) error

RunPreGateSecurityCheck scans a git diff for obvious secret patterns before sending to the review LLM. Returns a non-nil error if any pattern matches, blocking the review gate from spawning. This is a best-effort check — it does not replace a full secret scanner.

func SanitizeForAgentContext added in v1.35.0

func SanitizeForAgentContext(s string, maxLen int) string

SanitizeForAgentContext strips HTML tags from s and truncates to maxLen, appending " [truncated]" if truncation occurred.

func SerializeAcCriteria added in v1.35.0

func SerializeAcCriteria(criteria []AcCriterion) (string, error)

SerializeAcCriteria serializes acceptance criteria to a JSON string.

func StartSessionDriver added in v1.35.0

func StartSessionDriver(inst *Instance, allowedPath string)

StartSessionDriver launches a background goroutine that drives the session through its startup dialogs, fires the initial task prompt, and monitors for approval dialogs throughout the session lifetime.

allowedPath is the session's repo/workspace path — directory-access approval dialogs that mention this path are auto-approved.

Calling StartSessionDriver twice on the same instance is safe: the second call is a no-op (the idempotency guard uses atomic.Bool.CompareAndSwap).

func TransitionGuard added in v1.35.0

func TransitionGuard(item BacklogItemTransitionInput, to BacklogStatus) error

TransitionGuard validates business rules before a status transition. It returns nil when the transition is allowed, or a sentinel error when a guard condition is violated. It does NOT check CanTransition — callers must invoke CanTransition separately if structural validity is also required.

func ValidateEntMigration

func ValidateEntMigration(jsonPath, entDBPath string) error

ValidateEntMigration verifies that all sessions from JSON were successfully migrated to Ent

func ValidateTaskDepth added in v1.35.0

func ValidateTaskDepth(tasks []TaskNode, depth int) error

ValidateTaskDepth validates that the task tree does not exceed maxTaskDepth (3) and that all task statuses are valid enum values. Total task count is checked separately by validateTaskCount (both are called from validateTasks).

func ValidateWorkflowSlug added in v1.35.0

func ValidateWorkflowSlug(slug string) error

ValidateWorkflowSlug validates that slug conforms to the workflow slug format: - 2–64 characters - Lowercase alphanumeric with hyphens - No leading/trailing hyphens - No consecutive hyphens

func WriteBacklogContextFile added in v1.35.0

func WriteBacklogContextFile(item *ent.BacklogItem, priorSessions []*ent.ItemSession, worktreePath string) error

WriteBacklogContextFile builds the full context prompt and writes it atomically to .backlog-context.md in the worktree root. Appends a fallback instructions block. priorSessions must match what was passed to the live CLI prompt (BuildTokenBudgetedPrompt) so the on-disk fallback the agent re-reads after context compaction doesn't lose history.

func WriteSlashCommands added in v1.35.0

func WriteSlashCommands(item *ent.BacklogItem, worktreePath string) error

WriteSlashCommands creates the .claude/commands/backlog/ directory and writes per-item slash command markdown files. Retries directory creation up to 3 times.

Types

type AcCriterion added in v1.35.0

type AcCriterion struct {
	Index  int    `json:"index"`
	Text   string `json:"text"`
	Status string `json:"status"` // "pending", "in_progress", "done"
}

AcCriterion is a single acceptance criterion for a backlog item.

func ParseAcCriteria added in v1.35.0

func ParseAcCriteria(raw string) ([]AcCriterion, error)

ParseAcCriteria deserializes acceptance criteria from a JSON string.

type ActivityTracking

type ActivityTracking struct {
	// LastTerminalUpdate is when the terminal output was last updated
	LastTerminalUpdate time.Time `json:"last_terminal_update,omitempty"`

	// LastMeaningfulOutput is when meaningful (non-noise) output was detected
	LastMeaningfulOutput time.Time `json:"last_meaningful_output,omitempty"`

	// LastViewed is when the session was last viewed by the user
	LastViewed time.Time `json:"last_viewed,omitempty"`

	// LastAcknowledged is when the user last acknowledged session output
	LastAcknowledged time.Time `json:"last_acknowledged,omitempty"`

	// LastOutputSignature is a hash/signature of the last output for deduplication
	LastOutputSignature string `json:"last_output_signature,omitempty"`

	// LastAddedToQueue is when the session was last added to the review queue
	LastAddedToQueue time.Time `json:"last_added_to_queue,omitempty"`
}

ActivityTracking represents the activity tracking data for a session. This includes timestamps for various events and output tracking.

func (*ActivityTracking) HasRecentActivity

func (a *ActivityTracking) HasRecentActivity(within time.Duration) bool

HasRecentActivity returns true if there has been activity within the specified duration

func (*ActivityTracking) IsEmpty

func (a *ActivityTracking) IsEmpty() bool

IsEmpty returns true if the ActivityTracking has no meaningful data

type AgyAdapter added in v1.35.0

type AgyAdapter struct{}

func NewAgyAdapter added in v1.35.0

func NewAgyAdapter() *AgyAdapter

func (*AgyAdapter) CanHandle added in v1.35.0

func (a *AgyAdapter) CanHandle(program string) bool

func (*AgyAdapter) Export added in v1.35.0

func (a *AgyAdapter) Export(ctx context.Context, turns []CanonicalTurn, inst *Instance) error

func (*AgyAdapter) Import added in v1.35.0

func (a *AgyAdapter) Import(ctx context.Context, inst *Instance) ([]CanonicalTurn, error)

func (*AgyAdapter) Name added in v1.35.0

func (a *AgyAdapter) Name() string

type AnalyticsData added in v1.12.0

type AnalyticsData struct {
	ID                 string
	SessionID          string
	ToolName           string
	CommandPreview     string
	Cwd                string
	Decision           string
	RiskLevel          string
	RuleID             string
	RuleName           string
	Reason             string
	Alternative        string
	DurationMs         int64
	ApprovalID         string
	CommandProgram     string
	CommandCategory    string
	CommandSubcategory string
	PythonImports      []string
	CreatedAt          time.Time
}

AnalyticsData is the domain model for classification analytics.

type ApprovalAutomation

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

ApprovalAutomation orchestrates automatic approval handling.

Lock ordering (must always be acquired in this order):

mu > queueMu > subMu

func NewApprovalAutomation

func NewApprovalAutomation(sessionName string, controller *ClaudeController) *ApprovalAutomation

NewApprovalAutomation creates a new approval automation system.

func (*ApprovalAutomation) GetDetector

func (aa *ApprovalAutomation) GetDetector() *detection.ApprovalDetector

GetDetector returns the approval detector for configuration.

func (*ApprovalAutomation) GetPendingApprovals

func (aa *ApprovalAutomation) GetPendingApprovals() []*PendingApproval

GetPendingApprovals returns all approvals awaiting user response.

func (*ApprovalAutomation) GetPolicyEngine

func (aa *ApprovalAutomation) GetPolicyEngine() *PolicyEngine

GetPolicyEngine returns the policy engine for configuration.

func (*ApprovalAutomation) GetSessionName

func (aa *ApprovalAutomation) GetSessionName() string

GetSessionName returns the session name.

func (*ApprovalAutomation) IsRunning

func (aa *ApprovalAutomation) IsRunning() bool

IsRunning returns whether the automation is currently running.

func (*ApprovalAutomation) RespondToApproval

func (aa *ApprovalAutomation) RespondToApproval(requestID string, approved bool, userInput string, options ApprovalAutomationOptions) error

RespondToApproval processes a user response to a pending approval.

func (*ApprovalAutomation) Start

Start begins the approval automation processing loop.

func (*ApprovalAutomation) Stop

func (aa *ApprovalAutomation) Stop() error

Stop halts the approval automation system.

func (*ApprovalAutomation) Subscribe

func (aa *ApprovalAutomation) Subscribe(subscriberID string) <-chan ApprovalEvent

Subscribe creates a subscription for approval events.

func (*ApprovalAutomation) Unsubscribe

func (aa *ApprovalAutomation) Unsubscribe(subscriberID string)

Unsubscribe removes a subscription.

type ApprovalAutomationOptions

type ApprovalAutomationOptions struct {
	AutoExecute     bool          // Automatically execute approved commands
	UserTimeout     time.Duration // Time to wait for user response
	ProcessingDelay time.Duration // Delay between processing approvals
	MaxQueueSize    int           // Maximum pending approvals
	EnableAuditLog  bool          // Log all approval actions
}

ApprovalAutomationOptions configures approval automation behavior.

func DefaultApprovalAutomationOptions

func DefaultApprovalAutomationOptions() ApprovalAutomationOptions

DefaultApprovalAutomationOptions returns sensible defaults.

type ApprovalEvent

type ApprovalEvent struct {
	Type      ApprovalEventType
	Request   *detection.ApprovalRequest
	Decision  *PolicyDecision
	Timestamp time.Time
	Details   string
}

ApprovalEvent represents an event in the approval automation system.

type ApprovalEventType

type ApprovalEventType string

ApprovalEventType categorizes approval events.

const (
	EventDetected      ApprovalEventType = "detected"
	EventAutoApproved  ApprovalEventType = "auto_approved"
	EventAutoRejected  ApprovalEventType = "auto_rejected"
	EventAwaitingUser  ApprovalEventType = "awaiting_user"
	EventUserApproved  ApprovalEventType = "user_approved"
	EventUserRejected  ApprovalEventType = "user_rejected"
	EventExpired       ApprovalEventType = "expired"
	EventExecuted      ApprovalEventType = "executed"
	EventExecutionFail ApprovalEventType = "execution_failed"
)

type ApprovalMetadata

type ApprovalMetadata struct {
	ApprovalID string
	ToolName   string
	ToolInput  map[string]interface{}
	Cwd        string
	Orphaned   bool
}

ApprovalMetadata holds metadata about a pending approval for enriching review queue items.

type ApprovalMetadataProvider

type ApprovalMetadataProvider interface {
	// GetApprovalMetadataBySession returns approval metadata for the given session ID.
	// Returns nil if no approvals exist for the session.
	GetApprovalMetadataBySession(sessionID string) []ApprovalMetadata
}

ApprovalMetadataProvider provides approval metadata for enriching review queue items. This interface decouples the poller (session package) from the ApprovalStore (services package).

type ApprovalPolicy

type ApprovalPolicy struct {
	ID              string                   `json:"id"`
	Name            string                   `json:"name"`
	Description     string                   `json:"description"`
	ApprovalTypes   []detection.ApprovalType `json:"approval_types"` // Types this policy applies to
	Enabled         bool                     `json:"enabled"`
	Priority        int                      `json:"priority"`   // Higher priority policies checked first
	Conditions      []PolicyCondition        `json:"conditions"` // All must match
	Action          PolicyAction             `json:"action"`     // What to do when matched
	TimeRestriction *TimeRestriction         `json:"time_restriction,omitempty"`
	UsageLimit      *UsageLimit              `json:"usage_limit,omitempty"`
	CreatedAt       time.Time                `json:"created_at"`
	UpdatedAt       time.Time                `json:"updated_at"`
	// contains filtered or unexported fields
}

ApprovalPolicy defines a rule for automatic approval.

func CreateBusinessHoursPolicy

func CreateBusinessHoursPolicy() *ApprovalPolicy

CreateBusinessHoursPolicy creates a policy that only applies during business hours.

func CreateNoDestructivePolicy

func CreateNoDestructivePolicy() *ApprovalPolicy

CreateNoDestructivePolicy creates a policy for rejecting destructive commands.

func CreateSafeCommandPolicy

func CreateSafeCommandPolicy() *ApprovalPolicy

CreateSafeCommandPolicy creates a policy for automatically approving safe commands.

type ApprovalRuleData added in v1.12.0

type ApprovalRuleData struct {
	ID             string
	Name           string
	ToolName       string
	ToolPattern    string
	ToolCategory   string
	CommandPattern string
	FilePattern    string
	Decision       int
	RiskLevel      int
	Reason         string
	Alternative    string
	Priority       int
	Enabled        bool
	Source         string
	CreatedAt      time.Time
	UpdatedAt      time.Time

	// Structured CommandCriteria fields — correspond to classifier.CommandCriteria.
	Programs              []string
	Subcommands           []string
	BlockedSubcommands    []string
	RequiredFlags         []string
	ForbiddenFlags        []string
	RequiredFlagPrefixes  []string
	PythonModes           []string
	SafePythonImportsOnly bool
}

ApprovalRuleData is the domain model for an auto-approval rule.

type AttentionReason

type AttentionReason = queue.AttentionReason

AttentionReason re-export

func AttentionReasonFromDetected

func AttentionReasonFromDetected(detected detection.DetectedStatus) AttentionReason

AttentionReasonFromDetected maps a DetectedStatus to the AttentionReason that should be used when adding the session to the review queue. Returns the zero AttentionReason (empty string) when no attention is needed for that status.

type AutonomousDriver added in v1.35.0

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

AutonomousDriver monitors a session and injects orchestrator prompts when idle.

func NewAutonomousDriver added in v1.35.0

func NewAutonomousDriver(inst *Instance, pool HeadlessPoolClient, goal string, maxTurns int, opts ...DriverOption) *AutonomousDriver

NewAutonomousDriver creates an AutonomousDriver for inst. pool must not be nil; maxTurns ≤ 0 defaults to 20. Use functional options (e.g. WithStartupTimeout) to override defaults.

func (*AutonomousDriver) RegisterCompletionCallback added in v1.35.0

func (d *AutonomousDriver) RegisterCompletionCallback(cb CompletionCallback)

RegisterCompletionCallback sets the function called when the driver exits.

func (*AutonomousDriver) RegisterTurnCallback added in v1.35.0

func (d *AutonomousDriver) RegisterTurnCallback(cb TurnCallback)

RegisterTurnCallback sets the function called after each prompt injection.

func (*AutonomousDriver) Start added in v1.35.0

func (d *AutonomousDriver) Start(ctx context.Context) error

Start begins the autonomous driver goroutine. The second call is a no-op.

func (*AutonomousDriver) Stop added in v1.35.0

func (d *AutonomousDriver) Stop()

Stop cancels the driver goroutine. Context cancellation propagates into CallBlockingWithOptions: the headless pool passes ctx to runner.Run (which kills the subprocess) and the stream reader selects on ctx.Done, so Stop returns control to the caller nearly immediately — no blocking LLM call delay.

type AutonomousDriverOutcome added in v1.35.0

type AutonomousDriverOutcome struct {
	Done   bool
	Reason string
	PRUrl  string
	Turns  int
	Stuck  bool // true if exited via maxTurns without DONE signal
}

AutonomousDriverOutcome describes how an autonomous driver run concluded.

type AutonomousModeState added in v1.35.0

type AutonomousModeState struct {
	AutonomousMode     bool
	AutonomousTurn     int32
	AutonomousMaxTurns int32
	AutonomousOutcome  string
}

AutonomousModeState groups all autonomous-mode fields within InstanceSnapshot (CDD Epic 3, Task 3.1b). Access via snap.Autonomous.AutonomousMode etc.

type AvailableTargets

type AvailableTargets struct {
	VCSType         string
	Bookmarks       []BookmarkTarget
	RecentRevisions []RevisionTarget
	Worktrees       []WorktreeTarget
}

AvailableTargets contains the available workspace switch targets

type BacklogController added in v1.35.0

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

BacklogController implements services.FeatureController for the backlog feature. It enables/disables the BacklogLifecycleListener and SyncLoop at runtime without requiring a server restart.

Enable/Disable are safe to call concurrently.

func NewBacklogController added in v1.35.0

func NewBacklogController(
	listener *BacklogLifecycleListener,
	storage *Storage,
	registry *PluginRegistry,
	keyFunc func() ([]byte, error),
) *BacklogController

NewBacklogController creates a controller that manages the given listener. storage, registry, and keyFunc are used to create a new SyncLoop on Enable.

func (*BacklogController) Disable added in v1.35.0

func (c *BacklogController) Disable() error

Disable deactivates the backlog feature: sets listener disabled and stops the sync loop. Idempotent — calling Disable when already disabled is a no-op.

func (*BacklogController) Enable added in v1.35.0

func (c *BacklogController) Enable(_ context.Context) error

Enable activates the backlog feature: sets listener enabled and starts the sync loop. Idempotent — calling Enable when already enabled is a no-op.

func (*BacklogController) IsEnabled added in v1.35.0

func (c *BacklogController) IsEnabled() bool

IsEnabled reports whether the backlog feature is currently active.

type BacklogItemData added in v1.35.0

type BacklogItemData struct {
	ID                 string
	Title              string
	Description        string
	AcceptanceCriteria string // raw JSON []AcCriterion
	Priority           int
	Status             string
	RepoPath           string
	SkipReviewGate     bool
	SkipPlanning       bool
	PlanApproved       bool
	PlanApprovedAt     *time.Time
	PlanArtifactsPath  string
	Notes              string
	ExternalID         string
	ArchivedAt         *time.Time
	SourceID           string
	CreatedAt          time.Time
	UpdatedAt          time.Time
	// ItemSessions holds the eagerly-loaded item sessions for this backlog item.
	// Only populated when explicitly loaded by the caller (e.g. GetBacklogItem).
	ItemSessions []*ent.ItemSession
	// StatusEvents holds the eagerly-loaded status transition history.
	// Only populated when explicitly loaded by the caller (e.g. GetBacklogItem).
	StatusEvents []*ent.BacklogStatusEvent
}

BacklogItemData is the domain model for a backlog item.

type BacklogItemFilter added in v1.35.0

type BacklogItemFilter struct {
	// Statuses restricts results to these statuses. Empty means no restriction.
	Statuses []string
	// Priorities restricts results to these priority values. Empty means no restriction.
	Priorities []int
	// SortBy controls ordering ("priority", "updated_at"). Empty means default ordering.
	SortBy string
	// ExcludeTerminal, when true, excludes items with status "done" or "archived".
	ExcludeTerminal bool
	// Limit caps the number of results returned. 0 means use the default safety cap (1000).
	Limit int
	// Offset skips the first N results (for pagination). Only applied when Limit > 0.
	Offset int
}

BacklogItemFilter controls which items ListBacklogItems returns.

type BacklogItemPrecondition added in v1.35.0

type BacklogItemPrecondition struct {
	// ExpectedStatus, if non-empty, requires the item's current status to match.
	ExpectedStatus string
	// ExpectedUpdatedAt, if non-zero, requires the item's updated_at to match.
	ExpectedUpdatedAt *time.Time
}

BacklogItemPrecondition is used for optimistic locking on update/transition.

type BacklogItemTransitionInput added in v1.35.0

type BacklogItemTransitionInput struct {
	Status            BacklogStatus
	AcCriteriaJSON    string
	PlanApproved      bool
	SkipPlanning      bool
	PlanArtifactsPath string // path to plan artifacts written by triage session
	OverallOutcome    string // from linked ReviewVerdict
	OverrideReason    string
}

BacklogItemTransitionInput carries the fields needed by TransitionGuard.

type BacklogItemUpdate added in v1.35.0

type BacklogItemUpdate struct {
	Title              *string
	Description        *string
	AcceptanceCriteria *string // raw JSON
	Priority           *int
	RepoPath           *string
	SkipReviewGate     *bool
	SkipPlanning       *bool
	Notes              *string
	PlanApproved       *bool
	PlanApprovedAt     *time.Time
	PlanArtifactsPath  *string
}

BacklogItemUpdate carries the mutable fields for UpdateBacklogItem.

type BacklogLifecycleListener added in v1.35.0

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

BacklogLifecycleListener drives backlog item state transitions in response to session lifecycle events. It must be registered via Instance.RegisterLifecycleListener.

OnLifecycleEvent is non-blocking; all DB work is dispatched to a goroutine. Call SetEnabled(false) to make all callbacks no-ops without unwiring.

func NewBacklogLifecycleListener added in v1.35.0

func NewBacklogLifecycleListener(storage *Storage) *BacklogLifecycleListener

NewBacklogLifecycleListener creates a listener backed by the given storage. The review gate is disabled (sessionCreator=nil, headlessPool=nil).

func NewBacklogLifecycleListenerWithPool added in v1.35.0

func NewBacklogLifecycleListenerWithPool(storage *Storage, pool *headless.Pool) *BacklogLifecycleListener

NewBacklogLifecycleListenerWithPool creates a listener that uses a headless.Pool for review gate calls instead of spawning a tmux session.

func NewBacklogLifecycleListenerWithSpawner added in v1.35.0

func NewBacklogLifecycleListenerWithSpawner(storage *Storage, spawner ReviewGateSpawner) *BacklogLifecycleListener

NewBacklogLifecycleListenerWithSpawner creates a listener that will spawn a review gate session when a work session exits and SkipReviewGate is false.

func (*BacklogLifecycleListener) ReconcileStuck added in v1.35.0

func (l *BacklogLifecycleListener) ReconcileStuck(ctx context.Context)

ReconcileStuck calls ReconcileStuckItems and logs the result. Intended to be called on a periodic ticker as a safety net for abnormal session exits. No-op when the listener is disabled.

func (*BacklogLifecycleListener) SetEnabled added in v1.35.0

func (l *BacklogLifecycleListener) SetEnabled(v bool)

SetEnabled toggles whether this listener processes lifecycle events. Safe to call concurrently.

func (*BacklogLifecycleListener) SetHeadlessPool added in v1.35.0

func (l *BacklogLifecycleListener) SetHeadlessPool(p *headless.Pool)

SetHeadlessPool wires in the headless LLM pool after construction. Calling this enables the headless review gate path even when the listener was created via NewBacklogLifecycleListenerWithSpawner.

func (*BacklogLifecycleListener) Shutdown added in v1.35.0

func (l *BacklogLifecycleListener) Shutdown()

Shutdown cancels in-flight review gate calls. Safe to call concurrently.

func (*BacklogLifecycleListener) WireToInstance added in v1.35.0

func (l *BacklogLifecycleListener) WireToInstance(inst *Instance)

WireToInstance creates a per-instance listener shim and registers it on inst. Call this for every Instance that should participate in backlog lifecycle tracking.

type BacklogStatus added in v1.35.0

type BacklogStatus string

BacklogStatus represents the lifecycle state of a backlog item.

const (
	BacklogStatusIdea       BacklogStatus = "idea"
	BacklogStatusRefining   BacklogStatus = "refining"
	BacklogStatusReady      BacklogStatus = "ready"
	BacklogStatusInProgress BacklogStatus = "in_progress"
	BacklogStatusReview     BacklogStatus = "review"
	BacklogStatusDone       BacklogStatus = "done"
	BacklogStatusArchived   BacklogStatus = "archived"
)

type BookmarkTarget

type BookmarkTarget struct {
	Name       string
	RevisionID string
	IsRemote   bool
}

BookmarkTarget represents a bookmark/branch as a switch target

type CDPStreamManager added in v1.35.0

type CDPStreamManager = cdp.CDPStreamManager

CDPStreamManager is a local alias for the cdp package interface so that files within the session package can reference it without importing cdp directly.

type CanonicalBlock added in v1.35.0

type CanonicalBlock struct {
	Kind              CanonicalBlockKind `json:"kind"`
	Text              string             `json:"text,omitempty"`
	ToolID            string             `json:"tool_id,omitempty"`
	ToolName          string             `json:"tool_name,omitempty"`
	ToolArgs          json.RawMessage    `json:"tool_args,omitempty"`
	ToolResultID      string             `json:"tool_result_id,omitempty"`
	ToolResultContent string             `json:"tool_result_content,omitempty"`
	ToolResultIsError bool               `json:"tool_result_is_error,omitempty"`
}

func NewTextBlock added in v1.35.0

func NewTextBlock(text string) CanonicalBlock

NewTextBlock constructs a valid CanonicalBlock of text kind.

func NewThinkingBlock added in v1.35.0

func NewThinkingBlock(text string) CanonicalBlock

NewThinkingBlock constructs a valid CanonicalBlock of thinking kind.

func NewToolResultBlock added in v1.35.0

func NewToolResultBlock(id, name, content string, isError bool) CanonicalBlock

NewToolResultBlock constructs a valid CanonicalBlock of tool_result kind.

func NewToolUseBlock added in v1.35.0

func NewToolUseBlock(id, name string, args json.RawMessage) CanonicalBlock

NewToolUseBlock constructs a valid CanonicalBlock of tool_use kind.

func (CanonicalBlock) Validate added in v1.35.0

func (b CanonicalBlock) Validate() error

Validate checks if the block is in a valid state.

type CanonicalBlockKind added in v1.35.0

type CanonicalBlockKind string
const (
	BlockKindText       CanonicalBlockKind = "text"
	BlockKindThinking   CanonicalBlockKind = "thinking"
	BlockKindToolUse    CanonicalBlockKind = "tool_use"
	BlockKindToolResult CanonicalBlockKind = "tool_result"
	BlockKindImage      CanonicalBlockKind = "image"
)

type CanonicalRole added in v1.35.0

type CanonicalRole string
const (
	RoleUser      CanonicalRole = "user"
	RoleAssistant CanonicalRole = "assistant"
)

type CanonicalTurn added in v1.35.0

type CanonicalTurn struct {
	Role      CanonicalRole    `json:"role"`
	Blocks    []CanonicalBlock `json:"blocks"`
	Timestamp time.Time        `json:"timestamp"`
	TurnIndex int              `json:"turn_index"`
	Model     string           `json:"model,omitempty"`
}

func (CanonicalTurn) Validate added in v1.35.0

func (t CanonicalTurn) Validate() error

Validate checks if the turn and all of its blocks are in a valid state.

type Cell

type Cell struct {
	Char  rune
	Style CellStyle
}

Cell represents a single terminal cell with character and attributes

type CellStyle

type CellStyle struct {
	FgColor   string
	BgColor   string
	Bold      bool
	Italic    bool
	Underline bool
	Reverse   bool
}

CellStyle represents text styling attributes

func DefaultStyle

func DefaultStyle() CellStyle

DefaultStyle returns a default cell style

type Checkpoint

type Checkpoint struct {
	ID             string `json:"id"`
	SessionID      string `json:"session_id"`
	ParentID       string `json:"parent_id,omitempty"`
	Label          string `json:"label"`
	ScrollbackSeq  uint64 `json:"scrollback_seq"`
	ScrollbackPath string `json:"scrollback_path,omitempty"`
	ClaudeConvUUID string `json:"claude_conv_uuid,omitempty"`
	// ConvLineCount is the number of JSONL lines in the Claude conversation file at
	// checkpoint time. Used by ForkClaudeConversation to truncate the fork correctly.
	ConvLineCount uint64    `json:"conv_line_count,omitempty"`
	GitCommitSHA  string    `json:"git_commit_sha,omitempty"`
	Timestamp     time.Time `json:"timestamp"`

	// New: CLI-agnostic checkpoint details.
	CanonicalTurnIndex int    `json:"canonical_turn_index,omitempty"`
	CanonicalPath      string `json:"canonical_path,omitempty"`
}

Checkpoint represents a named bookmark of a session's state at a point in time. It captures the scrollback position, git SHA, and conversation UUID so that the session can later be forked or restored from this exact state.

type CheckpointList

type CheckpointList []Checkpoint

CheckpointList is a slice of Checkpoints with helper methods.

func (CheckpointList) FindByID

func (cl CheckpointList) FindByID(id string) *Checkpoint

FindByID returns the Checkpoint with the given ID, or nil if not found.

func (CheckpointList) FindByLabel

func (cl CheckpointList) FindByLabel(label string) *Checkpoint

FindByLabel returns the first Checkpoint with the given label, or nil if not found.

func (CheckpointList) Latest

func (cl CheckpointList) Latest() *Checkpoint

Latest returns the Checkpoint with the most recent Timestamp, or nil if empty.

type CircularBuffer

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

CircularBuffer is a thread-safe circular buffer with automatic disk fallback when the in-memory buffer fills up. This prevents memory overflow while maintaining a history of PTY output for status detection and debugging.

func NewCircularBuffer

func NewCircularBuffer(size int) *CircularBuffer

NewCircularBuffer creates a new circular buffer with the specified size in bytes. When the buffer fills up, old data is automatically overwritten (circular behavior).

func (*CircularBuffer) Cap

func (cb *CircularBuffer) Cap() int

Cap returns the total capacity of the buffer.

func (*CircularBuffer) Clear

func (cb *CircularBuffer) Clear()

Clear resets the buffer to empty state.

func (*CircularBuffer) Close

func (cb *CircularBuffer) Close() error

Close releases resources used by the circular buffer. If disk fallback is enabled, it removes the disk file.

func (*CircularBuffer) DisableDiskFallback

func (cb *CircularBuffer) DisableDiskFallback() error

DisableDiskFallback disables disk fallback and removes the disk file.

func (*CircularBuffer) EnableDiskFallback

func (cb *CircularBuffer) EnableDiskFallback(diskPath string) error

EnableDiskFallback enables automatic disk fallback when buffer is full. The diskPath parameter specifies where to store overflow data. This feature is currently a placeholder for future implementation.

func (*CircularBuffer) GetAll

func (cb *CircularBuffer) GetAll() []byte

GetAll returns all data currently in the buffer. Returns a copy to prevent concurrent modification issues.

func (*CircularBuffer) GetRecent

func (cb *CircularBuffer) GetRecent(n int) []byte

GetRecent returns the last n bytes from the buffer. If n is larger than the buffer size or the available data, returns all available data.

func (*CircularBuffer) Len

func (cb *CircularBuffer) Len() int

Len returns the number of bytes currently in the buffer.

func (*CircularBuffer) TotalBytesWritten added in v1.35.0

func (cb *CircularBuffer) TotalBytesWritten() int64

TotalBytesWritten returns the total bytes ever written to this buffer (monotonically increasing).

func (*CircularBuffer) Write

func (cb *CircularBuffer) Write(data []byte) (int, error)

Write appends data to the circular buffer. If the buffer is full, the oldest data is overwritten. This is an O(1) operation.

func (*CircularBuffer) WriteTo

func (cb *CircularBuffer) WriteTo(w io.Writer) (int64, error)

WriteTo implements io.WriterTo interface for efficient streaming.

type ClaudeAdapter added in v1.35.0

type ClaudeAdapter struct{}

func NewClaudeAdapter added in v1.35.0

func NewClaudeAdapter() *ClaudeAdapter

func (*ClaudeAdapter) CanHandle added in v1.35.0

func (a *ClaudeAdapter) CanHandle(program string) bool

func (*ClaudeAdapter) Export added in v1.35.0

func (a *ClaudeAdapter) Export(ctx context.Context, turns []CanonicalTurn, inst *Instance) error

func (*ClaudeAdapter) Import added in v1.35.0

func (a *ClaudeAdapter) Import(ctx context.Context, inst *Instance) ([]CanonicalTurn, error)

func (*ClaudeAdapter) Name added in v1.35.0

func (a *ClaudeAdapter) Name() string

type ClaudeCommandBuilder

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

ClaudeCommandBuilder constructs Claude CLI commands with session resumption support. This builder intelligently adds the --resume flag when appropriate to maintain conversation continuity across session restarts.

func NewClaudeCommandBuilder

func NewClaudeCommandBuilder(baseProgram string, claudeSession *ClaudeSessionData) *ClaudeCommandBuilder

NewClaudeCommandBuilder creates a new command builder for constructing Claude CLI commands. Parameters:

  • baseProgram: The base command string (e.g., "claude", "claude --model sonnet", "aider")
  • claudeSession: Optional session data for resumption support (can be nil)

func (*ClaudeCommandBuilder) Build

func (b *ClaudeCommandBuilder) Build() string

Build constructs the final command string with session resumption if applicable. The method follows these rules:

  1. If not a Claude command, returns baseProgram unchanged
  2. If no session data exists, returns baseProgram unchanged
  3. If session ID is invalid UUID, returns baseProgram unchanged with warning
  4. If all conditions met, returns "baseProgram --resume <sessionId>"

type ClaudeController

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

ClaudeController provides a high-level API for controlling Claude instances. It orchestrates all the underlying components (queue, executor, history, streams).

Locking discipline:

  • lifecycle (Locked[controllerLifecycle]): write-locked briefly at the boundary of Start/Stop transitions. Slow cleanup in Stop() runs OUTSIDE this lock so that status reads are never blocked by goroutine joins or disk I/O.
  • Sub-components (atomic.Pointer[T]): set once in Start(), cleared in Stop(). Readers call .Load() — a nil result means not yet initialized. Atomic access means GetCurrentStatus, GetRecentOutput, Subscribe, etc. never contend with Stop().
  • listeners (Locked[[]StatusChangeListener]): fan-out callbacks.
  • cache (Locked[cacheState]): tail-hash result cache for status/idle detection.

Cache-line layout: lifecycle.mu (a sync.RWMutex) and the atomic.Pointer fields are separated by [64]byte padding so that write operations on the mutex do not invalidate the cache line read by atomic.Load() calls (Go issue #67764).

func NewClaudeController

func NewClaudeController(instance InstanceContext) (*ClaudeController, error)

NewClaudeController creates a new controller for the given instance.

func (*ClaudeController) AddStatusChangeListener added in v1.35.0

func (cc *ClaudeController) AddStatusChangeListener(fn StatusChangeListener)

AddStatusChangeListener appends fn to the fan-out set of status-change listeners. All registered listeners fire on every status transition. Safe to call before or after Start().

func (*ClaudeController) CancelCommand

func (cc *ClaudeController) CancelCommand(commandID string) error

CancelCommand cancels a pending command in the queue.

func (*ClaudeController) ClearHistory

func (cc *ClaudeController) ClearHistory() error

ClearHistory removes all command history entries.

func (*ClaudeController) ClearQueue

func (cc *ClaudeController) ClearQueue() error

ClearQueue removes all pending commands from the queue.

func (*ClaudeController) GetCommandHistory

func (cc *ClaudeController) GetCommandHistory(limit int) []*HistoryEntry

GetCommandHistory returns recent command history.

func (*ClaudeController) GetCommandStatus

func (cc *ClaudeController) GetCommandStatus(commandID string) (*Command, error)

GetCommandStatus retrieves the current status of a command.

func (*ClaudeController) GetCurrentCommand

func (cc *ClaudeController) GetCurrentCommand() *Command

GetCurrentCommand returns the currently executing command, if any.

func (*ClaudeController) GetCurrentStatus

func (cc *ClaudeController) GetCurrentStatus() (detection.DetectedStatus, string)

GetCurrentStatus detects the current status of the Claude instance.

Two optimisations are applied on every call:

  1. Tail slicing — only the last statusDetectionTailBytes bytes of the terminal content are examined. Status indicators (◇ Ready, Thinking…, esc to interrupt) always appear near the current cursor position, so scanning the full scrollback is unnecessary.
  2. Content hash cache — a FNV-64a hash of the tail is compared against the previous call. If the tail is unchanged the cached result is returned immediately with zero allocations.

This function holds no lifecycle lock — it reads ptyAccess and statusDetector via atomic.Pointer, and the cache via Locked[cacheState]. It therefore never blocks when Stop() is running its slow cleanup.

func (*ClaudeController) GetEscapeParser added in v1.35.0

func (cc *ClaudeController) GetEscapeParser() *analytics.EscapeCodeParser

GetEscapeParser returns the escape code parser from the response stream. Returns nil if the controller is not started or has no response stream.

func (*ClaudeController) GetExecutionOptions

func (cc *ClaudeController) GetExecutionOptions() ExecutionOptions

GetExecutionOptions returns current execution options.

func (*ClaudeController) GetExitContent added in v1.15.0

func (cc *ClaudeController) GetExitContent() []byte

GetExitContent returns the last bytes captured before the PTY exited. Returns nil if the controller has no response stream or no exit content was recorded.

func (*ClaudeController) GetHistoryStatistics

func (cc *ClaudeController) GetHistoryStatistics() HistoryStatistics

GetHistoryStatistics returns statistics about command execution.

func (*ClaudeController) GetIdleDuration

func (cc *ClaudeController) GetIdleDuration() time.Duration

GetIdleDuration returns how long the session has been idle.

func (*ClaudeController) GetIdleState

func (cc *ClaudeController) GetIdleState() (detection.IdleState, time.Time)

GetIdleState returns the current idle state with timing information. Returns the state and the timestamp of last activity.

Applies the same tail-slice + hash-cache optimisations as GetCurrentStatus so that polling the idle state on an unchanged terminal is essentially free.

Holds no lifecycle lock — reads ptyAccess and idleDetector via atomic.Pointer. This also fixes the re-entrant RWMutex bug that existed when calling cc.instance.Preview() → GetRecentOutput() → cc.mu.RLock() while already holding cc.mu.RLock(); with atomic pointers there is no lock to re-enter.

func (*ClaudeController) GetIdleStateInfo

func (cc *ClaudeController) GetIdleStateInfo() detection.IdleStateInfo

GetIdleStateInfo returns comprehensive idle state information.

func (*ClaudeController) GetInstance

func (cc *ClaudeController) GetInstance() InstanceContext

GetInstance returns the InstanceContext backing this controller.

func (*ClaudeController) GetQueuedCommands

func (cc *ClaudeController) GetQueuedCommands() []*Command

GetQueuedCommands returns all commands currently in the queue.

func (*ClaudeController) GetRateLimitHandler added in v1.35.0

func (cc *ClaudeController) GetRateLimitHandler() *ratelimit.PTYConsumer

GetRateLimitHandler returns the rate limit PTY consumer (for callback wiring). Returns nil if the controller has not been started yet.

func (*ClaudeController) GetRateLimitResetTime added in v1.35.0

func (cc *ClaudeController) GetRateLimitResetTime() time.Time

GetRateLimitResetTime returns the reset time from the rate limit handler. Returns zero time if no handler is active or no reset time is known.

func (*ClaudeController) GetRateLimitState added in v1.12.0

func (cc *ClaudeController) GetRateLimitState() ratelimit.RateLimitState

GetRateLimitState returns the current rate limit detection state.

func (*ClaudeController) GetRecentOutput

func (cc *ClaudeController) GetRecentOutput(bytes int) []byte

GetRecentOutput returns recent output from the PTY buffer. Holds no lifecycle lock; returns nil if the controller is not started.

func (*ClaudeController) GetSessionName

func (cc *ClaudeController) GetSessionName() string

GetSessionName returns the session name for this controller.

func (*ClaudeController) GetStatusDetector added in v1.35.0

func (cc *ClaudeController) GetStatusDetector() detection.TerminalDetector

GetStatusDetector returns the status detector used by this controller. Used by GetDetectionEvents RPC to retrieve recent detection events for debugging.

func (*ClaudeController) GetTotalBytesWritten added in v1.35.0

func (cc *ClaudeController) GetTotalBytesWritten() int64

GetTotalBytesWritten returns the monotonic PTY byte offset from the response stream's circular buffer. Returns 0 if the controller is not started or has no response stream.

func (*ClaudeController) IsActive

func (cc *ClaudeController) IsActive() bool

IsActive returns whether the Claude instance is actively processing commands.

func (*ClaudeController) IsIdle

func (cc *ClaudeController) IsIdle() bool

IsIdle returns whether the Claude instance is currently idle (waiting for input). This uses pattern-based detection on terminal content.

func (*ClaudeController) IsRateLimitEnabled added in v1.12.0

func (cc *ClaudeController) IsRateLimitEnabled() bool

IsRateLimitEnabled returns whether rate limit detection is enabled.

func (*ClaudeController) IsStarted

func (cc *ClaudeController) IsStarted() bool

IsStarted returns whether the controller is currently started.

func (*ClaudeController) SearchHistory

func (cc *ClaudeController) SearchHistory(query string) []*HistoryEntry

SearchHistory searches command history by text.

func (*ClaudeController) SendCommand

func (cc *ClaudeController) SendCommand(text string, priority int) (string, error)

SendCommand sends a command to the Claude instance (queued execution).

func (*ClaudeController) SendCommandImmediate

func (cc *ClaudeController) SendCommandImmediate(text string) (*ExecutionResult, error)

SendCommandImmediate sends a command for immediate execution (bypasses queue).

func (*ClaudeController) SetExecutionOptions

func (cc *ClaudeController) SetExecutionOptions(options ExecutionOptions)

SetExecutionOptions updates command execution options.

func (*ClaudeController) SetOnEOFCallback added in v1.15.0

func (cc *ClaudeController) SetOnEOFCallback(fn func())

SetOnEOFCallback registers a function called when the PTY backing this controller exits unexpectedly (program exit, not an explicit Stop() call). Must be called before Start().

func (*ClaudeController) SetRateLimitEnabled added in v1.12.0

func (cc *ClaudeController) SetRateLimitEnabled(enabled bool)

SetRateLimitEnabled enables or disables rate limit detection.

func (*ClaudeController) SetStatusChangeListener added in v1.35.0

func (cc *ClaudeController) SetStatusChangeListener(fn StatusChangeListener)

SetStatusChangeListener registers fn as the sole status-change listener, replacing any previously registered listeners. Kept for backward compatibility; prefer AddStatusChangeListener.

func (*ClaudeController) Start

func (cc *ClaudeController) Start(ctx context.Context) error

Start initializes all components and begins background operations (streaming, command execution). This is the single entry point for starting the controller — no separate Initialize() call needed.

The lifecycle write lock is held for the duration of initialization to prevent concurrent Start() calls. Read-only operations (GetCurrentStatus, etc.) do not use this lock and are therefore unblocked — they simply see nil atomic pointers until initialization completes.

func (*ClaudeController) Stop

func (cc *ClaudeController) Stop() error

Stop stops all background operations and cleans up resources.

The lifecycle write lock is held only to cancel the context and clear the lifecycle fields. All slow cleanup (goroutine joins via executor.Stop/responseStream.Stop, disk I/O via queue.Save/history.Save) runs OUTSIDE the lock, so concurrent callers of GetCurrentStatus, GetRecentOutput, Subscribe, etc. are never blocked.

func (*ClaudeController) Subscribe

func (cc *ClaudeController) Subscribe(subscriberID string) (<-chan ResponseChunk, error)

Subscribe creates a new subscription to the response stream.

func (*ClaudeController) Unsubscribe

func (cc *ClaudeController) Unsubscribe(subscriberID string) error

Unsubscribe removes a subscription from the response stream.

type ClaudeConversationMessage

type ClaudeConversationMessage struct {
	Role      string
	Content   string
	Timestamp time.Time
	Model     string
}

ClaudeConversationMessage represents a message in a conversation

type ClaudeHistoryEntry

type ClaudeHistoryEntry struct {
	// ID is the unique identifier for this conversation
	ID string `json:"id"`
	// Name is the conversation title
	Name string `json:"name"`
	// Project is the project/directory path
	Project string `json:"project"`
	// CreatedAt is when the conversation started
	CreatedAt time.Time `json:"created_at"`
	// UpdatedAt is when the conversation was last updated
	UpdatedAt time.Time `json:"updated_at"`
	// Model is the Claude model used (e.g., "claude-sonnet-4")
	Model string `json:"model"`
	// MessageCount is the number of messages in the conversation
	MessageCount int `json:"message_count"`
}

ClaudeHistoryEntry represents a single entry from Claude's history.jsonl file

type ClaudeSession

type ClaudeSession struct {
	ID             string    `json:"id"`
	ConversationID string    `json:"conversation_id"`
	ProjectName    string    `json:"project_name"`
	LastActive     time.Time `json:"last_active"`
	WorkingDir     string    `json:"working_dir"`
	IsActive       bool      `json:"is_active"`
}

ClaudeSession represents a Claude Code session

type ClaudeSessionData

type ClaudeSessionData struct {
	ConversationUUID string            `json:"session_id,omitempty"`       // Claude Code conversation UUID (used for --resume)
	SquadSessionID   string            `json:"squad_session_id,omitempty"` // claude-squad's own session identifier (= Instance.UUID)
	ProjectName      string            `json:"project_name,omitempty"`     // Project name in Claude Code
	LastAttached     time.Time         `json:"last_attached,omitempty"`    // When this session was last used
	Settings         ClaudeSettings    `json:"settings,omitempty"`         // User preferences for Claude Code
	Metadata         map[string]string `json:"metadata,omitempty"`         // Additional session metadata
}

ClaudeSessionData represents Claude Code session information

func (*ClaudeSessionData) UnmarshalJSON added in v1.35.0

func (c *ClaudeSessionData) UnmarshalJSON(data []byte) error

UnmarshalJSON keeps backward compatibility with persisted state written before SquadSessionID was renamed from ConversationID. The legacy "conversation_id" key is read as a fallback when "squad_session_id" is absent, so existing JSON state files continue to hydrate the field on load.

type ClaudeSessionHistory

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

ClaudeSessionHistory manages access to Claude session history

func NewClaudeSessionHistory

func NewClaudeSessionHistory(historyPath string) (*ClaudeSessionHistory, error)

NewClaudeSessionHistory creates a new ClaudeSessionHistory instance

func NewClaudeSessionHistoryFromClaudeDir

func NewClaudeSessionHistoryFromClaudeDir() (*ClaudeSessionHistory, error)

NewClaudeSessionHistoryFromClaudeDir creates a ClaudeSessionHistory from ~/.claude directory

func (*ClaudeSessionHistory) Count

func (sh *ClaudeSessionHistory) Count() int

Count returns the total number of history entries

func (*ClaudeSessionHistory) GetAll

GetAll returns all history entries, sorted by UpdatedAt descending

func (*ClaudeSessionHistory) GetByID

GetByID returns a specific history entry by ID

func (*ClaudeSessionHistory) GetByProject

func (sh *ClaudeSessionHistory) GetByProject(projectPath string) []ClaudeHistoryEntry

GetByProject returns all history entries for a specific project path

func (*ClaudeSessionHistory) GetMessagesFromConversationFile

func (sh *ClaudeSessionHistory) GetMessagesFromConversationFile(sessionID string, limit int) ([]ClaudeConversationMessage, error)

GetMessagesFromConversationFile reads messages from the conversation file for the given sessionID. When limit > 0 only the last limit messages are returned (using an efficient reverse-read that avoids loading the full file). When limit == 0 all messages are returned.

Results are always in chronological order (oldest first).

func (*ClaudeSessionHistory) GetProjects

func (sh *ClaudeSessionHistory) GetProjects() []string

GetProjects returns a list of unique project paths from history

func (*ClaudeSessionHistory) LastLoadTime

func (sh *ClaudeSessionHistory) LastLoadTime() time.Time

LastLoadTime returns when the history was last loaded from disk

func (*ClaudeSessionHistory) Reload

func (sh *ClaudeSessionHistory) Reload() error

Reload loads history from ~/.claude/history.jsonl, which Claude maintains as a compact index of all conversations. Each line is one user message; we aggregate by sessionId to reconstruct per-session metadata (name, timestamps, message count).

func (*ClaudeSessionHistory) Search

func (sh *ClaudeSessionHistory) Search(query string) []ClaudeHistoryEntry

Search searches history entries by name or project path

type ClaudeSessionManager

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

ClaudeSessionManager handles Claude Code session detection and management

func NewClaudeSessionManager

func NewClaudeSessionManager() *ClaudeSessionManager

NewClaudeSessionManager creates a new Claude session manager

func (*ClaudeSessionManager) AttachToSession

func (csm *ClaudeSessionManager) AttachToSession(sessionID string) error

AttachToSession attempts to attach to a Claude Code session

func (*ClaudeSessionManager) CreateSessionData

func (csm *ClaudeSessionManager) CreateSessionData(session ClaudeSession, settings ClaudeSettings) ClaudeSessionData

CreateSessionData creates ClaudeSessionData from a detected session

func (*ClaudeSessionManager) DetectAvailableSessions

func (csm *ClaudeSessionManager) DetectAvailableSessions() ([]ClaudeSession, error)

DetectAvailableSessions scans for available Claude Code sessions

func (*ClaudeSessionManager) FindSessionByProject

func (csm *ClaudeSessionManager) FindSessionByProject(projectPath string) ([]ClaudeSession, error)

FindSessionByProject finds Claude sessions that match a given project/working directory

func (*ClaudeSessionManager) GetSessionByID

func (csm *ClaudeSessionManager) GetSessionByID(sessionID string) (*ClaudeSession, error)

GetSessionByID retrieves a specific Claude session by ID

type ClaudeSettings

type ClaudeSettings struct {
	AutoReattach          bool   `json:"auto_reattach"`           // Automatically reattach to last session on resume
	PreferredSessionName  string `json:"preferred_session_name"`  // Preferred session naming pattern
	CreateNewOnMissing    bool   `json:"create_new_on_missing"`   // Create new session if previous one is missing
	ShowSessionSelector   bool   `json:"show_session_selector"`   // Show session selection menu on resume
	SessionTimeoutMinutes int    `json:"session_timeout_minutes"` // Consider sessions stale after this time
}

ClaudeSettings contains user preferences for Claude Code integration

type CloudContext

type CloudContext struct {
	// Provider is the cloud provider name (aws/gcp/azure/custom)
	Provider string `json:"provider,omitempty"`

	// Region is the cloud region/zone
	Region string `json:"region,omitempty"`

	// InstanceID is the cloud instance identifier
	InstanceID string `json:"instance_id,omitempty"`

	// APIEndpoint is the API endpoint URL for the cloud service
	APIEndpoint string `json:"api_endpoint,omitempty"`

	// APIKeyRef is a reference to secure key storage (not the actual key)
	APIKeyRef string `json:"api_key_ref,omitempty"`

	// CloudSessionID is the cloud provider's session identifier
	CloudSessionID string `json:"cloud_session_id,omitempty"`

	// ConversationID is the conversation/thread identifier for AI services
	ConversationID string `json:"conversation_id,omitempty"`
}

CloudContext represents the cloud-related context for a session. This includes cloud provider details, region, and API configuration.

func (*CloudContext) IsConfigured

func (c *CloudContext) IsConfigured() bool

IsConfigured returns true if the CloudContext has minimum required configuration

func (*CloudContext) IsEmpty

func (c *CloudContext) IsEmpty() bool

IsEmpty returns true if the CloudContext has no meaningful data

type Command

type Command struct {
	ID        string        `json:"id"`
	Text      string        `json:"text"`
	Priority  int           `json:"priority"`  // Higher priority = executed first
	Timestamp time.Time     `json:"timestamp"` // When the command was queued
	Status    CommandStatus `json:"status"`
	Result    string        `json:"result,omitempty"`     // Command result/output
	Error     string        `json:"error,omitempty"`      // Error message if failed
	StartTime time.Time     `json:"start_time,omitempty"` // When execution started
	EndTime   time.Time     `json:"end_time,omitempty"`   // When execution finished
}

Command represents a command to be executed in a Claude instance.

type CommandExecutor

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

CommandExecutor executes commands by writing to PTY and monitoring responses.

func NewCommandExecutor

func NewCommandExecutor(
	sessionName string,
	ptyAccess *PTYAccess,
	responseStream *ResponseStream,
	statusDetector detection.TerminalDetector,
	queue *CommandQueue,
) *CommandExecutor

NewCommandExecutor creates a new command executor for the given session.

func NewCommandExecutorWithOptions

func NewCommandExecutorWithOptions(
	sessionName string,
	ptyAccess *PTYAccess,
	responseStream *ResponseStream,
	statusDetector detection.TerminalDetector,
	queue *CommandQueue,
	options ExecutionOptions,
) *CommandExecutor

NewCommandExecutorWithOptions creates a command executor with custom options.

func (*CommandExecutor) ExecuteImmediate

func (ce *CommandExecutor) ExecuteImmediate(cmd *Command) (*ExecutionResult, error)

ExecuteImmediate executes a command immediately without using the queue. This is useful for interactive commands that need immediate execution.

func (*CommandExecutor) GetCurrentCommand

func (ce *CommandExecutor) GetCurrentCommand() *Command

GetCurrentCommand returns the currently executing command, or nil if none.

func (*CommandExecutor) GetOptions

func (ce *CommandExecutor) GetOptions() ExecutionOptions

GetOptions returns the current execution options.

func (*CommandExecutor) GetSessionName

func (ce *CommandExecutor) GetSessionName() string

GetSessionName returns the session name for this executor.

func (*CommandExecutor) IsExecuting

func (ce *CommandExecutor) IsExecuting() bool

IsExecuting returns whether the executor is currently running.

func (*CommandExecutor) SetOptions

func (ce *CommandExecutor) SetOptions(options ExecutionOptions)

SetOptions updates execution options (only applies to future commands).

func (*CommandExecutor) SetResultCallback

func (ce *CommandExecutor) SetResultCallback(callback func(*ExecutionResult))

SetResultCallback sets a callback function to be invoked after each command execution.

func (*CommandExecutor) Start

func (ce *CommandExecutor) Start(ctx context.Context) error

Start begins processing commands from the queue.

func (*CommandExecutor) Stop

func (ce *CommandExecutor) Stop() error

Stop stops the command executor and waits for completion.

type CommandHistory

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

CommandHistory tracks all executed commands with persistence.

func NewCommandHistory

func NewCommandHistory(sessionName string) *CommandHistory

NewCommandHistory creates a new command history tracker.

func NewCommandHistoryWithPersistence

func NewCommandHistoryWithPersistence(sessionName string, persistDir string) (*CommandHistory, error)

NewCommandHistoryWithPersistence creates a command history with persistence enabled.

func (*CommandHistory) Add

func (ch *CommandHistory) Add(entry *HistoryEntry) error

Add adds a command execution to the history.

func (*CommandHistory) AddFromResult

func (ch *CommandHistory) AddFromResult(result *ExecutionResult) error

AddFromResult creates and adds a history entry from an execution result.

func (*CommandHistory) Clear

func (ch *CommandHistory) Clear() error

Clear removes all history entries.

func (*CommandHistory) Count

func (ch *CommandHistory) Count() int

Count returns the total number of entries in history.

func (*CommandHistory) GetAll

func (ch *CommandHistory) GetAll() []*HistoryEntry

GetAll returns all history entries (most recent first).

func (*CommandHistory) GetByCommandID

func (ch *CommandHistory) GetByCommandID(commandID string) []*HistoryEntry

GetByCommandID returns all history entries for a specific command ID.

func (*CommandHistory) GetByStatus

func (ch *CommandHistory) GetByStatus(status CommandStatus) []*HistoryEntry

GetByStatus returns entries with a specific command status.

func (*CommandHistory) GetByTimeRange

func (ch *CommandHistory) GetByTimeRange(start, end time.Time) []*HistoryEntry

GetByTimeRange returns entries within the specified time range.

func (*CommandHistory) GetFailed

func (ch *CommandHistory) GetFailed() []*HistoryEntry

GetFailed returns all failed command executions.

func (*CommandHistory) GetMaxEntries

func (ch *CommandHistory) GetMaxEntries() int

GetMaxEntries returns the current maximum entries limit.

func (*CommandHistory) GetPersistPath

func (ch *CommandHistory) GetPersistPath() string

GetPersistPath returns the path where history is persisted.

func (*CommandHistory) GetRecent

func (ch *CommandHistory) GetRecent(n int) []*HistoryEntry

GetRecent returns the N most recent history entries.

func (*CommandHistory) GetSessionName

func (ch *CommandHistory) GetSessionName() string

GetSessionName returns the session name for this history.

func (*CommandHistory) GetStatistics

func (ch *CommandHistory) GetStatistics() HistoryStatistics

GetStatistics returns statistics about command execution history.

func (*CommandHistory) GetSuccessful

func (ch *CommandHistory) GetSuccessful() []*HistoryEntry

GetSuccessful returns all successful command executions.

func (*CommandHistory) Load

func (ch *CommandHistory) Load() error

Load restores the history from disk.

func (*CommandHistory) Save

func (ch *CommandHistory) Save() error

Save persists the history to disk.

func (*CommandHistory) Search

func (ch *CommandHistory) Search(query string) []*HistoryEntry

Search searches history entries by command text (case-insensitive substring match).

func (*CommandHistory) SetMaxEntries

func (ch *CommandHistory) SetMaxEntries(max int)

SetMaxEntries sets the maximum number of entries to keep in history. Setting to 0 means unlimited. If current entries exceed the new limit, oldest entries are removed.

func (*CommandHistory) SetPersistPath

func (ch *CommandHistory) SetPersistPath(path string)

SetPersistPath sets the path for history persistence.

type CommandQueue

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

CommandQueue manages a priority queue of commands with persistence.

func NewCommandQueue

func NewCommandQueue(sessionName string) *CommandQueue

NewCommandQueue creates a new command queue for the given session.

func NewCommandQueueWithPersistence

func NewCommandQueueWithPersistence(sessionName string, persistDir string) (*CommandQueue, error)

NewCommandQueueWithPersistence creates a command queue with persistence enabled. The queue state will be saved to the specified directory.

func (*CommandQueue) Cancel

func (cq *CommandQueue) Cancel(id string) error

Cancel marks a command as cancelled and removes it from the queue. Returns an error if the command is not found or is already executing.

func (*CommandQueue) Clear

func (cq *CommandQueue) Clear() error

Clear removes all commands from the queue.

func (*CommandQueue) Dequeue

func (cq *CommandQueue) Dequeue() *Command

Dequeue removes and returns the highest priority command from the queue. Returns nil if the queue is empty.

func (*CommandQueue) Enqueue

func (cq *CommandQueue) Enqueue(cmd *Command) error

Enqueue adds a command to the queue with the specified priority. Higher priority commands are executed first.

func (*CommandQueue) Get

func (cq *CommandQueue) Get(id string) (*Command, error)

Get retrieves a command by ID without removing it from the queue.

func (*CommandQueue) GetPersistPath

func (cq *CommandQueue) GetPersistPath() string

GetPersistPath returns the path where the queue state is persisted.

func (*CommandQueue) IsEmpty

func (cq *CommandQueue) IsEmpty() bool

IsEmpty returns true if the queue is empty.

func (*CommandQueue) Len

func (cq *CommandQueue) Len() int

Len returns the number of commands in the queue.

func (*CommandQueue) List

func (cq *CommandQueue) List() []*Command

List returns all commands currently in the queue. The returned slice is a copy to prevent external modification.

func (*CommandQueue) ListByStatus

func (cq *CommandQueue) ListByStatus(status CommandStatus) []*Command

ListByStatus returns all commands with the specified status.

func (*CommandQueue) Load

func (cq *CommandQueue) Load() error

Load restores the queue state from disk.

func (*CommandQueue) NotifyChannel

func (cq *CommandQueue) NotifyChannel() <-chan struct{}

NotifyChannel returns a channel that receives a notification when commands are added. This can be used to wait for new commands without polling.

func (*CommandQueue) Peek

func (cq *CommandQueue) Peek() *Command

Peek returns the highest priority command without removing it. Returns nil if the queue is empty.

func (*CommandQueue) Save

func (cq *CommandQueue) Save() error

Save persists the queue state to disk.

func (*CommandQueue) SetPersistPath

func (cq *CommandQueue) SetPersistPath(path string)

SetPersistPath sets the path for queue persistence.

func (*CommandQueue) Update

func (cq *CommandQueue) Update(cmd *Command) error

Update updates the status and metadata of a command.

type CommandStatus

type CommandStatus int

CommandStatus represents the current status of a command in the queue.

const (
	CommandPending CommandStatus = iota
	CommandExecuting
	CommandCompleted
	CommandFailed
	CommandCancelled
)

func (CommandStatus) String

func (cs CommandStatus) String() string

String returns a human-readable string for the command status.

type CompletionCallback added in v1.35.0

type CompletionCallback func(instanceName string, outcome AutonomousDriverOutcome)

CompletionCallback is called when the driver exits with a final outcome.

type ContentProvider added in v1.35.0

type ContentProvider interface {
	GetContent(inst *Instance, statusInfo InstanceStatusInfo, paneActivity map[string]time.Time) string
	EvictInstance(title string)
}

ContentProvider fetches terminal content for a session. Defined at the consumption point so tests can inject fakes without tmux.

func NewPollerContentProvider added in v1.35.0

func NewPollerContentProvider() ContentProvider

NewPollerContentProvider creates a new pollerContentProvider. It is exported so server/dependencies.go can pass it to NewStartupScanner.

type ContextOptions

type ContextOptions struct {
	// Context loading flags
	LoadGit        bool // Git repository context (branch, commit, remotes)
	LoadFilesystem bool // Filesystem context (directory state, file counts)
	LoadTerminal   bool // Terminal context (output, command history)
	LoadUI         bool // UI context (position, focus state, expanded/collapsed)
	LoadActivity   bool // Activity context (last active, duration, events)
	LoadCloud      bool // Cloud context (API sessions, remote state)

	// Child data loading flags (from existing LoadOptions)
	LoadWorktree      bool // Git worktree data
	LoadDiffStats     bool // Diff statistics (added/removed counts)
	LoadDiffContent   bool // Full diff content (heavy - only load when needed)
	LoadTags          bool // Session tags
	LoadClaudeSession bool // Claude Code session data
}

ContextOptions specifies which optional contexts to load when querying sessions. This enables optimized queries that only load the data needed for each use case.

func FromLoadOptions

func FromLoadOptions(lo LoadOptions) ContextOptions

FromLoadOptions creates ContextOptions from the legacy LoadOptions type. This provides backward compatibility when migrating existing code.

func (ContextOptions) AnyChildDataLoaded

func (o ContextOptions) AnyChildDataLoaded() bool

AnyChildDataLoaded returns true if any child data is configured to load.

func (ContextOptions) AnyContextLoaded

func (o ContextOptions) AnyContextLoaded() bool

AnyContextLoaded returns true if any context is configured to load.

func (ContextOptions) Merge

Merge combines two ContextOptions, returning options that load the union of both. This is useful for combining requirements from multiple components.

func (ContextOptions) String

func (o ContextOptions) String() string

String returns a human-readable description of what will be loaded.

func (ContextOptions) ToLoadOptions

func (o ContextOptions) ToLoadOptions() LoadOptions

ToLoadOptions converts ContextOptions to the legacy LoadOptions type. This provides backward compatibility with existing code.

func (ContextOptions) WithActivity

func (o ContextOptions) WithActivity() ContextOptions

WithActivity returns a copy of options with activity context loading enabled.

func (ContextOptions) WithCloud

func (o ContextOptions) WithCloud() ContextOptions

WithCloud returns a copy of options with cloud context loading enabled.

func (ContextOptions) WithDiffContent

func (o ContextOptions) WithDiffContent() ContextOptions

WithDiffContent returns a copy of options with diff content loading enabled.

func (ContextOptions) WithFilesystem

func (o ContextOptions) WithFilesystem() ContextOptions

WithFilesystem returns a copy of options with filesystem context loading enabled.

func (ContextOptions) WithGit

func (o ContextOptions) WithGit() ContextOptions

WithGit returns a copy of options with git context loading enabled.

func (ContextOptions) WithTags

func (o ContextOptions) WithTags() ContextOptions

WithTags returns a copy of options with tag loading enabled.

func (ContextOptions) WithTerminal

func (o ContextOptions) WithTerminal() ContextOptions

WithTerminal returns a copy of options with terminal context loading enabled.

func (ContextOptions) WithUI

func (o ContextOptions) WithUI() ContextOptions

WithUI returns a copy of options with UI context loading enabled.

func (ContextOptions) WithoutDiffContent

func (o ContextOptions) WithoutDiffContent() ContextOptions

WithoutDiffContent returns a copy of options with diff content loading disabled.

func (ContextOptions) WithoutTags

func (o ContextOptions) WithoutTags() ContextOptions

WithoutTags returns a copy of options with tag loading disabled.

type ControllerManager

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

ControllerManager owns the ClaudeController and InstanceStatusManager references that were previously bare fields on Instance.

Instance keeps thin wrapper methods (with lifecycle guards) that delegate here. ControllerManager itself has no knowledge of Instance lifecycle; it only manages the controller and status-manager references.

Note: claudeSession is intentionally NOT included here because it is a rich data object with complex lifecycle management (persistence, re-attachment, session selection) that is tightly coupled to Instance business logic. It remains a direct field on Instance for now.

The controller field is protected by mu; statusManager uses atomic.Pointer for lock-free concurrent access. ControllerManager must not be copied after first use (enforced by noCopy).

func (*ControllerManager) GetController

func (cm *ControllerManager) GetController() *ClaudeController

GetController returns the current ClaudeController (may be nil).

func (*ControllerManager) GetStatusManager

func (cm *ControllerManager) GetStatusManager() *InstanceStatusManager

GetStatusManager returns the current InstanceStatusManager (may be nil).

func (*ControllerManager) HasController

func (cm *ControllerManager) HasController() bool

HasController reports whether a ClaudeController has been registered.

func (*ControllerManager) RegisterController

func (cm *ControllerManager) RegisterController(title string, controller *ClaudeController)

RegisterController wires a new controller into the status manager and stores it. Any existing controller is stopped first.

func (*ControllerManager) SetController

func (cm *ControllerManager) SetController(c *ClaudeController)

SetController replaces the controller. Callers are responsible for stopping the old controller before calling this.

func (*ControllerManager) SetStatusManager

func (cm *ControllerManager) SetStatusManager(m *InstanceStatusManager)

SetStatusManager replaces the status manager.

func (*ControllerManager) StopAndClearController

func (cm *ControllerManager) StopAndClearController()

StopAndClearController stops the controller (if running) and clears the reference.

func (*ControllerManager) UnregisterController

func (cm *ControllerManager) UnregisterController(title string)

UnregisterController stops and clears the controller, and removes it from the status manager.

type ConversationID added in v1.35.0

type ConversationID string

ConversationID represents a validated Claude/Antigravity conversation UUID.

func ParseConversationID added in v1.35.0

func ParseConversationID(s string) (ConversationID, error)

ParseConversationID parses and validates a raw string as a ConversationID.

type CriterionVerdict added in v1.35.0

type CriterionVerdict struct {
	CriterionIndex int    `json:"criterion_index"`
	Outcome        string `json:"outcome"`
	Evidence       string `json:"evidence"`
}

CriterionVerdict holds the review outcome for a single acceptance criterion.

func ParseHeadlessVerdictResult added in v1.35.0

func ParseHeadlessVerdictResult(text string) (overall string, verdicts []CriterionVerdict, summary string)

ParseHeadlessVerdictResult extracts verdict data from a headless LLM JSON response. It searches for the outermost JSON object in text, tolerating prose around it. Returns ReviewVerdictFail overall if parsing fails or no verdicts are present.

type DefaultStatusDeterminer added in v1.35.0

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

DefaultStatusDeterminer implements StatusDeterminer with the standard detection logic.

func NewDefaultStatusDeterminer added in v1.35.0

func NewDefaultStatusDeterminer(config ReviewQueuePollerConfig) *DefaultStatusDeterminer

NewDefaultStatusDeterminer creates a DefaultStatusDeterminer with the given config.

func (*DefaultStatusDeterminer) Determine added in v1.35.0

func (d *DefaultStatusDeterminer) Determine(
	inst *Instance,
	content string,
	statusInfo InstanceStatusInfo,
	detector detection.TerminalDetector,
) DetectionResult

Determine evaluates a session's state and returns a DetectionResult. It is pure: no queue mutations, no storage calls, no side effects.

type DefaultWorkflowEngine added in v1.35.0

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

DefaultWorkflowEngine implements WorkflowEngine using the hardcoded validTransitions map and TransitionGuard function from backlog.go.

func NewDefaultWorkflowEngine added in v1.35.0

func NewDefaultWorkflowEngine() *DefaultWorkflowEngine

NewDefaultWorkflowEngine constructs an engine backed by the static validTransitions map. The map is deep-copied to avoid shared mutable state.

func (*DefaultWorkflowEngine) AllowedTransitions added in v1.35.0

func (e *DefaultWorkflowEngine) AllowedTransitions(from BacklogStatus) []BacklogStatus

AllowedTransitions implements WorkflowEngine.

func (*DefaultWorkflowEngine) CanTransition added in v1.35.0

func (e *DefaultWorkflowEngine) CanTransition(from, to BacklogStatus) bool

CanTransition implements WorkflowEngine.

func (*DefaultWorkflowEngine) ValidateGates added in v1.35.0

ValidateGates implements WorkflowEngine by delegating to TransitionGuard.

type DetectionAction added in v1.35.0

type DetectionAction int

DetectionAction represents what the poller should do after status determination.

const (
	DetectionActionSkip   DetectionAction = iota // No change to queue
	DetectionActionAdd                           // Add/update item in queue
	DetectionActionRemove                        // Remove item from queue
)

type DetectionResult added in v1.35.0

type DetectionResult struct {
	Action       DetectionAction
	Reason       AttentionReason
	Priority     Priority
	Context      string
	ClaudeStatus detection.DetectedStatus
	// CleanWorktree is true when the worktree was inspected and found clean.
	// checkSession uses this to remove a queued UncommittedChanges entry immediately.
	CleanWorktree bool
}

DetectionResult is the output of status determination — pure data, no side effects.

func (DetectionResult) IsHighPriority added in v1.35.0

func (r DetectionResult) IsHighPriority() bool

IsHighPriority returns true when the result warrants bypassing grace-period suppression.

type DiffStatsData

type DiffStatsData struct {
	Added   int    `json:"added"`
	Removed int    `json:"removed"`
	Content string `json:"-"` // Excluded from serialization - generated on-demand
}

DiffStatsData represents the serializable data of a DiffStats Note: Content is excluded from JSON serialization to reduce state file size. Diffs are generated on-demand via GetSessionDiff RPC when needed.

type DiscoveryMode

type DiscoveryMode int

DiscoveryMode controls what instances are discovered and how they can be interacted with

const (
	// DiscoveryModeManaged discovers only squad-managed sessions (default, safest)
	DiscoveryModeManaged DiscoveryMode = iota

	// DiscoveryModeExtended discovers managed + external instances in read-only mode
	DiscoveryModeExtended

	// DiscoveryModeFull discovers all instances with attach capability (power user mode)
	DiscoveryModeFull
)

func ParseDiscoveryMode

func ParseDiscoveryMode(s string) DiscoveryMode

ParseDiscoveryMode parses a string into a DiscoveryMode

func (DiscoveryMode) String

func (dm DiscoveryMode) String() string

type DriverOption added in v1.35.0

type DriverOption func(*AutonomousDriver)

DriverOption is a functional option for configuring an AutonomousDriver.

func WithStartupTimeout added in v1.35.0

func WithStartupTimeout(d time.Duration) DriverOption

WithStartupTimeout overrides the default 60s startup idle-wait timeout. Use a longer timeout for sessions that spawn parallel subagents (e.g. triage).

type EntRepository

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

EntRepository implements the Repository interface using Ent ORM as the storage backend. It provides type-safe database operations with automatic schema migrations.

func NewEntRepository

func NewEntRepository(opts ...RepositoryOption) (*EntRepository, error)

NewEntRepository creates a new Ent repository with the given options. The database will be initialized with the schema if it doesn't exist.

func NewEntRepositoryFromClient added in v1.35.0

func NewEntRepositoryFromClient(client *ent.Client) *EntRepository

NewEntRepositoryFromClient wraps a pre-existing *ent.Client in an EntRepository. The caller is responsible for running schema migration on the client beforehand. Use this when you need to share an already-opened client across subsystems (e.g. injecting a test client or reusing an existing connection).

func (*EntRepository) AllRules added in v1.12.0

func (r *EntRepository) AllRules(ctx context.Context) ([]ApprovalRuleData, error)

func (*EntRepository) ArchiveBacklogItem added in v1.35.0

func (r *EntRepository) ArchiveBacklogItem(ctx context.Context, id string) (*BacklogItemData, error)

ArchiveBacklogItem sets the archived_at timestamp on a backlog item.

func (*EntRepository) AssignSessionsToProject added in v1.23.0

func (r *EntRepository) AssignSessionsToProject(ctx context.Context, projectName string, sessionTitles []string) error

AssignSessionsToProject links sessions (by title) to a project (by name).

func (*EntRepository) Close

func (r *EntRepository) Close() error

Close performs cleanup and releases resources

func (*EntRepository) Create

func (r *EntRepository) Create(ctx context.Context, data InstanceData) error

Create inserts a new session into the database

func (*EntRepository) CreateBacklogItem added in v1.35.0

func (r *EntRepository) CreateBacklogItem(ctx context.Context, data BacklogItemData) (*BacklogItemData, error)

CreateBacklogItem inserts a new backlog item.

func (*EntRepository) CreateItemSession added in v1.35.0

func (r *EntRepository) CreateItemSession(ctx context.Context, data ItemSessionData) (*ent.ItemSession, error)

CreateItemSession creates a new ItemSession linked to a BacklogItem.

func (*EntRepository) CreateItemSessionWithVerdict added in v1.35.0

func (r *EntRepository) CreateItemSessionWithVerdict(ctx context.Context, isData ItemSessionData, verdict ReviewVerdictData) (*ent.ItemSession, *ent.ReviewVerdict, error)

CreateItemSessionWithVerdict atomically creates an ItemSession and its initial ReviewVerdict in a single transaction. If the verdict write fails the ItemSession is rolled back, preventing dangling sessions with no verdict.

func (*EntRepository) CreateItemSource added in v1.35.0

func (r *EntRepository) CreateItemSource(ctx context.Context, data ItemSourceData) (*ItemSourceData, error)

CreateItemSource registers a new external item source.

func (*EntRepository) CreateProject added in v1.23.0

func (r *EntRepository) CreateProject(ctx context.Context, data ProjectData) (*ProjectData, error)

CreateProject inserts a new project.

func (*EntRepository) CreateSession

func (r *EntRepository) CreateSession(ctx context.Context, session *Session) error

CreateSession creates a new session from the Session domain model. Stub: not yet implemented; use InstanceData-based methods instead.

func (*EntRepository) CreateShell added in v1.35.0

func (r *EntRepository) CreateShell(ctx context.Context, sessionTitle string, data ShellData) (*ent.Shell, error)

CreateShell persists a new Shell entity for the given session title.

func (*EntRepository) CreateSourceSyncEvent added in v1.35.0

func (r *EntRepository) CreateSourceSyncEvent(ctx context.Context, sourceID string, cursorAfter string, created, updated, skipped, errored int, errMsg string, startedAt, finishedAt time.Time) error

CreateSourceSyncEvent records a completed (or failed) sync run for an ItemSource. errMsg should be non-empty only when the sync run failed outright (e.g. the plugin's Fetch call errored); errored counts per-item failures within an otherwise-successful fetch.

func (*EntRepository) Delete

func (r *EntRepository) Delete(ctx context.Context, title string) error

Delete removes a session from the database by title

func (*EntRepository) DeleteBacklogItem added in v1.35.0

func (r *EntRepository) DeleteBacklogItem(ctx context.Context, id string) error

DeleteBacklogItem permanently removes an item and all its child records.

func (*EntRepository) DeleteItemSource added in v1.35.0

func (r *EntRepository) DeleteItemSource(ctx context.Context, id string) error

DeleteItemSource removes an item source by UUID string.

func (*EntRepository) DeleteProject added in v1.23.0

func (r *EntRepository) DeleteProject(ctx context.Context, name string) error

DeleteProject removes a project; sessions are unassigned (FK cleared) atomically.

func (*EntRepository) DeleteRule added in v1.12.0

func (r *EntRepository) DeleteRule(ctx context.Context, id string) error

func (*EntRepository) DeleteShell added in v1.35.0

func (r *EntRepository) DeleteShell(ctx context.Context, shellID string) error

DeleteShell removes a Shell entity by ID.

func (*EntRepository) FinishSourceSync added in v1.35.0

func (r *EntRepository) FinishSourceSync(ctx context.Context, sourceID string, cursorAfter string, created, updated, skipped, errored int, startedAt, finishedAt time.Time) error

FinishSourceSync atomically advances an ItemSource's sync cursor/last_synced_at and records the SourceSyncEvent for a successful sync run. Wrapping both writes in one transaction prevents a crash between them from leaving the cursor advanced with no corresponding history row — which would silently hide the fact that a batch of items was processed (or dropped) in that run.

func (*EntRepository) Get

func (r *EntRepository) Get(ctx context.Context, title string) (*InstanceData, error)

Get retrieves a single session by title

func (*EntRepository) GetAllSessionArtifacts added in v1.35.0

func (r *EntRepository) GetAllSessionArtifacts(ctx context.Context) (map[string]string, error)

GetAllSessionArtifacts returns a map of title → raw artifacts JSON for all sessions that have a non-empty session_artifacts column. Single query replaces N per-session queries in LoadInstances (M-4 fix).

func (*EntRepository) GetBacklogItem added in v1.35.0

func (r *EntRepository) GetBacklogItem(ctx context.Context, id string) (*BacklogItemData, error)

GetBacklogItem retrieves a backlog item by UUID string.

func (*EntRepository) GetBacklogItemByExternalID added in v1.35.0

func (r *EntRepository) GetBacklogItemByExternalID(ctx context.Context, sourceID, externalID string) (*ent.BacklogItem, error)

GetBacklogItemByExternalID retrieves a BacklogItem by its external_id, scoped to sourceID. External IDs (e.g. GitHub issue/PR numbers) are only unique within their source, not globally — two different repos can both have an issue #1, so this must never match across sources.

func (*EntRepository) GetEntClient added in v1.35.0

func (r *EntRepository) GetEntClient() *ent.Client

GetEntClient returns the underlying *ent.Client so callers (e.g. ErrorRegistry) can operate on entities not managed by the Repository interface.

func (*EntRepository) GetItemSession added in v1.35.0

func (r *EntRepository) GetItemSession(ctx context.Context, id string) (*ent.ItemSession, error)

GetItemSession retrieves an ItemSession by entity UUID string. Loads the BacklogItem edge.

func (*EntRepository) GetItemSessionBySessionAndItem added in v1.35.0

func (r *EntRepository) GetItemSessionBySessionAndItem(ctx context.Context, sessionUUID string, itemID string) (*ent.ItemSession, error)

GetItemSessionBySessionAndItem looks up an ItemSession by both sessionUUID and backlog item ID.

func (*EntRepository) GetItemSessionBySessionUUID added in v1.35.0

func (r *EntRepository) GetItemSessionBySessionUUID(ctx context.Context, sessionUUID string) (*ent.ItemSession, error)

GetItemSessionBySessionUUID looks up the most recent active ItemSession by session UUID alone. session_uuid is not unique across records (a session may be reused), so we order by created_at descending and take the first match. Returns ErrNotFound if no record exists. Loads the BacklogItem edge.

func (*EntRepository) GetItemSourceByID added in v1.35.0

func (r *EntRepository) GetItemSourceByID(ctx context.Context, id string) (*ent.ItemSource, error)

GetItemSourceByID retrieves a raw *ent.ItemSource by UUID string.

func (*EntRepository) GetMostRecentReviewVerdictForItem added in v1.35.0

func (r *EntRepository) GetMostRecentReviewVerdictForItem(ctx context.Context, itemID string) (string, error)

GetMostRecentReviewVerdictForItem returns the OverallOutcome string from the most recently created ReviewVerdict associated with any ItemSession for the given BacklogItem UUID. Returns an empty string (not an error) when no verdict exists yet.

func (*EntRepository) GetSession

func (r *EntRepository) GetSession(ctx context.Context, title string, opts ContextOptions) (*Session, error)

GetSession retrieves a session using the new Session domain model. Stub: not yet implemented; use InstanceData-based methods instead.

func (*EntRepository) GetSessionArtifacts added in v1.35.0

func (r *EntRepository) GetSessionArtifacts(ctx context.Context, title string) (string, error)

GetSessionArtifacts loads the raw JSON artifact blob for a session. Returns ("", nil) if the session exists but has no artifacts stored yet.

func (*EntRepository) GetSubcommandBreakdown added in v1.35.0

func (r *EntRepository) GetSubcommandBreakdown(ctx context.Context, program string, since time.Time) ([]SubcommandDecisionCount, error)

func (*EntRepository) GetSubcommandTrend added in v1.35.0

func (r *EntRepository) GetSubcommandTrend(ctx context.Context, program, subcommand string, since time.Time) ([]AnalyticsData, error)

func (*EntRepository) GetWithOptions

func (r *EntRepository) GetWithOptions(ctx context.Context, title string, options LoadOptions) (*InstanceData, error)

GetWithOptions retrieves a single session with selective child data loading. EntRepository: Delegates to Get with full loading.

func (*EntRepository) List

func (r *EntRepository) List(ctx context.Context) ([]InstanceData, error)

List retrieves all sessions from the database

func (*EntRepository) ListAnalytics added in v1.12.0

func (r *EntRepository) ListAnalytics(ctx context.Context, limit int) ([]AnalyticsData, error)

func (*EntRepository) ListAnalyticsByProgramSince added in v1.35.0

func (r *EntRepository) ListAnalyticsByProgramSince(ctx context.Context, program string, since time.Time, limit int) ([]AnalyticsData, error)

func (*EntRepository) ListAnalyticsSince added in v1.35.0

func (r *EntRepository) ListAnalyticsSince(ctx context.Context, since time.Time, limit int) ([]AnalyticsData, error)

func (*EntRepository) ListBacklogItems added in v1.35.0

func (r *EntRepository) ListBacklogItems(ctx context.Context, filter BacklogItemFilter) ([]BacklogItemData, error)

ListBacklogItems returns backlog items with optional filtering.

func (*EntRepository) ListByStatus

func (r *EntRepository) ListByStatus(ctx context.Context, status Status) ([]InstanceData, error)

ListByStatus retrieves sessions filtered by status

func (*EntRepository) ListByStatusWithOptions

func (r *EntRepository) ListByStatusWithOptions(ctx context.Context, status Status, options LoadOptions) ([]InstanceData, error)

ListByStatusWithOptions retrieves sessions filtered by status with selective loading. EntRepository: Delegates to ListByStatus with full loading.

func (*EntRepository) ListByTag

func (r *EntRepository) ListByTag(ctx context.Context, tagName string) ([]InstanceData, error)

ListByTag retrieves sessions that have a specific tag

func (*EntRepository) ListByTagWithOptions

func (r *EntRepository) ListByTagWithOptions(ctx context.Context, tag string, options LoadOptions) ([]InstanceData, error)

ListByTagWithOptions retrieves sessions with a specific tag with selective loading. EntRepository: Delegates to ListByTag with full loading.

func (*EntRepository) ListItemSessions added in v1.35.0

func (r *EntRepository) ListItemSessions(ctx context.Context, itemID string) ([]*ent.ItemSession, error)

ListItemSessions returns all ItemSessions for a given BacklogItem UUID string.

func (*EntRepository) ListItemSources added in v1.35.0

func (r *EntRepository) ListItemSources(ctx context.Context) ([]ItemSourceData, error)

ListItemSources returns all registered item sources.

func (*EntRepository) ListProjects added in v1.23.0

func (r *EntRepository) ListProjects(ctx context.Context) ([]ProjectData, error)

ListProjects returns all projects.

func (*EntRepository) ListRecentCommandsByProgram added in v1.35.0

func (r *EntRepository) ListRecentCommandsByProgram(ctx context.Context, program, subcommand string, since time.Time, n int) ([]string, error)

func (*EntRepository) ListSessions

func (r *EntRepository) ListSessions(ctx context.Context, opts ContextOptions) ([]*Session, error)

ListSessions retrieves all sessions using the new Session domain model. Stub: not yet implemented; use InstanceData-based methods instead.

func (*EntRepository) ListShells added in v1.35.0

func (r *EntRepository) ListShells(ctx context.Context, sessionTitle string) ([]*ent.Shell, error)

ListShells returns all shells for the given session title, ordered by order_index.

func (*EntRepository) ListSourceSyncEvents added in v1.35.0

func (r *EntRepository) ListSourceSyncEvents(ctx context.Context, sourceID string) (events []*ent.SourceSyncEvent, truncated bool, err error)

ListSourceSyncEvents returns sync history events for an item source, most recent first, capped at maxSourceSyncEventsHistory rows. truncated is true when older events exist beyond the cap — callers should surface this to avoid silently hiding history for sources with long or frequent sync runs.

func (*EntRepository) ListWithOptions

func (r *EntRepository) ListWithOptions(ctx context.Context, options LoadOptions) ([]InstanceData, error)

ListWithOptions retrieves all sessions with selective child data loading. EntRepository: Delegates to List with full loading.

func (*EntRepository) ReconcileStuckItems added in v1.35.0

func (r *EntRepository) ReconcileStuckItems(ctx context.Context) (int, error)

ReconcileStuckItems finds in_progress items whose all linked ItemSessions have ended, and transitions them to review status. Returns the count of transitioned items. All updates are wrapped in a single transaction so they succeed or fail atomically.

func (*EntRepository) RecordAnalytics added in v1.12.0

func (r *EntRepository) RecordAnalytics(ctx context.Context, data AnalyticsData) error

func (*EntRepository) SaveReviewVerdict added in v1.35.0

func (r *EntRepository) SaveReviewVerdict(ctx context.Context, itemSessionID string, verdict ReviewVerdictData) (*ent.ReviewVerdict, error)

SaveReviewVerdict upserts a ReviewVerdict for a given ItemSession. The query-then-create/update is wrapped in a transaction to prevent a check-then-act race condition when concurrent callers save verdicts for the same item session.

func (*EntRepository) TransitionBacklogItemStatus added in v1.35.0

func (r *EntRepository) TransitionBacklogItemStatus(ctx context.Context, id string, toStatus BacklogStatus, precondition *BacklogItemPrecondition) (*BacklogItemData, error)

TransitionBacklogItemStatus changes the status of a backlog item with optional precondition.

func (*EntRepository) Update

func (r *EntRepository) Update(ctx context.Context, data InstanceData) error

Update modifies an existing session in the database

func (*EntRepository) UpdateAcCriterionStatus added in v1.35.0

func (r *EntRepository) UpdateAcCriterionStatus(ctx context.Context, itemID string, criterionIndex int, status string, note string) error

UpdateAcCriterionStatus updates a single acceptance criterion's status by index.

func (*EntRepository) UpdateBacklogItem added in v1.35.0

func (r *EntRepository) UpdateBacklogItem(ctx context.Context, id string, update BacklogItemUpdate, precondition *BacklogItemPrecondition) (*BacklogItemData, error)

UpdateBacklogItem modifies an existing backlog item with optional precondition check.

func (*EntRepository) UpdateGitHubPRNumber added in v1.35.0

func (r *EntRepository) UpdateGitHubPRNumber(ctx context.Context, title string, prNumber int) error

UpdateGitHubPRNumber persists a discovered PR number for a session. Called by PRStatusPoller when it auto-discovers a PR for a branch-based session.

func (*EntRepository) UpdateItemSessionEnded added in v1.35.0

func (r *EntRepository) UpdateItemSessionEnded(ctx context.Context, id string, endedAt time.Time) error

UpdateItemSessionEnded records the end time for an ItemSession.

func (*EntRepository) UpdateItemSessionFileTouch added in v1.35.0

func (r *EntRepository) UpdateItemSessionFileTouch(ctx context.Context, id string, touchAt time.Time) error

UpdateItemSessionFileTouch updates the last file touch timestamp on an ItemSession.

func (*EntRepository) UpdateItemSessionGitActivity added in v1.35.0

func (r *EntRepository) UpdateItemSessionGitActivity(ctx context.Context, id string, sha, msg string, commitAt time.Time, commitCount int) error

UpdateItemSessionGitActivity updates git-related fields on an ItemSession.

func (*EntRepository) UpdateItemSessionSessionUUID added in v1.35.0

func (r *EntRepository) UpdateItemSessionSessionUUID(ctx context.Context, id string, sessionUUID string) error

UpdateItemSessionSessionUUID updates the session_uuid field on an existing ItemSession.

func (*EntRepository) UpdateItemSessionStarted added in v1.35.0

func (r *EntRepository) UpdateItemSessionStarted(ctx context.Context, id string, startedAt time.Time) error

UpdateItemSessionStarted records the start time for an ItemSession.

func (*EntRepository) UpdateItemSessionTriageResult added in v1.35.0

func (r *EntRepository) UpdateItemSessionTriageResult(ctx context.Context, id string, triageResult string) error

UpdateItemSessionTriageResult stores the triage result JSON payload on an ItemSession.

func (*EntRepository) UpdateItemSource added in v1.35.0

func (r *EntRepository) UpdateItemSource(ctx context.Context, id string, update ItemSourceUpdate) (*ItemSourceData, error)

UpdateItemSource modifies an existing item source.

func (*EntRepository) UpdateLastAcknowledged added in v1.35.0

func (r *EntRepository) UpdateLastAcknowledged(ctx context.Context, title string, t time.Time) error

UpdateLastAcknowledged sets only the last_acknowledged field for a session, issuing a single UPDATE WHERE title=? without a prior SELECT.

func (*EntRepository) UpdateLastAddedToQueue added in v1.35.0

func (r *EntRepository) UpdateLastAddedToQueue(ctx context.Context, title string, t time.Time) error

UpdateLastAddedToQueue sets only the last_added_to_queue field for a session, issuing a single UPDATE WHERE title=? without a prior SELECT.

func (*EntRepository) UpdateLastViewed added in v1.35.0

func (r *EntRepository) UpdateLastViewed(ctx context.Context, title string, t time.Time) error

UpdateLastViewed sets only the last_viewed field for a session, issuing a single UPDATE WHERE title=? without a prior SELECT.

func (*EntRepository) UpdateProject added in v1.23.0

func (r *EntRepository) UpdateProject(ctx context.Context, data ProjectData) (*ProjectData, error)

UpdateProject modifies an existing project.

func (*EntRepository) UpdateReviewQueueState added in v1.35.0

func (r *EntRepository) UpdateReviewQueueState(ctx context.Context, title string, lastUserResponse, processingGraceUntil, lastPromptDetected time.Time, lastPromptSignature string) error

UpdateReviewQueueState efficiently updates only the review-queue interaction fields for a session, avoiding the full read-modify-write cycle of updateFieldInRepo.

func (*EntRepository) UpdateSession

func (r *EntRepository) UpdateSession(ctx context.Context, session *Session) error

UpdateSession updates an existing session using the Session domain model. Stub: not yet implemented; use InstanceData-based methods instead.

func (*EntRepository) UpdateSessionArtifacts added in v1.35.0

func (r *EntRepository) UpdateSessionArtifacts(ctx context.Context, title string, blob string) error

UpdateSessionArtifacts persists the JSON-encoded artifact blob for a session. Wrapped in a transaction for correctness under concurrent writes (M-6 fix). The per-title mutex in ArtifactExtractor (C-1) serializes calls at the application layer; the transaction is belt-and-suspenders for correctness.

func (*EntRepository) UpdateShellStatus added in v1.35.0

func (r *EntRepository) UpdateShellStatus(ctx context.Context, shellID, status string, exitCode *int) error

UpdateShellStatus updates the status (and optionally exit code + stopped_at) for a shell.

func (*EntRepository) UpdateTimestamps

func (r *EntRepository) UpdateTimestamps(ctx context.Context, title string, lastTerminalUpdate, lastMeaningfulOutput time.Time, lastOutputSignature string) error

UpdateTimestamps efficiently updates only timestamp fields for a session

func (*EntRepository) UpsertRule added in v1.12.0

func (r *EntRepository) UpsertRule(ctx context.Context, data ApprovalRuleData) error

type EntWorkflowRepository added in v1.35.0

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

EntWorkflowRepository implements WorkflowRepository using the ent ORM.

func NewEntWorkflowRepository added in v1.35.0

func NewEntWorkflowRepository(client *ent.Client) *EntWorkflowRepository

NewEntWorkflowRepository creates a new ent-backed workflow repository.

func (*EntWorkflowRepository) Create added in v1.35.0

Create inserts a new workflow definition. Returns ent.ConstraintError when a duplicate slug exists.

func (*EntWorkflowRepository) Delete added in v1.35.0

func (r *EntWorkflowRepository) Delete(ctx context.Context, id uuid.UUID) error

Delete removes a workflow by UUID.

func (*EntWorkflowRepository) GetByID added in v1.35.0

func (r *EntWorkflowRepository) GetByID(ctx context.Context, id uuid.UUID) (*ent.Workflow, error)

GetByID retrieves a workflow by UUID.

func (*EntWorkflowRepository) GetBySlug added in v1.35.0

func (r *EntWorkflowRepository) GetBySlug(ctx context.Context, slug string) (*ent.Workflow, error)

GetBySlug retrieves a workflow by slug.

func (*EntWorkflowRepository) ListAll added in v1.35.0

func (r *EntWorkflowRepository) ListAll(ctx context.Context) ([]*ent.Workflow, error)

ListAll returns all workflows sorted ascending by created_at. A safety cap of 1000 is applied to prevent runaway queries.

func (*EntWorkflowRepository) ListEnabled added in v1.35.0

func (r *EntWorkflowRepository) ListEnabled(ctx context.Context) ([]*ent.Workflow, error)

ListEnabled returns only workflows where cron_enabled is true.

func (*EntWorkflowRepository) Update added in v1.35.0

Update applies a partial update to an existing workflow by UUID.

type ErrDuplicateTag

type ErrDuplicateTag struct {
	Tag string
}

ErrDuplicateTag is returned when adding a tag that already exists.

func (ErrDuplicateTag) Error

func (e ErrDuplicateTag) Error() string

type ErrInvalidTransition

type ErrInvalidTransition struct {
	From Status
	To   Status
}

ErrInvalidTransition is returned when a status transition is not allowed by the state machine defined in state_machine.go.

func (ErrInvalidTransition) Error

func (e ErrInvalidTransition) Error() string

type ErrTagTooLong

type ErrTagTooLong struct {
	Tag    string
	MaxLen int
}

ErrTagTooLong is returned when a tag exceeds the maximum length.

func (ErrTagTooLong) Error

func (e ErrTagTooLong) Error() string

type ErrTooManyTags added in v1.9.0

type ErrTooManyTags struct {
	Count    int
	MaxCount int
}

ErrTooManyTags is returned when setting more tags than MaxTagCount allows.

func (ErrTooManyTags) Error added in v1.9.0

func (e ErrTooManyTags) Error() string

type ExecutionOptions

type ExecutionOptions struct {
	// Timeout for command execution (0 = no timeout)
	Timeout time.Duration
	// MaxOutputSize limits captured output (0 = unlimited)
	MaxOutputSize int
	// StatusCheckInterval for polling status detector
	StatusCheckInterval time.Duration
	// TerminalStatuses are statuses that indicate command completion
	TerminalStatuses []detection.DetectedStatus
}

ExecutionOptions configures command execution behavior.

func DefaultExecutionOptions

func DefaultExecutionOptions() ExecutionOptions

DefaultExecutionOptions returns sensible defaults for command execution.

type ExecutionResult

type ExecutionResult struct {
	Command       *Command
	Success       bool
	Output        string
	Error         error
	StartTime     time.Time
	EndTime       time.Time
	FinalStatus   detection.DetectedStatus
	StatusChanges []StatusChange
}

ExecutionResult represents the result of a command execution.

type ExternalApprovalCallback

type ExternalApprovalCallback func(*ExternalApprovalEvent)

ExternalApprovalCallback is called when an approval is detected.

type ExternalApprovalEvent

type ExternalApprovalEvent struct {
	Request      *detection.ApprovalRequest
	SessionID    string // Socket path or unique identifier
	SessionTitle string
	Source       ExternalApprovalSource
	Cwd          string
	Command      string
}

ExternalApprovalEvent represents an approval detected in an external session.

type ExternalApprovalMonitor

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

ExternalApprovalMonitor monitors external sessions for approval requests.

func NewExternalApprovalMonitor

func NewExternalApprovalMonitor() *ExternalApprovalMonitor

NewExternalApprovalMonitor creates a new external approval monitor.

func (*ExternalApprovalMonitor) GetAllPendingApprovals

func (m *ExternalApprovalMonitor) GetAllPendingApprovals() map[string][]*detection.ApprovalRequest

GetAllPendingApprovals returns pending approvals across all monitored sessions.

func (*ExternalApprovalMonitor) GetDetector

GetDetector returns the underlying approval detector for configuration.

func (*ExternalApprovalMonitor) GetMonitoredSessions

func (m *ExternalApprovalMonitor) GetMonitoredSessions() []string

GetMonitoredSessions returns the socket paths of all monitored sessions.

func (*ExternalApprovalMonitor) GetPendingApprovals

func (m *ExternalApprovalMonitor) GetPendingApprovals(socketPath string) []*detection.ApprovalRequest

GetPendingApprovals returns all pending approval requests for a session.

func (*ExternalApprovalMonitor) IntegrateWithDiscovery

func (m *ExternalApprovalMonitor) IntegrateWithDiscovery(
	discovery *ExternalSessionDiscovery,
	streamerManager *ExternalStreamerManager,
)

IntegrateWithDiscovery connects the approval monitor to external session discovery. This auto-monitors new external sessions as they're discovered.

func (*ExternalApprovalMonitor) IntegrateWithDiscoveryTmux

func (m *ExternalApprovalMonitor) IntegrateWithDiscoveryTmux(
	discovery *ExternalSessionDiscovery,
	tmuxStreamerManager *ExternalTmuxStreamerManager,
)

IntegrateWithDiscoveryTmux connects the approval monitor to external session discovery using tmux-based streaming instead of socket-based streaming.

func (*ExternalApprovalMonitor) MarkApprovalHandled

func (m *ExternalApprovalMonitor) MarkApprovalHandled(socketPath, requestID string, approved bool) error

MarkApprovalHandled marks an approval request as handled.

func (*ExternalApprovalMonitor) MonitorSession

func (m *ExternalApprovalMonitor) MonitorSession(
	streamer *ExternalStreamer,
	title string,
	source ExternalApprovalSource,
) error

MonitorSession starts monitoring an external session for approval requests.

func (*ExternalApprovalMonitor) MonitorSessionTmux

func (m *ExternalApprovalMonitor) MonitorSessionTmux(
	streamer *ExternalTmuxStreamer,
	tmuxSessionName string,
	title string,
	source ExternalApprovalSource,
) error

MonitorSessionTmux starts monitoring an external session using tmux-based streaming.

func (*ExternalApprovalMonitor) OnApproval

func (m *ExternalApprovalMonitor) OnApproval(callback ExternalApprovalCallback)

OnApproval registers a callback for approval events.

func (*ExternalApprovalMonitor) Start

func (m *ExternalApprovalMonitor) Start()

Start begins monitoring for approvals.

func (*ExternalApprovalMonitor) Stop

func (m *ExternalApprovalMonitor) Stop()

Stop stops all monitoring.

func (*ExternalApprovalMonitor) StopMonitoringSession

func (m *ExternalApprovalMonitor) StopMonitoringSession(socketPath string)

StopMonitoringSession stops monitoring a specific session.

type ExternalApprovalSource

type ExternalApprovalSource string

ExternalApprovalSource identifies the source of an external approval.

const (
	SourceIntelliJ ExternalApprovalSource = "IntelliJ"
	SourceTerminal ExternalApprovalSource = "Terminal"
	SourceVSCode   ExternalApprovalSource = "VS Code"
	SourceMux      ExternalApprovalSource = "mux"
	SourceUnknown  ExternalApprovalSource = "Unknown"
)

type ExternalInstanceMetadata

type ExternalInstanceMetadata struct {
	// TmuxSocket is the tmux server socket this instance belongs to
	// Empty string means the default tmux server
	TmuxSocket string

	// TmuxSessionName is the full tmux session name
	TmuxSessionName string

	// DiscoveredAt is when this external instance was first discovered
	DiscoveredAt time.Time

	// LastSeen is when this instance was last seen during discovery
	LastSeen time.Time

	// OriginalPID is the process ID when first discovered
	OriginalPID int

	// MuxSocketPath is the path to an ssq-mux Unix domain socket
	// If set, this instance was discovered via ssq-mux and supports
	// full bidirectional terminal access
	MuxSocketPath string

	// MuxEnabled indicates whether this instance supports mux protocol
	MuxEnabled bool

	// SourceTerminal identifies the source (e.g., "IntelliJ", "Terminal", "tmux")
	SourceTerminal string
}

ExternalInstanceMetadata contains metadata for externally discovered Claude instances

type ExternalItem added in v1.35.0

type ExternalItem struct {
	ExternalID  string
	Title       string
	Description string
	Labels      []string
	Priority    int // 1-5, derived from labels
	URL         string
}

ExternalItem is a platform-agnostic representation of an external issue/ticket.

type ExternalSessionDiscovery

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

ExternalSessionDiscovery discovers and manages external Claude sessions from ssq-mux multiplexed terminals.

func NewExternalSessionDiscovery

func NewExternalSessionDiscovery() *ExternalSessionDiscovery

NewExternalSessionDiscovery creates a new external session discovery service.

func (*ExternalSessionDiscovery) GetSession

func (e *ExternalSessionDiscovery) GetSession(socketPath string) *Instance

GetSession returns a specific external session by socket path (deprecated - use GetSessionByTmux).

func (*ExternalSessionDiscovery) GetSessionByTmux

func (e *ExternalSessionDiscovery) GetSessionByTmux(tmuxSessionName string) *Instance

GetSessionByTmux returns a specific external session by tmux session name.

func (*ExternalSessionDiscovery) GetSessions

func (e *ExternalSessionDiscovery) GetSessions() []*Instance

GetSessions returns all currently discovered external sessions.

func (*ExternalSessionDiscovery) OnSessionAdded

func (e *ExternalSessionDiscovery) OnSessionAdded(callback func(*Instance))

OnSessionAdded registers a callback for when a new external session is discovered. Multiple callbacks can be registered and will all be invoked.

func (*ExternalSessionDiscovery) OnSessionRemoved

func (e *ExternalSessionDiscovery) OnSessionRemoved(callback func(*Instance))

OnSessionRemoved registers a callback for when an external session is removed. Multiple callbacks can be registered and will all be invoked.

func (*ExternalSessionDiscovery) Start

func (e *ExternalSessionDiscovery) Start(interval time.Duration)

Start begins periodic discovery of external sessions.

func (*ExternalSessionDiscovery) Stop

func (e *ExternalSessionDiscovery) Stop()

Stop stops the discovery service.

type ExternalStreamer

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

ExternalStreamer connects to a mux socket and streams terminal output. It handles reconnection and broadcasts output to registered consumers.

func NewExternalStreamer

func NewExternalStreamer(socketPath string, bufferSize int) *ExternalStreamer

NewExternalStreamer creates a new streamer for the given mux socket.

func (*ExternalStreamer) AddConsumer

func (s *ExternalStreamer) AddConsumer(consumer OutputConsumer, catchUp bool) string

AddConsumer registers a callback to receive output data. If catchUp is true, the consumer receives buffered recent output first. Returns a token that must be passed to RemoveConsumer to deregister.

func (*ExternalStreamer) ConsumerCount

func (s *ExternalStreamer) ConsumerCount() int

ConsumerCount returns the number of registered consumers.

func (*ExternalStreamer) GetMetadata

func (s *ExternalStreamer) GetMetadata() *mux.SessionMetadata

GetMetadata returns the session metadata from the mux.

func (*ExternalStreamer) GetRecentOutput

func (s *ExternalStreamer) GetRecentOutput() []byte

GetRecentOutput returns the buffered recent output.

func (*ExternalStreamer) GetSnapshot

func (s *ExternalStreamer) GetSnapshot() ([]byte, error)

GetSnapshot requests a clean screen snapshot from the mux session. This uses tmux capture-pane on the server side to get clean terminal content without ANSI escape sequences, suitable for pattern matching and initial state. The snapshot request is coordinated with the readLoop to avoid race conditions.

func (*ExternalStreamer) IsConnected

func (s *ExternalStreamer) IsConnected() bool

IsConnected returns whether the streamer is currently connected.

func (*ExternalStreamer) RemoveConsumer

func (s *ExternalStreamer) RemoveConsumer(key string)

RemoveConsumer deregisters a consumer by the token returned from AddConsumer.

func (*ExternalStreamer) SendInput

func (s *ExternalStreamer) SendInput(data []byte) error

SendInput sends input data to the mux session.

func (*ExternalStreamer) SendResize

func (s *ExternalStreamer) SendResize(cols, rows uint16) error

SendResize sends a terminal resize command to the mux session.

func (*ExternalStreamer) SocketPath

func (s *ExternalStreamer) SocketPath() string

SocketPath returns the path to the mux socket.

func (*ExternalStreamer) Start

func (s *ExternalStreamer) Start() error

Start connects to the mux socket and begins streaming.

func (*ExternalStreamer) Stop

func (s *ExternalStreamer) Stop()

Stop disconnects and stops the streamer.

type ExternalStreamerManager

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

ExternalStreamerManager manages multiple external streamers.

func NewExternalStreamerManager

func NewExternalStreamerManager(bufferSize int) *ExternalStreamerManager

NewExternalStreamerManager creates a new streamer manager.

func (*ExternalStreamerManager) Count

func (m *ExternalStreamerManager) Count() int

Count returns the number of active streamers.

func (*ExternalStreamerManager) Get

func (m *ExternalStreamerManager) Get(socketPath string) *ExternalStreamer

Get returns a streamer if it exists.

func (*ExternalStreamerManager) GetOrCreate

func (m *ExternalStreamerManager) GetOrCreate(socketPath string) (*ExternalStreamer, error)

GetOrCreate returns an existing streamer or creates a new one.

func (*ExternalStreamerManager) Remove

func (m *ExternalStreamerManager) Remove(socketPath string)

Remove stops and removes a streamer.

func (*ExternalStreamerManager) StopAll

func (m *ExternalStreamerManager) StopAll()

StopAll stops all streamers.

type ExternalTmuxStreamer

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

ExternalTmuxStreamer provides terminal content streaming for external sessions.

It uses two strategies in priority order:

  1. Control mode (preferred): Starts "tmux -C attach-session -t <name> -r" which provides real-time %output notifications via the tmux control protocol. When an %output event arrives it signals that the pane content has changed, triggering a single capture-pane call to obtain the full terminal snapshot. This eliminates blind polling while preserving the full-snapshot semantic that consumers expect.

  2. Capture-pane polling (fallback): If control mode fails to start (e.g. older tmux, session not found) the streamer falls back to polling capture-pane every 500ms. This is less responsive but universally compatible.

func NewExternalTmuxStreamer

func NewExternalTmuxStreamer(tmuxSessionName string) *ExternalTmuxStreamer

NewExternalTmuxStreamer creates a new tmux-based streamer for an external session.

func (*ExternalTmuxStreamer) AddConsumer

func (s *ExternalTmuxStreamer) AddConsumer(consumer func(content string)) string

AddConsumer registers a callback to receive content updates. The consumer will be called with the full terminal content whenever it changes. Returns a token that must be passed to RemoveConsumer to deregister.

func (*ExternalTmuxStreamer) ConsumerCount

func (s *ExternalTmuxStreamer) ConsumerCount() int

ConsumerCount returns the number of registered consumers.

func (*ExternalTmuxStreamer) GetContent

func (s *ExternalTmuxStreamer) GetContent() string

GetContent returns the current terminal content.

func (*ExternalTmuxStreamer) IsRunning

func (s *ExternalTmuxStreamer) IsRunning() bool

IsRunning returns whether the streamer is currently running.

func (*ExternalTmuxStreamer) RemoveConsumer

func (s *ExternalTmuxStreamer) RemoveConsumer(key string)

RemoveConsumer deregisters a consumer by the token returned from AddConsumer.

func (*ExternalTmuxStreamer) Start

func (s *ExternalTmuxStreamer) Start() error

Start begins streaming the tmux session for content changes. It first attempts to use tmux control mode for event-driven updates. If control mode is unavailable, it falls back to capture-pane polling.

func (*ExternalTmuxStreamer) Stop

func (s *ExternalTmuxStreamer) Stop()

Stop stops the streamer.

type ExternalTmuxStreamerManager

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

ExternalTmuxStreamerManager manages multiple external tmux streamers.

func NewExternalTmuxStreamerManager

func NewExternalTmuxStreamerManager() *ExternalTmuxStreamerManager

NewExternalTmuxStreamerManager creates a new streamer manager.

func (*ExternalTmuxStreamerManager) Count

func (m *ExternalTmuxStreamerManager) Count() int

Count returns the number of active streamers.

func (*ExternalTmuxStreamerManager) Get

func (m *ExternalTmuxStreamerManager) Get(tmuxSessionName string) *ExternalTmuxStreamer

Get returns a streamer if it exists.

func (*ExternalTmuxStreamerManager) GetOrCreate

func (m *ExternalTmuxStreamerManager) GetOrCreate(tmuxSessionName string) (*ExternalTmuxStreamer, error)

GetOrCreate returns an existing streamer or creates a new one.

func (*ExternalTmuxStreamerManager) Remove

func (m *ExternalTmuxStreamerManager) Remove(tmuxSessionName string)

Remove stops and removes a streamer.

func (*ExternalTmuxStreamerManager) StopAll

func (m *ExternalTmuxStreamerManager) StopAll()

StopAll stops all streamers.

type FilesystemContext

type FilesystemContext struct {
	// ProjectPath is the root project/repository directory
	ProjectPath string `json:"project_path,omitempty"`

	// WorkingDir is the current working directory within the project
	WorkingDir string `json:"working_dir,omitempty"`

	// IsWorktree indicates if this session is using a git worktree
	IsWorktree bool `json:"is_worktree,omitempty"`

	// MainRepoPath is the parent repository path if this is a worktree
	MainRepoPath string `json:"main_repo_path,omitempty"`

	// ClonedRepoPath is the path to the cloned repository for external PRs
	ClonedRepoPath string `json:"cloned_repo_path,omitempty"`

	// ExistingWorktree is the path to an existing worktree being used
	ExistingWorktree string `json:"existing_worktree,omitempty"`

	// SessionType indicates the type of session workflow
	SessionType SessionType `json:"session_type,omitempty"`
}

FilesystemContext represents the filesystem-related context for a session. This includes project paths, working directories, and worktree information.

func (*FilesystemContext) IsEmpty

func (f *FilesystemContext) IsEmpty() bool

IsEmpty returns true if the FilesystemContext has no meaningful data

type ForceReleaseFunc added in v1.35.0

type ForceReleaseFunc func()

ForceReleaseFunc marks an unconditional-teardown closure: evicts regardless of refcount. No wrapper of ForceRelease exists in this plan — ForceRelease is always called directly with a sessionID. This type exists so that if a future caller wraps ForceRelease into a closure, the return type says so explicitly instead of degrading to a bare func().

type GitContext

type GitContext struct {
	// Branch is the current git branch name
	Branch string `json:"branch,omitempty"`

	// BaseCommitSHA is the commit SHA where this branch diverged from main/master
	BaseCommitSHA string `json:"base_commit_sha,omitempty"`

	// WorktreeID is a foreign key to the worktrees table (nil if no worktree)
	WorktreeID *int64 `json:"worktree_id,omitempty"`

	// PRNumber is the pull request number
	PRNumber int `json:"pr_number,omitempty"`

	// PRURL is the full URL to the pull request
	PRURL string `json:"pr_url,omitempty"`

	// Owner is the GitHub repository owner/organization
	Owner string `json:"owner,omitempty"`

	// Repo is the GitHub repository name
	Repo string `json:"repo,omitempty"`

	// SourceRef is the source branch reference for the PR
	SourceRef string `json:"source_ref,omitempty"`
}

GitContext represents the Git-related context for a session. This includes repository information, branch details, and GitHub PR integration.

func (*GitContext) IsEmpty

func (g *GitContext) IsEmpty() bool

IsEmpty returns true if the GitContext has no meaningful data

type GitHubIntegration added in v1.35.0

type GitHubIntegration struct {
	// Repository identity and PR linkage
	GitHubPRNumber  int
	GitHubPRURL     string
	GitHubOwner     string
	GitHubRepo      string
	GitHubSourceRef string
	ClonedRepoPath  string
	MainRepoPath    string
	IsWorktree      bool
	GitHubIsFork    bool

	// PR status fields (populated by PRStatusPoller)
	GitHubPRState          string
	GitHubPRIsDraft        bool
	GitHubPRPriority       string
	GitHubApprovedCount    int
	GitHubChangesReqCount  int
	GitHubCheckConclusion  string
	GitHubPRStatusTerminal bool
	LastPRStatusCheck      time.Time
}

GitHubIntegration groups all GitHub PR / URL integration fields within InstanceSnapshot (CDD Epic 3, Task 3.1a). Access via snap.GitHub.GitHubPRURL etc.

type GitHubIssuesPlugin added in v1.35.0

type GitHubIssuesPlugin struct{}

GitHubIssuesPlugin fetches backlog items from a GitHub repository's issue tracker.

func NewGitHubIssuesPlugin added in v1.35.0

func NewGitHubIssuesPlugin() *GitHubIssuesPlugin

NewGitHubIssuesPlugin returns a new GitHubIssuesPlugin.

func (*GitHubIssuesPlugin) Fetch added in v1.35.0

func (g *GitHubIssuesPlugin) Fetch(ctx context.Context, config PluginConfig, cursor string) ([]ExternalItem, string, error)

Fetch retrieves new and updated GitHub issues since the cursor. The cursor is an ISO 8601 timestamp passed as the `since` query parameter. Returns the updated cursor (the most recent updated_at seen) and the fetched items. If the token field is empty, Fetch returns an empty list and the original cursor.

func (*GitHubIssuesPlugin) MapToBacklogItem added in v1.35.0

func (g *GitHubIssuesPlugin) MapToBacklogItem(item ExternalItem, sourceID string) BacklogItemData

MapToBacklogItem converts a GitHub ExternalItem to a BacklogItemData.

func (*GitHubIssuesPlugin) PluginID added in v1.35.0

func (g *GitHubIssuesPlugin) PluginID() string

PluginID returns the unique identifier for this plugin.

type GitHubMetadataView

type GitHubMetadataView struct {
	PRNumber       int
	PRURL          string
	Owner          string
	Repo           string
	SourceRef      string
	ClonedRepoPath string
}

GitHubMetadataView is a read-only value object for GitHub session metadata. Constructed by Instance.GitHub() from the underlying fields. This is intentionally a value type (not a pointer) for safe concurrent reads.

func (GitHubMetadataView) IsEmpty

func (gh GitHubMetadataView) IsEmpty() bool

IsEmpty returns true if no GitHub metadata is set.

func (GitHubMetadataView) IsGitHubSession

func (gh GitHubMetadataView) IsGitHubSession() bool

IsGitHubSession returns true if owner and repo are both set.

func (GitHubMetadataView) IsPRSession

func (gh GitHubMetadataView) IsPRSession() bool

IsPRSession returns true if this metadata represents a PR-based session.

func (GitHubMetadataView) PRDisplayInfo

func (gh GitHubMetadataView) PRDisplayInfo() string

PRDisplayInfo returns human-readable PR description for UI display. Returns empty string if not a PR session.

func (GitHubMetadataView) RepoFullName

func (gh GitHubMetadataView) RepoFullName() string

RepoFullName returns "owner/repo" format, or empty string if either is missing.

type GitHubPRsPlugin added in v1.35.0

type GitHubPRsPlugin struct{}

GitHubPRsPlugin fetches open pull requests from a GitHub repository.

func NewGitHubPRsPlugin added in v1.35.0

func NewGitHubPRsPlugin() *GitHubPRsPlugin

NewGitHubPRsPlugin returns a new GitHubPRsPlugin.

func (*GitHubPRsPlugin) Fetch added in v1.35.0

func (g *GitHubPRsPlugin) Fetch(ctx context.Context, config PluginConfig, cursor string) ([]ExternalItem, string, error)

Fetch retrieves open pull requests. Cursor is unused (full refresh each time). Returns empty list when token is absent.

func (*GitHubPRsPlugin) MapToBacklogItem added in v1.35.0

func (g *GitHubPRsPlugin) MapToBacklogItem(item ExternalItem, sourceID string) BacklogItemData

MapToBacklogItem converts a GitHub PR ExternalItem to a BacklogItemData.

func (*GitHubPRsPlugin) PluginID added in v1.35.0

func (g *GitHubPRsPlugin) PluginID() string

PluginID returns the unique identifier for this plugin.

type GitHubRef

type GitHubRef struct {
	Owner    string
	Repo     string
	Branch   string
	PRNumber int
	Type     GitHubRefType
}

GitHubRef represents a parsed GitHub reference.

func ParseGitHubURL

func ParseGitHubURL(input string) (*GitHubRef, error)

ParseGitHubURL parses a GitHub URL and returns the components. Supported formats:

func ResolveGitHubInput

func ResolveGitHubInput(input string) (localPath string, ref *GitHubRef, err error)

ResolveGitHubInput is a convenience function using the default manager.

type GitHubRefType

type GitHubRefType int

GitHubRefType indicates what kind of GitHub reference this is.

const (
	GitHubRefTypeRepo GitHubRefType = iota
	GitHubRefTypeBranch
	GitHubRefTypePR
)

type GitManager added in v1.15.0

type GitManager interface {
	HasWorktree() bool
	GetWorktree() *git.GitWorktree
	SetWorktree(*git.GitWorktree)
	GetWorktreePath() string
	GetRepoPath() string
	GetRepoName() string
	GetBranchName() string
	GetBaseCommitSHA() string
	Setup() error
	Cleanup() error
	Remove() error
	Prune() error
	IsDirty() (bool, error)
	InvalidateDirtyCache()
	CommitChanges(commitMsg string) error
	PushChanges(commitMsg string, open bool) error
	IsBranchCheckedOut() (bool, error)
	OpenBranchURL() error
	ComputeDiffIfReady() (stats *git.DiffStats, needsPause bool)
	ComputeDiff() *git.DiffStats
	UpdateDiffStats()
	GetDiffStats() *git.DiffStats
	SetDiffStats(*git.DiffStats)
	ClearDiffStats()
	GetCurrentCommitSHA() (string, error)
	PrimeDirtyCacheJitter()
}

GitManager is the interface satisfied by *GitWorktreeManager. It covers all git worktree operations used by Instance and can be implemented by test doubles to avoid requiring a real git repository.

type GitWorktreeData

type GitWorktreeData struct {
	RepoPath      string `json:"repo_path"`
	WorktreePath  string `json:"worktree_path"`
	SessionName   string `json:"session_name"`
	BranchName    string `json:"branch_name"`
	BaseCommitSHA string `json:"base_commit_sha"`
}

GitWorktreeData represents the serializable data of a GitWorktree

type GitWorktreeManager

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

GitWorktreeManager owns the git worktree and diff-stats state that were previously bare fields on Instance.

Instance keeps thin wrapper methods that delegate here. GitWorktreeManager itself has no knowledge of Instance lifecycle; it only manages the worktree and diff operations.

func (*GitWorktreeManager) Cleanup

func (gm *GitWorktreeManager) Cleanup() error

Cleanup removes the worktree from the filesystem and git metadata. Returns nil if no worktree is set.

func (*GitWorktreeManager) ClearDiffStats

func (gm *GitWorktreeManager) ClearDiffStats()

ClearDiffStats sets diffStats to nil.

func (*GitWorktreeManager) CommitChanges

func (gm *GitWorktreeManager) CommitChanges(commitMsg string) error

CommitChanges stages all changes and creates a commit.

func (*GitWorktreeManager) ComputeDiff

func (gm *GitWorktreeManager) ComputeDiff() *git.DiffStats

ComputeDiff runs git diff and returns the result without storing it. Returns nil if no worktree is set.

func (*GitWorktreeManager) ComputeDiffIfReady

func (gm *GitWorktreeManager) ComputeDiffIfReady() (stats *git.DiffStats, needsPause bool)

ComputeDiffIfReady checks if the worktree path exists and computes a new diff. Returns (stats, needsPause) where needsPause is true if the worktree directory is missing. This method performs I/O and should be called WITHOUT holding Instance.mu. Returns (nil, false) if no worktree is set.

func (*GitWorktreeManager) GetBaseCommitSHA

func (gm *GitWorktreeManager) GetBaseCommitSHA() string

GetBaseCommitSHA returns the base commit SHA or "" if no worktree.

func (*GitWorktreeManager) GetBranchName

func (gm *GitWorktreeManager) GetBranchName() string

GetBranchName returns the branch name or "" if no worktree.

func (*GitWorktreeManager) GetCurrentCommitSHA

func (gm *GitWorktreeManager) GetCurrentCommitSHA() (string, error)

GetCurrentCommitSHA returns the current HEAD commit SHA for the worktree. Returns an empty string (not an error) if no worktree is set or the repo has no commits yet — this is safe to use in checkpoint creation.

func (*GitWorktreeManager) GetDiffStats

func (gm *GitWorktreeManager) GetDiffStats() *git.DiffStats

GetDiffStats returns the most recently computed diff stats (may be nil).

func (*GitWorktreeManager) GetRepoName

func (gm *GitWorktreeManager) GetRepoName() string

GetRepoName returns the repository name or "" if no worktree.

func (*GitWorktreeManager) GetRepoPath

func (gm *GitWorktreeManager) GetRepoPath() string

GetRepoPath returns the repo root path or "" if no worktree.

func (*GitWorktreeManager) GetWorktree

func (gm *GitWorktreeManager) GetWorktree() *git.GitWorktree

GetWorktree returns the underlying GitWorktree (may be nil before Setup).

func (*GitWorktreeManager) GetWorktreePath

func (gm *GitWorktreeManager) GetWorktreePath() string

GetWorktreePath returns the worktree path or "" if no worktree.

func (*GitWorktreeManager) HasWorktree

func (gm *GitWorktreeManager) HasWorktree() bool

HasWorktree reports whether a git worktree has been initialized.

func (*GitWorktreeManager) InvalidateDirtyCache added in v1.35.0

func (gm *GitWorktreeManager) InvalidateDirtyCache()

InvalidateDirtyCache clears the IsDirty TTL cache so the next call re-runs git status. Call after transitions that may change worktree dirty state (Resume, Stop). No-op if no worktree is set.

func (*GitWorktreeManager) IsBranchCheckedOut

func (gm *GitWorktreeManager) IsBranchCheckedOut() (bool, error)

IsBranchCheckedOut reports whether the branch is currently checked out.

func (*GitWorktreeManager) IsDirty

func (gm *GitWorktreeManager) IsDirty() (bool, error)

IsDirty reports whether the worktree has uncommitted changes.

func (*GitWorktreeManager) OpenBranchURL

func (gm *GitWorktreeManager) OpenBranchURL() error

OpenBranchURL opens the branch URL in the browser.

func (*GitWorktreeManager) PrimeDirtyCacheJitter added in v1.35.0

func (gm *GitWorktreeManager) PrimeDirtyCacheJitter()

PrimeDirtyCacheJitter staggers the dirty-cache TTL by setting the cache timestamp to a random point in [now-15s, now). Call this when adding a session to the poller so sessions added in a burst don't all run git-status subprocesses simultaneously when their caches expire.

func (*GitWorktreeManager) Prune

func (gm *GitWorktreeManager) Prune() error

Prune cleans up stale worktree references.

func (*GitWorktreeManager) PushChanges

func (gm *GitWorktreeManager) PushChanges(commitMsg string, open bool) error

PushChanges commits and pushes the worktree branch.

func (*GitWorktreeManager) Remove

func (gm *GitWorktreeManager) Remove() error

Remove removes the worktree from git without pruning.

func (*GitWorktreeManager) SetDiffStats

func (gm *GitWorktreeManager) SetDiffStats(stats *git.DiffStats)

SetDiffStats directly replaces the diff stats (used during deserialization).

func (*GitWorktreeManager) SetWorktree

func (gm *GitWorktreeManager) SetWorktree(wt *git.GitWorktree)

SetWorktree replaces the underlying GitWorktree. Used during session start and by tests.

func (*GitWorktreeManager) Setup

func (gm *GitWorktreeManager) Setup() error

Setup prepares the worktree (creates directories, checks out branch, etc.).

func (*GitWorktreeManager) UpdateDiffStats

func (gm *GitWorktreeManager) UpdateDiffStats()

UpdateDiffStats computes a new diff and stores it. Returns nil and clears stats if worktree is not ready.

type HeadlessPoolClient added in v1.35.0

type HeadlessPoolClient interface {
	CallBlockingWithOptions(ctx context.Context, key headless.FeatureKey, systemPrompt string, userPrompt string, opts headless.CallOptions) (string, error)
}

HeadlessPoolClient is the narrow interface AutonomousDriver needs from the headless pool. *headless.Pool satisfies this interface directly.

type HeadlessTriageResult added in v1.35.0

type HeadlessTriageResult struct {
	Summary     string             `json:"summary"`
	Suggestions []TriageSuggestion `json:"suggestions"`
	Tasks       []TriageTask       `json:"tasks,omitempty"`
}

HeadlessTriageResult is the parsed output from a headless triage LLM call.

func ParseHeadlessTriageResult added in v1.35.0

func ParseHeadlessTriageResult(raw string) (HeadlessTriageResult, error)

ParseHeadlessTriageResult unmarshals an LLM JSON response into HeadlessTriageResult. Tolerates preamble text before the JSON block (e.g. "Here is the result:\n\n{...}") and stray unrelated braces earlier in the response (e.g. an illustrative snippet).

The triage prompt instructs the model to emit the JSON object last, so candidates are tried from the end of the response backwards — the first candidate (i.e. the last brace-delimited span in raw) that unmarshals cleanly wins. This correctly skips over any earlier decoy object that happens to also be syntactically valid JSON but isn't the real result.

Caps tasks at maxHeadlessTriageTasks.

type HealthCheckResult

type HealthCheckResult struct {
	InstanceTitle     string
	IsHealthy         bool
	Issues            []string
	Actions           []string
	RecoveryAttempted bool
	RecoverySuccess   bool
}

HealthCheckResult represents the result of a session health check

type HibernationSweeper added in v1.35.0

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

HibernationSweeper periodically checks all sessions and hibernates those that have been idle longer than the configured timeout or that are consuming memory while the system is under pressure.

func NewHibernationSweeper added in v1.35.0

func NewHibernationSweeper(storage *Storage, cfg *appconfig.Config, reader memory.Reader) *HibernationSweeper

NewHibernationSweeper creates a HibernationSweeper using the given storage, config, and memory reader.

func (*HibernationSweeper) GetCachedRSSMB added in v1.35.0

func (s *HibernationSweeper) GetCachedRSSMB(sessionUUID string) int64

GetCachedRSSMB returns the last-measured RSS in MB for the given session UUID. Returns 0 if not yet measured or entry expired. Implements MemoryCacheReader.

func (*HibernationSweeper) SetLiveProvider added in v1.35.0

func (s *HibernationSweeper) SetLiveProvider(p LiveInstancesProvider)

SetLiveProvider wires the fast-path instance source. Call this after constructing the ReviewQueuePoller so that sweep() uses live in-memory instances instead of calling LoadInstances() (which spawns PTY/tmux subprocesses).

func (*HibernationSweeper) Start added in v1.35.0

func (s *HibernationSweeper) Start(ctx context.Context)

Start runs the periodic sweep loop. Blocks until ctx is cancelled.

func (*HibernationSweeper) SystemMemoryPct added in v1.35.0

func (s *HibernationSweeper) SystemMemoryPct() (float64, error)

SystemMemoryPct returns the current system memory usage percentage. The result is cached for sysMemCacheTTL to avoid a syscall on every ListSessions request. The mutex is released before calling the reader to avoid holding the lock during /proc I/O. Implements MemoryCacheReader.

type HistoryAdapter added in v1.35.0

type HistoryAdapter interface {
	Name() string
	CanHandle(program string) bool

	// Import reads this CLI's native format and returns canonical turns.
	Import(ctx context.Context, inst *Instance) ([]CanonicalTurn, error)

	// Export writes canonical turns into this CLI's native format so it can resume.
	Export(ctx context.Context, turns []CanonicalTurn, inst *Instance) error
}

type HistoryEntry

type HistoryEntry struct {
	Command       Command          `json:"command"`
	Result        *ExecutionResult `json:"result,omitempty"`
	Timestamp     time.Time        `json:"timestamp"`
	SessionName   string           `json:"session_name"`
	ExecutionTime time.Duration    `json:"execution_time"`
}

HistoryEntry represents a single command execution in history.

type HistoryFileDetector

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

HistoryFileDetector detects Claude JSONL history files for a given process.

func NewHistoryFileDetector

func NewHistoryFileDetector(inspector ProcessFileInspector) *HistoryFileDetector

NewHistoryFileDetector creates a new HistoryFileDetector.

func NewHistoryFileDetectorWithHomeDir added in v1.12.0

func NewHistoryFileDetectorWithHomeDir(inspector ProcessFileInspector, homeDir string) *HistoryFileDetector

NewHistoryFileDetectorWithHomeDir creates a HistoryFileDetector with a fixed home directory. Use this in tests to avoid writing to the real home dir.

func NewHistoryFileDetectorWithRealInspector

func NewHistoryFileDetectorWithRealInspector() *HistoryFileDetector

NewHistoryFileDetectorWithRealInspector creates a HistoryFileDetector using the real gopsutil-based ProcessInspector on darwin.

func (*HistoryFileDetector) Detect

func (d *HistoryFileDetector) Detect(pid int32) (*HistoryFileInfo, error)

Detect scans the open files of the given PID for Claude JSONL history files. Returns nil, nil if no matching file is found or the process is dead.

func (*HistoryFileDetector) DetectByPath added in v1.12.0

func (d *HistoryFileDetector) DetectByPath(projectPath string) (*HistoryFileInfo, error)

DetectByPath scans ~/.claude/projects/<encoded-path>/ for the most recently modified conversation JSONL file. It does NOT require a live process, making it suitable for sessions whose tmux session is dead (e.g. after a reboot).

Returns nil, nil if the project directory does not exist or contains no valid conversation files.

type HistoryFileInfo

type HistoryFileInfo struct {
	ConversationUUID string
	HistoryFilePath  string
	ProjectDir       string
}

HistoryFileInfo contains information about a detected Claude history file.

type HistoryFileWatcher

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

HistoryFileWatcher watches ~/.claude/projects/ for new JSONL files.

func NewHistoryFileWatcher

func NewHistoryFileWatcher(watchDir string, callback func(filePath string)) *HistoryFileWatcher

NewHistoryFileWatcher creates a watcher for the given directory. If watchDir is empty, defaults to ~/.claude/projects/.

func (*HistoryFileWatcher) Start

func (w *HistoryFileWatcher) Start(ctx context.Context) error

Start begins watching the directory. It returns without error even if the directory does not exist (degraded mode — polling fallback still works).

func (*HistoryFileWatcher) Stop

func (w *HistoryFileWatcher) Stop()

Stop closes the watcher.

func (*HistoryFileWatcher) Stopped added in v1.35.0

func (w *HistoryFileWatcher) Stopped() <-chan struct{}

Stopped returns a channel that is closed when the watcher goroutine has exited.

type HistoryLinker

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

HistoryLinker is a background service that correlates running sessions with their Claude JSONL history files. It populates Instance.claudeSession.ConversationUUID and Instance.HistoryFilePath when a conversation file is detected.

Detection uses two complementary paths:

  • Polling (every 5 s): scans all running sessions via proc_pidinfo open-files
  • fsnotify (fast path): watcher callback fires as soon as a new JSONL is created

Both paths call the same correlateSession helper, which is idempotent. Sessions that repeatedly yield no JSONL file are throttled via exponential backoff to reduce subprocess spawn rate on idle worktrees.

func NewHistoryLinker

func NewHistoryLinker(detector *HistoryFileDetector, watcher *HistoryFileWatcher) *HistoryLinker

NewHistoryLinker creates a HistoryLinker backed by the given detector and watcher. Call SetInstances (or AddInstance) to register sessions before starting.

func NewHistoryLinkerFromRealInspector added in v1.8.0

func NewHistoryLinkerFromRealInspector() *HistoryLinker

NewHistoryLinkerFromRealInspector creates a HistoryLinker backed by the real gopsutil-based process inspector and an fsnotify watcher on ~/.claude/projects/. This is the production constructor; use NewHistoryLinker in tests.

func (*HistoryLinker) AddInstance

func (hl *HistoryLinker) AddInstance(instance *Instance)

AddInstance adds a single instance for monitoring.

func (*HistoryLinker) Instances added in v1.8.0

func (hl *HistoryLinker) Instances() []*Instance

Instances returns a snapshot of the currently monitored instances. Used by shutdown hooks that need the live set (including externally added sessions).

func (*HistoryLinker) RegisterFileCallback added in v1.35.0

func (hl *HistoryLinker) RegisterFileCallback(cb func(filePath string))

RegisterFileCallback registers a callback that receives the file path whenever a JSONL history file is created or modified. Used to wire the TokenStore into the existing fsnotify infrastructure without creating a second watcher.

func (*HistoryLinker) RemoveInstance

func (hl *HistoryLinker) RemoveInstance(title string)

RemoveInstance stops monitoring the named instance.

func (*HistoryLinker) ScanAll

func (hl *HistoryLinker) ScanAll()

ScanAll triggers an immediate correlation pass over all monitored instances, including those already linked to a UUID. Exported for use by HistoryFileWatcher callbacks and called on startup. Resets backoffs and force-rechecks all sessions so that UUID changes (e.g., /clear creating a new conversation) are detected promptly rather than waiting for the next cold restore.

func (*HistoryLinker) SetInstances

func (hl *HistoryLinker) SetInstances(instances []*Instance)

SetInstances replaces the full instance list.

func (*HistoryLinker) Start

func (hl *HistoryLinker) Start(ctx context.Context)

Start performs an initial synchronous scan and then runs a background poll loop until ctx is cancelled. The fsnotify watcher is also started here so that new JSONL files trigger instant correlation.

type HistoryStatistics

type HistoryStatistics struct {
	TotalCommands        int
	SuccessfulCommands   int
	FailedCommands       int
	CancelledCommands    int
	AverageExecutionTime time.Duration
	FirstCommandTime     time.Time
	LastCommandTime      time.Time
}

HistoryStatistics provides summary statistics about command history.

type Instance

type Instance struct {
	// ID is the stable, immutable identifier for this instance.
	// Set once at creation; never changes even if Title is renamed.
	// Falls back to Title when empty for backward compatibility.
	ID string
	// Title is the title of the instance.
	Title string
	// UUID is a stable unique identifier for this instance, generated at creation time.
	// Unlike Title, UUID does not change when the session is renamed.
	UUID string
	// Path is the path to the workspace repository root.
	Path string
	// WorkingDir is the directory within the repository to start in.
	WorkingDir string
	// Branch is the branch of the instance.
	Branch string
	// Status is the status of the instance.
	Status Status
	// Program is the program to run in the instance.
	Program string
	// Height is the height of the instance.
	Height int
	// Width is the width of the instance.
	Width int
	// CreatedAt is the time the instance was created.
	CreatedAt time.Time
	// UpdatedAt is the time the instance was last updated.
	UpdatedAt time.Time
	// AutoYes is true if the instance should automatically press enter when prompted.
	AutoYes bool
	// Prompt is passed as a CLI argument to the program at process-spawn time (buildClaudeCommand),
	// so it only takes effect on a truly fresh spawn (claudeSessionID == "", no --resume) or OneShot.
	// Use for content that must exist before the process's first turn, e.g. backlog task context.
	// See InitialPrompt for the tmux-typed alternative — the two are independent and can both be
	// set on the same instance (e.g. Omnibar sends attachments via Prompt, typed text via InitialPrompt).
	Prompt string
	// InitialPrompt, unlike Prompt, is typed into the tmux pane as simulated keystrokes once the
	// session reaches Ready state (session_driver.go) — the only delivery path that works for
	// resuming/attaching to an already-running pane, where a CLI arg can't be injected after the
	// fact. Replaces the static driverInitialPrompt when non-empty.
	InitialPrompt string
	// ExistingWorktree is an optional path to an existing worktree to reuse
	ExistingWorktree string
	// Category is used for organizing sessions into groups
	Category string
	// IsExpanded indicates whether this session's category is expanded in the UI
	IsExpanded bool
	// SessionType determines the session workflow (directory, new_worktree, existing_worktree)
	SessionType SessionType
	// CreateIfMissing: when SessionTypeDirectory, create the directory and run git init
	// if the path does not exist. Set from the request's create_if_missing field.
	// Not persisted — only relevant during initial session start.
	CreateIfMissing bool `json:"-"`
	// TmuxPrefix is the prefix to use for tmux session names
	TmuxPrefix string
	// TmuxServerSocket is the server socket name for tmux isolation (used with -L flag)
	// If empty, uses the default tmux server. For complete isolation (e.g., testing),
	// set to a unique value like "test" or "teatest_123" to create separate tmux servers.
	TmuxServerSocket string
	// Tags are multi-valued labels for flexible session organization
	// Sessions can have multiple tags and appear in multiple groups simultaneously
	// Examples: ["frontend", "urgent", "client-work"]
	Tags []string
	// AutonomousMode enables autonomous Earpiece mode (crew autonomy).
	// When true, the Fixer will inject correction prompts without user confirmation.
	// When false (default), the session runs in supervised mode.
	AutonomousMode bool `json:"autonomous_mode,omitempty"`
	// AutonomousTurn is the current turn during an active autonomous run.
	AutonomousTurn int32 `json:"autonomous_turn,omitempty"`
	// AutonomousMaxTurns is the configured max turns for the current run.
	AutonomousMaxTurns int32 `json:"autonomous_max_turns,omitempty"`
	// AutonomousOutcome is the result of the last autonomous run: "", "done", or "stuck".
	AutonomousOutcome string `json:"autonomous_outcome,omitempty"`

	// GitHub integration fields for PR/URL-based session creation
	// GitHubPRNumber is the PR number if this session was created from a PR URL
	GitHubPRNumber int `json:"github_pr_number,omitempty"`
	// GitHubPRURL is the full URL to the PR on GitHub
	GitHubPRURL string `json:"github_pr_url,omitempty"`
	// GitHubOwner is the repository owner (user or organization)
	GitHubOwner string `json:"github_owner,omitempty"`
	// GitHubRepo is the repository name
	GitHubRepo string `json:"github_repo,omitempty"`
	// GitHubSourceRef is the original URL or reference used to create this session
	GitHubSourceRef string `json:"github_source_ref,omitempty"`
	// ClonedRepoPath is the path where we cloned the repo (if cloned)
	ClonedRepoPath string `json:"cloned_repo_path,omitempty"`
	// MainRepoPath is the path to the main repository when Path is a worktree
	// Detected automatically via `git rev-parse --git-common-dir`
	MainRepoPath string `json:"main_repo_path,omitempty"`
	// IsWorktree indicates whether Path is a git worktree (not the main repo)
	IsWorktree bool `json:"is_worktree,omitempty"`
	// GitHubIsFork is true when the remote repo is a fork (PR lookup uses upstream)
	GitHubIsFork bool `json:"github_is_fork,omitempty"`

	// PR status fields — populated by PRStatusPoller; not set on session creation
	// GitHubPRState is the PR lifecycle state: "open", "closed", "merged"
	GitHubPRState string `json:"github_pr_state,omitempty"`
	// GitHubPRIsDraft is true when the PR is in draft mode
	GitHubPRIsDraft bool `json:"github_pr_is_draft,omitempty"`
	// GitHubPRPriority is the derived priority: blocking/ready/pending/draft/complete/no_pr
	GitHubPRPriority string `json:"github_pr_priority,omitempty"`
	// GitHubApprovedCount is the count of current non-dismissed APPROVED reviews
	GitHubApprovedCount int `json:"github_approved_count,omitempty"`
	// GitHubChangesReqCount is the count of current non-dismissed CHANGES_REQUESTED reviews
	GitHubChangesReqCount int `json:"github_changes_req_count,omitempty"`
	// GitHubCheckConclusion is the CI rollup: success/failure/pending/action_required/neutral/""
	GitHubCheckConclusion string `json:"github_check_conclusion,omitempty"`
	// GitHubPRStatusTerminal is true when the PR is merged/closed and polling should stop
	GitHubPRStatusTerminal bool `json:"github_pr_status_terminal,omitempty"`
	// LastPRStatusCheck is when the PR status was last successfully fetched
	LastPRStatusCheck time.Time `json:"last_pr_status_check,omitempty"`

	Checkpoints      CheckpointList
	ActiveCheckpoint string
	ForkedFromID     string

	// OneShot runs claude in -p mode; the session exits after the task completes.
	OneShot bool

	// Hidden excludes this session from the default session list and review queue.
	// Set true for system/background sessions (triage, validation) that should not
	// appear in the user-facing session viewer.
	Hidden bool

	// ProjectID is the optional project this session belongs to.
	ProjectID string

	// HistoryFilePath is the path to the Claude conversation JSONL history file.
	// Set by HistoryLinker when it correlates this session to an open JSONL file.
	HistoryFilePath string

	// MCPServerURL is the URL of the stapler-squad HTTP MCP endpoint.
	// When set, passed as --mcp-config to claude on session start so no
	// settings-file injection is needed.
	MCPServerURL string `json:"mcp_server_url,omitempty"`

	// AppendSystemPrompt, when non-empty and the program is claude, passes
	// --append-system-prompt to inject extra instructions into the system prompt
	// without modifying any file on disk. Survives context compaction.
	AppendSystemPrompt string `json:"append_system_prompt,omitempty"`

	// AllowedTools, when non-empty, passes --allowedTools to claude to pre-approve
	// specific tool calls without requiring interactive permission prompts.
	// Format: "Bash,Read,Edit" or "Bash(git commit *),Read".
	AllowedTools string `json:"allowed_tools,omitempty"`

	// PermissionMode, when non-empty, passes --permission-mode to claude.
	// Values: "default", "acceptEdits", "bypassPermissions", "auto".
	PermissionMode string `json:"permission_mode,omitempty"`

	// CreationProgress holds a human-readable progress message during Creating state.
	// Set by the async creation goroutine; cleared once the session becomes Active.
	// Not persisted to the database — only meaningful in-memory during startup.
	CreationProgress string `json:"-"`

	// LaunchCommand is the full command passed to tmux on session start, including
	// any injected flags (--resume, --mcp-config, -y, initial prompt). Set once on
	// first start and updated on restart. Empty for external (mux-discovered) sessions.
	LaunchCommand string `json:"launch_command,omitempty"`

	// RateLimitAutoResume controls whether the rate-limit manager will automatically
	// send recovery input when a rate limit expires. Persisted so the setting survives
	// server restarts. Defaults to true (enabled) when zero value.
	RateLimitAutoResume *bool `json:"rate_limit_auto_resume,omitempty"`

	// PauseReason records why this session was paused. Use PauseReason* constants.
	// Empty when session has never been paused.
	PauseReason string `json:"pause_reason,omitempty"`

	// WorkflowID is the UUID of the Workflow that spawned this session.
	// Empty for manually-created sessions.
	WorkflowID string `json:"workflow_id,omitempty"`

	// EnvVars are session-level environment variables injected at tmux session creation.
	EnvVars map[string]string `json:"env_vars,omitempty"`
	// CLIFlags are additional CLI flags appended to the program launch command.
	CLIFlags string `json:"cli_flags,omitempty"`

	// ArchivedAt is set when the session is archived. Nil means not archived.
	ArchivedAt *time.Time `json:"archived_at,omitempty"`

	// ReviewState holds all review queue and terminal activity timestamps.
	// Fields are embedded (promoted) so external code can still access inst.LastViewed etc.
	// Protected by mu (via sendSyncErr / Snapshot).
	ReviewState

	// Instance type and management metadata
	// InstanceType indicates whether this is a squad-managed or external instance
	InstanceType InstanceType
	// IsManaged is true if this is a squad-managed session (backward compatible helper)
	IsManaged bool
	// ExternalMetadata contains additional information for externally discovered instances
	ExternalMetadata *ExternalInstanceMetadata
	// Permissions defines what operations are allowed on this instance
	Permissions InstancePermissions

	// Artifacts holds structured artifacts extracted from the session's JSONL history.
	// Populated asynchronously by ArtifactExtractor. Protected by mu.
	Artifacts *artifacts.SessionArtifactsBlob
	// contains filtered or unexported fields
}

Instance is a running instance of claude code.

func FromInstanceData

func FromInstanceData(data InstanceData) (*Instance, error)

FromInstanceData creates a new Instance from serialized data

func NewInstance

func NewInstance(opts InstanceOptions) (*Instance, error)

func NewInstanceWithCleanup

func NewInstanceWithCleanup(opts InstanceOptions) (*Instance, tmux.CleanupFunc, error)

NewInstanceWithCleanup creates a new Instance and returns it along with a cleanup function. Usage: instance, cleanup, err := NewInstanceWithCleanup(opts); if err == nil { defer cleanup() }

func SessionToInstance

func SessionToInstance(s *Session) *Instance

SessionToInstance converts a Session back to the legacy Instance type. This adapter enables interoperability during the migration period. Note: Some Session features (like CloudContext) don't have Instance equivalents.

func (*Instance) AddShellInMemory added in v1.35.0

func (i *Instance) AddShellInMemory(sh *Shell)

AddShellInMemory registers a pre-built Shell directly into the in-memory registry without spawning a tmux process. Used by ReconcileShells and by tests that need to inject shells into an Instance without going through the full SpawnShell / tmux path.

func (*Instance) AddTag

func (i *Instance) AddTag(tag string) error

AddTag adds a tag to the instance. Delegates to TagManager.Add. Returns ErrTagTooLong if the tag exceeds MaxTagLength, or ErrDuplicateTag if it already exists.

func (*Instance) Approve

func (i *Instance) Approve() error

Approve transitions the instance to Active (approval granted). Returns an error if the current state does not allow this transition.

func (*Instance) Attach

func (i *Instance) Attach() (chan struct{}, error)

Attach attaches to the tmux session and returns a done channel.

func (*Instance) CDPDisplayEnv added in v1.35.0

func (i *Instance) CDPDisplayEnv() []string

CDPDisplayEnv returns the extra environment variable strings to inject into the tmux session for CDP:

  • "CDP_PORT=<N>" — the allocated CDP debugging port
  • "PATH=<wrapperDir>:<original PATH>" — prepends the wrapper script dir so Chrome launcher scripts resolve to our wrappers, not the real binary

Returns nil if CDP is unavailable or if Allocate has not been called yet.

func (*Instance) CDPManager added in v1.35.0

func (i *Instance) CDPManager() CDPStreamManager

CDPManager returns the CDPStreamManager for this instance. Always non-nil after NewInstance() — returns a no-op manager when Chrome is unavailable.

func (*Instance) CaptureCurrentState

func (i *Instance) CaptureCurrentState() error

CaptureCurrentState records the pane's current working directory into WorkingDir. Called during graceful shutdown so cold restore can restart in the right directory. No-op if the session is not started, paused, or the tmux session is dead.

func (*Instance) CapturePaneContent

func (i *Instance) CapturePaneContent() (string, error)

CapturePaneContent captures the current visible tmux pane content. This is a simple wrapper around TmuxSession.CapturePaneContent() for compatibility with the terminal WebSocket handlers.

func (*Instance) CapturePaneContentRaw

func (i *Instance) CapturePaneContentRaw() (string, error)

CapturePaneContentRaw captures pane content with ANSI codes preserved (no line joining). Essential for hybrid streaming where cursor positioning codes must be preserved.

func (*Instance) CleanupWorktree

func (i *Instance) CleanupWorktree() error

CleanupWorktree removes the git worktree, keeping session intact.

func (*Instance) ClearConversationState added in v1.35.0

func (i *Instance) ClearConversationState()

ClearConversationState removes the stored Claude conversation UUID and history file path so that the next Resume starts a fresh conversation rather than attempting --resume with a potentially stale or path-mismatched UUID.

func (*Instance) ClosePR

func (i *Instance) ClosePR() error

ClosePR closes the PR without merging Returns an error if this is not a PR session or if the GitHub API call fails

func (*Instance) CreateCheckpoint

func (i *Instance) CreateCheckpoint(label string, scrollbackSeq uint64) (*Checkpoint, error)

CreateCheckpoint captures a named state bookmark for this session. scrollbackSeq should be the current scrollback high-water mark (from ScrollbackManager); pass 0 if the caller does not have access to scrollback state. Thread-safe: routed through the actor mailbox. Returns an error if the instance is not started.

func (*Instance) CurrentBranch added in v1.35.0

func (i *Instance) CurrentBranch() string

CurrentBranch returns the branch the session is currently on. For worktree sessions, it returns the stored Branch field (set at creation and on worktree changes). For directory sessions, Branch is never stored, so it reads the branch live from the working directory via git. Returns "" if the branch cannot be determined.

func (*Instance) DeleteShell added in v1.35.0

func (i *Instance) DeleteShell(ctx context.Context, shellID string) error

DeleteShell stops a shell (if running), waits for active handlers to drain, then removes it from memory and the database.

func (*Instance) Deny

func (i *Instance) Deny() error

Deny transitions the instance to Paused (approval denied). Returns an error if the current state does not allow this transition.

func (*Instance) Destroy

func (i *Instance) Destroy() error

Destroy completely destroys the instance - both tmux session and worktree

func (*Instance) DetectAndPopulateWorktreeInfo

func (i *Instance) DetectAndPopulateWorktreeInfo() error

DetectAndPopulateWorktreeInfo detects if the instance path is a worktree and populates the IsWorktree, MainRepoPath, GitHubOwner, and GitHubRepo fields. NOTE: This method writes to GitHub fields (i.GitHubOwner, i.GitHubRepo) directly. A future pass could route writes through a setter method for encapsulation. This is useful for sessions created from existing worktrees where we want to display the actual repository information in the UI.

IMPORTANT: For sessions with git worktrees, we check BOTH paths: 1. The worktree path (gitWorktree.GetWorktreePath()) - to detect IsWorktree and MainRepoPath 2. The original path (i.Path) - as fallback for GitHub owner/repo if worktree detection fails

This is necessary because: - i.Path is the main repository path (e.g., ~/Documents/personal-wiki) - gitWorktree.GetWorktreePath() is the actual worktree (e.g., ~/.stapler-squad/worktrees/...) - The main repo has .git as a directory; the worktree has .git as a file pointing to the main repo

func (*Instance) FireLifecycleEventForTest added in v1.35.0

func (i *Instance) FireLifecycleEventForTest(event LifecycleEvent, reason string)

FireLifecycleEventForTest is the exported version of fireLifecycleEvent, used exclusively in cross-package tests that need to simulate an unexpected exit.

func (*Instance) ForceStatus added in v1.35.0

func (i *Instance) ForceStatus(s Status)

ForceStatus sets the instance status directly without state machine validation. Only call from error recovery paths where the normal transition would itself fail (e.g. the async-creation goroutine cannot cleanly call Stop() because the session was never fully started). Callers must hold no locks.

func (*Instance) ForkFromCheckpoint

func (i *Instance) ForkFromCheckpoint(checkpointID, newTitle string, configDir string) (*Instance, error)

ForkFromCheckpoint creates a new, unstarted Instance that is an independent branch of i, seeded from the state captured at the checkpoint identified by checkpointID.

func (*Instance) GeneratePRContextPrompt

func (i *Instance) GeneratePRContextPrompt() (string, error)

GeneratePRContextPrompt generates a context prompt for Claude based on PR information This can be used to initialize a Claude Code session with comprehensive PR context Returns an error if this is not a PR session or if the GitHub API call fails

func (*Instance) GetCategoryPath

func (i *Instance) GetCategoryPath() []string

GetCategoryPath returns the category path as a slice of strings for nested category support Supports "Work/Frontend" syntax by splitting on "/" delimiter

func (*Instance) GetCheckpoints

func (i *Instance) GetCheckpoints() CheckpointList

GetCheckpoints returns a snapshot copy of the checkpoint list, safe for concurrent reads from outside the instance's lock domain.

func (*Instance) GetClaudeConversationUUID added in v1.35.0

func (i *Instance) GetClaudeConversationUUID() string

GetClaudeConversationUUID returns the stored Claude conversation UUID, empty if none. Thread-safe: acquires stateMutex read lock.

func (*Instance) GetClaudeSession

func (i *Instance) GetClaudeSession() *ClaudeSessionData

GetClaudeSession returns the Claude session data for this instance. Thread-safe: acquires stateMutex read lock.

func (*Instance) GetController

func (i *Instance) GetController() *ClaudeController

GetController returns the ClaudeController if one exists.

func (*Instance) GetConversationUUID

func (i *Instance) GetConversationUUID() string

GetConversationUUID returns the Claude conversation UUID, or "" if not linked. Thread-safe: acquires stateMutex read lock.

func (*Instance) GetCreatedAt added in v1.1.0

func (i *Instance) GetCreatedAt() time.Time

GetCreatedAt returns the time this instance was created. The field is immutable after creation.

func (*Instance) GetCurrentPaneContent

func (i *Instance) GetCurrentPaneContent(lines int) (string, error)

GetCurrentPaneContent captures the current visible tmux pane content. Delegates to processManager.CaptureViewport.

func (*Instance) GetDetectedContext added in v1.35.0

func (i *Instance) GetDetectedContext() string

GetDetectedContext returns the human-readable context string from the terminal detection layer. Returns an empty string when no controller is active or no context is available.

func (*Instance) GetDetectedStatus added in v1.35.0

func (i *Instance) GetDetectedStatus() detection.DetectedStatus

GetDetectedStatus returns the raw DetectedStatus from the terminal detection layer. Returns detection.StatusUnknown when no controller is active or no status has been detected. Use this for sub-status display; do not use for lifecycle decisions.

func (*Instance) GetDiffStats

func (i *Instance) GetDiffStats() *git.DiffStats

GetDiffStats returns the current git diff statistics.

func (*Instance) GetEffectiveRootDir

func (i *Instance) GetEffectiveRootDir() string

GetEffectiveRootDir returns the root directory where this session operates. For worktree sessions, this is the worktree path. For directory sessions, this is Path. Used for injecting configuration files (e.g., .claude/settings.local.json).

func (*Instance) GetEffectiveStatus

func (i *Instance) GetEffectiveStatus() Status

GetEffectiveStatus returns the most accurate status for this instance, combining the lifecycle status with real-time terminal detection when available. Unlike Status (which only reflects lifecycle transitions), this consults the ClaudeController's detected terminal state to surface NeedsApproval, Idle, etc.

func (*Instance) GetEscapeParser added in v1.35.0

func (i *Instance) GetEscapeParser() *analytics.EscapeCodeParser

GetEscapeParser returns the escape code parser from the session's response stream. Returns nil if the controller is not running or has no response stream.

func (*Instance) GetExitContent added in v1.15.0

func (i *Instance) GetExitContent() []byte

GetExitContent returns the last terminal bytes captured before the PTY exited. Returns nil if the controller is not running or no exit content was recorded.

func (*Instance) GetGitHubRepoFullName

func (i *Instance) GetGitHubRepoFullName() string

GetGitHubRepoFullName returns "owner/repo" format, or empty string. Delegates to GitHubMetadataView.RepoFullName.

func (*Instance) GetGitWorktree

func (i *Instance) GetGitWorktree() (*git.GitWorktree, error)

GetGitWorktree returns the git worktree for the instance.

func (*Instance) GetLifecycleStatus added in v1.35.0

func (i *Instance) GetLifecycleStatus() Status

GetLifecycleStatus returns the current lifecycle status as a typed Status value.

func (*Instance) GetPRComments

func (i *Instance) GetPRComments() ([]github.PRComment, error)

GetPRComments fetches all comments on the PR Returns an error if this is not a PR session or if the GitHub API call fails

func (*Instance) GetPRDiff

func (i *Instance) GetPRDiff() (string, error)

GetPRDiff fetches the diff for the PR Returns an error if this is not a PR session or if the GitHub API call fails

func (*Instance) GetPRDisplayInfo

func (i *Instance) GetPRDisplayInfo() string

GetPRDisplayInfo returns a human-readable PR description for UI display. Delegates to GitHubMetadataView.PRDisplayInfo.

func (*Instance) GetPTYReader

func (i *Instance) GetPTYReader() (*os.File, error)

GetPTYReader returns the PTY file handle for the tmux session.

func (*Instance) GetPaneCursorPosition

func (i *Instance) GetPaneCursorPosition() (x, y int, err error)

GetPaneCursorPosition gets the current cursor position in the tmux pane. Returns cursor X (column) and Y (row) coordinates, both 0-based.

func (*Instance) GetPaneDimensions

func (i *Instance) GetPaneDimensions() (width, height int, err error)

GetPaneDimensions gets the current dimensions of the tmux pane. Returns width (columns) and height (rows).

func (*Instance) GetPanePID

func (i *Instance) GetPanePID() (int32, error)

GetPanePID returns the PID of the foreground process in the tmux pane. The DoesSessionExist guard is omitted here: TmuxSession.GetPanePID already uses the CM fast path (no subprocess) and falls back to display-message which returns an error if the session is gone. Avoiding a separate list-sessions call per instance prevents N concurrent tmux list-sessions subprocesses during HistoryLinker.ScanAll.

func (*Instance) GetPermissions

func (i *Instance) GetPermissions() InstancePermissions

GetPermissions returns the permissions for this instance based on its type.

func (*Instance) GetRateLimitResetTime added in v1.35.0

func (i *Instance) GetRateLimitResetTime() time.Time

GetRateLimitResetTime returns the time when the rate limit is expected to reset. Returns zero time if no controller is active or no reset time is known.

func (*Instance) GetRateLimitState added in v1.12.0

func (i *Instance) GetRateLimitState() int

GetRateLimitState returns the current rate limit detection state.

func (*Instance) GetReviewItem

func (i *Instance) GetReviewItem() (*ReviewItem, bool)

GetReviewItem returns the review item for this instance if it exists.

func (*Instance) GetReviewQueue

func (i *Instance) GetReviewQueue() *ReviewQueue

GetReviewQueue returns the review queue for this instance.

func (*Instance) GetScrollbackHistory

func (i *Instance) GetScrollbackHistory(startLine, endLine string) (string, error)

GetScrollbackHistory captures scrollback history from tmux using line ranges. Uses tmux's native scrollback capabilities instead of stored sequences. startLine and endLine follow tmux conventions: negative numbers go back from current position, use "-" for the start/end of history.

func (*Instance) GetSessionGoal added in v1.35.0

func (i *Instance) GetSessionGoal() *SessionGoalData

GetSessionGoal returns a thread-safe shallow copy of the current SessionGoalData (nil if not set). A copy is returned so callers cannot mutate the shared struct.

func (*Instance) GetShellExitCh added in v1.35.0

func (i *Instance) GetShellExitCh(shellID string) (<-chan struct{}, bool)

GetShellExitCh returns a channel that is closed when the shell exits. Multiple callers can select on it without coordination (closed-channel fan-out).

func (*Instance) GetShellPTYReader added in v1.35.0

func (i *Instance) GetShellPTYReader(shellID string) (*os.File, error)

GetShellPTYReader returns the PTY for streaming shell output. Lazily attaches if not yet attached (ADR-3: lazy PTY attach).

func (*Instance) GetStableID added in v1.14.0

func (i *Instance) GetStableID() string

GetStableID returns a stable identifier for this instance. If UUID is set, returns it. Falls back to Title for backward compatibility with sessions that pre-date UUID assignment.

func (*Instance) GetStatus added in v1.12.0

func (i *Instance) GetStatus() int

GetStatus returns the current lifecycle status of this instance as an int. This is intentionally returns int to implement the SessionAccessor interface.

func (*Instance) GetStatusIconForType

func (i *Instance) GetStatusIconForType() string

GetStatusIconForType returns the appropriate status icon based on instance type.

func (*Instance) GetStatusManager

func (i *Instance) GetStatusManager() *InstanceStatusManager

GetStatusManager returns the status manager.

func (*Instance) GetTags

func (i *Instance) GetTags() []string

GetTags returns a copy of the instance's tags. Delegates to TagManager.All.

func (*Instance) GetTimeSinceLastMeaningfulOutput

func (i *Instance) GetTimeSinceLastMeaningfulOutput() time.Duration

GetTimeSinceLastMeaningfulOutput returns how long ago meaningful output was recorded. Fast path: reads the atomic shadow (no lock) once initialised via SyncAtomicTimestamps or UpdateTimestamps. Fallback: acquires stateMutex.RLock when the atomic is zero (before first write, or in tests that set LastMeaningfulOutput directly).

func (*Instance) GetTimeSinceLastTerminalUpdate

func (i *Instance) GetTimeSinceLastTerminalUpdate() time.Duration

GetTimeSinceLastTerminalUpdate delegates to ReviewState.TimeSinceLastTerminalUpdate. Falls back to time since creation if no terminal output has been recorded.

func (*Instance) GetTitle added in v1.1.0

func (i *Instance) GetTitle() string

GetTitle returns the session title/name.

func (*Instance) GetTmuxSession

func (i *Instance) GetTmuxSession() *tmux.TmuxSession

GetTmuxSession returns the underlying tmux session for direct access. Returns nil if the session hasn't been started yet or if the backend is not tmux.

func (*Instance) GetTmuxSessionName added in v1.15.0

func (i *Instance) GetTmuxSessionName() string

GetTmuxSessionName returns the sanitized tmux session name for reconciliation. Returns empty string for external or uninitialized sessions.

func (*Instance) GetTotalBytesWritten added in v1.35.0

func (i *Instance) GetTotalBytesWritten() int64

GetTotalBytesWritten returns the monotonic PTY byte offset from the session's circular buffer. This is the same counter used by Stage 1 analytics so Stage 2 session_seq values remain stable across WebSocket reconnections. Returns 0 if no controller is active or the buffer is unavailable.

func (*Instance) GetVCSInfo

func (i *Instance) GetVCSInfo() (*VCSInfo, error)

GetVCSInfo returns information about the VCS for this session

func (*Instance) GetWorkingDirectory

func (i *Instance) GetWorkingDirectory() string

GetWorkingDirectory returns the working directory for this instance.

func (*Instance) GitHub

func (i *Instance) GitHub() GitHubMetadataView

GitHub returns a read-only view of the GitHub metadata for this instance.

func (*Instance) HasClaudeSession

func (i *Instance) HasClaudeSession() bool

HasClaudeSession returns true if this instance has Claude session data. Thread-safe: acquires stateMutex read lock.

func (*Instance) HasGitHubPR added in v1.35.0

func (i *Instance) HasGitHubPR() bool

HasGitHubPR reports whether a GitHub PR has been associated with this session. Safe for use from any goroutine.

func (*Instance) HasGitWorktree

func (i *Instance) HasGitWorktree() bool

HasGitWorktree returns true if the instance has a git worktree.

func (*Instance) HasTag

func (i *Instance) HasTag(tag string) bool

HasTag returns true if the instance has the specified tag. Delegates to TagManager.Has.

func (*Instance) HasUpdated

func (i *Instance) HasUpdated() (updated bool, hasPrompt bool)

HasUpdated reports whether terminal content has changed since the last check. Returns (updated, hasPrompt) and side-effects terminal timestamps on change.

func (*Instance) Hibernate added in v1.35.0

func (i *Instance) Hibernate(ctx context.Context) error

Hibernate transitions an Active session to Hibernated. It transitions state and dispatches the heavy I/O to a goroutine.

func (*Instance) Hibernated added in v1.35.0

func (i *Instance) Hibernated() bool

Hibernated returns true if the instance is hibernated.

func (*Instance) IsActive added in v1.35.0

func (i *Instance) IsActive() bool

IsActive returns true if the instance has a live AI process.

func (*Instance) IsCreating added in v1.35.0

func (i *Instance) IsCreating() bool

IsCreating returns true if the instance is in the Creating state.

func (*Instance) IsGitHubSession

func (i *Instance) IsGitHubSession() bool

IsGitHubSession returns true if this session has GitHub owner and repo set. Delegates to GitHubMetadataView.IsGitHubSession.

func (*Instance) IsHibernated added in v1.35.0

func (i *Instance) IsHibernated() bool

IsHibernated returns true if the instance has been hibernated (checkpoint written, tmux killed).

func (*Instance) IsPRSession

func (i *Instance) IsPRSession() bool

IsPRSession returns true if this session was created from a GitHub PR URL. Delegates to GitHubMetadataView.IsPRSession.

func (*Instance) IsPaused added in v1.35.0

func (i *Instance) IsPaused() bool

IsPaused returns true if the instance is paused (worktree removed, branch preserved).

func (*Instance) IsRateLimitEnabled added in v1.12.0

func (i *Instance) IsRateLimitEnabled() bool

IsRateLimitEnabled returns whether rate limit auto-resume is enabled. Returns the persisted RateLimitAutoResume field (default: true when nil).

func (*Instance) IsStopped added in v1.35.0

func (i *Instance) IsStopped() bool

IsStopped returns true if the instance is in the terminal Stopped state.

func (*Instance) Kill

func (i *Instance) Kill() error

Kill terminates the instance and cleans up all resources Kill destroys both tmux session and worktree (legacy method)

func (*Instance) KillExternalSession

func (i *Instance) KillExternalSession() error

KillExternalSession terminates an external mux session by killing its tmux session. This only works for external sessions that were started via ssq-mux with tmux integration. Returns an error if this is not an external instance or lacks tmux session name.

func (*Instance) KillSession

func (i *Instance) KillSession() error

KillSession terminates the tmux session only (leaves worktree intact).

func (*Instance) KillSessionKeepWorktree

func (i *Instance) KillSessionKeepWorktree() error

KillSessionKeepWorktree terminates tmux session but preserves worktree for recovery scenarios.

func (*Instance) LastMeaningfulOutputTime added in v1.1.0

func (i *Instance) LastMeaningfulOutputTime() time.Time

LastMeaningfulOutputTime returns the time of the last meaningful terminal output.

func (*Instance) ListAvailableTargets

func (i *Instance) ListAvailableTargets() (*AvailableTargets, error)

ListAvailableTargets returns available switch targets (branches, bookmarks, worktrees)

func (*Instance) ListShellsInMemory added in v1.35.0

func (i *Instance) ListShellsInMemory() []*Shell

ListShellsInMemory returns in-memory shells sorted by OrderIndex.

func (*Instance) MarkAcknowledged added in v1.1.0

func (i *Instance) MarkAcknowledged()

MarkAcknowledged records that the user has acknowledged (dismissed) this session from the review queue.

func (*Instance) MarkNeedsApproval added in v1.1.0

func (i *Instance) MarkNeedsApproval() error

MarkNeedsApproval is a no-op: NeedsApproval is no longer a lifecycle state. Approval state is now tracked as sub-status via the detection layer. Deprecated: do not call from new code.

func (*Instance) MarkUserResponded added in v1.1.0

func (i *Instance) MarkUserResponded() time.Time

MarkUserResponded records that the user has responded to this session. Returns the timestamp that was set so callers can persist it without a second lock acquisition.

func (*Instance) MarkViewed added in v1.1.0

func (i *Instance) MarkViewed()

MarkViewed records that the user has viewed this session.

func (*Instance) MatchesID added in v1.18.0

func (i *Instance) MatchesID(id string) bool

MatchesID reports whether id refers to this instance. Accepts the stable UUID, the legacy Title, or the full tmux session name (e.g. "staplersquad_my-session") so that hook notifications sent from inside managed tmux sessions are correctly attributed to their human-readable session.

func (*Instance) MergePR

func (i *Instance) MergePR(method string) error

MergePR merges the PR using the specified merge method method can be: "merge", "squash", or "rebase" Returns an error if this is not a PR session or if the GitHub API call fails

func (*Instance) NeedsReview

func (i *Instance) NeedsReview() bool

NeedsReview returns true if this session is in the review queue.

func (*Instance) Pause

func (i *Instance) Pause() error

Pause stops the tmux session and removes the worktree, preserving the branch.

func (*Instance) Paused

func (i *Instance) Paused() bool

Paused returns true if the instance is paused.

func (*Instance) PostComment

func (i *Instance) PostComment(body string) error

PostComment posts a comment to the PR Returns an error if this is not a PR session or if the GitHub API call fails

func (*Instance) Preview

func (i *Instance) Preview() (string, error)

Preview returns the current visible terminal content. Prefers the in-memory PTY buffer from ClaudeController; falls back to capture-pane.

func (*Instance) PreviewFullHistory

func (i *Instance) PreviewFullHistory() (string, error)

PreviewFullHistory captures the entire tmux pane output including full scrollback history.

func (*Instance) ReconcileShells added in v1.35.0

func (i *Instance) ReconcileShells(ctx context.Context)

ReconcileShells is called after an Instance is loaded from ent on startup. It queries ent for shells marked "running" and checks whether their sibling tmux sessions still exist. Live sessions are rebuilt in memory (without PTY attach — lazy). Dead sessions are marked stopped in ent.

The map lock is never held during I/O: all subprocess calls and DB writes happen outside any map operation; each final map insert is an independent Store call that holds only the bucket lock for nanoseconds.

func (*Instance) RecoverFromStopped added in v1.23.1

func (i *Instance) RecoverFromStopped()

RecoverFromStopped resets a stale Stopped status to Creating so the instance can be hot-restored via Start(false). Only call this during startup reconciliation when the tmux session is confirmed alive; it bypasses the state machine intentionally. Deprecated: prefer transitionTo(ctx, Active) on the Stopped→Active path.

func (*Instance) RefreshPRInfo

func (i *Instance) RefreshPRInfo() (*github.PRInfo, error)

RefreshPRInfo fetches the latest PR information from GitHub Returns an error if this is not a PR session or if the GitHub API call fails

func (*Instance) RefreshTmuxClient

func (i *Instance) RefreshTmuxClient() error

RefreshTmuxClient forces the tmux client to refresh, triggering a redraw of the process running inside. This is critical after resizing to ensure cursor positions and line wrapping are recalculated for the new dimensions.

func (*Instance) RegisterLifecycleListener added in v1.15.0

func (i *Instance) RegisterLifecycleListener(l LifecycleListener)

RegisterLifecycleListener adds a listener that will receive EventStarted and EventExited notifications for this instance. The listener is called synchronously on the goroutine that fires the event; implementations must return quickly (no long blocking operations).

func (*Instance) RegisterStatusChangeCallback added in v1.35.0

func (i *Instance) RegisterStatusChangeCallback(fn func(detection.DetectedStatus, string))

RegisterStatusChangeCallback appends fn to the controller's fan-out listener set. Unlike SetStatusChangeCallback, it does not replace existing listeners. Safe to call before or after the controller is started.

func (*Instance) RemoveTag

func (i *Instance) RemoveTag(tag string)

RemoveTag removes a tag from the instance. Delegates to TagManager.Remove.

func (*Instance) Rename

func (i *Instance) Rename(newTitle string) error

Rename renames this session. Validates title constraints and updates UpdatedAt.

func (*Instance) RepoName

func (i *Instance) RepoName() (string, error)

RepoName returns the name of the git repository. Returns an error if the instance has not been started or has no worktree.

func (*Instance) ResizePTY

func (i *Instance) ResizePTY(cols, rows int) error

ResizePTY resizes the terminal dimensions. This is used when clients resize their terminal windows.

func (*Instance) Restart

func (i *Instance) Restart(preserveOutput bool) error

Restart restarts the session by killing and recreating the tmux session. The git worktree is preserved during restart. If preserveOutput is true, captures terminal output before killing the session. For Claude sessions, uses --resume flag with the stored session ID.

func (*Instance) RestartShell added in v1.35.0

func (i *Instance) RestartShell(ctx context.Context, shellID string) error

RestartShell stops a shell (if running) and relaunches it with the same command and workdir.

func (*Instance) Resume

func (i *Instance) Resume() error

Resume recreates the worktree and restarts the tmux session

func (*Instance) ResumeFromHibernation added in v1.35.0

func (i *Instance) ResumeFromHibernation(ctx context.Context) error

ResumeFromHibernation transitions a Hibernated session back to Active. The actual process re-launch happens asynchronously via resumeFromHibernationLocked.

func (*Instance) RunWithResume added in v1.35.0

func (i *Instance) RunWithResume(ctx context.Context, message string) (string, error)

RunWithResume spawns a new claude subprocess using --resume <uuid> and -p <message>, waits for completion, and returns the result text. Updates ConversationUUID on success.

func (*Instance) SendInputViaControlMode added in v1.35.0

func (i *Instance) SendInputViaControlMode(ctx context.Context, data []byte) error

SendInputViaControlMode sends raw bytes through the existing control mode connection, avoiding the subprocess spawn overhead and timeout risk of exec.CommandContext.

func (*Instance) SendKeys

func (i *Instance) SendKeys(keys string) error

SendKeys sends keys to the tmux session.

func (*Instance) SendPrompt

func (i *Instance) SendPrompt(prompt string) error

SendPrompt sends a prompt to the tmux session. Delegates to processManager.SendPromptWithEnter.

func (*Instance) SetArchivedAt added in v1.35.0

func (i *Instance) SetArchivedAt(t *time.Time)

SetArchivedAt sets or clears the ArchivedAt timestamp atomically. Pass nil to clear (unarchive).

func (*Instance) SetArchivedAtIfNil added in v1.35.0

func (i *Instance) SetArchivedAtIfNil(t time.Time) bool

SetArchivedAtIfNil sets ArchivedAt to t only if it is currently nil. Returns true if the value was set (CAS semantics). Now actor-routed.

func (*Instance) SetArtifacts added in v1.35.0

func (i *Instance) SetArtifacts(blob *artifacts.SessionArtifactsBlob)

SetArtifacts atomically updates the in-memory Artifacts cache.

func (*Instance) SetAutoYes added in v1.35.0

func (i *Instance) SetAutoYes(v bool)

SetAutoYes sets the AutoYes flag. Used by daemon.go to opt in automated sessions to non-interactive behaviour.

func (*Instance) SetAutonomousComplete added in v1.35.0

func (i *Instance) SetAutonomousComplete(done bool)

SetAutonomousComplete clears the autonomous-mode flag and turn counters, and records the outcome ("done" or "stuck") atomically.

func (*Instance) SetAutonomousMode added in v1.35.0

func (i *Instance) SetAutonomousMode(mode bool, outcome string)

SetAutonomousMode sets the autonomous mode flag and outcome string atomically. Pass outcome="" to clear it when enabling; the existing value is preserved unless explicitly overwritten by the caller.

func (*Instance) SetAutonomousTurn added in v1.35.0

func (i *Instance) SetAutonomousTurn(turn, maxTurns int32)

SetAutonomousTurn atomically updates the current turn counter and max-turns cap during an active autonomous run.

func (*Instance) SetCategory added in v1.35.0

func (i *Instance) SetCategory(category string)

SetCategory sets the session category.

func (*Instance) SetClaudeConversationUUID added in v1.35.0

func (i *Instance) SetClaudeConversationUUID(uuid string)

SetClaudeConversationUUID stores the Claude conversation UUID so it is used in subsequent --resume flags. Fires the claudeSessionIDSavedCallback if set. No-op (including callback) if uuid is unchanged.

func (*Instance) SetClaudeSession

func (i *Instance) SetClaudeSession(sessionData *ClaudeSessionData)

SetClaudeSession sets the Claude session data for this instance. Thread-safe: acquires stateMutex write lock.

func (*Instance) SetClaudeSessionIDSavedCallback added in v1.35.0

func (i *Instance) SetClaudeSessionIDSavedCallback(fn func())

SetClaudeSessionIDSavedCallback registers a callback that fires when SetClaudeConversationUUID is called. Used by the service layer to trigger a storage save when the session_id is discovered.

func (*Instance) SetCreationProgress added in v1.35.0

func (i *Instance) SetCreationProgress(msg string)

SetCreationProgress sets the human-readable creation progress message.

func (*Instance) SetGitHubPR added in v1.35.0

func (i *Instance) SetGitHubPR(prURL string, prNumber int)

SetGitHubPR atomically sets the GitHub PR URL and PR number discovered after a RunOneShot or PR-discovery poll. Pass prNumber=0 if not yet known.

func (*Instance) SetGitHubPRNumber added in v1.35.0

func (i *Instance) SetGitHubPRNumber(n int)

SetGitHubPRNumber atomically updates the in-memory GitHubPRNumber field. Replaces the stateMutex-based implementation; now actor-routed so it is serialised with buildSnapshot.

func (*Instance) SetGitWorktree

func (i *Instance) SetGitWorktree(worktree *git.GitWorktree)

SetGitWorktree sets the git worktree for testing purposes.

func (*Instance) SetHibernateReason added in v1.35.0

func (i *Instance) SetHibernateReason(reason string)

SetHibernateReason sets the reason string that will be recorded in the checkpoint. Must be called before Hibernate(). Values: "manual", "idle", "resource_pressure".

func (*Instance) SetHistoryInfo

func (i *Instance) SetHistoryInfo(conversationUUID, historyFilePath string)

SetHistoryInfo updates the conversation UUID and history file path. Thread-safe: acquires stateMutex write lock. No-op if the UUID is already set to the same value.

func (*Instance) SetLastAddedToQueue added in v1.35.0

func (i *Instance) SetLastAddedToQueue(t time.Time)

SetLastAddedToQueue records when this session was last added to the review queue.

func (*Instance) SetLastMeaningfulOutput added in v1.1.0

func (i *Instance) SetLastMeaningfulOutput(t time.Time)

SetLastMeaningfulOutput sets the time of the last meaningful terminal output.

func (*Instance) SetLastPRStatusCheck added in v1.35.0

func (i *Instance) SetLastPRStatusCheck(t time.Time)

SetLastPRStatusCheck records the time of the most recent PR-status fetch.

func (*Instance) SetMCPServerURL added in v1.35.0

func (i *Instance) SetMCPServerURL(url string)

SetMCPServerURL sets the MCP server URL on this instance.

func (*Instance) SetPauseReason added in v1.35.0

func (i *Instance) SetPauseReason(reason string)

SetPauseReason sets the reason this session was paused.

func (*Instance) SetPreviewSize

func (i *Instance) SetPreviewSize(width, height int) error

SetPreviewSize sets the detached terminal dimensions for preview rendering.

func (*Instance) SetProgram added in v1.35.0

func (i *Instance) SetProgram(program string)

SetProgram atomically updates the Program field during program-switch.

func (*Instance) SetRateLimitCallbacks added in v1.35.0

func (i *Instance) SetRateLimitCallbacks(
	onDetected func(sessionID string, resetTime time.Time),
	onRecovery func(sessionID string, success bool, errMsg string),
)

SetRateLimitCallbacks registers server-layer callbacks for rate limit events. onDetected is called when a rate limit is detected; onRecovery is called when recovery completes. Both are invoked from goroutines in the ratelimit package. Safe to call before or after the controller is started; callbacks are wired at controller start time via wireRateLimitCallbacks.

func (*Instance) SetRateLimitEnabled added in v1.12.0

func (i *Instance) SetRateLimitEnabled(enabled bool)

SetRateLimitEnabled enables or disables rate limit auto-resume. The setting is persisted in RateLimitAutoResume so it survives restarts, and is applied immediately to the running controller if one exists.

func (*Instance) SetReviewQueue

func (i *Instance) SetReviewQueue(queue *ReviewQueue)

SetReviewQueue sets the review queue for this instance.

func (*Instance) SetSessionGoalCached added in v1.35.0

func (i *Instance) SetSessionGoalCached(g *SessionGoalData)

SetSessionGoalCached atomically updates the in-memory sessionGoal cache.

func (*Instance) SetShellRepository added in v1.35.0

func (i *Instance) SetShellRepository(repo ShellRepository)

SetShellRepository injects the shell persistence backend. Called by Storage after loading or creating an instance. Pass nil to disable persistence (e.g., in tests).

func (*Instance) SetStatusChangeCallback added in v1.35.0

func (i *Instance) SetStatusChangeCallback(fn func(detection.DetectedStatus, string))

SetStatusChangeCallback registers fn to be called on every terminal status change detected by the ClaudeController. Safe to call before or after the controller is started; the callback is wired at controller start time via wireStatusChangeCallback.

func (*Instance) SetStatusManager

func (i *Instance) SetStatusManager(manager *InstanceStatusManager)

SetStatusManager sets the status manager for idle detection.

func (*Instance) SetTags

func (i *Instance) SetTags(tags []string) error

SetTags replaces all tags with a new deduplicated set. Delegates to TagManager.Set. Returns ErrTagTooLong on the first tag that exceeds MaxTagLength.

func (*Instance) SetTitle

func (i *Instance) SetTitle(title string) error

SetTitle sets the title of the instance. Returns an error if the instance has started. We can't change the title once it's been used for a tmux session etc.

func (*Instance) SetTitleDirect added in v1.35.0

func (i *Instance) SetTitleDirect(title string)

SetTitleDirect sets the Title field directly without tmux-session constraints. Use only from RPC handlers that have already validated uniqueness and title constraints (e.g. UpdateSession, RenameSession rollback).

func (*Instance) SetTmuxSession

func (i *Instance) SetTmuxSession(session *tmux.TmuxSession)

SetTmuxSession sets the tmux session for testing purposes.

func (*Instance) SetWindowSize

func (i *Instance) SetWindowSize(cols, rows int) error

SetWindowSize propagates window size changes to the tmux session. This enables proper terminal resizing in environments like IntelliJ where SIGWINCH doesn't work.

func (*Instance) SetWorkingDir added in v1.35.0

func (i *Instance) SetWorkingDir(dir string)

SetWorkingDir sets the working directory for this session.

func (*Instance) Snapshot added in v1.35.0

func (i *Instance) Snapshot() *InstanceSnapshot

Snapshot returns the most recently published atomic snapshot of this Instance's mutable fields. The returned pointer is never nil. Callers must not mutate the returned struct.

On the first call for an Instance that bypassed finishInstanceConstruction (e.g. struct literals in tests), the snapshot is built lazily under stateMutex and stored via CAS so concurrent first-callers converge on one value.

func (*Instance) SpawnShell added in v1.35.0

func (i *Instance) SpawnShell(ctx context.Context, req SpawnShellRequest) (*Shell, error)

SpawnShell creates and starts a new shell as an independent sibling tmux session. It persists the shell to the ent repository, registers it in memory, and launches the watchShellExit goroutine.

func (*Instance) Start

func (i *Instance) Start(firstTimeSetup bool) error

Start starts the instance by routing through the actor mailbox. firstTimeSetup is true if this is a new instance. Otherwise, it's one loaded from storage.

func (*Instance) StartControlMode added in v1.15.0

func (i *Instance) StartControlMode() error

StartControlMode starts the control mode stream on the underlying tmux session.

func (*Instance) StartController

func (i *Instance) StartController() error

StartController creates and starts a ClaudeController for this instance. The controller enables automated idle detection and queue management.

func (*Instance) StartWithCleanup

func (i *Instance) StartWithCleanup(firstTimeSetup bool) (tmux.CleanupFunc, error)

StartWithCleanup starts the instance and returns a cleanup function. Usage: cleanup, err := instance.StartWithCleanup(firstTimeSetup); if err == nil { defer cleanup() }

func (*Instance) Started

func (i *Instance) Started() bool

Started returns true if the instance has been started.

func (*Instance) StopControlMode added in v1.15.0

func (i *Instance) StopControlMode() error

StopControlMode stops the control mode stream.

func (*Instance) StopController

func (i *Instance) StopController()

StopController stops and cleans up the ClaudeController for this instance.

func (*Instance) StopShell added in v1.35.0

func (i *Instance) StopShell(ctx context.Context, shellID string) error

StopShell stops a running shell by setting status first (stop-while-streaming guard), then closing the handle.

func (*Instance) SubscribeControlModeUpdates added in v1.15.0

func (i *Instance) SubscribeControlModeUpdates() (string, <-chan []byte)

SubscribeControlModeUpdates returns a subscriber ID and a read-only output channel. Returns a pre-closed channel if the tmux session is not available.

func (*Instance) SwitchWorkspace

func (i *Instance) SwitchWorkspace(req WorkspaceSwitchRequest) (*WorkspaceSwitchResult, error)

SwitchWorkspace switches the session's workspace according to the request. For directory changes, this is a simple cd operation. For revision/worktree switches, this restarts Claude with --resume to preserve conversation.

func (*Instance) TapEnter

func (i *Instance) TapEnter()

TapEnter sends an enter key press to the tmux session if AutoYes is enabled.

func (*Instance) TmuxAlive

func (i *Instance) TmuxAlive() bool

TmuxAlive returns true if the tmux session is alive. This is a sanity check before attaching.

func (*Instance) TmuxSessionExists added in v1.23.1

func (i *Instance) TmuxSessionExists() bool

TmuxSessionExists reports whether the underlying tmux session is currently alive. Used at startup to reconcile stale Stopped status against live tmux sessions.

func (*Instance) ToInstanceData

func (i *Instance) ToInstanceData() InstanceData

ToInstanceData converts an Instance to its serializable form

func (*Instance) ToSession

func (i *Instance) ToSession() *Session

ToSession converts this Instance to the new Session type. This is a convenience method that wraps InstanceToSession.

func (*Instance) UnsubscribeControlModeUpdates added in v1.15.0

func (i *Instance) UnsubscribeControlModeUpdates(id string)

UnsubscribeControlModeUpdates removes a subscriber by ID.

func (*Instance) UpdateDiffStats

func (i *Instance) UpdateDiffStats() error

UpdateDiffStats updates the git diff statistics for this instance. Performs I/O (git diff) outside the lock, then updates state under the write lock.

func (*Instance) UpdatePRStatus added in v1.12.0

func (i *Instance) UpdatePRStatus(state, priority, checkConclusion string, approvedCount, changesReqCount int, isDraft, terminal bool) prUpdateResult

UpdatePRStatus atomically updates the PR status fields on this instance. Called by PRStatusPoller on each successful fetch. Returns prUpdateResult indicating whether the priority changed.

func (*Instance) UpdateTerminalTimestamps

func (i *Instance) UpdateTerminalTimestamps(content string, forceUpdate bool)

UpdateTerminalTimestamps is a coordinator method that bridges ProcessManager (I/O) with ReviewState (timestamp recording). It:

  1. Calls processManager.FilterBanners/HasMeaningfulContent (no lock needed, read-only ops)
  2. Acquires stateMutex
  3. Delegates to ReviewState.UpdateTimestamps

This method intentionally stays on Instance because it coordinates two sub-managers. The forceUpdate parameter bypasses meaningful content checking for user-initiated interactions.

func (*Instance) VNCDisplayEnv added in v1.35.0

func (i *Instance) VNCDisplayEnv() string

VNCDisplayEnv returns the DISPLAY environment variable assignment for this session's display, e.g. "DISPLAY=:101" or "DISPLAY=:0". Returns "" if no display is available (VNC unavailable or StartDisplay not yet called).

func (*Instance) VNCManager added in v1.35.0

func (i *Instance) VNCManager() VNCProcessManager

VNCManager returns the VNCProcessManager for this instance. Always non-nil — returns a no-op manager on unsupported platforms.

func (*Instance) Workspace added in v1.12.0

func (i *Instance) Workspace() Workspace

Workspace returns where this session is operating. Use this as the single source of truth for path resolution instead of accessing inst.Path directly, which is wrong for worktree sessions.

func (*Instance) WriteToPTY

func (i *Instance) WriteToPTY(data []byte) (int, error)

WriteToPTY writes data to the PTY, sending input to the terminal session. This is used for forwarding client input to the tmux session.

type InstanceAcquirer added in v1.35.0

type InstanceAcquirer interface {
	Acquire(sessionID string) (*LiveInstance, ReleaseFunc, error)
}

InstanceAcquirer is the narrowest interface for callers that only ever call Acquire. WorkspaceService, MCP tool handlers, and most RPC handlers should be typed against this rather than *Registry (Interface Segregation — matches WorkspaceService's existing LiveInstanceFinder convention).

type InstanceContext added in v1.1.0

type InstanceContext interface {
	GetTitle() string
	GetStableID() string
	GetPTYReader() (*os.File, error)
	Preview() (string, error)
	LastMeaningfulOutputTime() time.Time
	GetCreatedAt() time.Time
	SetLastMeaningfulOutput(t time.Time)
	GetStatus() int
	WriteToPTY(data []byte) (int, error)
}

InstanceContext is the narrow interface ClaudeController needs from its owning Instance. Using an interface breaks the bidirectional Instance ↔ ClaudeController dependency.

type InstanceData

type InstanceData struct {
	Title         string    `json:"title"`
	UUID          string    `json:"uuid,omitempty"`
	Path          string    `json:"path"`
	WorkingDir    string    `json:"working_dir"`
	Branch        string    `json:"branch"`
	Status        Status    `json:"status"`
	Height        int       `json:"height"`
	Width         int       `json:"width"`
	CreatedAt     time.Time `json:"created_at"`
	UpdatedAt     time.Time `json:"updated_at"`
	AutoYes       bool      `json:"auto_yes"`
	Prompt        string    `json:"prompt"`
	InitialPrompt string    `json:"initial_prompt,omitempty"`

	Program          string          `json:"program"`
	ExistingWorktree string          `json:"existing_worktree,omitempty"`
	Worktree         GitWorktreeData `json:"worktree"`
	DiffStats        DiffStatsData   `json:"diff_stats"`

	// New fields for session organization and grouping
	Category   string   `json:"category,omitempty"`
	IsExpanded bool     `json:"is_expanded,omitempty"`
	Tags       []string `json:"tags,omitempty"` // Multi-valued tags for flexible organization

	// Session type determines the workflow (directory, new_worktree, existing_worktree)
	SessionType SessionType `json:"session_type,omitempty"`

	// GitHub integration fields for PR/URL-based session creation
	GitHubPRNumber  int    `json:"github_pr_number,omitempty"`
	GitHubPRURL     string `json:"github_pr_url,omitempty"`
	GitHubOwner     string `json:"github_owner,omitempty"`
	GitHubRepo      string `json:"github_repo,omitempty"`
	GitHubSourceRef string `json:"github_source_ref,omitempty"`
	ClonedRepoPath  string `json:"cloned_repo_path,omitempty"`
	// Worktree detection fields
	MainRepoPath string `json:"main_repo_path,omitempty"` // Path to main repo when this is a worktree
	IsWorktree   bool   `json:"is_worktree,omitempty"`    // True if path is a git worktree
	GitHubIsFork bool   `json:"github_is_fork,omitempty"` // True when remote repo is a fork
	// PR status fields — populated by PRStatusPoller
	GitHubPRState          string    `json:"github_pr_state,omitempty"`
	GitHubPRIsDraft        bool      `json:"github_pr_is_draft,omitempty"`
	GitHubPRPriority       string    `json:"github_pr_priority,omitempty"`
	GitHubApprovedCount    int       `json:"github_approved_count,omitempty"`
	GitHubChangesReqCount  int       `json:"github_changes_req_count,omitempty"`
	GitHubCheckConclusion  string    `json:"github_check_conclusion,omitempty"`
	GitHubPRStatusTerminal bool      `json:"github_pr_status_terminal,omitempty"`
	LastPRStatusCheck      time.Time `json:"last_pr_status_check,omitempty"`
	// Crew autonomy mode — when true, the Fixer injects correction prompts without user confirmation.
	AutonomousMode bool `json:"autonomous_mode,omitempty"`

	// Claude Code session persistence
	ClaudeSession ClaudeSessionData `json:"claude_session,omitempty"`
	// Tmux session prefix for isolation
	TmuxPrefix string `json:"tmux_prefix,omitempty"`

	// Terminal update timestamps for activity tracking
	LastTerminalUpdate   time.Time `json:"last_terminal_update,omitempty"`
	LastMeaningfulOutput time.Time `json:"last_meaningful_output,omitempty"`

	// Content signature for detecting actual terminal changes vs restarts
	// This is a SHA256 hash of the terminal content used to prevent false "new activity"
	// notifications when app restarts but terminal content hasn't changed
	LastOutputSignature string `json:"last_output_signature,omitempty"`

	// Review queue spam prevention
	LastAddedToQueue time.Time `json:"last_added_to_queue,omitempty"`

	// User interaction tracking
	// LastViewed tracks when the user last viewed this session (terminal, session details, etc.)
	// Used for smarter review queue notifications (don't notify if just viewed)
	LastViewed time.Time `json:"last_viewed,omitempty"`

	// Review queue snooze tracking
	// LastAcknowledged tracks when the user last dismissed this session from review queue
	// Sessions acknowledged after their last update won't appear in the queue until they update again
	LastAcknowledged time.Time `json:"last_acknowledged,omitempty"`

	// Prompt detection and interaction tracking for smart review queue behavior
	LastPromptDetected   time.Time `json:"last_prompt_detected,omitempty"`
	LastPromptSignature  string    `json:"last_prompt_signature,omitempty"`
	LastUserResponse     time.Time `json:"last_user_response,omitempty"`
	ProcessingGraceUntil time.Time `json:"processing_grace_until,omitempty"`

	// Checkpoint metadata for session state bookmarking (session resumption)
	Checkpoints      CheckpointList `json:"checkpoints,omitempty"`
	ActiveCheckpoint string         `json:"active_checkpoint,omitempty"`
	ForkedFromID     string         `json:"forked_from_id,omitempty"`

	// History file linkage for cold restore
	HistoryFilePath string `json:"history_file_path,omitempty"`

	// OneShot runs claude in -p mode; session exits after task completes.
	OneShot bool `json:"one_shot,omitempty"`

	// Hidden excludes this session from the default session list and review queue.
	Hidden bool `json:"hidden,omitempty"`

	// ProjectID is the optional project this session belongs to.
	ProjectID string `json:"project_id,omitempty"`

	// LaunchCommand is the full command passed to tmux on session start, including
	// any injected flags (--resume, --mcp-config, -y, initial prompt).
	LaunchCommand string `json:"launch_command,omitempty"`

	// MCPServerURL is the stapler-squad HTTP MCP endpoint passed to claude via
	// --mcp-config on session start. Persisted so restarts re-inject the flag.
	MCPServerURL string `json:"mcp_server_url,omitempty"`

	// PauseReason records why this session was paused.
	// Values: "manual", "auto:inactivity", "auto:session_limit", "auto:resource".
	// Empty when session has never been paused.
	PauseReason string `json:"pause_reason,omitempty"`

	// WorkflowID is the UUID of the Workflow that spawned this session.
	// Empty for manually-created sessions.
	WorkflowID string `json:"workflow_id,omitempty"`

	// ArchivedAt is set when the session is archived. Nil means not archived.
	ArchivedAt *time.Time `json:"archived_at,omitempty"`
}

InstanceData represents the serializable data of an Instance

func (InstanceData) GetStableID added in v1.35.0

func (d InstanceData) GetStableID() string

GetStableID mirrors Instance.GetStableID for InstanceData: returns UUID when set, Title otherwise. Used by Registry.AcquireAll and ListInstanceIDs to produce stable per-session keys without constructing live Instance objects.

func (InstanceData) MatchesID added in v1.35.0

func (d InstanceData) MatchesID(id string) bool

MatchesID reports whether id refers to this InstanceData. Unlike Instance.MatchesID, there is no tmux-name arm because InstanceData has no GetTmuxSessionName (that method requires the live processManager). For tmux-name matching, call Instance.MatchesID.

type InstanceOptions

type InstanceOptions struct {
	// Title is the title of the instance.
	Title string
	// Path is the path to the workspace repository root.
	Path string
	// WorkingDir is the directory within the repository to start in.
	// If empty, defaults to repository root.
	WorkingDir string
	// Branch is the git branch name to use when creating a new worktree.
	// If empty and SessionType is SessionTypeNewWorktree, a branch name is derived from the title.
	Branch string
	// Program is the program to run in the instance (e.g. "claude", "aider --model ollama_chat/gemma3:1b")
	Program string
	// If AutoYes is true, automatically accept prompts
	AutoYes bool
	// Prompt is passed as a CLI argument at process-spawn time — only takes effect on a fresh
	// spawn or OneShot. See InitialPrompt for the tmux-typed alternative; the two are independent
	// and may both be set (see Instance.Prompt/Instance.InitialPrompt for the full explanation).
	Prompt string
	// InitialPrompt, when non-empty, is typed into the tmux pane once the session reaches Ready state,
	// replacing the static "Please proceed..." fallback. Use for resume/attach flows where a CLI
	// arg can no longer be injected.
	InitialPrompt string
	// ExistingWorktree is an optional path to an existing worktree to reuse
	ExistingWorktree string
	// Category is used for organizing sessions into groups
	Category string
	// Tags are multi-valued labels for flexible organization
	Tags []string
	// SessionType determines the session workflow (directory, new_worktree, existing_worktree)
	SessionType SessionType
	// TmuxPrefix is the prefix to use for tmux session names (e.g., "staplersquad_")
	TmuxPrefix string
	// TmuxServerSocket is the server socket name for tmux isolation (used with -L flag)
	// If empty, uses the default tmux server. For complete isolation (e.g., testing),
	// set to a unique value like "test" or "teatest_123" to create separate tmux servers.
	TmuxServerSocket string
	// GitHub integration fields for PR/URL-based session creation
	GitHubPRNumber  int    // PR number if created from PR URL
	GitHubPRURL     string // Full URL to the PR
	GitHubOwner     string // Repository owner
	GitHubRepo      string // Repository name
	GitHubSourceRef string // Original URL/reference used to create session
	ClonedRepoPath  string // Path where repo was cloned (if cloned)

	// ResumeId is the Claude conversation ID to resume (from history browser).
	// When set, the session will start with --resume <id> flag.
	ResumeId string

	// OneShot runs claude in -p mode; the session exits after the task completes.
	OneShot bool

	// Hidden excludes the session from the default session list and review queue.
	Hidden bool

	// ProjectID associates the session with a project.
	ProjectID string

	// MCPServerURL, when non-empty and the program is claude, passes
	// --mcp-config '{"stapler-squad":{"type":"http","url":"<MCPServerURL>"}}' so the
	// session can call back into stapler-squad without any file injection.
	MCPServerURL string

	// AppendSystemPrompt, when non-empty and the program is claude, passes
	// --append-system-prompt so extra instructions are injected into the system
	// prompt without touching any file on disk.
	AppendSystemPrompt string

	// AllowedTools pre-approves specific Claude Code tool calls (--allowedTools).
	AllowedTools string
	// PermissionMode sets Claude Code's permission handling mode (--permission-mode).
	PermissionMode string

	// CreateIfMissing: when SessionTypeDirectory, create the directory and run git init
	// if the path does not exist. Only set when the user has confirmed the action.
	CreateIfMissing bool

	// AutonomousMode, when true, starts an AutonomousDriver after session creation
	// so the session runs to completion without manual steering.
	AutonomousMode bool

	// WorkflowID is the UUID of the Workflow that spawned this session.
	// Set by the scheduler; empty for manually-created sessions.
	WorkflowID string

	// EnvVars are session-level environment variables injected at tmux session creation time.
	EnvVars map[string]string
	// CLIFlags are additional CLI flags appended to the program launch command.
	CLIFlags string
}

Options for creating a new instance

type InstancePermissions

type InstancePermissions struct {
	// View operations
	CanView bool

	// Attach to the terminal session
	CanAttach bool

	// Send commands to the terminal
	CanSendCommand bool

	// Pause the session (stop tmux, keep worktree)
	CanPause bool

	// Resume a paused session
	CanResume bool

	// Destroy the session completely
	CanDestroy bool

	// Perform git operations (commit, push, worktree management)
	CanModifyGit bool

	// Add to review queue
	CanAddToQueue bool

	// RequiresConfirmation maps operation names to whether they need confirmation
	// Used for high-risk operations on external instances
	RequiresConfirmation map[string]bool
}

InstancePermissions defines what operations are allowed on an instance

func GetExternalPermissions

func GetExternalPermissions(allowAttach bool) InstancePermissions

GetExternalPermissions returns limited permissions for external instances allowAttach controls whether attach operations are permitted (power user mode)

func GetManagedPermissions

func GetManagedPermissions() InstancePermissions

GetManagedPermissions returns full permissions for squad-managed instances

func GetMuxExternalPermissions

func GetMuxExternalPermissions() InstancePermissions

GetMuxExternalPermissions returns permissions for mux-enabled external instances. Mux instances support full bidirectional terminal access and can be destroyed since they're explicitly opted-in by launching through ssq-mux with tmux session.

type InstanceReader added in v1.35.0

type InstanceReader interface {
	// Identity
	GetTitle() string
	GetStableID() string

	// Descriptive metadata
	GetWorkingDirectory() string

	// GetStatus returns the current lifecycle status as int.
	// Deprecated: use GetLifecycleStatus() or the typed predicates below.
	GetStatus() int

	// GetLifecycleStatus returns the current lifecycle status as a typed Status value.
	GetLifecycleStatus() Status

	// Typed state predicates — prefer these over comparing GetStatus() against constants.
	IsActive() bool
	IsPaused() bool
	IsHibernated() bool
	IsStopped() bool

	// Git / diff
	GetDiffStats() *git.DiffStats

	// Activity timestamps
	GetTimeSinceLastMeaningfulOutput() time.Duration
}

InstanceReader exposes a minimal read-only view of an Instance for server-layer code that only needs to observe session state. It is not yet used at every call site (some helpers still take *Instance directly for field access); adopt it incrementally as call sites are converted to use getter methods.

*Instance satisfies this interface automatically. Use it to supply lightweight test doubles without starting a real tmux session.

type InstanceSnapshot added in v1.35.0

type InstanceSnapshot struct {
	// Identity / config
	ID               string
	UUID             string
	Title            string
	Path             string
	WorkingDir       string
	Branch           string
	CreatedAt        time.Time
	UpdatedAt        time.Time
	Status           Status
	Program          string
	Height           int
	Width            int
	AutoYes          bool
	IsExpanded       bool
	Prompt           string
	InitialPrompt    string
	Category         string
	SessionType      SessionType
	TmuxPrefix       string
	TmuxServerSocket string
	Tags             []string // defensive deep copy — see buildSnapshot

	// Autonomous mode (grouped — access as snap.Autonomous.AutonomousMode)
	Autonomous AutonomousModeState

	// GitHub PR / URL integration (grouped — access as snap.GitHub.GitHubPRURL)
	GitHub GitHubIntegration

	// Checkpoints
	Checkpoints      CheckpointList // defensive deep copy — see buildSnapshot
	ActiveCheckpoint string
	ForkedFromID     string

	// Misc config
	OneShot             bool
	Hidden              bool
	ProjectID           string
	HistoryFilePath     string
	MCPServerURL        string
	AppendSystemPrompt  string
	AllowedTools        string
	PermissionMode      string
	RateLimitAutoResume *bool // copy of pointee — see buildSnapshot
	PauseReason         string
	WorkflowID          string
	EnvVars             map[string]string // defensive deep copy — see buildSnapshot
	CLIFlags            string
	ArchivedAt          *time.Time // copy of pointee — see buildSnapshot

	// Review queue / activity state (embedded value — copied by value)
	ReviewState

	// Instance type and management metadata
	InstanceType     InstanceType
	IsManaged        bool
	ExternalMetadata *ExternalInstanceMetadata // copy of pointee — see buildSnapshot
	Permissions      InstancePermissions       // RequiresConfirmation map deep-copied
	Artifacts        *artifacts.SessionArtifactsBlob
}

InstanceSnapshot is a point-in-time, read-safe copy of all mutable Instance fields. Published via Instance.snapshot (atomic.Pointer) inside stateMutex at the end of every mutator so lock-free readers always see consistent state.

Excluded: manager/dependency objects (gitManager, vncManager, cdpManager, processManager, controllerManager, tagManager, shellRepo, historyDetector) and callback registrations (lifecycleListeners, onRateLimitDetected, onStatusChange). Those are behavior, not data; callers needing them go through dedicated accessors or mailbox round-trips (Epic 3).

type InstanceStatusInfo

type InstanceStatusInfo struct {
	BasicStatus        Status                   // Creating, Active, Paused, Stopped, Hibernated
	ClaudeStatus       detection.DetectedStatus // If ClaudeController is active
	StatusContext      string                   // Context/details about current status (e.g., error message)
	PendingApprovals   int                      // Number of pending approvals
	QueuedCommands     int                      // Number of queued commands
	LastCommandStatus  string                   // Status of last command
	IsControllerActive bool                     // Whether ClaudeController is running
	IdleState          detection.IdleStateInfo  // NEW: Idle state information
}

InstanceStatusInfo provides extended status information for an instance.

func (InstanceStatusInfo) GetColorCode

func (info InstanceStatusInfo) GetColorCode() string

GetColorCode returns a color code for the status (for lipgloss styling).

func (InstanceStatusInfo) GetStatusDescription

func (info InstanceStatusInfo) GetStatusDescription() string

GetStatusDescription returns a human-readable status description.

func (InstanceStatusInfo) GetStatusIcon

func (info InstanceStatusInfo) GetStatusIcon() string

GetStatusIcon returns an icon representing the instance status.

func (InstanceStatusInfo) HasPendingWork

func (info InstanceStatusInfo) HasPendingWork() bool

HasPendingWork returns true if the instance has pending commands or approvals.

func (InstanceStatusInfo) IsWaitingForUser

func (info InstanceStatusInfo) IsWaitingForUser() bool

IsWaitingForUser returns true if the instance is waiting for user input.

func (InstanceStatusInfo) NeedsAttention

func (info InstanceStatusInfo) NeedsAttention() bool

NeedsAttention returns true if the instance requires user attention.

type InstanceStatusManager

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

InstanceStatusManager manages status information for instances.

func NewInstanceStatusManager

func NewInstanceStatusManager() *InstanceStatusManager

NewInstanceStatusManager creates a new status manager.

func (*InstanceStatusManager) GetAllControllers

func (ism *InstanceStatusManager) GetAllControllers() map[string]*ClaudeController

GetAllControllers returns all registered controllers.

func (*InstanceStatusManager) GetController

func (ism *InstanceStatusManager) GetController(instanceTitle string) (*ClaudeController, bool)

GetController retrieves a controller for an instance.

func (*InstanceStatusManager) GetStatus

func (ism *InstanceStatusManager) GetStatus(instance *Instance) InstanceStatusInfo

GetStatus retrieves comprehensive status for an instance.

func (*InstanceStatusManager) RegisterController

func (ism *InstanceStatusManager) RegisterController(instanceTitle string, controller *ClaudeController)

RegisterController registers a controller for an instance.

func (*InstanceStatusManager) UnregisterController

func (ism *InstanceStatusManager) UnregisterController(instanceTitle string)

UnregisterController removes a controller for an instance.

type InstanceStore added in v1.1.0

type InstanceStore interface {
	LoadInstances() ([]*Instance, error)
	// ListInstanceData returns raw persisted InstanceData without constructing Instance
	// objects or spawning PTY processes. Use this for read-only existence/title checks
	// where calling LoadInstances() would create unnecessary side effects.
	ListInstanceData() ([]InstanceData, error)
	SaveInstances([]*Instance) error
	AddInstance(*Instance) error
	DeleteInstance(title string) error
	UpdateInstanceLastUserResponse(title string, t time.Time) error
}

InstanceStore is the minimal interface the server layer needs for session persistence. Defining it here (alongside the concrete Storage) allows test fakes to be built without depending on the full Storage implementation.

type InstanceType

type InstanceType int

InstanceType represents the type of session instance

const (
	// InstanceTypeManaged represents a session fully managed by stapler-squad
	// with complete lifecycle control, git worktrees, and all features
	InstanceTypeManaged InstanceType = iota

	// InstanceTypeExternal represents a Claude instance discovered externally
	// (not created by stapler-squad) with limited interaction capabilities
	InstanceTypeExternal
)

func (InstanceType) String

func (it InstanceType) String() string

type ItemSessionData added in v1.35.0

type ItemSessionData struct {
	ItemID       string // BacklogItem UUID
	SessionUUID  string
	SessionRole  string
	AcSnapshot   string // JSON
	TriageResult string
}

ItemSessionData is the input data for creating a new ItemSession.

type ItemSourceData added in v1.35.0

type ItemSourceData struct {
	ID              string
	PluginID        string
	DisplayName     string
	Config          string // JSON, may contain encrypted token
	Enabled         bool
	TokenConfigured bool
	LastSyncedAt    *time.Time
	CreatedAt       time.Time
	UpdatedAt       time.Time
}

ItemSourceData is the domain model for an external item source.

type ItemSourcePlugin added in v1.35.0

type ItemSourcePlugin interface {
	// PluginID returns the unique identifier for this plugin (e.g., "github_issues").
	PluginID() string
	// Fetch retrieves new and updated items since the cursor. Returns items and the new cursor.
	Fetch(ctx context.Context, config PluginConfig, cursor string) ([]ExternalItem, string, error)
	// MapToBacklogItem converts an external item to a BacklogItemData.
	MapToBacklogItem(item ExternalItem, sourceID string) BacklogItemData
}

ItemSourcePlugin is the interface all external source integrations must implement.

type ItemSourceUpdate added in v1.35.0

type ItemSourceUpdate struct {
	DisplayName *string
	Enabled     *bool
	Config      *string
}

ItemSourceUpdate carries the mutable fields for UpdateItemSource.

type LifecycleEvent added in v1.15.0

type LifecycleEvent int

LifecycleEvent is a notification type emitted by an Instance when key state transitions occur (e.g., the session starts, or the program exits unexpectedly).

const (
	// EventStarted fires at the end of start() when the instance has successfully
	// transitioned to Running and the controller is up.
	EventStarted LifecycleEvent = iota
	// EventExited fires when the underlying program exits unexpectedly (not via an
	// operator-initiated Kill/Stop). Callers may use this to drive auto-restart logic.
	EventExited
)

type LifecycleListener added in v1.15.0

type LifecycleListener interface {
	OnLifecycleEvent(event LifecycleEvent, reason string)
}

LifecycleListener is implemented by any component that wants to receive Instance lifecycle notifications. Implementations must be non-blocking; use a goroutine or channel if the handler needs to do significant work.

type LiveInstance added in v1.35.0

type LiveInstance struct {
	*Instance
	// contains filtered or unexported fields
}

LiveInstance is the actor-owning handle for a session. It wraps *Instance with lifecycle fields for the actor goroutine (IAC Epic 3). Supported construction paths from outside this package:

  • Registry.Acquire(sessionID) — load-or-construct for an existing persisted session
  • Registry.Register(inst) — for brand-new sessions in CreateSession (R2.18a)
  • NewLiveInstance(inst) — direct wrap when the caller already holds *Instance

The actor goroutine (runActor in actor.go) is started by NewLiveInstance via finishLiveInstanceConstruction and exits when Stop()/stopActor() cancels the ctx.

func NewLiveInstance added in v1.35.0

func NewLiveInstance(inst *Instance) *LiveInstance

NewLiveInstance wraps an already-constructed *Instance in a LiveInstance and starts its actor goroutine. Use Registry.Acquire or Registry.Register where possible; call this directly only when the caller already holds a freshly- constructed *Instance (e.g. CreateSession, which builds its own via NewInstance and then passes it to Registry.Register).

func (*LiveInstance) Stop added in v1.35.0

func (l *LiveInstance) Stop()

Stop signals this instance's actor to exit and waits for it to drain. Idempotent: safe to call multiple times; the second and subsequent calls return immediately once the first call's <-done wait completes.

type LiveInstancesProvider added in v1.35.0

type LiveInstancesProvider interface {
	GetInstances() []*Instance
}

LiveInstancesProvider is satisfied by ReviewQueuePoller. It returns the live in-memory instances without constructing new Instance objects or spawning PTY processes. HibernationSweeper uses this as a fast path to avoid LoadInstances().

type LoadOptions

type LoadOptions struct {
	// LoadWorktree controls whether git worktree data is loaded
	LoadWorktree bool

	// LoadDiffStats controls whether diff statistics (added/removed counts) are loaded
	LoadDiffStats bool

	// LoadDiffContent controls whether full diff content is loaded
	// Note: This implies LoadDiffStats=true, as we need counts to interpret content
	LoadDiffContent bool

	// LoadTags controls whether session tags are loaded
	LoadTags bool

	// LoadClaudeSession controls whether Claude Code session data is loaded
	LoadClaudeSession bool
}

LoadOptions controls what child data is loaded for sessions. This allows selective loading to optimize performance by avoiding unnecessary data retrieval.

func (LoadOptions) WithDiffContent

func (o LoadOptions) WithDiffContent() LoadOptions

WithDiffContent returns a copy of options with diff content loading enabled.

func (LoadOptions) WithTags

func (o LoadOptions) WithTags() LoadOptions

WithTags returns a copy of options with tag loading enabled.

func (LoadOptions) WithoutDiffContent

func (o LoadOptions) WithoutDiffContent() LoadOptions

WithoutDiffContent returns a copy of options with diff content loading disabled.

func (LoadOptions) WithoutTags

func (o LoadOptions) WithoutTags() LoadOptions

WithoutTags returns a copy of options with tag loading disabled.

type Locked added in v1.35.0

type Locked[T any] struct {
	// contains filtered or unexported fields
}

Locked bundles a value T with a RWMutex, enforcing lock discipline by only exposing the value through Read/Write callbacks.

This is the Go equivalent of Rust's RwLock<T>: the data and its lock are inseparable, making it structurally impossible to access the value without correct lock discipline. Instead of a mutex sitting next to a field (which the compiler cannot enforce is held on access), callers receive or mutate the value only through Read or Write.

var listeners Locked[[]StatusChangeListener]

// Add a listener — write lock taken automatically
listeners.Write(func(ls *[]StatusChangeListener) {
    *ls = append(*ls, fn)
})

// Read all listeners — read lock taken automatically
var snapshot []StatusChangeListener
listeners.Read(func(ls []StatusChangeListener) {
    snapshot = append(snapshot, ls...)
})

func (*Locked[T]) Read added in v1.35.0

func (l *Locked[T]) Read(fn func(T))

Read calls fn with a read-only copy of the value, holding the read lock for the duration. Multiple goroutines may call Read concurrently. Errors from fn should be captured via closure variables.

func (*Locked[T]) Write added in v1.35.0

func (l *Locked[T]) Write(fn func(*T))

Write calls fn with a pointer to the value, holding the exclusive write lock for the duration. fn may mutate the value freely. Errors from fn should be captured via closure variables.

type MemoryCacheReader added in v1.35.0

type MemoryCacheReader interface {
	GetCachedRSSMB(sessionUUID string) int64
	SystemMemoryPct() (float64, error)
}

MemoryCacheReader is implemented by HibernationSweeper so SessionService can read cached RSS values without importing the sweeper concretely.

type MigrationOptions

type MigrationOptions struct {
	// JSONPath is the path to the existing JSON state file
	JSONPath string

	// SQLitePath is the path where the SQLite database will be created
	SQLitePath string

	// BackupPath is the path where the JSON backup will be saved
	BackupPath string

	// ForceOverwrite allows overwriting existing SQLite database
	ForceOverwrite bool

	// DryRun performs validation without actually migrating
	DryRun bool
}

MigrationOptions configures the migration from JSON to SQLite

type MigrationResult

type MigrationResult struct {
	TotalSessions      int
	MigratedSessions   int
	SkippedSessions    int
	Errors             []string
	Duration           time.Duration
	BackupCreated      bool
	BackupPath         string
	SQLiteDatabasePath string
}

MigrationResult contains the results of the migration process

func MigrateJSONToEnt

func MigrateJSONToEnt(opts MigrationOptions) (*MigrationResult, error)

MigrateJSONToEnt migrates session data from JSON to Ent ORM storage.

type NativeProcessManager added in v1.35.0

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

NativeProcessManager implements ProcessManager using a raw PTY and process supervision. It launches the configured program directly under a PTY master fd (via creack/pty) and restarts it with exponential backoff when it exits unexpectedly.

Phase 2 implementation: Start(), Close(), IsAlive(), GetPTY(), GetPanePID(), GetSessionIdentifier(), SetWindowSize(), GetPaneDimensions(), SendKeys(), TapEnter(), SetOnExitCallback(), SubscribeToControlModeUpdates(), and GetCurrentWorkingDirectory() are fully functional. Content capture (CapturePaneContent variants) and precise CWD via lsof/proc are deferred to Phase 3.

func NewNativeProcessManager added in v1.35.0

func NewNativeProcessManager(opts ProcessManagerOptions) *NativeProcessManager

NewNativeProcessManager creates a NativeProcessManager with the given options. Call Start() to launch the process.

func (*NativeProcessManager) Attach added in v1.35.0

func (n *NativeProcessManager) Attach() (chan struct{}, error)

Attach is not supported for the native backend; returns an error. Interactive TUI attach requires a proper terminal multiplexer.

func (*NativeProcessManager) CapturePaneContent added in v1.35.0

func (n *NativeProcessManager) CapturePaneContent() (string, error)

CapturePaneContent returns an empty string until scrollback capture is implemented.

func (*NativeProcessManager) CapturePaneContentRaw added in v1.35.0

func (n *NativeProcessManager) CapturePaneContentRaw() (string, error)

CapturePaneContentRaw returns an empty string until scrollback capture is implemented.

func (*NativeProcessManager) CapturePaneContentWithOptions added in v1.35.0

func (n *NativeProcessManager) CapturePaneContentWithOptions(_, _ string) (string, error)

CapturePaneContentWithOptions returns an empty string until scrollback capture is implemented.

func (*NativeProcessManager) CaptureViewport added in v1.35.0

func (n *NativeProcessManager) CaptureViewport(_ int) (string, error)

CaptureViewport returns an empty string until scrollback capture is implemented.

func (*NativeProcessManager) Close added in v1.35.0

func (n *NativeProcessManager) Close() error

Close terminates the supervised process and stops the restart loop. Implements NM-3 (SIGTERM before context cancel) and NM-5 (goroutines exit).

func (*NativeProcessManager) DetachSafely added in v1.35.0

func (n *NativeProcessManager) DetachSafely() error

DetachSafely is a no-op for the native backend.

func (*NativeProcessManager) FilterBanners added in v1.35.0

func (n *NativeProcessManager) FilterBanners(content string) (string, int)

FilterBanners returns content unchanged; banner detection is tmux-specific.

func (*NativeProcessManager) GetCurrentWorkingDirectory added in v1.35.0

func (n *NativeProcessManager) GetCurrentWorkingDirectory() (string, error)

GetCurrentWorkingDirectory returns the directory passed to the most recent Start() call. Phase 3 follow-on: replace with /proc/<pid>/cwd on Linux or lsof on macOS for the true current working directory of the running process.

func (*NativeProcessManager) GetCursorPosition added in v1.35.0

func (n *NativeProcessManager) GetCursorPosition() (x, y int, err error)

GetCursorPosition returns (0, 0) for the native backend. There are zero callers in the server/ package that require real cursor position from the native backend (confirmed in plan.md).

func (*NativeProcessManager) GetPTY added in v1.35.0

func (n *NativeProcessManager) GetPTY() (*os.File, error)

GetPTY returns the PTY master file descriptor.

func (*NativeProcessManager) GetPaneDimensions added in v1.35.0

func (n *NativeProcessManager) GetPaneDimensions() (width, height int, err error)

GetPaneDimensions returns the last window size set via SetWindowSize. Tracks the value in memory to avoid a TIOCGWINSZ syscall on the hot path (GetPaneDimensions is called 5× per resize event in connectrpc_websocket.go).

func (*NativeProcessManager) GetPanePID added in v1.35.0

func (n *NativeProcessManager) GetPanePID() (int32, error)

GetPanePID returns the PID of the supervised process.

func (*NativeProcessManager) GetSessionIdentifier added in v1.35.0

func (n *NativeProcessManager) GetSessionIdentifier() string

GetSessionIdentifier returns the stable session name set at construction.

func (*NativeProcessManager) HasMeaningfulContent added in v1.35.0

func (n *NativeProcessManager) HasMeaningfulContent(_ string) bool

HasMeaningfulContent always returns false until content analysis is implemented.

func (*NativeProcessManager) HasSession added in v1.35.0

func (n *NativeProcessManager) HasSession() bool

HasSession reports whether a process has been started at least once. Alias for IsAlive() on the native backend.

func (*NativeProcessManager) HasUpdated added in v1.35.0

func (n *NativeProcessManager) HasUpdated() (updated bool, hasPrompt bool, content string)

HasUpdated always returns (false, false, "") until content diffing is implemented.

func (*NativeProcessManager) IsAlive added in v1.35.0

func (n *NativeProcessManager) IsAlive() bool

IsAlive reports whether the supervised process is currently running.

func (*NativeProcessManager) RefreshClient added in v1.35.0

func (n *NativeProcessManager) RefreshClient() error

RefreshClient is a no-op for the native backend (no tmux client to refresh).

func (*NativeProcessManager) ResetExitOnce added in v1.35.0

func (n *NativeProcessManager) ResetExitOnce()

ResetExitOnce is a no-op for the native backend; the restart loop does not use a sync.Once guard.

func (*NativeProcessManager) RestoreWithWorkDir added in v1.35.0

func (n *NativeProcessManager) RestoreWithWorkDir(_ string) error

RestoreWithWorkDir is a no-op for the native backend; the process is already running after Start() and does not need re-attachment.

func (*NativeProcessManager) SendInputViaControlMode added in v1.35.0

func (n *NativeProcessManager) SendInputViaControlMode(_ context.Context, data []byte) error

SendInputViaControlMode writes raw bytes directly to the PTY master. The native backend has no concept of tmux control mode; bytes are written directly.

func (*NativeProcessManager) SendKeys added in v1.35.0

func (n *NativeProcessManager) SendKeys(keys string) (int, error)

SendKeys writes the given string to the PTY master.

func (*NativeProcessManager) SendPromptWithEnter added in v1.35.0

func (n *NativeProcessManager) SendPromptWithEnter(prompt string) error

SendPromptWithEnter sends text followed by Enter.

func (*NativeProcessManager) SetDetachedSize added in v1.35.0

func (n *NativeProcessManager) SetDetachedSize(width, height int, _ string) error

SetDetachedSize updates the stored window size without requiring an active PTY. The instanceTitle parameter is ignored; it exists only for interface compatibility.

func (*NativeProcessManager) SetOnExitCallback added in v1.35.0

func (n *NativeProcessManager) SetOnExitCallback(fn func(string))

SetOnExitCallback registers a callback invoked when the supervised process exits unexpectedly (before the restart loop relaunches it).

func (*NativeProcessManager) SetWindowSize added in v1.35.0

func (n *NativeProcessManager) SetWindowSize(cols, rows int) error

SetWindowSize resizes the PTY to the given columns and rows.

func (*NativeProcessManager) Start added in v1.35.0

func (n *NativeProcessManager) Start(dir string) error

Start launches the configured program under a PTY in the given directory. If the process is already running, Start is a no-op. Start resets the stop signal so it is safe to call after Close().

func (*NativeProcessManager) StartControlMode added in v1.35.0

func (n *NativeProcessManager) StartControlMode() error

StartControlMode is a no-op for the native backend; raw PTY reads replace control mode.

func (*NativeProcessManager) StopControlMode added in v1.35.0

func (n *NativeProcessManager) StopControlMode() error

StopControlMode is a no-op for the native backend.

func (*NativeProcessManager) SubscribeToControlModeUpdates added in v1.35.0

func (n *NativeProcessManager) SubscribeToControlModeUpdates() (string, chan []byte)

SubscribeToControlModeUpdates adds a subscriber that receives raw PTY output bytes. Returns the subscription ID and a channel that receives byte slices.

func (*NativeProcessManager) TapEnter added in v1.35.0

func (n *NativeProcessManager) TapEnter() error

TapEnter sends a carriage return + newline sequence to the PTY.

func (*NativeProcessManager) UnsubscribeFromControlModeUpdates added in v1.35.0

func (n *NativeProcessManager) UnsubscribeFromControlModeUpdates(id string)

UnsubscribeFromControlModeUpdates removes a subscriber by ID and closes its channel.

type OutputConsumer

type OutputConsumer func(data []byte)

OutputConsumer is a callback that receives terminal output from external sessions.

type PRStatusPoller added in v1.12.0

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

PRStatusPoller polls GitHub PR status for all sessions at a shared interval. Uses a single workspace-level ticker (not per-session goroutines) and an ETag cache so unchanged PRs return HTTP 304 and cost zero rate-limit quota.

func NewPRStatusPoller added in v1.12.0

func NewPRStatusPoller(storage *Storage) *PRStatusPoller

NewPRStatusPoller creates a new poller with default configuration.

func NewPRStatusPollerWithConfig added in v1.12.0

func NewPRStatusPollerWithConfig(storage *Storage, config PRStatusPollerConfig) *PRStatusPoller

NewPRStatusPollerWithConfig creates a poller with custom configuration.

func (*PRStatusPoller) AddInstance added in v1.12.0

func (p *PRStatusPoller) AddInstance(inst *Instance)

AddInstance adds a single instance to monitor.

func (*PRStatusPoller) GetInstances added in v1.35.0

func (p *PRStatusPoller) GetInstances() []*Instance

GetInstances returns a defensive copy of the currently monitored instances. Callers must not modify the returned slice elements.

func (*PRStatusPoller) RemoveInstance added in v1.12.0

func (p *PRStatusPoller) RemoveInstance(title string)

RemoveInstance removes an instance from monitoring.

func (*PRStatusPoller) SetInstances added in v1.12.0

func (p *PRStatusPoller) SetInstances(instances []*Instance)

SetInstances replaces the full list of monitored instances.

func (*PRStatusPoller) SetOnUpdated added in v1.12.0

func (p *PRStatusPoller) SetOnUpdated(fn func(*Instance))

SetOnUpdated registers a callback called when a session's PR priority changes. The callback is invoked from a goroutine; it must be concurrency-safe.

func (*PRStatusPoller) Start added in v1.12.0

func (p *PRStatusPoller) Start(ctx context.Context)

Start begins the polling loop. Safe to call multiple times; subsequent calls are no-ops.

func (*PRStatusPoller) Stop added in v1.12.0

func (p *PRStatusPoller) Stop()

Stop gracefully shuts down the poller and waits for in-flight requests.

type PRStatusPollerConfig added in v1.12.0

type PRStatusPollerConfig struct {
	// PollInterval controls how often all sessions are checked.
	PollInterval time.Duration
	// ConcurrentFetches limits simultaneous gh CLI calls (respects secondary rate limits).
	ConcurrentFetches int
	// CallTimeout is the maximum time for a single gh API call.
	CallTimeout time.Duration
	// AuthCacheDuration controls how long a successful auth check is cached.
	AuthCacheDuration time.Duration
	// NoPRBackoff is how long to wait before re-checking a session after ErrNoPR.
	// Zero disables the backoff (always re-check).
	NoPRBackoff time.Duration
}

PRStatusPollerConfig contains configuration for the PR status poller.

func DefaultPRStatusPollerConfig added in v1.12.0

func DefaultPRStatusPollerConfig() PRStatusPollerConfig

DefaultPRStatusPollerConfig returns sensible defaults.

type PTYAccess

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

PTYAccess provides thread-safe access to a tmux session's PTY for reading and writing. It wraps the PTY file descriptor with synchronization primitives to enable concurrent access from multiple goroutines (e.g., command execution, response streaming, status monitoring).

func NewPTYAccess

func NewPTYAccess(sessionName string, pty *os.File, buffer *CircularBuffer) *PTYAccess

NewPTYAccess creates a new PTYAccess wrapper for a PTY file descriptor. The buffer parameter specifies the circular buffer for storing PTY output history.

func (*PTYAccess) Close

func (p *PTYAccess) Close() error

Close marks the PTY access as closed and prevents further operations. It does NOT close the underlying PTY file descriptor - that's handled by the tmux session.

func (*PTYAccess) GetBuffer

func (p *PTYAccess) GetBuffer() []byte

GetBuffer returns the most recent output from the circular buffer. This provides access to historical PTY output without blocking. Returns a copy of the buffer contents to prevent concurrent modification issues.

func (*PTYAccess) GetFile added in v1.35.0

func (p *PTYAccess) GetFile() (*os.File, bool)

GetFile returns the underlying PTY *os.File and whether the PTY has been closed. Returns (f, false) when open, (nil, false) when not yet initialized, (nil, true) when closed. The returned file must not be used after a subsequent UpdatePTY or Close call.

func (*PTYAccess) GetRecentOutput

func (p *PTYAccess) GetRecentOutput(n int) []byte

GetRecentOutput returns the last n bytes from the circular buffer. This is useful for status detection and response streaming.

func (*PTYAccess) GetSessionName

func (p *PTYAccess) GetSessionName() string

GetSessionName returns the name of the session this PTY access is for.

func (*PTYAccess) IsClosed

func (p *PTYAccess) IsClosed() bool

IsClosed returns whether the PTY access has been closed.

func (*PTYAccess) Read

func (p *PTYAccess) Read(buf []byte) (int, error)

Read reads data from the PTY in a thread-safe manner. This is a blocking call that will wait for data to be available. Returns the number of bytes read and any error encountered.

func (*PTYAccess) UpdatePTY

func (p *PTYAccess) UpdatePTY(pty *os.File) error

UpdatePTY updates the underlying PTY file descriptor. This is used when the PTY needs to be refreshed (e.g., after detach/reattach).

func (*PTYAccess) Write

func (p *PTYAccess) Write(data []byte) (int, error)

Write writes data to the PTY in a thread-safe manner. Returns the number of bytes written and any error encountered.

type PTYCategory

type PTYCategory int

PTYCategory represents grouping of PTYs

const (
	PTYCategorySquad    PTYCategory = iota // Squad-managed sessions
	PTYCategoryOrphaned                    // Unmanaged Claude instances
	PTYCategoryOther                       // Other tools (aider, etc.)
)

func (PTYCategory) String

func (c PTYCategory) String() string

type PTYConnection

type PTYConnection struct {
	Path         string            // /dev/pts/12
	PID          int               // Process ID
	Command      string            // "claude" or "aider"
	SessionName  string            // Associated squad session (if any)
	Status       PTYStatus         // Current status
	LastActivity time.Time         // Last activity timestamp
	Controller   *ClaudeController // Connected controller (if any)

	// Ownership and management metadata
	IsManaged       bool   // True if this is a squad-managed session
	TmuxSocket      string // Which tmux server socket (empty = default)
	TmuxSessionName string // Full tmux session name
	CanAttach       bool   // Whether attach operations are allowed
	CanDestroy      bool   // Whether destroy operations are allowed
	Owner           string // "squad" for managed, "external" for discovered
}

PTYConnection represents a discovered PTY

func (*PTYConnection) GetDisplayName

func (conn *PTYConnection) GetDisplayName() string

GetDisplayName returns a human-readable name for the PTY

func (*PTYConnection) GetPTYBasename

func (conn *PTYConnection) GetPTYBasename() string

GetPTYBasename returns just the PTY number (e.g., "12" from "/dev/pts/12")

func (*PTYConnection) GetStatusColor

func (conn *PTYConnection) GetStatusColor() string

GetStatusColor returns a color code for PTY status

func (*PTYConnection) GetStatusIcon

func (conn *PTYConnection) GetStatusIcon() string

GetStatusIcon returns a visual indicator for PTY status

type PTYDiscovery

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

PTYDiscovery manages PTY discovery and monitoring

func NewPTYDiscovery

func NewPTYDiscovery(opts ...PTYDiscoveryOption) *PTYDiscovery

NewPTYDiscovery creates a new PTY discovery service with default configuration. Optional PTYDiscoveryOption values are applied after initialization.

func NewPTYDiscoveryWithConfig

func NewPTYDiscoveryWithConfig(config PTYDiscoveryConfig, opts ...PTYDiscoveryOption) *PTYDiscovery

NewPTYDiscoveryWithConfig creates a new PTY discovery service with custom configuration. Optional PTYDiscoveryOption values are applied after initialization.

func (*PTYDiscovery) GetConnection

func (pd *PTYDiscovery) GetConnection(path string) *PTYConnection

GetConnection returns a specific PTY connection by path

func (*PTYDiscovery) GetConnections

func (pd *PTYDiscovery) GetConnections() []*PTYConnection

GetConnections returns all discovered PTY connections

func (*PTYDiscovery) GetConnectionsByCategory

func (pd *PTYDiscovery) GetConnectionsByCategory() map[PTYCategory][]*PTYConnection

GetConnectionsByCategory returns PTYs grouped by category

func (*PTYDiscovery) Refresh

func (pd *PTYDiscovery) Refresh() error

Refresh performs a full PTY discovery scan

func (*PTYDiscovery) SetSessions

func (pd *PTYDiscovery) SetSessions(sessions []*Instance)

SetSessions updates the session map for correlation

func (*PTYDiscovery) Start

func (pd *PTYDiscovery) Start()

Start begins PTY discovery monitoring

func (*PTYDiscovery) Stop

func (pd *PTYDiscovery) Stop()

Stop halts PTY discovery monitoring

type PTYDiscoveryConfig

type PTYDiscoveryConfig struct {
	// Primary tmux server socket for squad-managed sessions
	// Empty string means use the default tmux server
	PrimarySocket string

	// ExternalSockets are additional tmux servers to scan for external instances
	// Only used when Mode is Extended or Full
	ExternalSockets []string

	// Mode controls discovery scope and permissions
	Mode DiscoveryMode

	// ManagedPrefix is the tmux session prefix for squad-managed sessions
	// Default: "staplersquad_"
	ManagedPrefix string

	// DiscoverExternal enables discovery of non-prefixed Claude instances
	// Automatically enabled for Extended and Full modes
	DiscoverExternal bool

	// AllowExternalAttach permits attaching to external instances
	// Only effective in Full mode
	AllowExternalAttach bool

	// RequireConfirmation requires user confirmation for external operations
	// Recommended to keep true for safety
	RequireConfirmation bool

	// DiscoveryInterval controls how often to refresh discovery
	DiscoveryInterval time.Duration

	// ParallelDiscovery enables parallel scanning of multiple tmux servers
	ParallelDiscovery bool
}

PTYDiscoveryConfig controls PTY discovery scope and behavior

func DefaultPTYDiscoveryConfig

func DefaultPTYDiscoveryConfig() PTYDiscoveryConfig

DefaultPTYDiscoveryConfig returns the default discovery configuration

func (*PTYDiscoveryConfig) CanAttachExternal

func (c *PTYDiscoveryConfig) CanAttachExternal() bool

CanAttachExternal returns true if attaching to external instances is allowed

func (*PTYDiscoveryConfig) ShouldDiscoverExternal

func (c *PTYDiscoveryConfig) ShouldDiscoverExternal() bool

ShouldDiscoverExternal returns true if external instances should be discovered

type PTYDiscoveryOption added in v1.18.0

type PTYDiscoveryOption func(*PTYDiscovery)

PTYDiscoveryOption is a functional option for PTYDiscovery construction.

func WithSessionLister added in v1.18.0

func WithSessionLister(l tmux.SessionLister) PTYDiscoveryOption

WithSessionLister injects a SessionLister; used in tests to avoid exec.Command forks.

type PTYStatus

type PTYStatus int

PTYStatus represents the current state of a PTY

const (
	PTYReady PTYStatus = iota // Waiting for input
	PTYBusy                   // Executing command
	PTYIdle                   // No activity
	PTYError                  // Error state
)

func (PTYStatus) String

func (s PTYStatus) String() string

type PTYSubscriber added in v1.35.0

type PTYSubscriber interface {
	// Push appends data to the buffer. Must be goroutine-safe and never block.
	// Returns ErrSubscriberFull if the buffer is at capacity; the caller should
	// then close the subscriber and force the consumer to reconnect.
	Push(data []byte) error
	// Chan returns the receive-only channel from which the consumer reads buffered
	// data. The channel is closed when Close is called and all queued data is drained.
	Chan() <-chan []byte
	// Close signals that no more data will be pushed and releases resources.
	Close()
}

PTYSubscriber is a lossless, ordered buffer for raw PTY bytes from a single session. fanOut calls Push; the consumer reads from Chan. Implementations must be goroutine-safe.

The interface is intentionally minimal so that alternative backends (e.g. a memory-mapped circular file for large or persistent sessions) can be substituted without changing callers.

type PendingApproval

type PendingApproval struct {
	Request      *detection.ApprovalRequest
	Decision     *PolicyDecision
	ReceivedAt   time.Time
	ExpiresAt    time.Time
	Status       PendingApprovalStatus
	UserResponse *detection.ApprovalResponse
}

PendingApproval represents an approval request awaiting action.

type PendingApprovalStatus

type PendingApprovalStatus string

PendingApprovalStatus tracks the state of a pending approval.

const (
	PendingStatusAwaiting  PendingApprovalStatus = "awaiting"
	PendingStatusProcessed PendingApprovalStatus = "processed"
	PendingStatusExpired   PendingApprovalStatus = "expired"
	PendingStatusCancelled PendingApprovalStatus = "cancelled"
)

type PluginConfig added in v1.35.0

type PluginConfig struct {
	Raw string // JSON
}

PluginConfig is opaque config passed to a plugin. Plugins decode their own fields.

type PluginRegistry added in v1.35.0

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

PluginRegistry holds registered source plugins.

func NewDefaultRegistry added in v1.35.0

func NewDefaultRegistry() *PluginRegistry

NewDefaultRegistry returns a registry with all built-in plugins registered.

func NewPluginRegistry added in v1.35.0

func NewPluginRegistry() *PluginRegistry

NewPluginRegistry creates a new empty PluginRegistry.

func (*PluginRegistry) Get added in v1.35.0

Get retrieves a plugin by ID.

func (*PluginRegistry) Register added in v1.35.0

func (r *PluginRegistry) Register(p ItemSourcePlugin)

Register adds a plugin to the registry.

type PolicyAction

type PolicyAction string

PolicyAction specifies what to do when a policy matches.

const (
	ActionAutoApprove PolicyAction = "auto_approve"
	ActionAutoReject  PolicyAction = "auto_reject"
	ActionPrompt      PolicyAction = "prompt"
	ActionLog         PolicyAction = "log_only"
)

type PolicyAuditEntry

type PolicyAuditEntry struct {
	Timestamp      time.Time                  `json:"timestamp"`
	RequestID      string                     `json:"request_id"`
	PolicyID       string                     `json:"policy_id"`
	PolicyName     string                     `json:"policy_name"`
	Action         PolicyAction               `json:"action"`
	MatchedRequest *detection.ApprovalRequest `json:"matched_request"`
	Reason         string                     `json:"reason"`
}

PolicyAuditEntry records policy evaluation results.

type PolicyCondition

type PolicyCondition struct {
	Field    string `json:"field"`    // Field to check (e.g., "command", "file_path")
	Operator string `json:"operator"` // "equals", "contains", "regex", "not_contains"
	Value    string `json:"value"`    // Value to compare against
	// contains filtered or unexported fields
}

PolicyCondition represents a single condition that must be met.

type PolicyDecision

type PolicyDecision struct {
	Request       *detection.ApprovalRequest `json:"request"`
	Timestamp     time.Time                  `json:"timestamp"`
	Decision      PolicyAction               `json:"decision"`
	Matched       bool                       `json:"matched"`
	MatchedPolicy *ApprovalPolicy            `json:"matched_policy,omitempty"`
	Reason        string                     `json:"reason"`
}

PolicyDecision represents the result of policy evaluation.

type PolicyEngine

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

PolicyEngine manages approval policies and evaluates approval requests.

func NewPolicyEngine

func NewPolicyEngine() *PolicyEngine

NewPolicyEngine creates a new approval policy engine.

func (*PolicyEngine) AddPolicy

func (pe *PolicyEngine) AddPolicy(policy *ApprovalPolicy) error

AddPolicy adds a new approval policy.

func (*PolicyEngine) ClearAuditLog

func (pe *PolicyEngine) ClearAuditLog()

ClearAuditLog removes all audit log entries.

func (*PolicyEngine) Evaluate

func (pe *PolicyEngine) Evaluate(request *detection.ApprovalRequest) (*PolicyDecision, error)

Evaluate evaluates an approval request against all policies.

func (*PolicyEngine) GetAuditLog

func (pe *PolicyEngine) GetAuditLog(limit int) []PolicyAuditEntry

GetAuditLog returns recent audit log entries.

func (*PolicyEngine) GetPolicy

func (pe *PolicyEngine) GetPolicy(id string) *ApprovalPolicy

GetPolicy retrieves a policy by ID.

func (*PolicyEngine) GetStatistics

func (pe *PolicyEngine) GetStatistics() PolicyStatistics

GetStatistics returns statistics about policy usage.

func (*PolicyEngine) ListPolicies

func (pe *PolicyEngine) ListPolicies() []*ApprovalPolicy

ListPolicies returns all policies, sorted by priority.

func (*PolicyEngine) RemovePolicy

func (pe *PolicyEngine) RemovePolicy(id string) bool

RemovePolicy removes a policy by ID.

func (*PolicyEngine) SetMaxAuditLog

func (pe *PolicyEngine) SetMaxAuditLog(max int)

SetMaxAuditLog sets the maximum number of audit log entries to keep.

func (*PolicyEngine) UpdatePolicy

func (pe *PolicyEngine) UpdatePolicy(updated *ApprovalPolicy) error

UpdatePolicy updates an existing policy.

type PolicyStatistics

type PolicyStatistics struct {
	TotalPolicies     int
	EnabledPolicies   int
	TotalEvaluations  int
	AutoApprovals     int
	AutoRejections    int
	PromptedApprovals int
	LoggedOnly        int
}

PolicyStatistics provides summary statistics.

type Priority

type Priority = queue.Priority

Priority re-export

type ProcessFileInspector

type ProcessFileInspector interface {
	OpenFiles(pid int32) ([]string, error)
	IsAlive(pid int32, expectedCreateTimeMs int64) bool
}

ProcessFileInspector is the interface used by HistoryFileDetector. This allows mocking in tests.

type ProcessManager added in v1.35.0

type ProcessManager interface {
	// Lifecycle
	Start(dir string) error
	RestoreWithWorkDir(workDir string) error
	Close() error
	IsAlive() bool

	// Identification
	GetSessionIdentifier() string

	// Existence / state
	HasSession() bool

	// Working directory (via pane or process introspection)
	GetCurrentWorkingDirectory() (string, error)

	// Terminal I/O
	GetPTY() (*os.File, error)
	SendKeys(keys string) (int, error)
	TapEnter() error
	SendPromptWithEnter(prompt string) error
	SendInputViaControlMode(ctx context.Context, data []byte) error

	// Terminal state
	CapturePaneContent() (string, error)
	CapturePaneContentRaw() (string, error)
	CapturePaneContentWithOptions(startLine, endLine string) (string, error)
	CaptureViewport(lines int) (string, error)
	GetCursorPosition() (x, y int, err error)
	GetPaneDimensions() (width, height int, err error)
	SetWindowSize(cols, rows int) error
	SetDetachedSize(width, height int, instanceTitle string) error
	RefreshClient() error

	// Process metadata
	GetPanePID() (int32, error)

	// Content helpers
	HasUpdated() (updated bool, hasPrompt bool, content string)
	FilterBanners(content string) (string, int)
	HasMeaningfulContent(content string) bool

	// Streaming (control mode)
	StartControlMode() error
	StopControlMode() error
	// SubscribeToControlModeUpdates returns a subscription ID and a bidirectional channel.
	// The channel must be bidirectional (chan []byte, not <-chan []byte) because some callers
	// write synthetic frames for testing. Implementations must not write to the channel themselves.
	SubscribeToControlModeUpdates() (string, chan []byte)
	UnsubscribeFromControlModeUpdates(id string)

	// Attach (interactive TUI)
	Attach() (chan struct{}, error)
	DetachSafely() error

	// Exit notifications
	SetOnExitCallback(fn func(string))
	ResetExitOnce()
}

ProcessManager abstracts terminal process lifecycle and I/O. Implementations: TmuxBackend (wraps TmuxProcessManager), NativeProcessManager (Phase 2).

func NewProcessManager added in v1.35.0

func NewProcessManager(_ context.Context, defaultBackend ProcessManagerBackend, opts ProcessManagerOptions) ProcessManager

NewProcessManager returns the ProcessManager implementation selected by the registered backend. Falls back to TmuxBackend for unknown values.

type ProcessManagerBackend added in v1.35.0

type ProcessManagerBackend string

ProcessManagerBackend identifies the backend implementation.

const (
	BackendTmux   ProcessManagerBackend = "tmux"
	BackendNative ProcessManagerBackend = "native"
)

type ProcessManagerOptions added in v1.35.0

type ProcessManagerOptions struct {
	SessionName  string
	Prefix       string
	ServerSocket string
	Program      string
	Args         []string
}

ProcessManagerOptions holds constructor parameters for NewProcessManager.

type ProjectData added in v1.23.0

type ProjectData struct {
	// ID is the unique project name (used as string external identifier)
	ID          string
	Name        string
	Description string
	CreatedAt   time.Time
	UpdatedAt   time.Time
}

ProjectData is the domain model for a project that groups sessions.

type Registry added in v1.35.0

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

Registry owns the sessionID → live-actor mapping plus refcounts. Its mutex guards map membership only — not per-field Instance state. Construct with NewRegistry; the zero value is not usable.

func NewRegistry added in v1.35.0

func NewRegistry(storage *Storage, onConstruct func(*LiveInstance)) *Registry

NewRegistry constructs a Registry. onConstruct may be nil (e.g. daemon.go's own Registry, which has no SessionService to wire callbacks for); Acquire nil-checks before calling it.

func (*Registry) Acquire added in v1.35.0

func (r *Registry) Acquire(sessionID string) (*LiveInstance, ReleaseFunc, error)

Acquire returns the live handle for sessionID, constructing its actor on first access. On success, the caller MUST call the returned ReleaseFunc exactly once — prefer WithInstance for synchronous single-call-stack callers to avoid forgetting it.

Three outcomes:

  1. Not in storage → ErrSessionNotFound
  2. Not in map, construction succeeds → new entry, refcount=1
  3. Already in map (or races with concurrent Acquire) → refcount++

func (*Registry) AcquireAll added in v1.35.0

func (r *Registry) AcquireAll() ([]*LiveInstance, ReleaseFunc, error)

AcquireAll acquires every session known to Storage in one call; returns one release closing over all of them. Sugar for sweep-style callers (health.go, hibernation_sweeper.go). Sessions that fail to Acquire are logged and skipped, not returned.

func (*Registry) Count added in v1.35.0

func (r *Registry) Count() int

Count returns the number of live entries.

func (*Registry) ForceRelease added in v1.35.0

func (r *Registry) ForceRelease(sessionID string)

ForceRelease tears down sessionID's actor and map entry immediately, regardless of refcount (R2.18 — DeleteSession's force-invalidate; also used by CreateSession to abort a Register()'d entry when the immediately-following storage.AddInstance fails).

Other holders' *LiveInstance pointers stay valid Go values; their next command must return a typed error (Story 2.5.9c's contract, implemented in Epic 3), never hang.

For CreateSession's abort path: use ForceRelease (not the release() closure Register returned) because a concurrent Acquire racing between Register and the abort would bump refcount to 2, making plain release() decrement 2→1 and leave the phantom entry alive. ForceRelease deletes unconditionally, regardless of current refcount.

func (*Registry) List added in v1.35.0

func (r *Registry) List() []*LiveInstance

List returns a snapshot of all currently-live instances, holding the lock only for the copy.

func (*Registry) Register added in v1.35.0

func (r *Registry) Register(instance *LiveInstance) (ReleaseFunc, error)

Register is the construction-time counterpart to Acquire (R2.18a). CreateSession builds a brand-new *LiveInstance via NewInstance (no persisted row exists yet for Acquire to look up) and hands it to Register before calling storage.AddInstance.

Register deliberately does NOT invoke onConstruct: CreateSession already performs its own explicit post-construction wiring, so routing Register through onConstruct would wire the same callbacks twice. onConstruct exists solely to backfill wiring for the Acquire-from-storage path (sessions loaded on server restart), which has no other caller positioned to do it.

No double-checked locking here (unlike Acquire): Register has no storage I/O to release the lock around, so the whole check-then-insert runs under one lock acquisition.

func (*Registry) Shutdown added in v1.35.0

func (r *Registry) Shutdown()

Shutdown force-stops every actor regardless of refcount. Register this as a shutdownHooks entry (Story 2.5.5d) so it fires on server shutdown.

func (*Registry) Storage added in v1.35.0

func (r *Registry) Storage() *Storage

Storage returns the Registry's backing storage. Used by callers (e.g. daemon.go) that need access to storage through a Registry reference.

func (*Registry) WithInstance added in v1.35.0

func (r *Registry) WithInstance(ctx context.Context, sessionID string, fn func(*LiveInstance) error) error

WithInstance is the preferred entry point for synchronous, single-call-stack callers (RPC handlers, one-shot lookups) where forgetting release() is the common failure mode. Reserve raw Acquire/release() for genuinely long-lived holders (WebSocket streams, poller caches, background goroutines).

type RegistryInspector added in v1.35.0

type RegistryInspector interface {
	List() []*LiveInstance
	Count() int
}

RegistryInspector is the narrowest interface for callers that only enumerate live instances without acquiring individual handles.

type ReleaseFunc added in v1.35.0

type ReleaseFunc func()

ReleaseFunc is the refcount-gated teardown closure returned by Acquire and Register. It is idempotent (safe to call more than once via an internal sync.Once) and must be called exactly once per successful Acquire/Register to avoid refcount leaks. Distinct from ForceReleaseFunc so that future callers storing it generically cannot silently conflate refcount-gated and unconditional teardown (type-driven-audit finding B).

type RepoPathManager

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

RepoPathManager handles GOPATH-style repository path management. Repositories are stored in a consistent location based on their URL:

  • ~/.stapler-squad/repos/github.com/owner/repo (main clone)
  • Worktrees are created relative to the main repo as needed

func NewRepoPathManager

func NewRepoPathManager() *RepoPathManager

NewRepoPathManager creates a new RepoPathManager with the default base directory.

func NewRepoPathManagerWithBase

func NewRepoPathManagerWithBase(baseDir string) *RepoPathManager

NewRepoPathManagerWithBase creates a RepoPathManager with a custom base directory.

func (*RepoPathManager) EnsureRepoCloned

func (m *RepoPathManager) EnsureRepoCloned(ref *GitHubRef) (string, error)

EnsureRepoCloned ensures the repository is cloned to the local path. If already cloned, it fetches the latest changes. Returns the path to the cloned repository.

func (*RepoPathManager) GetCloneURL

func (m *RepoPathManager) GetCloneURL(ref *GitHubRef) string

GetCloneURL returns the git clone URL for a GitHub ref.

func (*RepoPathManager) GetRepoPath

func (m *RepoPathManager) GetRepoPath(ref *GitHubRef) string

GetRepoPath returns the local path where a GitHub repo should be stored. Format: ~/.stapler-squad/repos/github.com/owner/repo

func (*RepoPathManager) ResolveGitHubInput

func (m *RepoPathManager) ResolveGitHubInput(input string) (localPath string, ref *GitHubRef, err error)

ResolveGitHubInput takes a GitHub URL/shorthand and returns a resolved path. It clones the repo if necessary and returns the local path. Also returns the parsed GitHubRef for storing metadata.

type Repository

type Repository interface {
	// Create inserts a new session into storage
	Create(ctx context.Context, data InstanceData) error

	// Update modifies an existing session in storage
	Update(ctx context.Context, data InstanceData) error

	// Delete removes a session from storage by title
	Delete(ctx context.Context, title string) error

	// Get retrieves a single session by title with full child data
	// For selective loading, use GetWithOptions instead
	Get(ctx context.Context, title string) (*InstanceData, error)

	// GetWithOptions retrieves a single session with selective child data loading
	// Use LoadOptions presets (LoadMinimal, LoadSummary, LoadFull) or custom options
	GetWithOptions(ctx context.Context, title string, options LoadOptions) (*InstanceData, error)

	// List retrieves all sessions with summary child data (no diff content)
	// For selective loading, use ListWithOptions instead
	List(ctx context.Context) ([]InstanceData, error)

	// ListWithOptions retrieves all sessions with selective child data loading
	// Use LoadOptions presets (LoadMinimal, LoadSummary, LoadFull) or custom options
	ListWithOptions(ctx context.Context, options LoadOptions) ([]InstanceData, error)

	// ListByStatus retrieves sessions filtered by status with summary child data
	// For selective loading, use ListByStatusWithOptions instead
	ListByStatus(ctx context.Context, status Status) ([]InstanceData, error)

	// ListByStatusWithOptions retrieves sessions filtered by status with selective loading
	ListByStatusWithOptions(ctx context.Context, status Status, options LoadOptions) ([]InstanceData, error)

	// ListByTag retrieves sessions with a specific tag with summary child data
	// For selective loading, use ListByTagWithOptions instead
	ListByTag(ctx context.Context, tag string) ([]InstanceData, error)

	// ListByTagWithOptions retrieves sessions with a specific tag with selective loading
	ListByTagWithOptions(ctx context.Context, tag string, options LoadOptions) ([]InstanceData, error)

	// UpdateTimestamps efficiently updates only timestamp fields for a session
	// This is optimized for frequent updates from WebSocket terminal streaming
	UpdateTimestamps(ctx context.Context, title string, lastTerminalUpdate, lastMeaningfulOutput time.Time, lastOutputSignature string) error

	// UpdateReviewQueueState efficiently updates the review-queue interaction fields
	// (LastUserResponse, ProcessingGraceUntil, LastPromptDetected, LastPromptSignature)
	// without the read-modify-write overhead of a full Get+Update cycle.
	UpdateReviewQueueState(ctx context.Context, title string, lastUserResponse, processingGraceUntil, lastPromptDetected time.Time, lastPromptSignature string) error

	// UpdateLastAddedToQueue sets only the last_added_to_queue field for a session.
	// Issues a single UPDATE WHERE title=? without a prior SELECT.
	UpdateLastAddedToQueue(ctx context.Context, title string, t time.Time) error

	// UpdateLastAcknowledged sets only the last_acknowledged field for a session.
	// Issues a single UPDATE WHERE title=? without a prior SELECT.
	UpdateLastAcknowledged(ctx context.Context, title string, t time.Time) error

	// UpdateLastViewed sets only the last_viewed field for a session.
	// Issues a single UPDATE WHERE title=? without a prior SELECT.
	UpdateLastViewed(ctx context.Context, title string, t time.Time) error

	// Close performs cleanup and releases resources
	Close() error

	// GetSession retrieves a session using the new Session domain model.
	// Use ContextOptions to control which optional contexts are loaded.
	// Returns nil if session not found.
	GetSession(ctx context.Context, title string, opts ContextOptions) (*Session, error)

	// ListSessions retrieves all sessions using the new Session domain model.
	// Use ContextOptions to control which optional contexts are loaded.
	ListSessions(ctx context.Context, opts ContextOptions) ([]*Session, error)

	// CreateSession creates a new session from the Session domain model.
	CreateSession(ctx context.Context, session *Session) error

	// UpdateSession updates an existing session using the Session domain model.
	UpdateSession(ctx context.Context, session *Session) error

	// AllRules returns all auto-approval rules.
	AllRules(ctx context.Context) ([]ApprovalRuleData, error)
	// UpsertRule creates or updates an auto-approval rule.
	UpsertRule(ctx context.Context, rule ApprovalRuleData) error
	// DeleteRule removes an auto-approval rule by ID.
	DeleteRule(ctx context.Context, id string) error

	// RecordAnalytics logs a classification decision.
	RecordAnalytics(ctx context.Context, data AnalyticsData) error
	// ListAnalytics retrieves recent classification decisions.
	ListAnalytics(ctx context.Context, limit int) ([]AnalyticsData, error)

	// ListAnalyticsSince retrieves analytics entries with created_at >= since.
	// Replaces the in-Go date filter in LoadWindow. Implements AC-1.
	// Pass limit=0 for no limit.
	ListAnalyticsSince(ctx context.Context, since time.Time, limit int) ([]AnalyticsData, error)

	// ListAnalyticsByProgramSince retrieves entries for a specific program since a time.
	// Uses the compound index (command_program, created_at). Implements AC-3.
	// Pass limit=0 for no limit.
	ListAnalyticsByProgramSince(ctx context.Context, program string, since time.Time, limit int) ([]AnalyticsData, error)

	// GetSubcommandBreakdown returns per-(subcommand, decision) counts for a program
	// in the given time window. Uses SQL GROUP BY via ent Aggregate. Implements AC-4.
	GetSubcommandBreakdown(ctx context.Context, program string, since time.Time) ([]SubcommandDecisionCount, error)

	// ListRecentCommandsByProgram returns the most recent n command_preview strings
	// for (program, subcommand). Pass subcommand="" to match all subcommands.
	// Implements AC-5.
	ListRecentCommandsByProgram(ctx context.Context, program, subcommand string, since time.Time, n int) ([]string, error)

	// GetSubcommandTrend returns raw analytics rows for (program, subcommand) since
	// a given time. The caller buckets these using ComputeDailyBuckets. Implements AC-6.
	// Pass subcommand="" to match all subcommands for the program.
	GetSubcommandTrend(ctx context.Context, program, subcommand string, since time.Time) ([]AnalyticsData, error)

	// CreateProject inserts a new project.
	CreateProject(ctx context.Context, data ProjectData) (*ProjectData, error)
	// ListProjects returns all projects.
	ListProjects(ctx context.Context) ([]ProjectData, error)
	// UpdateProject modifies an existing project.
	UpdateProject(ctx context.Context, data ProjectData) (*ProjectData, error)
	// DeleteProject removes a project by name; sessions are unassigned.
	DeleteProject(ctx context.Context, name string) error
	// AssignSessionsToProject links sessions (by title) to a project (by name).
	AssignSessionsToProject(ctx context.Context, projectName string, sessionTitles []string) error

	// CreateBacklogItem inserts a new backlog item.
	CreateBacklogItem(ctx context.Context, data BacklogItemData) (*BacklogItemData, error)
	// GetBacklogItem retrieves a backlog item by UUID string.
	GetBacklogItem(ctx context.Context, id string) (*BacklogItemData, error)
	// ListBacklogItems returns backlog items with optional filtering.
	ListBacklogItems(ctx context.Context, filter BacklogItemFilter) ([]BacklogItemData, error)
	// UpdateBacklogItem modifies an existing backlog item with optional precondition check.
	UpdateBacklogItem(ctx context.Context, id string, update BacklogItemUpdate, precondition *BacklogItemPrecondition) (*BacklogItemData, error)
	// ArchiveBacklogItem sets the archived_at timestamp on a backlog item.
	ArchiveBacklogItem(ctx context.Context, id string) (*BacklogItemData, error)
	// DeleteBacklogItem permanently removes an item and all its child records.
	DeleteBacklogItem(ctx context.Context, id string) error
	// TransitionBacklogItemStatus changes the status of a backlog item with optional precondition.
	TransitionBacklogItemStatus(ctx context.Context, id string, toStatus BacklogStatus, precondition *BacklogItemPrecondition) (*BacklogItemData, error)

	// CreateItemSource registers a new external item source.
	CreateItemSource(ctx context.Context, data ItemSourceData) (*ItemSourceData, error)
	// ListItemSources returns all registered item sources.
	ListItemSources(ctx context.Context) ([]ItemSourceData, error)
	// UpdateItemSource modifies an existing item source.
	UpdateItemSource(ctx context.Context, id string, update ItemSourceUpdate) (*ItemSourceData, error)
	// DeleteItemSource removes an item source by UUID string.
	DeleteItemSource(ctx context.Context, id string) error
}

Repository defines the interface for session persistence operations. This abstraction allows multiple storage backends (SQLite, JSON, etc.) while maintaining a consistent API for session management.

type RepositoryOption

type RepositoryOption func(interface{}) error

RepositoryOption is a function that configures a repository

func WithDatabasePath

func WithDatabasePath(path string) RepositoryOption

WithDatabasePath sets the database file path for the repository

type ResponseChunk

type ResponseChunk struct {
	Data      []byte
	Timestamp time.Time
	Error     error
}

ResponseChunk represents a chunk of output from the Claude instance.

type ResponseStream

type ResponseStream struct {
	OnEOF func() // Called when the PTY exits unexpectedly (program exit, not Stop())
	// contains filtered or unexported fields
}

ResponseStream manages real-time streaming of Claude instance responses to multiple subscribers. It reads from the PTY access layer and broadcasts output to all active subscribers.

func NewResponseStream

func NewResponseStream(sessionName string, ptyAccess *PTYAccess) *ResponseStream

NewResponseStream creates a new response stream for the given session. The bufferSize parameter determines how many chunks can be buffered per subscriber.

func NewResponseStreamWithBuffer

func NewResponseStreamWithBuffer(sessionName string, ptyAccess *PTYAccess, bufferSize int) *ResponseStream

NewResponseStreamWithBuffer creates a response stream with a custom buffer size.

func (*ResponseStream) GetBufferSize

func (rs *ResponseStream) GetBufferSize() int

GetBufferSize returns the current buffer size setting.

func (*ResponseStream) GetEscapeParser added in v1.35.0

func (rs *ResponseStream) GetEscapeParser() *analytics.EscapeCodeParser

GetEscapeParser returns the escape code parser for this stream. Used by the WebSocket handler for Stage 2 analytics observations. Returns nil if no parser is configured.

func (*ResponseStream) GetExitTail added in v1.15.0

func (rs *ResponseStream) GetExitTail() []byte

GetExitTail returns a copy of the last bytes seen before the PTY exited. Returns nil if the stream has not yet exited or no output was captured.

func (*ResponseStream) GetSubscriberCount

func (rs *ResponseStream) GetSubscriberCount() int

GetSubscriberCount returns the number of active subscribers.

func (*ResponseStream) GetSubscriberIDs

func (rs *ResponseStream) GetSubscriberIDs() []string

GetSubscriberIDs returns the IDs of all active subscribers.

func (*ResponseStream) GetSubscriberInfo

func (rs *ResponseStream) GetSubscriberInfo(subscriberID string) (created time.Time, exists bool)

GetSubscriberInfo returns information about a specific subscriber.

func (*ResponseStream) GetTotalBytesWritten added in v1.35.0

func (rs *ResponseStream) GetTotalBytesWritten() int64

GetTotalBytesWritten returns the monotonic PTY byte offset from the circular buffer. This is the same counter used by Stage 1 (Parse) so Stage 2 (ParseStage2) session_seq values are stable across WebSocket reconnections. Returns 0 if no buffer is available.

func (*ResponseStream) IsStarted

func (rs *ResponseStream) IsStarted() bool

IsStarted returns whether the stream is currently active.

func (*ResponseStream) SetBufferSize

func (rs *ResponseStream) SetBufferSize(size int)

SetBufferSize sets the buffer size for future subscribers. Does not affect existing subscribers.

func (*ResponseStream) SetOnOutput added in v1.9.0

func (rs *ResponseStream) SetOnOutput(fn func())

SetOnOutput registers a callback invoked each time PTY bytes arrive. Used by ClaudeController to drive event-based activity tracking in IdleDetector. Must be called before Start().

func (*ResponseStream) SetStableSessionID added in v1.35.0

func (rs *ResponseStream) SetStableSessionID(id string)

SetStableSessionID switches the escape parser's recorded session identifier from the tmux session name (used at construction time, before the owning Instance's stable UUID is available) to the stable UUID. This only affects how escape_event rows are tagged — it does not change rs.sessionName, which is still used for logging, PTY naming, and history keyed off the tmux name.

func (*ResponseStream) Start

func (rs *ResponseStream) Start(ctx context.Context) error

Start begins streaming responses from the PTY to all subscribers. This is a non-blocking call that starts a background goroutine. Use the provided context to stop the stream.

func (*ResponseStream) Stop

func (rs *ResponseStream) Stop() error

Stop stops the response stream and closes all subscriber channels. This is a blocking call that waits for the streaming goroutine to finish.

func (*ResponseStream) Subscribe

func (rs *ResponseStream) Subscribe(subscriberID string) (<-chan ResponseChunk, error)

Subscribe registers a new subscriber and returns a channel for receiving response chunks. The subscriber ID should be unique. Returns an error if the ID is already in use.

func (*ResponseStream) Unsubscribe

func (rs *ResponseStream) Unsubscribe(subscriberID string) error

Unsubscribe removes a subscriber and closes their channel.

type RestartState

type RestartState struct {
	// Working directory to restore
	WorkingDir string
	// Claude session ID for --resume flag
	ClaudeSessionID string
	// Environment variables to restore
	Environment map[string]string
	// Original command/program
	Program string
	// AutoYes flag
	AutoYes bool
	// Original prompt
	Prompt string
}

RestartState holds the state needed to restart a session

type ReviewGateSpawner added in v1.35.0

type ReviewGateSpawner interface {
	// SpawnReviewSession creates a one-shot review session for item using prompt.
	// itemSessionID is the UUID of the work ItemSession being reviewed.
	SpawnReviewSession(ctx context.Context, item *ent.BacklogItem, itemSessionID string, prompt string) (*Instance, error)
}

ReviewGateSpawner can create a short-lived review session for a backlog item. Deprecated: use headless.Pool via NewBacklogLifecycleListenerWithSpawner instead. Retained for backward compatibility with existing tests and callers.

type ReviewItem

type ReviewItem = queue.ReviewItem

ReviewItem re-export

type ReviewQueue

type ReviewQueue = queue.ReviewQueue

ReviewQueue re-export

func NewReviewQueue

func NewReviewQueue() *ReviewQueue

NewReviewQueue creates a new review queue.

type ReviewQueueObserver

type ReviewQueueObserver = queue.ReviewQueueObserver

ReviewQueueObserver re-export

type ReviewQueuePoller

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

ReviewQueuePoller automatically monitors sessions and adds them to the review queue when they become idle or need attention.

func NewReviewQueuePoller

func NewReviewQueuePoller(queue *ReviewQueue, statusManager StatusProvider, storage *Storage) *ReviewQueuePoller

NewReviewQueuePoller creates a new poller for automatically managing the review queue. The storage parameter is optional (can be nil) but required for persisting LastAddedToQueue timestamps.

func NewReviewQueuePollerWithConfig

func NewReviewQueuePollerWithConfig(queue *ReviewQueue, statusManager StatusProvider, storage *Storage, config ReviewQueuePollerConfig) *ReviewQueuePoller

NewReviewQueuePollerWithConfig creates a poller with custom configuration. The storage parameter is optional (can be nil) but required for persisting LastAddedToQueue timestamps.

func (*ReviewQueuePoller) AddInstance

func (rqp *ReviewQueuePoller) AddInstance(instance *Instance)

AddInstance adds a single instance to monitor.

func (*ReviewQueuePoller) CheckSession

func (rqp *ReviewQueuePoller) CheckSession(inst *Instance)

CheckSession checks a single session immediately (exported for ReactiveQueueManager). This allows external components to trigger immediate re-evaluation without waiting for the next poll cycle, providing <100ms feedback on user interactions. Fetches a fresh pane activity snapshot for accurate cache invalidation.

func (*ReviewQueuePoller) FindInstance

func (rqp *ReviewQueuePoller) FindInstance(sessionID string) *Instance

FindInstance finds an instance by session ID (exported for ReactiveQueueManager). Returns nil if the instance is not found in the monitored list.

func (*ReviewQueuePoller) ForceReconcile added in v1.24.0

func (rqp *ReviewQueuePoller) ForceReconcile()

ForceReconcile immediately runs session reconciliation outside the normal 30s cadence. Safe to call concurrently; typically used by the fork pressure monitor to rapidly clean up dead sessions when subprocess failures indicate stale Active states.

func (*ReviewQueuePoller) GetConfig

func (rqp *ReviewQueuePoller) GetConfig() ReviewQueuePollerConfig

GetConfig returns the current configuration.

func (*ReviewQueuePoller) GetInstances

func (rqp *ReviewQueuePoller) GetInstances() []*Instance

GetInstances returns a snapshot of all live in-memory instances held by the poller. Use this instead of LoadInstances() for read-only operations to avoid the side effect of FromInstanceData() calling Start() on every non-paused instance.

func (*ReviewQueuePoller) GetMonitoredCount

func (rqp *ReviewQueuePoller) GetMonitoredCount() int

GetMonitoredCount returns the number of instances being monitored.

func (*ReviewQueuePoller) IsRunning

func (rqp *ReviewQueuePoller) IsRunning() bool

IsRunning returns true if the poller is currently running.

func (*ReviewQueuePoller) RemoveInstance

func (rqp *ReviewQueuePoller) RemoveInstance(instanceTitle string)

RemoveInstance removes an instance from monitoring.

func (*ReviewQueuePoller) SetActivityChannel added in v1.23.0

func (rqp *ReviewQueuePoller) SetActivityChannel(ch <-chan struct{})

SetActivityChannel wires an external signal channel to the poll loop. When a signal arrives on ch, the loop snaps back to the fast interval (PollInterval). Must be called before Start(); subsequent calls have no effect once the loop is running.

func (*ReviewQueuePoller) SetApprovalProvider

func (rqp *ReviewQueuePoller) SetApprovalProvider(provider ApprovalMetadataProvider)

SetApprovalProvider sets the approval metadata provider for enriching review queue items.

func (*ReviewQueuePoller) SetInstances

func (rqp *ReviewQueuePoller) SetInstances(instances []*Instance)

SetInstances sets the list of instances to monitor.

func (*ReviewQueuePoller) Start

func (rqp *ReviewQueuePoller) Start(ctx context.Context)

Start begins polling for idle sessions.

func (*ReviewQueuePoller) Stop

func (rqp *ReviewQueuePoller) Stop()

Stop stops the poller.

func (*ReviewQueuePoller) UpdateConfig

func (rqp *ReviewQueuePoller) UpdateConfig(config ReviewQueuePollerConfig)

UpdateConfig updates the poller configuration.

type ReviewQueuePollerConfig

type ReviewQueuePollerConfig struct {
	PollInterval       time.Duration // How often to check sessions (fast path, default 2s)
	SlowPollInterval   time.Duration // Interval when review queue is empty (default 8s); 0 = no backoff
	IdleThreshold      time.Duration // Duration before considering session idle and adding to queue
	InputWaitDuration  time.Duration // Time waiting for input before flagging
	StalenessThreshold time.Duration // Duration since last meaningful output before considering stale
	ReconcileInterval  time.Duration // How often to reconcile in-memory state against tmux reality (0 = disabled)
}

ReviewQueuePollerConfig contains configuration for the review queue poller.

func DefaultReviewQueuePollerConfig

func DefaultReviewQueuePollerConfig() ReviewQueuePollerConfig

DefaultReviewQueuePollerConfig returns sensible defaults for polling.

type ReviewQueueStatistics

type ReviewQueueStatistics = queue.ReviewQueueStatistics

ReviewQueueStatistics re-export

type ReviewQueueWriter added in v1.35.0

type ReviewQueueWriter interface {
	Add(item *ReviewItem) bool
}

ReviewQueueWriter is the write-side interface for the review queue. It is satisfied by *ReviewQueue and can be used in place of the concrete type wherever only Add is required, making it easy to supply a test double.

type ReviewState

type ReviewState struct {
	// LastAcknowledged tracks when the user last acknowledged this session in the review queue.
	// Sessions acknowledged after their last update won't appear in the queue until they update again.
	LastAcknowledged time.Time

	// LastAddedToQueue tracks when this session was last added to the review queue.
	// Used to prevent notification spam by enforcing a minimum re-add interval.
	LastAddedToQueue time.Time

	// LastTerminalUpdate is the timestamp of the last output received from the terminal (any output).
	LastTerminalUpdate time.Time

	// LastMeaningfulOutput is the timestamp of the last meaningful output (excludes tmux status banners).
	// Used by the review queue to determine session staleness.
	LastMeaningfulOutput time.Time

	// LastOutputSignature is a hash of the terminal content, used to detect actual changes
	// vs app restarts with unchanged content (prevents false "new activity" notifications).
	LastOutputSignature string

	// LastViewed tracks when the user last interacted with this session
	// (viewing the terminal, attaching via tmux, or viewing session details).
	// Used for smarter review queue notifications (don't notify if just viewed).
	LastViewed time.Time

	// LastPromptDetected is the timestamp when we last detected a prompt requiring user input.
	// Used to distinguish new prompts from the same prompt re-appearing.
	LastPromptDetected time.Time

	// LastPromptSignature is a hash of the prompt content (last 10 lines before cursor).
	// Used to determine if this is the same prompt or a new one.
	LastPromptSignature string

	// LastUserResponse is the timestamp when the user last provided input/interaction.
	// Used to determine if user responded AFTER a prompt was detected.
	LastUserResponse time.Time

	// ProcessingGraceUntil is the deadline for waiting for the session to respond after
	// user interaction. If the session shows no activity by this time, it may be re-added
	// to the review queue.
	ProcessingGraceUntil time.Time
	// contains filtered or unexported fields
}

ReviewState holds all timestamps and state related to the review queue and terminal activity tracking for a session. It is embedded in Instance so all field accesses remain unchanged.

Fields are protected by Instance.mu; do not lock ReviewState independently. Methods on ReviewState are intentionally non-locking — callers must hold mu if concurrent access is possible.

Direct field access via Go embedding promotion (inst.LastMeaningfulOutput etc.) is used by:

  • session/review_queue_poller.go: reads LastMeaningfulOutput, LastAcknowledged, LastAddedToQueue, ProcessingGraceUntil, LastPromptDetected, LastPromptSignature, LastUserResponse, LastViewed, LastTerminalUpdate, LastOutputSignature
  • server/dependencies.go: reads LastMeaningfulOutput, LastTerminalUpdate, LastAddedToQueue, LastAcknowledged
  • server/adapters/instance_adapter.go: reads LastTerminalUpdate, LastMeaningfulOutput
  • server/review_queue_manager.go: writes LastUserResponse directly

All access is either within the session package (under mu) or through Instance methods that acquire mu.

TODO: Migrate cross-package field accesses (server/) to accessor methods to enable future encapsulation of ReviewState as a composed (non-embedded) field.

func (*ReviewState) ComputePromptSignature

func (rs *ReviewState) ComputePromptSignature(content string) string

ComputePromptSignature computes a hash of the prompt content using the last 10 lines. Returns "" if content is empty. Caller may call this without holding any lock.

func (*ReviewState) DetectAndTrackPrompt

func (rs *ReviewState) DetectAndTrackPrompt(content string, statusInfo InstanceStatusInfo, sessionTitle string) bool

DetectAndTrackPrompt detects whether the current status represents a new user-facing prompt and records it. Returns true only when a NEW prompt is detected (signature changed or first). Caller must hold Instance.mu when writing prompt fields.

func (*ReviewState) IsAcknowledgedAfterOutput

func (rs *ReviewState) IsAcknowledgedAfterOutput() bool

IsAcknowledgedAfterOutput returns true if the user acknowledged this session more recently than the last meaningful terminal output — meaning no new output has occurred since the user last dismissed the session from the review queue. Returns false when LastMeaningfulOutput is zero: if no output has ever been recorded, the acknowledgment cannot logically be "after" output, so the session is not snoozed. Caller must hold the relevant mutex if concurrent access is possible.

func (*ReviewState) IsInProcessingGracePeriod

func (rs *ReviewState) IsInProcessingGracePeriod() bool

IsInProcessingGracePeriod returns true if the session is within its processing grace window. Caller must hold the relevant mutex if concurrent access is possible.

func (*ReviewState) SyncAtomicTimestamps added in v1.35.0

func (rs *ReviewState) SyncAtomicTimestamps()

SyncAtomicTimestamps initialises atomic shadow fields from their time.Time counterparts. Must be called once after constructing ReviewState from persisted or restored data so that lock-free readers see the correct initial value immediately.

func (*ReviewState) TimeSinceLastMeaningfulOutput

func (rs *ReviewState) TimeSinceLastMeaningfulOutput(createdAt time.Time) time.Duration

TimeSinceLastMeaningfulOutput returns how long ago meaningful terminal output was received. If LastMeaningfulOutput is zero, returns the duration since the given createdAt time. Caller must hold the relevant mutex if concurrent access is possible.

func (*ReviewState) TimeSinceLastTerminalUpdate

func (rs *ReviewState) TimeSinceLastTerminalUpdate(createdAt time.Time) time.Duration

TimeSinceLastTerminalUpdate returns how long ago any terminal output was received. If LastTerminalUpdate is zero, returns the duration since the given createdAt time. Caller must hold the relevant mutex if concurrent access is possible.

func (*ReviewState) UpdateTimestamps

func (rs *ReviewState) UpdateTimestamps(rawContent, filteredContent string, shouldUpdateMeaningful bool, sessionTitle string)

UpdateTimestamps updates terminal activity timestamps based on processed content.

  • rawContent: original captured output, used for the LastTerminalUpdate non-blank check.
  • filteredContent: rawContent with tmux banners stripped, used for signature computation.
  • shouldUpdateMeaningful: true when the content carries meaningful signal (not just banners).
  • sessionTitle: used only for structured debug logging.

Caller must hold Instance.mu.

func (*ReviewState) UserRespondedAfterPrompt

func (rs *ReviewState) UserRespondedAfterPrompt() bool

UserRespondedAfterPrompt returns true if the user responded (LastUserResponse) after a prompt was detected (LastPromptDetected), indicating the session is no longer waiting. Caller must hold the relevant mutex if concurrent access is possible.

type ReviewVerdictData added in v1.35.0

type ReviewVerdictData struct {
	ItemSessionID  string
	OverallOutcome string
	PerCriterion   string // JSON
	Summary        string
	DiffHash       string
	PromptHash     string
	DiffTokenCount int
	DiffTruncated  bool
	OverrideBy     string
	OverrideReason string
	OverrideAt     *time.Time
}

ReviewVerdictData is the input data for saving a ReviewVerdict.

type RevisionTarget

type RevisionTarget struct {
	ID          string
	ShortID     string
	Description string
	Author      string
	Timestamp   time.Time
	IsCurrent   bool
}

RevisionTarget represents a revision as a switch target

type Session

type Session struct {
	// Identity
	ID        string    `json:"id"`
	Title     string    `json:"title"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`

	// Process
	Status  Status `json:"status"`
	Program string `json:"program"`

	// Configuration
	AutoYes bool   `json:"auto_yes,omitempty"`
	Prompt  string `json:"prompt,omitempty"`

	// Optional contexts (nil = not loaded or not applicable)
	Git        *GitContext        `json:"git,omitempty"`
	Filesystem *FilesystemContext `json:"filesystem,omitempty"`
	Terminal   *TerminalContext   `json:"terminal,omitempty"`
	UI         *UIPreferences     `json:"ui,omitempty"`
	Activity   *ActivityTracking  `json:"activity,omitempty"`
	Cloud      *CloudContext      `json:"cloud,omitempty"`
}

Session represents the core domain entity for an AI agent session. It contains only universally required fields, with optional contexts for deployment-specific functionality.

Context types are defined in contexts.go: - GitContext: Git repository, branch, PR integration - FilesystemContext: Paths, working directories, worktree detection - TerminalContext: Terminal dimensions, tmux configuration - UIPreferences: Categories, tags, display preferences - ActivityTracking: Timestamps, output signatures, queue tracking - CloudContext: Cloud provider, API configuration

func InstanceToSession

func InstanceToSession(i *Instance) *Session

InstanceToSession converts a legacy Instance to the new Session type. This adapter enables gradual migration while maintaining backward compatibility. It populates all relevant contexts from the Instance fields.

func NewSession

func NewSession(title, program string) *Session

NewSession creates a new Session with the required fields. Optional contexts can be added using the With* methods.

func (*Session) GetBranch

func (s *Session) GetBranch() string

GetBranch returns the Git branch name, or empty string if no Git context.

func (*Session) GetCategory

func (s *Session) GetCategory() string

GetCategory returns the UI category, or empty string if no UI preferences.

func (*Session) GetLastMeaningfulOutput

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

GetLastMeaningfulOutput returns when the session had meaningful output, or zero time if no activity tracking.

func (*Session) GetLastViewed

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

GetLastViewed returns when the session was last viewed, or zero time if no activity tracking.

func (*Session) GetPath

func (s *Session) GetPath() string

GetPath returns the filesystem project path, or empty string if no filesystem context.

func (*Session) GetTags

func (s *Session) GetTags() []string

GetTags returns the UI tags, or empty slice if no UI preferences.

func (*Session) GetTerminalDimensions

func (s *Session) GetTerminalDimensions() (width, height int)

GetTerminalDimensions returns the terminal width and height, or 0,0 if no terminal context.

func (*Session) GetTmuxSessionName

func (s *Session) GetTmuxSessionName() string

GetTmuxSessionName returns the tmux session name, or empty string if no terminal context.

func (*Session) GetWorkingDir

func (s *Session) GetWorkingDir() string

GetWorkingDir returns the working directory, or empty string if no filesystem context.

func (*Session) HasActivityTracking

func (s *Session) HasActivityTracking() bool

HasActivityTracking returns true if activity tracking is available.

func (*Session) HasCloudContext

func (s *Session) HasCloudContext() bool

HasCloudContext returns true if cloud context is available.

func (*Session) HasFilesystemContext

func (s *Session) HasFilesystemContext() bool

HasFilesystemContext returns true if filesystem context is available.

func (*Session) HasGitContext

func (s *Session) HasGitContext() bool

HasGitContext returns true if Git context is available.

func (*Session) HasTerminalContext

func (s *Session) HasTerminalContext() bool

HasTerminalContext returns true if terminal context is available.

func (*Session) HasUIPreferences

func (s *Session) HasUIPreferences() bool

HasUIPreferences returns true if UI preferences are available.

func (*Session) IsCloudConfigured

func (s *Session) IsCloudConfigured() bool

IsCloudConfigured returns true if the cloud context is properly configured.

func (*Session) NeedsReviewQueueAttention

func (s *Session) NeedsReviewQueueAttention() bool

NeedsReviewQueueAttention returns true if session has unacknowledged output.

func (*Session) WithActivityTracking

func (s *Session) WithActivityTracking(activity *ActivityTracking) *Session

WithActivityTracking adds activity tracking to the session.

func (*Session) WithCloudContext

func (s *Session) WithCloudContext(cloud *CloudContext) *Session

WithCloudContext adds cloud context to the session.

func (*Session) WithFilesystemContext

func (s *Session) WithFilesystemContext(fs *FilesystemContext) *Session

WithFilesystemContext adds filesystem context to the session.

func (*Session) WithGitContext

func (s *Session) WithGitContext(git *GitContext) *Session

WithGitContext adds Git context to the session.

func (*Session) WithTerminalContext

func (s *Session) WithTerminalContext(terminal *TerminalContext) *Session

WithTerminalContext adds terminal context to the session.

func (*Session) WithUIPreferences

func (s *Session) WithUIPreferences(ui *UIPreferences) *Session

WithUIPreferences adds UI preferences to the session.

type SessionGoalData added in v1.35.0

type SessionGoalData struct {
	UUID        string     `json:"uuid"`
	SessionUUID string     `json:"session_uuid"`
	Goal        string     `json:"goal"`
	Status      string     `json:"status"`
	Tasks       []TaskNode `json:"tasks,omitempty"`
	SetBy       string     `json:"set_by,omitempty"`
	UpdatedAt   time.Time  `json:"updated_at"`
}

SessionGoalData holds the goal state for a session, including the task tree.

func (*SessionGoalData) TasksDone added in v1.35.0

func (g *SessionGoalData) TasksDone() int

TasksDone returns the count of all tasks with status "done" (including nested children).

func (*SessionGoalData) TasksTotal added in v1.35.0

func (g *SessionGoalData) TasksTotal() int

TasksTotal returns the total count of all tasks (including nested children) in the goal.

type SessionHealthChecker

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

SessionHealthChecker manages session health validation and recovery

func NewSessionHealthChecker

func NewSessionHealthChecker(storage *Storage) *SessionHealthChecker

NewSessionHealthChecker creates a new session health checker

func (*SessionHealthChecker) CheckAllSessions

func (h *SessionHealthChecker) CheckAllSessions() ([]HealthCheckResult, error)

CheckAllSessions performs a health check on all active sessions

func (*SessionHealthChecker) RecoverUnhealthySessions

func (h *SessionHealthChecker) RecoverUnhealthySessions() error

RecoverUnhealthySessions attempts to recover all unhealthy sessions

func (*SessionHealthChecker) ScheduledHealthCheck

func (h *SessionHealthChecker) ScheduledHealthCheck(interval time.Duration, stopChan <-chan struct{})

ScheduledHealthCheck runs health checks at regular intervals

type SessionType

type SessionType = config.SessionType

SessionType is an alias for config.SessionType so callers can use either package.

type Shell added in v1.35.0

type Shell struct {
	// ID is the stable UUID for this shell. Also the fragment used in the tmux session name.
	ID string
	// Name is the user-visible label for the shell tab.
	Name string
	// Command is the command running in the shell (e.g. "bash", "python").
	Command string
	// WorkingDir is the working directory for the shell process.
	WorkingDir string
	// TmuxSessionName is the full computed tmux session name:
	// "{parentPrefix}_shell_{shellID}"
	TmuxSessionName string
	// Status is the current lifecycle status.
	Status ShellStatus
	// ExitCode is the process exit code (meaningful when Status != ShellStatusRunning).
	ExitCode int
	// OrderIndex controls tab display order.
	OrderIndex int
	// StartedAt is when the shell was spawned.
	StartedAt time.Time
	// contains filtered or unexported fields
}

Shell represents a custom shell attached to a session. It is the in-memory projection of the ent Shell entity; changes are written back through the repository.

type ShellData added in v1.35.0

type ShellData struct {
	// ID is the UUID for the shell. If empty, the caller must populate it.
	ID string
	// Name is the user-visible label.
	Name string
	// Command is the command to run in the shell.
	Command string
	// WorkingDir is the starting directory for the shell process.
	WorkingDir string
	// TmuxSessionName is the full sibling tmux session name.
	TmuxSessionName string
	// OrderIndex is the display order for the tab.
	OrderIndex int
}

ShellData carries the input fields for creating a new shell.

type ShellHandle added in v1.35.0

type ShellHandle interface {
	// GetPTY returns the PTY file for reading terminal output.
	// Returns ErrShellStopped if the shell has been closed.
	GetPTY() (*os.File, error)
	// Resize updates the PTY dimensions.
	Resize(cols, rows int) error
	// Close stops the shell process and releases resources.
	Close() error
}

ShellHandle is the interface for managing a single shell PTY. It is implemented by session/tmux.ShellTmuxHandle for real sessions and can be mocked in tests.

type ShellRegistry added in v1.35.0

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

ShellRegistry is a concurrent shell+handle store. Zero value is not usable; create with newShellRegistry(). The exported API intentionally has no Lock/Unlock methods — mutations go through named operations that hold the bucket lock only for fast in-memory work.

func (*ShellRegistry) Add added in v1.35.0

func (r *ShellRegistry) Add(sh *Shell, handle *tmux.ShellTmuxHandle)

Add stores a new shell+handle pair. Overwrites any existing entry for the same ID.

func (*ShellRegistry) AddStopped added in v1.35.0

func (r *ShellRegistry) AddStopped(sh *Shell)

AddStopped stores a shell that has no live handle (already stopped or error).

func (*ShellRegistry) Get added in v1.35.0

func (r *ShellRegistry) Get(shellID string) (*Shell, bool)

Get returns the Shell for shellID, or (nil, false) if absent.

func (*ShellRegistry) GetBoth added in v1.35.0

func (r *ShellRegistry) GetBoth(shellID string) (*Shell, *tmux.ShellTmuxHandle, bool)

GetBoth returns both shell and handle in one atomic load.

func (*ShellRegistry) GetHandle added in v1.35.0

func (r *ShellRegistry) GetHandle(shellID string) (*tmux.ShellTmuxHandle, bool)

GetHandle returns the ShellTmuxHandle for shellID, or (nil, false) if absent.

func (*ShellRegistry) Len added in v1.35.0

func (r *ShellRegistry) Len() int

Len returns the number of shells in the registry.

func (*ShellRegistry) List added in v1.35.0

func (r *ShellRegistry) List() []*Shell

List returns all shells sorted by OrderIndex.

func (*ShellRegistry) Remove added in v1.35.0

func (r *ShellRegistry) Remove(shellID string)

Remove deletes the entry for shellID. No-op if not present.

func (*ShellRegistry) SetHandle added in v1.35.0

func (r *ShellRegistry) SetHandle(shellID string, handle *tmux.ShellTmuxHandle)

SetHandle atomically replaces the handle for shellID without changing the shell.

func (*ShellRegistry) UpdateForRestart added in v1.35.0

func (r *ShellRegistry) UpdateForRestart(shellID string, newHandle *tmux.ShellTmuxHandle, newSessionName string, exitCh, watcherDone chan struct{})

UpdateForRestart atomically replaces a shell's mutable restart fields with new values (Status=Running, ExitCode=0, new TmuxSessionName, new exitCh/watcherDone). If the shellID is not found it stores a brand-new entry built from newShell.

func (*ShellRegistry) UpdateStatus added in v1.35.0

func (r *ShellRegistry) UpdateStatus(shellID string, status ShellStatus, exitCode *int) bool

UpdateStatus atomically updates Shell.Status and Shell.ExitCode for shellID. Returns true if the entry was found and updated.

type ShellRepository added in v1.35.0

type ShellRepository interface {
	// CreateShell persists a new shell record under the given session title.
	CreateShell(ctx context.Context, sessionTitle string, data ShellData) (*ent.Shell, error)
	// ListShells returns all shell records for the given session title, ordered by order_index.
	ListShells(ctx context.Context, sessionTitle string) ([]*ent.Shell, error)
	// UpdateShellStatus sets the status (and optionally exit code) for the shell with the given ID.
	UpdateShellStatus(ctx context.Context, shellID, status string, exitCode *int) error
	// DeleteShell removes the shell record with the given ID.
	DeleteShell(ctx context.Context, shellID string) error
}

ShellRepository is the minimal persistence interface for per-session shell management. It is implemented by EntRepository; pass nil to disable persistence (e.g., tests).

type ShellStatus added in v1.35.0

type ShellStatus string

ShellStatus represents the lifecycle status of a custom shell.

const (
	// ShellStatusRunning means the shell process is alive and the PTY is open.
	ShellStatusRunning ShellStatus = "running"
	// ShellStatusStopped means the shell exited cleanly (via exit command or StopShell).
	ShellStatusStopped ShellStatus = "stopped"
	// ShellStatusError means the shell exited with a non-zero status unexpectedly.
	ShellStatusError ShellStatus = "error"
)

type SpawnShellRequest added in v1.35.0

type SpawnShellRequest struct {
	// Name is the optional user-visible label. Defaults to the command base name.
	Name string
	// Command is the command to run. Defaults to $SHELL or /bin/sh.
	Command string
	// WorkingDir is the starting directory. Defaults to the session's WorkingDir.
	WorkingDir string
}

SpawnShellRequest carries the parameters for Instance.SpawnShell.

type StartupScanner added in v1.35.0

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

StartupScanner scans running sessions for pre-existing approval prompts and adds matches to the review queue immediately, before the first regular poll cycle.

func NewStartupScanner added in v1.35.0

func NewStartupScanner(statusManager StatusProvider, contentProvider ContentProvider) *StartupScanner

NewStartupScanner creates a StartupScanner using the provided status and content providers.

func (*StartupScanner) Scan added in v1.35.0

func (ss *StartupScanner) Scan(instances []*Instance, queue ReviewQueueWriter) int

Scan iterates over instances and adds any that need attention to the queue. Returns the number of sessions added to the queue.

type Status

type Status int
const (
	// Creating is the status when the instance is being initialized.
	Creating Status = 0
	// Active is the status when the instance has a live AI process (running or ready).
	Active Status = 1
	// Paused is if the instance is paused (worktree removed but branch preserved).
	Paused Status = 2
	// Stopped is a terminal state: the instance has been shut down and cannot transition further.
	Stopped Status = 3
	// Hibernated is the status when the instance has been checkpointed and the tmux session killed.
	Hibernated Status = 4
	// Restoring is the transient startup state when a hibernated session is being restored.
	// Never persisted to the database — transitions to Active or Creating on completion.
	Restoring Status = 5

	// Deprecated: use Active.
	Running = Active
	// Deprecated: use Active.
	Ready = Active
	// Deprecated: use Creating.
	Loading = Creating
)

func StatusFromDetected

func StatusFromDetected(detected detection.DetectedStatus) Status

StatusFromDetected maps a DetectedStatus to the corresponding lifecycle Status. All detected states map to Active because the instance process is still executing. NeedsApproval, InputRequired, Error, and TestsFailing are sub-status signals surfaced via GetEffectiveStatus() — they do not change the lifecycle state.

func (Status) String

func (s Status) String() string

String returns a human-readable name for the status.

type StatusChange

type StatusChange struct {
	Timestamp time.Time
	Status    detection.DetectedStatus
	Context   string
}

StatusChange represents a change in detected status during execution.

type StatusChangeListener added in v1.35.0

type StatusChangeListener func(newStatus detection.DetectedStatus, sessionName string)

StatusChangeListener is called when the controller detects a terminal status transition. Always invoked from the controller's own background goroutine, outside any lock.

type StatusDeterminer added in v1.35.0

type StatusDeterminer interface {
	Determine(
		inst *Instance,
		content string,
		statusInfo InstanceStatusInfo,
		detector detection.TerminalDetector,
	) DetectionResult
}

StatusDeterminer evaluates whether a session should be added to, removed from, or left unchanged in the review queue. It is a pure function — no queue operations.

type StatusProvider added in v1.35.0

type StatusProvider interface {
	GetStatus(inst *Instance) InstanceStatusInfo
	GetController(instanceTitle string) (*ClaudeController, bool)
}

StatusProvider is the interface ReviewQueuePoller uses to fetch session status. Defined at the consumption point (the poller), not the production point.

type Storage

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

Storage handles saving and loading instances via the repository backend.

func NewStorageWithRepository

func NewStorageWithRepository(repo Repository) (*Storage, error)

NewStorageWithRepository creates a Storage backed by a Repository.

func (*Storage) AddInstance

func (s *Storage) AddInstance(instance *Instance) error

AddInstance adds a new instance to storage. Unlike SaveInstances, this does not require instance.Started() to be true.

func (*Storage) AllRules added in v1.12.0

func (s *Storage) AllRules(ctx context.Context) ([]ApprovalRuleData, error)

AllRules returns all auto-approval rules from the repository.

func (*Storage) ArchiveBacklogItem added in v1.35.0

func (s *Storage) ArchiveBacklogItem(ctx context.Context, id string) (*BacklogItemData, error)

ArchiveBacklogItem sets the archived_at timestamp.

func (*Storage) AssignSessionsToProject added in v1.23.0

func (s *Storage) AssignSessionsToProject(ctx context.Context, projectName string, sessionTitles []string) error

AssignSessionsToProject links sessions to a project in storage.

func (*Storage) Close

func (s *Storage) Close() error

Close performs graceful shutdown of storage.

func (*Storage) CreateBacklogItem added in v1.35.0

func (s *Storage) CreateBacklogItem(ctx context.Context, data BacklogItemData) (*BacklogItemData, error)

CreateBacklogItem inserts a new backlog item.

func (*Storage) CreateItemSession added in v1.35.0

func (s *Storage) CreateItemSession(ctx context.Context, data ItemSessionData) (*ent.ItemSession, error)

CreateItemSession creates a new ItemSession linked to a BacklogItem.

func (*Storage) CreateItemSessionWithVerdict added in v1.35.0

func (s *Storage) CreateItemSessionWithVerdict(ctx context.Context, isData ItemSessionData, verdict ReviewVerdictData) (*ent.ItemSession, *ent.ReviewVerdict, error)

CreateItemSessionWithVerdict atomically creates an ItemSession and its initial ReviewVerdict in a single transaction. Falls back gracefully if the backend is not ent-based.

func (*Storage) CreateItemSource added in v1.35.0

func (s *Storage) CreateItemSource(ctx context.Context, data ItemSourceData) (*ItemSourceData, error)

CreateItemSource registers a new external item source.

func (*Storage) CreateProject added in v1.23.0

func (s *Storage) CreateProject(ctx context.Context, data ProjectData) (*ProjectData, error)

CreateProject inserts a new project into storage.

func (*Storage) CreateSourceSyncEvent added in v1.35.0

func (s *Storage) CreateSourceSyncEvent(ctx context.Context, sourceID, cursorAfter string, created, updated, skipped, errored int, errMsg string, startedAt, finishedAt time.Time) error

CreateSourceSyncEvent records a sync run for an item source. Direct EntRepository delegation, like ListSourceSyncEvents above.

func (*Storage) DeleteAllInstances

func (s *Storage) DeleteAllInstances() error

DeleteAllInstances removes all stored instances.

func (*Storage) DeleteBacklogItem added in v1.35.0

func (s *Storage) DeleteBacklogItem(ctx context.Context, id string) error

DeleteBacklogItem permanently removes an item and all its child records.

func (*Storage) DeleteInstance

func (s *Storage) DeleteInstance(title string) error

DeleteInstance removes an instance from storage.

func (*Storage) DeleteItemSource added in v1.35.0

func (s *Storage) DeleteItemSource(ctx context.Context, id string) error

DeleteItemSource removes an item source by UUID string.

func (*Storage) DeleteProject added in v1.23.0

func (s *Storage) DeleteProject(ctx context.Context, name string) error

DeleteProject removes a project from storage (sessions are unassigned).

func (*Storage) DeleteRule added in v1.12.0

func (s *Storage) DeleteRule(ctx context.Context, id string) error

DeleteRule removes an auto-approval rule from the repository.

func (*Storage) FindInstanceDataByID added in v1.35.0

func (s *Storage) FindInstanceDataByID(id string) (*InstanceData, error)

FindInstanceDataByID finds the first InstanceData whose stable ID or title matches id. Returns ErrInstanceDataNotFound when no match exists.

func (*Storage) GetAllInstanceArtifacts added in v1.35.0

func (s *Storage) GetAllInstanceArtifacts() (map[string]string, error)

GetAllInstanceArtifacts returns a map of title → raw artifacts JSON for all sessions that have stored artifacts. Single bulk query (M-4 fix).

func (*Storage) GetBacklogItem added in v1.35.0

func (s *Storage) GetBacklogItem(ctx context.Context, id string) (*BacklogItemData, error)

GetBacklogItem retrieves a backlog item by UUID string.

func (*Storage) GetEntClient added in v1.35.0

func (s *Storage) GetEntClient() *ent.Client

GetEntClient returns the *ent.Client from the underlying EntRepository, or nil when the repository is not ent-backed (e.g. in-memory test doubles).

func (*Storage) GetInstanceArtifacts added in v1.35.0

func (s *Storage) GetInstanceArtifacts(title string) (string, error)

GetInstanceArtifacts loads the raw JSON-encoded artifact blob for a session. Returns ("", nil) if the session exists but has no artifacts yet.

func (*Storage) GetItemSession added in v1.35.0

func (s *Storage) GetItemSession(ctx context.Context, id string) (*ent.ItemSession, error)

GetItemSession looks up an ItemSession by entity UUID (loads BacklogItem edge).

func (*Storage) GetItemSessionBySessionAndItem added in v1.35.0

func (s *Storage) GetItemSessionBySessionAndItem(ctx context.Context, sessionUUID string, itemID string) (*ent.ItemSession, error)

GetItemSessionBySessionAndItem looks up an ItemSession by both sessionUUID and backlog item ID. Returns ErrNotFound if no matching record exists.

func (*Storage) GetItemSessionBySessionUUID added in v1.35.0

func (s *Storage) GetItemSessionBySessionUUID(ctx context.Context, sessionUUID string) (*ent.ItemSession, error)

GetItemSessionBySessionUUID looks up the ItemSession for a given session UUID (loads BacklogItem edge).

func (*Storage) GetMostRecentReviewVerdictForItem added in v1.35.0

func (s *Storage) GetMostRecentReviewVerdictForItem(ctx context.Context, itemID string) (string, error)

GetMostRecentReviewVerdictForItem returns the OverallOutcome of the most recent ReviewVerdict linked to any ItemSession for itemID. Returns "" when none exists.

func (*Storage) GetSession

func (s *Storage) GetSession(ctx context.Context, title string, opts ContextOptions) (*Session, error)

GetSession retrieves a session by title using the Session domain model. Use ContextOptions presets (ContextMinimal, ContextUIView, etc.) to control what is loaded.

func (*Storage) GetSessionGoal added in v1.35.0

func (s *Storage) GetSessionGoal(ctx context.Context, sessionUUID string) (*SessionGoalData, error)

GetSessionGoal retrieves the goal for a session by session UUID. Returns ErrNotFound if no goal has been set for the session.

func (*Storage) GetSubcommandBreakdown added in v1.35.0

func (s *Storage) GetSubcommandBreakdown(ctx context.Context, program string, since time.Time) ([]SubcommandDecisionCount, error)

GetSubcommandBreakdown returns per-(subcommand, decision) counts for a program.

func (*Storage) GetSubcommandTrend added in v1.35.0

func (s *Storage) GetSubcommandTrend(ctx context.Context, program, subcommand string, since time.Time) ([]AnalyticsData, error)

GetSubcommandTrend returns raw analytics rows for (program, subcommand) since a time.

func (*Storage) ListAnalytics added in v1.12.0

func (s *Storage) ListAnalytics(ctx context.Context, limit int) ([]AnalyticsData, error)

ListAnalytics retrieves recent classification decisions from the repository.

func (*Storage) ListAnalyticsByProgramSince added in v1.35.0

func (s *Storage) ListAnalyticsByProgramSince(ctx context.Context, program string, since time.Time, limit int) ([]AnalyticsData, error)

ListAnalyticsByProgramSince retrieves entries for a specific program since a time.

func (*Storage) ListAnalyticsSince added in v1.35.0

func (s *Storage) ListAnalyticsSince(ctx context.Context, since time.Time, limit int) ([]AnalyticsData, error)

ListAnalyticsSince retrieves analytics entries with created_at >= since.

func (*Storage) ListBacklogItems added in v1.35.0

func (s *Storage) ListBacklogItems(ctx context.Context, filter BacklogItemFilter) ([]BacklogItemData, error)

ListBacklogItems returns backlog items with optional filtering.

func (*Storage) ListInstanceData added in v1.18.0

func (s *Storage) ListInstanceData() ([]InstanceData, error)

ListInstanceData returns raw InstanceData from the repository without constructing Instance objects. This avoids the side effect of FromInstanceData() calling Start() (which spawns PTY processes). Use for read-only existence and title checks.

func (*Storage) ListInstanceIDs added in v1.35.0

func (s *Storage) ListInstanceIDs() ([]string, error)

ListInstanceIDs returns the stable ID (UUID if set, else Title) for every stored InstanceData. Used by Registry.AcquireAll to seed the initial live-handle set.

func (*Storage) ListItemSessions added in v1.35.0

func (s *Storage) ListItemSessions(ctx context.Context, itemID string) ([]*ent.ItemSession, error)

ListItemSessions returns all ItemSessions for a given BacklogItem UUID string.

func (*Storage) ListItemSources added in v1.35.0

func (s *Storage) ListItemSources(ctx context.Context) ([]ItemSourceData, error)

ListItemSources returns all registered item sources.

func (*Storage) ListProjects added in v1.23.0

func (s *Storage) ListProjects(ctx context.Context) ([]ProjectData, error)

ListProjects returns all projects from storage.

func (*Storage) ListRecentCommandsByProgram added in v1.35.0

func (s *Storage) ListRecentCommandsByProgram(ctx context.Context, program, subcommand string, since time.Time, n int) ([]string, error)

ListRecentCommandsByProgram returns the most recent n command_preview strings.

func (*Storage) ListSessionRecords added in v1.35.0

func (s *Storage) ListSessionRecords() []tokens.SessionRecord

ListSessionRecords returns a snapshot of all sessions as SessionRecords, for use by the tokens.Associator to match JSONL files to stapler-squad sessions.

func (*Storage) ListSessions

func (s *Storage) ListSessions(ctx context.Context, opts ContextOptions) ([]*Session, error)

ListSessions retrieves all sessions using the Session domain model. Use ContextOptions presets (ContextMinimal, ContextUIView, etc.) to control what is loaded.

func (*Storage) ListSourceSyncEvents added in v1.35.0

func (s *Storage) ListSourceSyncEvents(ctx context.Context, sourceID string) (events []*ent.SourceSyncEvent, truncated bool, err error)

ListSourceSyncEvents returns sync history events for an item source, most recent first. Direct EntRepository delegation, like GetItemSession below.

func (*Storage) LoadInstances

func (s *Storage) LoadInstances() ([]*Instance, error)

LoadInstances loads the list of instances from the repository.

func (*Storage) RecordAnalytics added in v1.12.0

func (s *Storage) RecordAnalytics(ctx context.Context, data AnalyticsData) error

RecordAnalytics logs a classification decision to the repository.

func (*Storage) SaveInstances

func (s *Storage) SaveInstances(instances []*Instance) error

SaveInstances upserts each started instance into the repository.

func (*Storage) SaveInstancesSync

func (s *Storage) SaveInstancesSync(instances []*Instance) error

SaveInstancesSync saves instances synchronously (same as SaveInstances for the repo backend).

func (*Storage) SaveReviewVerdict added in v1.35.0

func (s *Storage) SaveReviewVerdict(ctx context.Context, itemSessionID string, verdict ReviewVerdictData) (*ent.ReviewVerdict, error)

SaveReviewVerdict upserts a ReviewVerdict for a given ItemSession UUID.

func (*Storage) SaveSession

func (s *Storage) SaveSession(ctx context.Context, session *Session) error

SaveSession upserts a session using the Session domain model. If the session exists it is updated; otherwise it is created. Deprecated InstanceData-based methods (SaveInstances, LoadInstances) remain for backward compatibility.

func (*Storage) SetSessionGoal added in v1.35.0

func (s *Storage) SetSessionGoal(ctx context.Context, sessionUUID string, goal string, status string, tasks []TaskNode, setBy string) (*SessionGoalData, error)

SetSessionGoal upserts the goal for a session (1:1 per session_uuid). If a goal already exists for the session, it is replaced.

func (*Storage) TransitionBacklogItemStatus added in v1.35.0

func (s *Storage) TransitionBacklogItemStatus(ctx context.Context, id string, toStatus BacklogStatus, precondition *BacklogItemPrecondition) (*BacklogItemData, error)

TransitionBacklogItemStatus changes the status of a backlog item.

func (*Storage) UpdateAcCriterionStatus added in v1.35.0

func (s *Storage) UpdateAcCriterionStatus(ctx context.Context, itemID string, criterionIndex int, status string, note string) error

UpdateAcCriterionStatus updates a single acceptance criterion's status by index.

func (*Storage) UpdateBacklogItem added in v1.35.0

func (s *Storage) UpdateBacklogItem(ctx context.Context, id string, update BacklogItemUpdate, precondition *BacklogItemPrecondition) (*BacklogItemData, error)

UpdateBacklogItem modifies an existing backlog item.

func (*Storage) UpdateInstance

func (s *Storage) UpdateInstance(instance *Instance) error

UpdateInstance updates an existing instance in storage.

func (*Storage) UpdateInstanceAcknowledged added in v1.18.0

func (s *Storage) UpdateInstanceAcknowledged(title string) error

UpdateInstanceAcknowledged sets the LastAcknowledged timestamp to now for a specific instance. Used by AcknowledgeSession when the instance is not available in the live poller.

func (*Storage) UpdateInstanceArtifacts added in v1.35.0

func (s *Storage) UpdateInstanceArtifacts(title string, blob string) error

UpdateInstanceArtifacts persists the JSON-encoded artifact blob for a session. Only the session_artifacts column is touched; all other fields are unchanged.

func (*Storage) UpdateInstanceForkFlag added in v1.12.0

func (s *Storage) UpdateInstanceForkFlag(_ string, _ bool) error

UpdateInstanceForkFlag is intentionally a no-op: fork status is not persisted in the ent schema. Callers (e.g. PRStatusPoller) call this as a persistence hook, but no DB write occurs.

func (*Storage) UpdateInstanceLastAddedToQueue

func (s *Storage) UpdateInstanceLastAddedToQueue(title string, lastAddedToQueue time.Time) error

UpdateInstanceLastAddedToQueue updates ONLY the LastAddedToQueue field for a specific instance.

func (*Storage) UpdateInstanceLastUserResponse

func (s *Storage) UpdateInstanceLastUserResponse(title string, lastUserResponse time.Time) error

UpdateInstanceLastUserResponse persists the LastUserResponse timestamp for a session. Uses a direct UPDATE (no read round-trip) via UpdateReviewQueueState.

func (*Storage) UpdateInstancePRNumber added in v1.12.0

func (s *Storage) UpdateInstancePRNumber(title string, prNumber int) error

UpdateInstancePRNumber persists the discovered PR number for a session so it survives restarts and avoids repeated branch-name lookups in PRStatusPoller.

func (*Storage) UpdateInstancePRStatus added in v1.12.0

func (s *Storage) UpdateInstancePRStatus(_, _, _, _ string, _, _ int, _, _ bool) error

UpdateInstancePRStatus updates the PR status fields for a specific instance. PR fields are not stored in the ent schema — they live in memory and are re-populated by PRStatusPoller on each poll cycle. No DB write is needed.

func (*Storage) UpdateInstanceProcessingGrace

func (s *Storage) UpdateInstanceProcessingGrace(title string, processingGraceUntil time.Time) error

UpdateInstanceProcessingGrace persists the ProcessingGraceUntil timestamp. Uses a direct UPDATE (no read round-trip) via UpdateReviewQueueState.

func (*Storage) UpdateInstanceTimestampsOnly

func (s *Storage) UpdateInstanceTimestampsOnly(title string, lastTerminalUpdate, lastMeaningfulOutput time.Time, lastOutputSignature string, lastViewed time.Time) error

UpdateInstanceTimestampsOnly updates ONLY the timestamp fields in storage without creating Instance objects. This preserves in-memory state like controllers. This is critical for WebSocket terminal streaming which updates timestamps frequently.

func (*Storage) UpdateItemSessionEnded added in v1.35.0

func (s *Storage) UpdateItemSessionEnded(ctx context.Context, id string, endedAt time.Time) error

UpdateItemSessionEnded records the end time for an ItemSession.

func (*Storage) UpdateItemSessionSessionUUID added in v1.35.0

func (s *Storage) UpdateItemSessionSessionUUID(ctx context.Context, id string, sessionUUID string) error

UpdateItemSessionSessionUUID updates the session_uuid on an existing ItemSession record.

func (*Storage) UpdateItemSessionStarted added in v1.35.0

func (s *Storage) UpdateItemSessionStarted(ctx context.Context, id string, startedAt time.Time) error

UpdateItemSessionStarted records the start time for an ItemSession.

func (*Storage) UpdateItemSessionTriageResult added in v1.35.0

func (s *Storage) UpdateItemSessionTriageResult(ctx context.Context, id string, triageResult string) error

UpdateItemSessionTriageResult stores the triage result JSON payload on an ItemSession.

func (*Storage) UpdateItemSource added in v1.35.0

func (s *Storage) UpdateItemSource(ctx context.Context, id string, update ItemSourceUpdate) (*ItemSourceData, error)

UpdateItemSource modifies an existing item source.

func (*Storage) UpdateProject added in v1.23.0

func (s *Storage) UpdateProject(ctx context.Context, data ProjectData) (*ProjectData, error)

UpdateProject modifies an existing project in storage.

func (*Storage) UpdateSessionTaskStatus added in v1.35.0

func (s *Storage) UpdateSessionTaskStatus(ctx context.Context, sessionUUID string, taskID string, newStatus string) (*SessionGoalData, error)

UpdateSessionTaskStatus loads the goal for a session, finds the task by ID, updates its status, and saves the goal back. Returns ErrNotFound if no goal exists, or an error if task_id is not found in the tree. The read-modify-write is wrapped in a transaction to prevent concurrent update races.

func (*Storage) UpsertRule added in v1.12.0

func (s *Storage) UpsertRule(ctx context.Context, rule ApprovalRuleData) error

UpsertRule creates or updates an auto-approval rule in the repository.

type SubcommandDecisionCount added in v1.35.0

type SubcommandDecisionCount struct {
	Subcommand string
	Decision   string
	Count      int
}

SubcommandDecisionCount holds a (subcommand, decision) aggregate count. Returned by GetSubcommandBreakdown.

type Subscriber

type Subscriber struct {
	ID string
	Ch chan ResponseChunk
	// contains filtered or unexported fields
}

Subscriber represents a client that is receiving response chunks.

type SyncLoop added in v1.35.0

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

SyncLoop drives periodic sync of all enabled ItemSources.

func NewSyncLoop added in v1.35.0

func NewSyncLoop(storage *Storage, registry *PluginRegistry) *SyncLoop

NewSyncLoop creates a SyncLoop with the default interval and no key provider.

func NewSyncLoopWithKeyProvider added in v1.35.0

func NewSyncLoopWithKeyProvider(storage *Storage, registry *PluginRegistry, keyFunc func() ([]byte, error)) *SyncLoop

NewSyncLoopWithKeyProvider creates a SyncLoop with a key provider for decryption.

func (*SyncLoop) Start added in v1.35.0

func (sl *SyncLoop) Start(ctx context.Context)

Start runs the sync loop until ctx is cancelled or Stop is called.

func (*SyncLoop) Stop added in v1.35.0

func (sl *SyncLoop) Stop()

Stop gracefully shuts down the sync loop. Safe to call multiple times.

func (*SyncLoop) SyncByID added in v1.35.0

func (sl *SyncLoop) SyncByID(ctx context.Context, sourceID string) error

SyncByID looks up an ItemSource by ID and syncs it, regardless of its Enabled flag — unlike the periodic loop (runAllSources), which only syncs enabled sources, this is for an explicit manual/on-demand trigger where the caller already decided to sync this specific source.

func (*SyncLoop) SyncOne added in v1.35.0

func (sl *SyncLoop) SyncOne(ctx context.Context, source *ent.ItemSource) error

SyncOne fetches and upserts items for a single ItemSource. Concurrent calls for the same source (e.g. a manual TriggerSync racing the periodic tick) are serialized via a per-source lock — see syncSourceLocks.

func (*SyncLoop) TestDecryptConfigToken added in v1.35.0

func (sl *SyncLoop) TestDecryptConfigToken(raw string) (string, error)

decryptConfigToken decrypts an encrypted token in config JSON if needed. If the config has "encrypted":true, it decrypts the token field using the provided key function. If decryption is not available or not needed, returns the raw config unchanged. Exported for testing.

type TagManager

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

TagManager provides CRUD operations for session tags. It is a pure data structure with no I/O or external dependencies. Thread safety is provided by Instance.mu -- callers must hold the lock when calling TagManager methods.

TagManager stores a pointer to the Instance.Tags slice so that mutations are automatically visible via inst.Tags (used by instance_adapter.go, review_queue_poller.go, and ToInstanceData for serialization).

func NewTagManager

func NewTagManager(tags *[]string) TagManager

NewTagManager creates a TagManager backed by the given slice pointer.

func (*TagManager) Add

func (tm *TagManager) Add(tag string) error

Add adds a tag if it does not already exist and does not exceed MaxTagLength. Returns ErrTagTooLong if the tag exceeds MaxTagLength. Returns ErrDuplicateTag if the tag already exists.

func (*TagManager) All

func (tm *TagManager) All() []string

All returns a copy of the tag slice.

func (*TagManager) Has

func (tm *TagManager) Has(tag string) bool

Has returns true if the tag exists.

func (*TagManager) Remove

func (tm *TagManager) Remove(tag string)

Remove removes a tag by value. No-op if the tag does not exist.

func (*TagManager) Set

func (tm *TagManager) Set(tags []string) error

Set replaces all tags with a new deduplicated set. Returns ErrTagTooLong on the first tag that exceeds MaxTagLength. Returns ErrTooManyTags if the deduplicated count exceeds MaxTagCount.

type TaskNode added in v1.35.0

type TaskNode struct {
	ID       string     `json:"id"`
	Title    string     `json:"title"`
	Status   string     `json:"status"`
	Children []TaskNode `json:"children,omitempty"`
}

TaskNode represents a single task in the goal's task tree.

func DecodeTasks added in v1.35.0

func DecodeTasks(s string) ([]TaskNode, error)

DecodeTasks deserializes a JSON string to a task tree.

type TerminalContext

type TerminalContext struct {
	// Height is the terminal height in rows
	Height int `json:"height,omitempty"`

	// Width is the terminal width in columns
	Width int `json:"width,omitempty"`

	// TmuxSessionName is the name of the tmux session
	TmuxSessionName string `json:"tmux_session_name,omitempty"`

	// TmuxPrefix is the prefix used for tmux session naming
	TmuxPrefix string `json:"tmux_prefix,omitempty"`

	// TmuxServerSocket is the path to the tmux server socket
	TmuxServerSocket string `json:"tmux_server_socket,omitempty"`

	// TerminalType indicates the terminal backend type
	// Possible values: "tmux", "mux", "pty", "web"
	TerminalType string `json:"terminal_type,omitempty"`
}

TerminalContext represents the terminal-related context for a session. This includes terminal dimensions, tmux configuration, and terminal type.

func (*TerminalContext) IsEmpty

func (t *TerminalContext) IsEmpty() bool

IsEmpty returns true if the TerminalContext has no meaningful data

type TerminalState

type TerminalState struct {

	// Terminal dimensions
	Rows int
	Cols int

	// Terminal screen buffer (2D grid)
	Grid [][]Cell

	// Cursor state
	CursorRow     int
	CursorCol     int
	CursorVisible bool

	// Saved cursor state
	SavedCursorRow int
	SavedCursorCol int

	// Current text style for new characters
	CurrentStyle CellStyle

	// Tab stops (column index -> is set)
	TabStops map[int]bool

	// State version for delta tracking
	Version uint64
	// contains filtered or unexported fields
}

TerminalState maintains the current terminal screen state

func NewTerminalState

func NewTerminalState(rows, cols int) *TerminalState

NewTerminalState creates a new terminal state with given dimensions

func (*TerminalState) Clone

func (ts *TerminalState) Clone() *TerminalState

Clone creates a deep copy of the terminal state

func (*TerminalState) GenerateDelta

func (ts *TerminalState) GenerateDelta(fromState *TerminalState) *sessionv1.TerminalData

GenerateDelta generates a delta from another state to this state

func (*TerminalState) GenerateState

func (ts *TerminalState) GenerateState() *sessionv1.TerminalData

GenerateState generates a complete terminal state message (MOSH-style). This is the preferred method over GenerateDelta for robust synchronization.

func (*TerminalState) ProcessOutput

func (ts *TerminalState) ProcessOutput(data []byte) error

ProcessOutput processes terminal output and updates state

func (*TerminalState) Resize

func (ts *TerminalState) Resize(rows, cols int)

Resize resizes the terminal state

type TimeRestriction

type TimeRestriction struct {
	DaysOfWeek []time.Weekday `json:"days_of_week"` // Empty = all days
	StartHour  int            `json:"start_hour"`   // 0-23
	EndHour    int            `json:"end_hour"`     // 0-23
}

TimeRestriction limits when a policy is active.

type TmuxBackend added in v1.35.0

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

TmuxBackend implements ProcessManager by delegating to TmuxManager. It is the default backend used when process_manager_backend = "tmux" (or empty).

func NewTmuxBackend added in v1.35.0

func NewTmuxBackend(mgr TmuxManager) *TmuxBackend

NewTmuxBackend creates a TmuxBackend wrapping the given TmuxManager.

func (*TmuxBackend) Attach added in v1.35.0

func (b *TmuxBackend) Attach() (chan struct{}, error)

func (*TmuxBackend) CapturePaneContent added in v1.35.0

func (b *TmuxBackend) CapturePaneContent() (string, error)

func (*TmuxBackend) CapturePaneContentRaw added in v1.35.0

func (b *TmuxBackend) CapturePaneContentRaw() (string, error)

func (*TmuxBackend) CapturePaneContentWithOptions added in v1.35.0

func (b *TmuxBackend) CapturePaneContentWithOptions(start, end string) (string, error)

func (*TmuxBackend) CaptureViewport added in v1.35.0

func (b *TmuxBackend) CaptureViewport(lines int) (string, error)

func (*TmuxBackend) Close added in v1.35.0

func (b *TmuxBackend) Close() error

func (*TmuxBackend) DetachSafely added in v1.35.0

func (b *TmuxBackend) DetachSafely() error

func (*TmuxBackend) FilterBanners added in v1.35.0

func (b *TmuxBackend) FilterBanners(content string) (string, int)

func (*TmuxBackend) GetCurrentWorkingDirectory added in v1.35.0

func (b *TmuxBackend) GetCurrentWorkingDirectory() (string, error)

GetCurrentWorkingDirectory returns the current working directory of the pane. Delegates to the underlying Session().GetPaneCurrentPath() via type assertion.

func (*TmuxBackend) GetCursorPosition added in v1.35.0

func (b *TmuxBackend) GetCursorPosition() (x, y int, err error)

func (*TmuxBackend) GetPTY added in v1.35.0

func (b *TmuxBackend) GetPTY() (*os.File, error)

func (*TmuxBackend) GetPaneDimensions added in v1.35.0

func (b *TmuxBackend) GetPaneDimensions() (width, height int, err error)

func (*TmuxBackend) GetPanePID added in v1.35.0

func (b *TmuxBackend) GetPanePID() (int32, error)

func (*TmuxBackend) GetSessionIdentifier added in v1.35.0

func (b *TmuxBackend) GetSessionIdentifier() string

GetSessionIdentifier implements ProcessManager by delegating to GetTmuxSessionName. This is the name-mapping method: backend-agnostic callers use GetSessionIdentifier, but the value is identical to what GetTmuxSessionName returns for the tmux backend.

func (*TmuxBackend) HasMeaningfulContent added in v1.35.0

func (b *TmuxBackend) HasMeaningfulContent(content string) bool

func (*TmuxBackend) HasSession added in v1.35.0

func (b *TmuxBackend) HasSession() bool

func (*TmuxBackend) HasUpdated added in v1.35.0

func (b *TmuxBackend) HasUpdated() (updated bool, hasPrompt bool, content string)

func (*TmuxBackend) IsAlive added in v1.35.0

func (b *TmuxBackend) IsAlive() bool

func (*TmuxBackend) RefreshClient added in v1.35.0

func (b *TmuxBackend) RefreshClient() error

func (*TmuxBackend) ResetExitOnce added in v1.35.0

func (b *TmuxBackend) ResetExitOnce()

func (*TmuxBackend) RestoreWithWorkDir added in v1.35.0

func (b *TmuxBackend) RestoreWithWorkDir(w string) error

func (*TmuxBackend) SendInputViaControlMode added in v1.35.0

func (b *TmuxBackend) SendInputViaControlMode(ctx context.Context, data []byte) error

func (*TmuxBackend) SendKeys added in v1.35.0

func (b *TmuxBackend) SendKeys(keys string) (int, error)

func (*TmuxBackend) SendPromptWithEnter added in v1.35.0

func (b *TmuxBackend) SendPromptWithEnter(p string) error

func (*TmuxBackend) SetDetachedSize added in v1.35.0

func (b *TmuxBackend) SetDetachedSize(w, h int, title string) error

func (*TmuxBackend) SetOnExitCallback added in v1.35.0

func (b *TmuxBackend) SetOnExitCallback(fn func(string))

func (*TmuxBackend) SetWindowSize added in v1.35.0

func (b *TmuxBackend) SetWindowSize(cols, rows int) error

func (*TmuxBackend) Start added in v1.35.0

func (b *TmuxBackend) Start(dir string) error

func (*TmuxBackend) StartControlMode added in v1.35.0

func (b *TmuxBackend) StartControlMode() error

func (*TmuxBackend) StopControlMode added in v1.35.0

func (b *TmuxBackend) StopControlMode() error

func (*TmuxBackend) SubscribeToControlModeUpdates added in v1.35.0

func (b *TmuxBackend) SubscribeToControlModeUpdates() (string, chan []byte)

func (*TmuxBackend) TapEnter added in v1.35.0

func (b *TmuxBackend) TapEnter() error

func (*TmuxBackend) TmuxManager added in v1.35.0

func (b *TmuxBackend) TmuxManager() TmuxManager

TmuxManager returns the underlying TmuxManager for type assertions in reconciliation paths that need tmux-specific operations (e.g. Session(), SetSession()).

func (*TmuxBackend) UnsubscribeFromControlModeUpdates added in v1.35.0

func (b *TmuxBackend) UnsubscribeFromControlModeUpdates(id string)

type TmuxManager added in v1.15.0

type TmuxManager interface {
	HasSession() bool
	Session() *tmux.TmuxSession
	SetSession(*tmux.TmuxSession)
	GetTmuxSessionName() string
	IsAlive() bool
	Close() error
	DetachSafely() error
	DoesSessionExist() bool
	SetDetachedSize(width, height int, instanceTitle string) error
	Attach() (chan struct{}, error)
	CapturePaneContent() (string, error)
	CapturePaneContentRaw() (string, error)
	CapturePaneContentWithOptions(startLine, endLine string) (string, error)
	GetPaneDimensions() (width, height int, err error)
	GetCursorPosition() (x, y int, err error)
	GetPTY() (*os.File, error)
	SendKeys(keys string) (int, error)
	SetWindowSize(cols, rows int) error
	RefreshClient() error
	TapEnter() error
	HasUpdated() (updated bool, hasPrompt bool, content string)
	RestoreWithWorkDir(workDir string) error
	Start(dir string) error
	FilterBanners(content string) (string, int)
	HasMeaningfulContent(content string) bool
	CaptureViewport(lines int) (string, error)
	SendPromptWithEnter(prompt string) error
	GetPanePID() (int32, error)
	SetOnExitCallback(fn func(string))
	ResetExitOnce()
	StartControlMode() error
	StopControlMode() error
	SubscribeToControlModeUpdates() (string, chan []byte)
	UnsubscribeFromControlModeUpdates(id string)
	SendInputViaControlMode(ctx context.Context, data []byte) error
}

TmuxManager is the interface satisfied by *TmuxProcessManager. It covers all tmux session operations used by Instance and can be implemented by test doubles to avoid requiring a real tmux server.

type TmuxProcessManager

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

TmuxProcessManager owns the tmux session and preview-size tracking state that were previously scattered as bare fields on Instance.

Instance keeps thin wrapper methods (with started/paused guards) that delegate here. TmuxProcessManager itself has no knowledge of Instance lifecycle; it only manages the tmux session and the preview-resize bookkeeping.

func (*TmuxProcessManager) Attach

func (tm *TmuxProcessManager) Attach() (chan struct{}, error)

Attach returns a channel that closes when the user detaches from the session.

func (*TmuxProcessManager) CapturePaneContent

func (tm *TmuxProcessManager) CapturePaneContent() (string, error)

CapturePaneContent returns the current visible pane content.

func (*TmuxProcessManager) CapturePaneContentRaw

func (tm *TmuxProcessManager) CapturePaneContentRaw() (string, error)

CapturePaneContentRaw returns pane content with ANSI escape codes preserved.

func (*TmuxProcessManager) CapturePaneContentWithOptions

func (tm *TmuxProcessManager) CapturePaneContentWithOptions(startLine, endLine string) (string, error)

CapturePaneContentWithOptions captures pane content between startLine and endLine.

func (*TmuxProcessManager) CaptureViewport

func (tm *TmuxProcessManager) CaptureViewport(lines int) (string, error)

CaptureViewport captures the last N lines of the pane. If lines <= 0, captures the current viewport height.

func (*TmuxProcessManager) Close

func (tm *TmuxProcessManager) Close() error

Close terminates the tmux session.

func (*TmuxProcessManager) DetachSafely

func (tm *TmuxProcessManager) DetachSafely() error

DetachSafely detaches the current tmux client from the session without closing it.

func (*TmuxProcessManager) DoesSessionExist

func (tm *TmuxProcessManager) DoesSessionExist() bool

DoesSessionExist returns true if the tmux session name is registered with the server.

func (*TmuxProcessManager) FilterBanners

func (tm *TmuxProcessManager) FilterBanners(content string) (string, int)

FilterBanners strips banner/header content from terminal output.

func (*TmuxProcessManager) GetCursorPosition

func (tm *TmuxProcessManager) GetCursorPosition() (x, y int, err error)

GetCursorPosition returns the current cursor column and row (0-based).

func (*TmuxProcessManager) GetPTY

func (tm *TmuxProcessManager) GetPTY() (*os.File, error)

GetPTY returns the PTY master file for reading terminal output.

func (*TmuxProcessManager) GetPaneDimensions

func (tm *TmuxProcessManager) GetPaneDimensions() (width, height int, err error)

GetPaneDimensions returns the current pane width and height.

func (*TmuxProcessManager) GetPanePID

func (tm *TmuxProcessManager) GetPanePID() (int32, error)

GetPanePID returns the PID of the foreground process in the pane.

func (*TmuxProcessManager) GetTmuxSessionName added in v1.15.0

func (tm *TmuxProcessManager) GetTmuxSessionName() string

GetTmuxSessionName returns the sanitized tmux session name for reconciliation. Returns empty string when no session has been initialized.

func (*TmuxProcessManager) HasMeaningfulContent

func (tm *TmuxProcessManager) HasMeaningfulContent(content string) bool

HasMeaningfulContent reports whether the terminal output contains substantive content.

func (*TmuxProcessManager) HasSession

func (tm *TmuxProcessManager) HasSession() bool

HasSession reports whether a tmux session has been initialized.

func (*TmuxProcessManager) HasUpdated

func (tm *TmuxProcessManager) HasUpdated() (updated bool, hasPrompt bool, content string)

HasUpdated reports whether the pane content has changed since the last check.

func (*TmuxProcessManager) IsAlive

func (tm *TmuxProcessManager) IsAlive() bool

IsAlive reports whether the tmux session process is still running.

func (*TmuxProcessManager) RefreshClient

func (tm *TmuxProcessManager) RefreshClient() error

RefreshClient forces the tmux client to redraw.

func (*TmuxProcessManager) ResetExitOnce added in v1.15.0

func (tm *TmuxProcessManager) ResetExitOnce()

ResetExitOnce resets the sync.Once guard so that the exit callback can fire again on the next start cycle (e.g., after a restart). No-op if no session.

func (*TmuxProcessManager) RestoreWithWorkDir

func (tm *TmuxProcessManager) RestoreWithWorkDir(workDir string) error

RestoreWithWorkDir re-attaches to an existing session in the given directory.

func (*TmuxProcessManager) SendInputViaControlMode added in v1.35.0

func (tm *TmuxProcessManager) SendInputViaControlMode(ctx context.Context, data []byte) error

SendInputViaControlMode sends raw bytes through the existing control mode connection.

func (*TmuxProcessManager) SendKeys

func (tm *TmuxProcessManager) SendKeys(keys string) (int, error)

SendKeys sends a string of keys to the tmux session and returns the number of bytes written.

func (*TmuxProcessManager) SendPromptWithEnter

func (tm *TmuxProcessManager) SendPromptWithEnter(prompt string) error

SendPromptWithEnter sends text to the session followed by Enter key. Includes a brief pause between text and Enter to prevent interpretation issues.

func (*TmuxProcessManager) Session

func (tm *TmuxProcessManager) Session() *tmux.TmuxSession

Session returns the underlying tmux session (may be nil before Start).

func (*TmuxProcessManager) SetDetachedSize

func (tm *TmuxProcessManager) SetDetachedSize(width, height int, instanceTitle string) error

SetDetachedSize updates the tmux window dimensions without attaching. Rate-limits PTY-not-initialized warnings to avoid log spam.

func (*TmuxProcessManager) SetOnExitCallback added in v1.15.0

func (tm *TmuxProcessManager) SetOnExitCallback(fn func(string))

SetOnExitCallback registers a callback that fires when the tmux session exits unexpectedly. No-op if no session is initialized.

func (*TmuxProcessManager) SetSession

func (tm *TmuxProcessManager) SetSession(s *tmux.TmuxSession)

SetSession replaces the underlying tmux session. Used by tests and by Instance.start() when reusing a pre-created session.

func (*TmuxProcessManager) SetWindowSize

func (tm *TmuxProcessManager) SetWindowSize(cols, rows int) error

SetWindowSize resizes the tmux window to the given columns and rows.

func (*TmuxProcessManager) Start

func (tm *TmuxProcessManager) Start(dir string) error

Start creates and starts the tmux session in the given directory.

func (*TmuxProcessManager) StartControlMode added in v1.15.0

func (tm *TmuxProcessManager) StartControlMode() error

StartControlMode starts the tmux control mode stream. Returns nil if no session is initialized.

func (*TmuxProcessManager) StopControlMode added in v1.15.0

func (tm *TmuxProcessManager) StopControlMode() error

StopControlMode stops the tmux control mode stream. Returns nil if no session is initialized.

func (*TmuxProcessManager) SubscribeToControlModeUpdates added in v1.15.0

func (tm *TmuxProcessManager) SubscribeToControlModeUpdates() (string, chan []byte)

SubscribeToControlModeUpdates registers a new subscriber for real-time terminal output. Returns a pre-closed channel if no session is initialized.

func (*TmuxProcessManager) TapEnter

func (tm *TmuxProcessManager) TapEnter() error

TapEnter sends an Enter key to the session.

func (*TmuxProcessManager) UnsubscribeFromControlModeUpdates added in v1.15.0

func (tm *TmuxProcessManager) UnsubscribeFromControlModeUpdates(id string)

UnsubscribeFromControlModeUpdates removes a subscriber by ID. No-op if no session is initialized.

type TransitionDef added in v1.35.0

type TransitionDef struct {
	From Status
	To   Status
	// Guard is called before the status is updated. Return non-nil to abort.
	// nil means unconditionally allowed.
	Guard func(ctx context.Context, i *Instance) error
	// After is called once the status has been updated (side-effects: process
	// management, worktree ops, scrollback restore, etc.).
	// nil means no post-transition side-effect.
	After func(ctx context.Context, i *Instance)
}

TransitionDef describes a single valid state machine transition with optional guard (pre-condition) and after (post-transition side-effect) hooks.

type TriageSuggestion added in v1.35.0

type TriageSuggestion struct {
	Text      string `json:"text"`
	Rationale string `json:"rationale"`
}

TriageSuggestion is a canonical suggestion entry shared by the headless triage path and the submit_triage_result MCP tool.

type TriageTask added in v1.35.0

type TriageTask struct {
	Text     string `json:"text"`
	Estimate string `json:"estimate"`
	Category string `json:"category"`
}

TriageTask is a canonical implementation task shared by the headless triage path and the submit_triage_result MCP tool.

type TurnCallback added in v1.35.0

type TurnCallback func(turn, maxTurns int, prompt string)

TurnCallback is called after each successful turn injection.

type UIPreferences

type UIPreferences struct {
	// Category is the organizational category for the session
	Category string `json:"category,omitempty"`

	// IsExpanded indicates if the session is expanded in grouped views
	IsExpanded bool `json:"is_expanded,omitempty"`

	// Tags are the user-defined tags for multi-dimensional organization
	Tags []string `json:"tags,omitempty"`

	// GroupingStrategy is the current grouping mode (e.g., "category", "tag", "branch")
	GroupingStrategy string `json:"grouping_strategy,omitempty"`

	// SortOrder is the preferred sort order (e.g., "name", "date", "status")
	SortOrder string `json:"sort_order,omitempty"`
}

UIPreferences represents the UI-related preferences for a session. This includes categorization, tags, and display preferences.

func (*UIPreferences) HasTag

func (u *UIPreferences) HasTag(tag string) bool

HasTag returns true if the UIPreferences contains the specified tag

func (*UIPreferences) IsEmpty

func (u *UIPreferences) IsEmpty() bool

IsEmpty returns true if the UIPreferences has no meaningful data

type UsageLimit

type UsageLimit struct {
	MaxUses     int           `json:"max_uses"`     // 0 = unlimited
	TimeWindow  time.Duration `json:"time_window"`  // 0 = no time window
	PerApproval bool          `json:"per_approval"` // Track per approval type vs globally
}

UsageLimit restricts how many times a policy can be used.

type VCSInfo

type VCSInfo struct {
	// VCSType is "jj" or "git"
	VCSType string
	// HasJJ indicates if JJ is available
	HasJJ bool
	// HasGit indicates if Git is available
	HasGit bool
	// IsColocated indicates if this is a JJ+Git colocated repo
	IsColocated bool
	// RepoPath is the repository root path
	RepoPath string
	// CurrentBookmark is the current branch/bookmark name
	CurrentBookmark string
	// CurrentRevision is the current revision (short ID)
	CurrentRevision string
	// HasUncommittedChanges indicates if there are uncommitted changes
	HasUncommittedChanges bool
	// ModifiedFileCount is the count of modified/added/deleted files
	ModifiedFileCount int
}

VCSInfo contains version control information for a session

type VNCProcessManager added in v1.35.0

type VNCProcessManager = vnc.VNCProcessManager

VNCProcessManager is a local alias for the vnc package interface so that files within the session package can reference it without importing vnc directly.

type WorkflowCreateInput added in v1.35.0

type WorkflowCreateInput struct {
	Slug              string
	Name              string
	Description       string
	Command           string
	TargetDirectory   string
	InputTemplate     string
	SessionType       string
	Model             string
	AgentType         string
	CronExpression    string
	CronEnabled       bool
	KeepSessions      *int // nil = use default (0, disabled); 0 = keep all
	ArchiveAfterHours *int // nil = use default (0, disabled); 0 = disabled
}

WorkflowCreateInput holds the fields for creating a new workflow.

type WorkflowEngine added in v1.35.0

type WorkflowEngine interface {
	// CanTransition returns true if transitioning from → to is structurally allowed.
	CanTransition(from, to BacklogStatus) bool
	// ValidateGates runs guard rules for the transition. Returns nil if gates pass.
	ValidateGates(item BacklogItemTransitionInput, to BacklogStatus) error
	// AllowedTransitions returns the set of statuses reachable from from.
	AllowedTransitions(from BacklogStatus) []BacklogStatus
}

WorkflowEngine is the policy object that governs which backlog status transitions are permitted and what guards must pass.

type WorkflowRepository added in v1.35.0

type WorkflowRepository interface {
	Create(ctx context.Context, w WorkflowCreateInput) (*ent.Workflow, error)
	Update(ctx context.Context, id uuid.UUID, w WorkflowUpdateInput) (*ent.Workflow, error)
	Delete(ctx context.Context, id uuid.UUID) error
	GetByID(ctx context.Context, id uuid.UUID) (*ent.Workflow, error)
	GetBySlug(ctx context.Context, slug string) (*ent.Workflow, error)
	ListAll(ctx context.Context) ([]*ent.Workflow, error)
	ListEnabled(ctx context.Context) ([]*ent.Workflow, error) // cron_enabled=true
}

WorkflowRepository defines persistence operations for workflow definitions.

type WorkflowUpdateInput added in v1.35.0

type WorkflowUpdateInput struct {
	Name              *string
	Description       *string
	Command           *string
	TargetDirectory   *string
	InputTemplate     *string
	SessionType       *string
	Model             *string
	AgentType         *string
	CronExpression    *string
	CronEnabled       *bool
	KeepSessions      *int // nil = do not update; 0 = keep all (disabled)
	ArchiveAfterHours *int // nil = do not update; 0 = disabled
}

WorkflowUpdateInput holds optional fields for updating an existing workflow. Pointer fields are only applied when non-nil (partial update).

type Workspace added in v1.12.0

type Workspace struct {
	// EffectivePath is the directory where the session process runs.
	// For worktree sessions: the worktree directory.
	// For directory sessions: the session's Path field.
	EffectivePath string

	// RepoRoot is the git repository root (the main checkout, not the worktree).
	// For directory sessions, this is the same as EffectivePath.
	RepoRoot string
}

Workspace describes where a session is operating. Use Instance.Workspace() to obtain this value; do not construct directly.

type WorkspacePath added in v1.35.0

type WorkspacePath string

WorkspacePath represents a cleaned, resolved workspace root path.

func NewWorkspacePath added in v1.35.0

func NewWorkspacePath(s string) (WorkspacePath, error)

NewWorkspacePath resolves symlinks and cleans a path to guarantee a single canonical representation.

type WorkspaceSwitchRequest

type WorkspaceSwitchRequest struct {
	// Type is the type of switch operation
	Type WorkspaceSwitchType
	// Target is the destination (directory path, revision/branch, or worktree path)
	Target string
	// ChangeStrategy determines how to handle uncommitted changes
	ChangeStrategy vcs.ChangeStrategy
	// CreateIfMissing creates the bookmark/branch/worktree if it doesn't exist
	CreateIfMissing bool
	// BaseRevision is the base for new bookmark creation (empty = current)
	BaseRevision string
	// VCSPreference overrides the default VCS preference for this operation
	VCSPreference vcs.VCSPreference
}

WorkspaceSwitchRequest represents a request to switch the workspace

type WorkspaceSwitchResult

type WorkspaceSwitchResult struct {
	// Success indicates if the switch was successful
	Success bool
	// Error contains any error that occurred
	Error error
	// PreviousRevision is the revision before the switch
	PreviousRevision string
	// CurrentRevision is the revision after the switch
	CurrentRevision string
	// VCSType is the VCS that was used
	VCSType vcs.VCSType
	// ChangesHandled describes how uncommitted changes were handled
	ChangesHandled string
}

WorkspaceSwitchResult contains the result of a workspace switch operation

type WorkspaceSwitchType

type WorkspaceSwitchType int

WorkspaceSwitchType defines the type of workspace switch operation

const (
	// SwitchTypeDirectory is a simple directory change (no VCS, no restart)
	SwitchTypeDirectory WorkspaceSwitchType = iota
	// SwitchTypeRevision switches to a different revision/branch
	SwitchTypeRevision
	// SwitchTypeWorktree switches to or creates a different worktree
	SwitchTypeWorktree
)

func (WorkspaceSwitchType) String

func (t WorkspaceSwitchType) String() string

type WorktreeInfo

type WorktreeInfo struct {
	// IsWorktree is true if the path is a git worktree (not the main repo)
	IsWorktree bool
	// MainRepoPath is the path to the main repository's .git directory
	// For a worktree at ~/.stapler-squad/worktrees/foo, this might be /path/to/main/repo/.git
	MainRepoPath string
	// MainRepoRoot is the working directory root of the main repository
	MainRepoRoot string
	// RemoteURL is the git remote origin URL (e.g., https://github.com/owner/repo.git)
	RemoteURL string
	// GitHubOwner is the owner extracted from a GitHub remote URL
	GitHubOwner string
	// GitHubRepo is the repo name extracted from a GitHub remote URL
	GitHubRepo string
}

WorktreeInfo contains information about a git worktree

func DetectWorktree

func DetectWorktree(path string) (*WorktreeInfo, error)

DetectWorktree checks if the given path is a git worktree and extracts relevant info. Results are cached per-path for 5 minutes to avoid repeated git subprocess calls on every LoadInstances invocation for sessions whose GitHubOwner was never resolved. Returns WorktreeInfo with IsWorktree=false if it's not a worktree or not a git repo.

type WorktreePRPoller added in v1.35.0

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

WorktreePRPoller polls GitHub PR status for worktrees that have no active session. It is the counterpart to PRStatusPoller (which covers session-backed worktrees). The two pollers divide the worktree space: PRStatusPoller owns worktrees with a running session; WorktreePRPoller owns the rest.

Concurrency design:

  • data cache is a sync.Map — lock-free reads in the steady state
  • auth state is an atomic.Value (pollerAuthResult) — same pattern as PRStatusPoller
  • onUpdated callback is an atomic.Value — writers Store, readers Load, no lock

func NewWorktreePRPoller added in v1.35.0

func NewWorktreePRPoller(etagCache *github.ETagCache, prPoller *PRStatusPoller) *WorktreePRPoller

NewWorktreePRPoller creates a WorktreePRPoller with default configuration. source may be nil at construction time; call SetSource before Start.

func NewWorktreePRPollerWithConfig added in v1.35.0

func NewWorktreePRPollerWithConfig(etagCache *github.ETagCache, prPoller *PRStatusPoller, cfg WorktreePRPollerConfig) *WorktreePRPoller

NewWorktreePRPollerWithConfig creates a WorktreePRPoller with custom configuration.

func (*WorktreePRPoller) GetPRData added in v1.35.0

func (p *WorktreePRPoller) GetPRData(repoPath, branch string) *github.PRInfo

GetPRData returns cached PR info for a worktree, or nil if not yet known.

func (*WorktreePRPoller) SetOnUpdated added in v1.35.0

func (p *WorktreePRPoller) SetOnUpdated(fn func(repoPath, branch string, info *github.PRInfo))

SetOnUpdated registers a callback invoked whenever cached PR data changes. Safe to call before or after Start; the callback is replaced atomically.

func (*WorktreePRPoller) SetSource added in v1.35.0

func (p *WorktreePRPoller) SetSource(src WorktreeSource)

SetSource sets the worktree data source. Safe to call before Start.

func (*WorktreePRPoller) Start added in v1.35.0

func (p *WorktreePRPoller) Start(ctx context.Context)

Start begins the polling loop. It is a no-op if already started.

func (*WorktreePRPoller) Stop added in v1.35.0

func (p *WorktreePRPoller) Stop()

Stop gracefully shuts down the poller and waits for in-flight requests.

type WorktreePRPollerConfig added in v1.35.0

type WorktreePRPollerConfig struct {
	PollInterval      time.Duration
	CallTimeout       time.Duration
	AuthCacheDuration time.Duration
}

WorktreePRPollerConfig controls polling cadence and auth caching.

func DefaultWorktreePRPollerConfig added in v1.35.0

func DefaultWorktreePRPollerConfig() WorktreePRPollerConfig

DefaultWorktreePRPollerConfig returns sensible defaults matching PRStatusPoller.

type WorktreeScanItem added in v1.35.0

type WorktreeScanItem struct {
	RepoPath     string
	Branch       string
	WorktreePath string
}

WorktreeScanItem is the minimal worktree info the poller needs from the unfinished-work scanner. Using a local struct avoids an import cycle:

session → session/unfinished → pkg/events → session

The server layer bridges the two packages via WorktreeSource (adapter pattern).

type WorktreeSource added in v1.35.0

type WorktreeSource interface {
	// ScanDone returns a channel that receives the scan time after every scan pass.
	ScanDone() <-chan time.Time
	// GetWorktrees returns a snapshot of all currently-known worktrees.
	GetWorktrees() []WorktreeScanItem
}

WorktreeSource provides the set of currently-known worktrees. Implement this interface by wrapping an *unfinished.Scanner in the server layer.

type WorktreeTarget

type WorktreeTarget struct {
	Name       string
	Path       string
	Bookmark   string
	RevisionID string
	IsCurrent  bool
}

WorktreeTarget represents a worktree as a switch target

Source Files

Directories

Path Synopsis
Package cdp provides per-session Chrome DevTools Protocol (CDP) browser streaming.
Package cdp provides per-session Chrome DevTools Protocol (CDP) browser streaming.
binaries
Package binaries provides per-binary BinaryDetector implementations.
Package binaries provides per-binary BinaryDetector implementations.
dtypes
Package dtypes contains shared types for the detection package and its sub-packages.
Package dtypes contains shared types for the detection package and its sub-packages.
ent
tag
Package framebuffer provides Mosh-style terminal state diffing.
Package framebuffer provides Mosh-style terminal state diffing.
Package headless provides a subprocess-based interface for running claude -p headlessly.
Package headless provides a subprocess-based interface for running claude -p headlessly.
Package hibernation provides checkpoint writing and cleanup for hibernated sessions.
Package hibernation provides checkpoint writing and cleanup for hibernated sessions.
Package memory provides session memory measurement for the hibernation sweeper.
Package memory provides session memory measurement for the hibernation sweeper.
memorytest
Package memorytest provides test doubles for the memory package.
Package memorytest provides test doubles for the memory package.
Package mux provides PTY multiplexing functionality for external Claude sessions.
Package mux provides PTY multiplexing functionality for external Claude sessions.
Package tokens provides JSONL-based token usage parsing and aggregation for Claude Code sessions.
Package tokens provides JSONL-based token usage parsing and aggregation for Claude Code sessions.
Package unfinished provides background scanning for git worktrees that have uncommitted changes, commits ahead of the default branch, or commits behind.
Package unfinished provides background scanning for git worktrees that have uncommitted changes, commits ahead of the default branch, or commits behind.
Package vcs provides an abstraction layer over version control systems.
Package vcs provides an abstraction layer over version control systems.
Package vnc provides per-session virtual display and VNC server lifecycle management.
Package vnc provides per-session virtual display and VNC server lifecycle management.
Package workspace provides workspace tracking and status management for stapler-squad sessions.
Package workspace provides workspace tracking and status management for stapler-squad sessions.

Jump to

Keyboard shortcuts

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