session

package
v0.4.0 Latest Latest
Warning

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

Go to latest
Published: Oct 22, 2026 License: MIT Imports: 30 Imported by: 0

Documentation

Index

Constants

View Source
const (
	ReviewClassificationClean           = "clean"
	ReviewClassificationDirtyOnly       = "dirty-only"
	ReviewClassificationUniqueCommits   = "unique-commits"
	ReviewClassificationMissingWorktree = "missing-worktree"
	ReviewClassificationNeedsReview     = "needs-human-review"
	ReviewClassificationPreserve        = "preserve-before-delete"
	ReviewClassificationProbablySafe    = "probably-safe-to-delete"
	ReviewClassificationSafe            = "safe-to-delete"
	ReviewClassificationError           = "error"
)
View Source
const (
	StaleCategoryActive      = "active"
	StaleCategoryClean       = "stale-clean"
	StaleCategoryNeedsReview = "stale-needs-review"
	StaleCategoryBroken      = "broken"
)
View Source
const (
	SessionStatusAttention        = "attention"
	SessionStatusUnseenArtifact   = "unseen_artifact"
	SessionStatusBrokenOrStale    = "broken_or_stale"
	SessionStatusDirty            = "dirty"
	SessionStatusActive           = "active"
	SessionStatusCleanupCandidate = "cleanup_candidate"
	SessionStatusIdle             = "idle"
)
View Source
const DefaultStaleThreshold = 14 * 24 * time.Hour
View Source
const DefaultTmuxHistoryLimit = 50000
View Source
const DefaultTmuxMouse = "off"
View Source
const LocalOnlyOwnerPiMCP = "devx-pi-mcp"

LocalOnlyOwnerPiMCP is the only owner allowed to create local-only sessions.

View Source
const LocalOnlyWindow = "devx-local"

LocalOnlyWindow is the name of the inert first window of a local-only tmux session. It runs no shell and no project command.

View Source
const MaxDisplayNameLen = 100

MaxDisplayNameLen is the maximum length of a session display name.

View Source
const MaxSessionNameLen = 100

MaxSessionNameLen is the maximum allowed length for a session name. The TUI input and the validation regex both enforce this limit.

View Source
const MaxStaleThresholdDays = 3650

Variables

View Source
var ErrAdoptNotAllowed = errors.New("session cannot be adopted")

ErrAdoptNotAllowed is returned when a session cannot be adopted for an agent.

View Source
var ErrLocalOnlyNotOwned = errors.New("not owned by this local-only agent")

ErrLocalOnlyNotOwned is returned when a session or tmux session with the requested name exists but was not created for this agent.

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

Functions

func AllocatePortsLegacy

func AllocatePortsLegacy() (fePort, apiPort int, err error)

AllocatePortsLegacy allocates two unique ports for frontend and API (backwards compatibility)

func AttachEditorToSession

func AttachEditorToSession(sessionName, path string) error

AttachEditorToSession handles editor attachment logic for session attach

func AttachReadyTmuxSession added in v0.4.0

func AttachReadyTmuxSession(sessionName string) error

AttachReadyTmuxSession performs a complete already-ensured handoff.

func AttachTmuxSession

func AttachTmuxSession(sessionName string) error

AttachTmuxSession attaches to an existing tmux session

func BranchExists

func BranchExists(repoPath, branchName string) (bool, error)

BranchExists checks if a branch exists in the repository

func BuildReviewPrompt added in v0.4.0

func BuildReviewPrompt(sess *Session, review *SessionReview) string

func ClearAttentionFlag

func ClearAttentionFlag(sessionName string) error

ClearAttentionFlag clears the attention flag for a session

func ClearRegistry

func ClearRegistry() error

ClearRegistry removes all sessions and clears the sessions file

func ClearSessionReview added in v0.4.0

func ClearSessionReview(name string) error

func CopyBootstrapFiles

func CopyBootstrapFiles(projectRoot, worktreePath string, bootstrapFiles []string) error

CopyBootstrapFiles copies the given bootstrap files from the project root to the worktree. When bootstrapFiles is nil, it falls back to the global viper "bootstrap_files" key for backward compatibility; callers should prefer passing the project's own config so resolution does not depend on the current working directory.

func CreateWorktree

func CreateWorktree(repoPath, name string, detach bool) (string, error)

CreateWorktree creates a new git worktree and returns the path to it. If the branch is already checked out in an existing worktree (anywhere in the repo — including paths created by external tools like Claude Code), that existing worktree path is returned and reused rather than failing.

func DeriveInstanceID added in v0.4.0

func DeriveInstanceID(name, path string, createdAt time.Time) string

DeriveInstanceID returns the instance id the migration assigns to an EXISTING record that has none. It is a deterministic hash of the record's identity (name, path, exact created_at), so a read-only dry run shows the exact ids and plan hash that --apply will write, with no key or other state. Instance ids are identifiers, not secrets or capabilities: no caller ever supplies one, they are only compared against DevX's own records. A record recreated under the same name and path has a different created_at (to the nanosecond), hence a different id. New records get random ids (NewInstanceID).

func EnsureLocalOnlyTmuxSession added in v0.4.0

func EnsureLocalOnlyTmuxSession(name string, sess *Session) error

EnsureLocalOnlyTmuxSession makes sure the local-only session's tmux session exists. A new one gets a single inert window (no shell, no project command) and is tagged with the owning agent id at creation. An existing tmux session is adopted only if it carries that same tag.

func EnsureTmuxSession added in v0.4.0

func EnsureTmuxSession(sessionName, worktreePath string) error

EnsureTmuxSession checks whether the named tmux session is alive and, if not, recreates it via tmuxp so the full pane layout and startup commands are restored. Called by the web server before attaching ttyd, so sessions survive a machine reboot without any manual steps.

func EnsureTmuxSessionInContainer added in v0.4.0

func EnsureTmuxSessionInContainer(sessionName, containerName string, sess *Session) error

EnsureTmuxSessionInContainer ensures the named tmux session is alive on the host tmux server, with every pane running inside the container via docker exec.

The approach: 1. Read the project's .tmuxp.yaml to discover window/pane structure and commands 2. Create the tmux session directly (no tmuxp) with guard scripts that:

  • Verify the container is running before each exec
  • Auto-reconnect when docker exec exits (Ctrl-C, crash, etc.)
  • Never drop to a host shell — show error + wait instead

3. Verify post-launch that panes are actually inside the container

The project's .tmuxp.yaml is never modified — we read it as a declarative spec and build the tmux session ourselves.

func FetchOrigin added in v0.3.0

func FetchOrigin(repoPath string) error

FetchOrigin fetches remote refs from origin, pruning deleted branches. Failure is non-fatal (caller warns and continues).

func GenerateEnvrc

func GenerateEnvrc(worktreePath string, data EnvrcData) error

GenerateEnvrc creates an .envrc file in the worktree directory

func GenerateTmuxpConfig

func GenerateTmuxpConfig(worktreePath string, data TmuxpData, projectPath string) error

GenerateTmuxpConfig creates a .tmuxp.yaml file in the worktree directory. projectPath is the root of the project (containing .devx/) and is used to find the project-level template. It must be passed explicitly so that config lookup is project-path-based rather than relying on os.Getwd(), which is unreliable when creating sessions via --project flag or the web UI.

func GetCurrentSessionName

func GetCurrentSessionName() string

GetCurrentSessionName attempts to determine the current session based on working directory

func GetEditorCommand

func GetEditorCommand() string

GetEditorCommand returns the editor command to use, checking in this order: 1. devx config "editor" setting 2. VISUAL environment variable 3. EDITOR environment variable 4. Empty string if none are set

func GetProjectRoot

func GetProjectRoot() (string, error)

GetProjectRoot finds the git repository root directory

func IsEditorAvailable

func IsEditorAvailable() bool

IsEditorAvailable checks if the configured editor command is available

func IsProcessRunning

func IsProcessRunning(pid int) bool

IsProcessRunning checks if a process with the given PID is still running. The liveness probe is platform-specific (see process_unix.go and process_windows.go): Windows has no signal 0.

func IsTmuxRunning

func IsTmuxRunning() bool

IsTmuxRunning checks if we're already inside a tmux session

func IsValidDisplayName added in v0.4.0

func IsValidDisplayName(dn string) bool

IsValidDisplayName returns true if dn is a valid display name. Empty is valid (used to clear). Max length is 100 characters. Control characters (including null bytes, ANSI escapes, newlines) are rejected to prevent terminal escape injection.

func IsValidSessionName added in v0.3.0

func IsValidSessionName(name string) bool

IsValidSessionName returns true if name passes both the character-class regex and path-traversal guards. Names are used as git branch names, tmux targets, and path components under .worktrees/, so "." and ".." segments must be rejected.

Validation is two-stage: (1) the regex enforces the allowed character set and maximum length; (2) the segment loop enforces structural constraints (path traversal, git-rejected patterns) that regex alone cannot cleanly express.

func IsWorktreeCheckedOut

func IsWorktreeCheckedOut(repoPath, branchName string) (bool, string, error)

IsWorktreeCheckedOut checks if a branch is already checked out in a worktree

func LaunchEditor

func LaunchEditor(path string) (int, error)

LaunchEditor launches the configured editor with the given path It runs asynchronously and returns the process PID

func LaunchEditorForSession

func LaunchEditorForSession(sessionName, path string) error

LaunchEditorForSession launches the editor for a session and updates the session metadata

func LaunchTmuxSession

func LaunchTmuxSession(worktreePath, sessionName string) error

LaunchTmuxSession launches a tmux session using tmuxp

func LocalOnlyTmuxTag added in v0.4.0

func LocalOnlyTmuxTag(name string) (value string, present bool, err error)

LocalOnlyTmuxTag returns the DEVX_LOCAL_ONLY_AGENT value the local-only creator set on the live tmux session with exactly this name (present=false if there is no such session, value "" if it has no tag). Read-only.

func MarkReviewed added in v0.4.0

func MarkReviewed(name string, at time.Time) error

MarkReviewed records an explicit stale-review/snooze marker without treating the review as real activity or changing UpdatedAt.

func MatchesBoundInstance added in v0.4.0

func MatchesBoundInstance(s *Session, boundID string, boundCreatedAt time.Time) bool

MatchesBoundInstance reports whether record s is the session instance an agent was bound to (boundID, recorded with the record's created_at as boundCreatedAt). It is the single identity rule:

  • the record carries an id: it must equal boundID;
  • the record has no id (an older DevX writer dropped the field): its created_at must equal boundCreatedAt to the nanosecond (older writers preserve created_at; a recreated record gets a new one).

An empty boundID never matches (unbound agents are not identified here).

func NewInstanceID added in v0.4.0

func NewInstanceID() string

NewInstanceID returns a fresh random session instance id ("si_" + 96 bits).

func PersistSessionReview added in v0.4.0

func PersistSessionReview(name string, review *SessionReview) error

func PruneWorktrees

func PruneWorktrees(repoPath string) error

PruneWorktrees removes stale worktree references. --expire now bypasses git's default 3-month grace period so recently-deleted worktrees are pruned immediately rather than showing as "missing but registered".

func PullFromOrigin

func PullFromOrigin(repoPath, branch string) error

PullFromOrigin pulls the latest changes from origin for the specified branch

func ReleaseManagedAgent added in v0.4.0

func ReleaseManagedAgent(name, agentID string) error

ReleaseManagedAgent clears the adoption marker if it still names agentID.

func RemoteBranchExists added in v0.3.0

func RemoteBranchExists(repoPath, branchName string) (bool, error)

RemoteBranchExists checks if a branch exists on origin.

func RemoveSession

func RemoveSession(name string, sess *Session) error

RemoveSession removes a single session completely (helper for commands)

func RemoveSessionReviewDetails added in v0.4.0

func RemoveSessionReviewDetails(name string) error

func ResolveReviewBase added in v0.4.0

func ResolveReviewBase(repoPath, requested string) (string, error)

func ReviewIsStale added in v0.4.0

func ReviewIsStale(sess *Session) bool

func RunCleanupCommand

func RunCleanupCommand(sess *Session) error

RunCleanupCommand executes the configured cleanup command with session environment variables

func RunCleanupCommandForShell

func RunCleanupCommandForShell(sess *Session) error

RunCleanupCommandForShell executes cleanup command through shell for complex commands

func SaveSessionReviewDetails added in v0.4.0

func SaveSessionReviewDetails(name string, review *SessionReview) error

func SessionsMetadataFingerprint added in v0.4.0

func SessionsMetadataFingerprint() string

SessionsMetadataFingerprint returns a cheap version string for the sessions metadata file. Web caches use this to notice mutations made by other devx processes without parsing the whole store on every request.

func SetAttentionFlag

func SetAttentionFlag(sessionName, reason string) error

SetAttentionFlag sets the attention flag for a session.

func SetAttentionFlagWithSource added in v0.4.0

func SetAttentionFlagWithSource(sessionName, reason, source string) error

SetAttentionFlagWithSource sets the attention flag with a structured source.

func StaleThresholdDuration added in v0.4.0

func StaleThresholdDuration(days int) (time.Duration, error)

func StartReadyTmuxSession added in v0.4.0

func StartReadyTmuxSession(sessionName string) (func() error, error)

StartReadyTmuxSession starts the terminal handoff and returns a waiter. Callers can safely persist open-side effects after this function succeeds.

func TerminateEditor

func TerminateEditor(sessionName string) error

TerminateEditor terminates the editor process for a session

func TmuxHasSession added in v0.4.0

func TmuxHasSession(name string) bool

TmuxHasSession reports whether a tmux session with exactly this name exists.

func ValidInstanceID added in v0.4.0

func ValidInstanceID(id string) bool

ValidInstanceID reports whether id is a well-formed session instance id.

func ValidatePort

func ValidatePort(port int) error

ValidatePort checks if a port number is valid

func WorktreeExists

func WorktreeExists(repoPath, worktreePath string) (bool, error)

WorktreeExists checks if a worktree exists at the specified path

Types

type EnvrcData

type EnvrcData struct {
	Ports          map[string]int    // service name -> port number
	Routes         map[string]string // service name -> local hostname (*.localhost)
	ExternalRoutes map[string]string // service name -> external hostname (*.domain.com), if CF configured
	Name           string
}

type GatepostMeta added in v0.4.0

type GatepostMeta struct {
	Enabled             bool     `json:"enabled,omitempty"`
	Runtime             string   `json:"runtime,omitempty"`
	ProxyContainerName  string   `json:"proxy_container_name,omitempty"`
	InternalNetworkName string   `json:"internal_network_name,omitempty"`
	EgressNetworkName   string   `json:"egress_network_name,omitempty"`
	PortsNetworkName    string   `json:"ports_network_name,omitempty"`
	SessionDir          string   `json:"session_dir,omitempty"`
	AuditDir            string   `json:"audit_dir,omitempty"`
	ConfigDir           string   `json:"config_dir,omitempty"`
	AgentHomeDir        string   `json:"agent_home_dir,omitempty"`
	AuditLog            string   `json:"audit_log,omitempty"`
	CompanionLog        string   `json:"companion_log,omitempty"`
	ControlURL          string   `json:"control_url,omitempty"`
	LogsURL             string   `json:"logs_url,omitempty"`
	LogsTokenPath       string   `json:"logs_token_path,omitempty"`
	LogsPID             int      `json:"logs_pid,omitempty"`
	ProviderMode        string   `json:"provider_mode,omitempty"`
	ProviderCommand     string   `json:"provider_command,omitempty"`
	RegisteredProviders []string `json:"registered_providers,omitempty"`
	ProviderWarnings    []string `json:"provider_warnings,omitempty"`
	ControlToken        string   `json:"-"`
	EventToken          string   `json:"-"`
	Bypass              bool     `json:"bypass,omitempty"`
}

GatepostMeta describes the optional Gatepost capability attached to a session. Runtime-specific details stay behind Runtime; DevX consumes this as a stable contract for control, logs, and host-side bypass operations.

type LocalOnlyMeta added in v0.4.0

type LocalOnlyMeta struct {
	Owner     string    `json:"owner"`
	AgentID   string    `json:"agent_id"`
	CreatedAt time.Time `json:"created_at"`
	// Unknown holds marker members this build does not know (see
	// unknown_fields.go); they are written back unchanged.
	Unknown map[string]json.RawMessage `json:"-"`
}

LocalOnlyMeta marks a session that DevX created for a managed agent and must never expose. Local-only sessions have no allocated service ports, no routes, no generated .envrc/.tmuxp.yaml, and no project template windows; every route builder skips them even if ports or routes are later added to the record by hand.

func (LocalOnlyMeta) MarshalJSON added in v0.4.0

func (m LocalOnlyMeta) MarshalJSON() ([]byte, error)

MarshalJSON encodes the marker plus any preserved unknown members.

func (*LocalOnlyMeta) UnmarshalJSON added in v0.4.0

func (m *LocalOnlyMeta) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes a local-only marker and keeps unknown members, so a field a newer build adds to the marker survives this build's writes (and a marker restored from a backup keeps it).

type LocalOnlyRequest added in v0.4.0

type LocalOnlyRequest struct {
	Name         string
	ProjectAlias string
	ProjectPath  string
	AgentID      string
}

LocalOnlyRequest describes a local-only session to create (or resume).

type PortAllocation

type PortAllocation struct {
	Ports map[string]int // service name -> port number
}

PortAllocation represents allocated ports with their service names

func AllocatePorts

func AllocatePorts(serviceNames []string) (*PortAllocation, error)

AllocatePorts allocates unique ports for the given service names

type ReviewOptions added in v0.4.0

type ReviewOptions struct {
	BaseBranch string
	MaxFiles   int
}

type Session

type Session struct {
	Name               string            `json:"name"`
	ProjectAlias       string            `json:"project_alias,omitempty"` // Reference to project in registry
	ProjectPath        string            `json:"project_path,omitempty"`  // Resolved project path
	Branch             string            `json:"branch"`
	Path               string            `json:"path"`
	Ports              map[string]int    `json:"ports"`
	Routes             map[string]string `json:"routes,omitempty"`     // service -> hostname mapping
	EditorPID          int               `json:"editor_pid,omitempty"` // PID of the editor process
	AttentionFlag      bool              `json:"attention_flag,omitempty"`
	AttentionReason    string            `json:"attention_reason,omitempty"` // "claude_done", "claude_stuck", "manual", etc.
	AttentionSource    string            `json:"attention_source,omitempty"`
	AttentionTime      time.Time         `json:"attention_time,omitempty"`
	DisplayName        string            `json:"display_name,omitempty"`
	Pinned             bool              `json:"pinned,omitempty"`
	LastAttached       time.Time         `json:"last_attached,omitempty"`
	LastArtifactSeenAt time.Time         `json:"last_artifact_seen_at,omitempty"`
	LastReviewedAt     time.Time         `json:"last_reviewed_at,omitempty"`
	Review             *SessionReview    `json:"review,omitempty"`
	CreatedAt          time.Time         `json:"created_at"`
	UpdatedAt          time.Time         `json:"updated_at"`
	Target             TargetMeta        `json:"target,omitempty"`
	// ManagedAgent records the MCP-managed Pi agent adopted into this normal
	// (human-created) session via `devx agent adopt`. Unlike LocalOnly it
	// changes nothing about routing, ports or services.
	ManagedAgent string `json:"managed_agent,omitempty"`
	// LocalOnly marks a managed-agent session that must never be routed or
	// published (see localonly.go).
	LocalOnly *LocalOnlyMeta `json:"local_only,omitempty"`
	// InstanceID identifies this session record, independent of its name,
	// path and timestamps: a session removed and recreated with the same
	// name and path gets a new one. It is assigned when the record is
	// created (see NewInstanceID) and never changed afterwards; records from
	// before it existed get one through `devx session instances`.
	InstanceID string `json:"instance_id,omitempty"`
	// Unknown holds members of the on-disk record this build does not know
	// (written by a newer DevX). They are written back unchanged so this
	// build never strips another build's fields; see unknown_fields.go.
	Unknown map[string]json.RawMessage `json:"-"`
}

func AdoptManagedAgent added in v0.4.0

func AdoptManagedAgent(name, agentID string) (*Session, error)

AdoptManagedAgent records agentID as the managed agent of an existing, human-created session. It is idempotent for the same agent and refuses local-only sessions (they already belong to an MCP-created agent), sessions running in a container target, and sessions already adopted by a different agent. It changes no ports, routes or services.

func CreateLocalOnlySession added in v0.4.0

func CreateLocalOnlySession(req LocalOnlyRequest) (*Session, error)

CreateLocalOnlySession creates, or resumes an interrupted creation of, a local-only session: metadata first (with the marker, so the record is never routable at any instant), then a git worktree on a new branch named after the session. It never fetches, allocates ports, writes env files, copies bootstrap files, renders templates, syncs routes or starts tmux.

Resuming is allowed only when the existing record carries a marker for the same agent. On worktree failure the owned record is removed again, so a failed first attempt leaves nothing behind.

func VerifyManagedAgent added in v0.4.0

func VerifyManagedAgent(name, agentID, boundInstance string, boundCreatedAt time.Time) (*Session, error)

VerifyManagedAgent returns a copy of session name if it is still the session agentID adopted. It writes nothing and never re-adopts. Accepted:

  • the adoption marker names agentID (and, when boundInstance is set, the record's instance id equals it, or is missing with createdAt matching exactly); or
  • the marker is gone (an older DevX writer dropped the field) but the record is provably the bound instance: instance id equals boundInstance (or is missing with created_at equal to boundCreatedAt to the nanosecond), it is a host session, and no marker names anyone else.

A removed and recreated session never matches.

func (*Session) ActivityAt added in v0.4.0

func (s *Session) ActivityAt() (time.Time, bool)

ActivityAt returns the latest intentional session activity. Creation counts until the session has been attached; cosmetic metadata updates do not.

func (*Session) IsContainerized added in v0.4.0

func (s *Session) IsContainerized() bool

IsContainerized returns true if the session runs inside a container.

func (*Session) IsLocalOnly added in v0.4.0

func (s *Session) IsLocalOnly() bool

IsLocalOnly reports whether the session carries a local-only marker. Any marker, even an incomplete one, counts: callers that route or expose sessions must fail closed.

func (*Session) Label added in v0.4.0

func (s *Session) Label() string

Label returns the display name if set, otherwise the session name.

func (Session) MarshalJSON added in v0.4.0

func (s Session) MarshalJSON() ([]byte, error)

MarshalJSON encodes the record plus any preserved unknown members.

func (*Session) TargetType added in v0.4.0

func (s *Session) TargetType() string

TargetType returns the effective target type, defaulting to "host".

func (*Session) UnmarshalJSON added in v0.4.0

func (s *Session) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes a session record and keeps every member this build does not know in Unknown, so it is written back unchanged.

type SessionReview added in v0.4.0

type SessionReview struct {
	BaseBranch     string    `json:"base_branch,omitempty"`
	HeadSHA        string    `json:"head_sha,omitempty"`
	StatusHash     string    `json:"status_hash,omitempty"`
	ReviewedAt     time.Time `json:"reviewed_at,omitempty"`
	Harness        string    `json:"harness,omitempty"`
	Classification string    `json:"classification"`
	Summary        string    `json:"summary,omitempty"`
	Details        string    `json:"details,omitempty"`
	Stale          bool      `json:"stale,omitempty"`
	Error          string    `json:"error,omitempty"`

	UniqueCommits  []string `json:"unique_commits,omitempty"`
	ChangedFiles   []string `json:"changed_files,omitempty"`
	DirtyFiles     []string `json:"dirty_files,omitempty"`
	UntrackedFiles []string `json:"untracked_files,omitempty"`

	UniqueCommitCount  int  `json:"unique_commit_count,omitempty"`
	ChangedFileCount   int  `json:"changed_file_count,omitempty"`
	DirtyFileCount     int  `json:"dirty_file_count,omitempty"`
	UntrackedFileCount int  `json:"untracked_file_count,omitempty"`
	Truncated          bool `json:"truncated,omitempty"`
}

SessionReview is a persisted snapshot of a session/worktree cleanup review. It is intentionally advisory: devx never deletes sessions based on this data.

func CompactSessionReview added in v0.4.0

func CompactSessionReview(review *SessionReview) *SessionReview

func LoadSessionReviewDetails added in v0.4.0

func LoadSessionReviewDetails(name string) (*SessionReview, error)

func MergeReviewDetails added in v0.4.0

func MergeReviewDetails(summary, details *SessionReview) *SessionReview

func RefreshSessionReviewStale added in v0.4.0

func RefreshSessionReviewStale(name string, sess *Session) (*SessionReview, error)

func ReviewSession added in v0.4.0

func ReviewSession(sess *Session, opts ReviewOptions) (*SessionReview, error)

func RunReviewHarness added in v0.4.0

func RunReviewHarness(ctx context.Context, sess *Session, review *SessionReview, harness string, command []string) (*SessionReview, error)

type SessionStatusSummary added in v0.4.0

type SessionStatusSummary struct {
	Primary          string    `json:"primary"`
	Color            string    `json:"color"`
	Label            string    `json:"label"`
	Badges           []string  `json:"badges,omitempty"`
	Reasons          []string  `json:"reasons,omitempty"`
	Priority         int       `json:"priority"`
	Dirty            bool      `json:"dirty"`
	UnseenArtifacts  int       `json:"unseen_artifacts,omitempty"`
	ArtifactCount    int       `json:"artifact_count,omitempty"`
	WorktreeExists   bool      `json:"worktree_exists"`
	TmuxStatus       string    `json:"tmux_status,omitempty"`
	EditorRunning    bool      `json:"editor_running,omitempty"`
	CleanupCandidate bool      `json:"cleanup_candidate"`
	ChecksComplete   bool      `json:"checks_complete"`
	CleanupVerified  bool      `json:"cleanup_verified"`
	CheckedAt        time.Time `json:"checked_at"`
}

SessionStatusSummary is the compact, derived display status shared by API/UI.

func DeriveSessionStatus added in v0.4.0

func DeriveSessionStatus(sess *Session, stale StaleStatus, artifactCount, unseenArtifacts int) SessionStatusSummary

type SessionStore

type SessionStore struct {
	Sessions      map[string]*Session `json:"sessions"`
	NumberedSlots map[int]string      `json:"numbered_slots,omitempty"`
	// Unknown holds top-level members this build does not know.
	Unknown map[string]json.RawMessage `json:"-"`
}

func LoadRegistry

func LoadRegistry() (*SessionStore, error)

LoadRegistry is an alias for LoadSessions for compatibility

func LoadSessions

func LoadSessions() (*SessionStore, error)

LoadSessions loads the sessions from the metadata file

func (*SessionStore) AddSession

func (s *SessionStore) AddSession(name, branch, path string, ports map[string]int) error

AddSession adds a new session to the store

func (*SessionStore) AddSessionWithProject

func (s *SessionStore) AddSessionWithProject(name, branch, path string, ports map[string]int, projectAlias, projectPath string) error

AddSessionWithProject adds a new session to the store with project information

func (*SessionStore) AssignSlot added in v0.2.0

func (s *SessionStore) AssignSlot(name string) (int, error)

AssignSlot assigns a numbered slot (1-9) to a session. If the session already has a slot, returns the existing slot (stable). If a free slot exists, assigns the lowest available. If all 9 are full, evicts the session with the oldest LastAttached.

func (*SessionStore) GetSession

func (s *SessionStore) GetSession(name string) (*Session, bool)

GetSession retrieves a session by name

func (*SessionStore) GetSessionForSlot added in v0.2.0

func (s *SessionStore) GetSessionForSlot(slot int) string

GetSessionForSlot returns the session name assigned to a slot, or "" if empty.

func (*SessionStore) GetSlotForSession added in v0.2.0

func (s *SessionStore) GetSlotForSession(name string) int

GetSlotForSession returns the slot number for a session, or 0 if unassigned.

func (*SessionStore) MarkActive added in v0.4.0

func (s *SessionStore) MarkActive(name string, at time.Time) (int, error)

MarkActive atomically records an intentional open and ensures the session has an MRU number slot. All entry points use this shared activation policy.

func (SessionStore) MarshalJSON added in v0.4.0

func (s SessionStore) MarshalJSON() ([]byte, error)

MarshalJSON encodes the store plus any preserved unknown top-level members.

func (*SessionStore) Mutate added in v0.4.0

func (s *SessionStore) Mutate(fn func(*SessionStore) error) error

Mutate applies fn to the LATEST on-disk store under the sessions file lock and persists the result atomically, then refreshes this in-memory store to match. Use this for create/remove/reconcile flows that change more than one session or the slot map, so concurrent writers are never clobbered.

func (*SessionStore) Overwrite added in v0.4.0

func (s *SessionStore) Overwrite() error

Overwrite replaces the entire on-disk store with this in-memory store under the sessions lock, writing atomically.

Use this ONLY for a freshly constructed or fully-owned store (e.g. clearing the registry, or seeding a known state) where there are no concurrent writers whose updates could be lost. For targeted changes to an existing store, use UpdateSession / RemoveSession / AssignSlot / Mutate instead, which re-read under the lock and cannot drop concurrent updates.

func (*SessionStore) ReconcileSlots added in v0.2.0

func (s *SessionStore) ReconcileSlots()

ReconcileSlots removes slot assignments for sessions that no longer exist.

func (*SessionStore) RecordAttach added in v0.2.0

func (s *SessionStore) RecordAttach(name string) error

RecordAttach updates the LastAttached timestamp for a session

func (*SessionStore) RemoveSession

func (s *SessionStore) RemoveSession(name string) error

RemoveSession removes a session from the store, re-reading the latest on-disk store under the lock so concurrent writers are not clobbered.

func (*SessionStore) SetPinned added in v0.4.0

func (s *SessionStore) SetPinned(name string, pinned bool) error

SetPinned updates durable presentation state without treating the change as session activity or changing UpdatedAt.

func (*SessionStore) UnmarshalJSON added in v0.4.0

func (s *SessionStore) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes the store and keeps unknown top-level members.

func (*SessionStore) UpdateSession

func (s *SessionStore) UpdateSession(name string, updateFn func(*Session)) error

UpdateSession updates an existing session.

The mutation is applied under the sessions file lock against the LATEST on-disk store, not this (possibly stale) in-memory snapshot. This prevents lost updates when another devx process (TUI, web daemon, concurrent CLI) has written the file since this store was loaded. The in-memory receiver is refreshed to match what was persisted.

type StaleAnalysisMode added in v0.4.0

type StaleAnalysisMode string
const (
	StaleAnalysisModeFastList            StaleAnalysisMode = "fast-list"
	StaleAnalysisModeCleanupVerification StaleAnalysisMode = "cleanup-verification"
)

type StaleAnalysisOptions added in v0.4.0

type StaleAnalysisOptions struct {
	Threshold              time.Duration
	Mode                   StaleAnalysisMode
	MaxConcurrentGitChecks int
	// contains filtered or unexported fields
}

StaleAnalysisOptions selects an explicit stale-analysis mode. Fast-list mode is cheap enough for polling UI state and intentionally skips git probes; cleanup-verification mode performs git checks and is required for pruning.

func CleanupStaleAnalysisOptions added in v0.4.0

func CleanupStaleAnalysisOptions(threshold time.Duration) StaleAnalysisOptions

func FastStaleAnalysisOptions added in v0.4.0

func FastStaleAnalysisOptions(threshold time.Duration) StaleAnalysisOptions

type StaleStatus added in v0.4.0

type StaleStatus struct {
	SessionName               string         `json:"session_name"`
	Category                  string         `json:"category"`
	LastActiveAt              time.Time      `json:"last_active_at"`
	LastReviewedAt            time.Time      `json:"last_reviewed_at,omitempty"`
	Age                       time.Duration  `json:"-"`
	AgeSeconds                int64          `json:"age_seconds"`
	WorktreeExists            bool           `json:"worktree_exists"`
	TmuxStatus                string         `json:"tmux_status"`
	EditorStatus              string         `json:"editor_status"`
	HasUncommitted            bool           `json:"has_uncommitted"`
	HasUntracked              bool           `json:"has_untracked"`
	HasIgnored                bool           `json:"has_ignored"`
	HasUnpushedCommits        bool           `json:"has_unpushed_commits"`
	UnpushedCommits           int            `json:"unpushed_commits"`
	GitStatusUnknown          bool           `json:"git_status_unknown"`
	UnpushedStatusUnknown     bool           `json:"unpushed_status_unknown"`
	GitChecksIncomplete       bool           `json:"git_checks_incomplete"`
	CleanupCandidate          bool           `json:"cleanup_candidate"`
	PotentialCleanupCandidate bool           `json:"potential_cleanup_candidate"`
	Reasons                   []string       `json:"reasons"`
	CleanupReview             *SessionReview `json:"cleanup_review,omitempty"`
}

StaleStatus describes whether a session is old enough and safe enough for automated cleanup. Only stale-clean sessions are removed in bulk.

func AnalyzeStaleSession added in v0.4.0

func AnalyzeStaleSession(sess *Session, threshold time.Duration) StaleStatus

func AnalyzeStaleSessionWithOptions added in v0.4.0

func AnalyzeStaleSessionWithOptions(sess *Session, opts StaleAnalysisOptions) StaleStatus

type StaleSummary added in v0.4.0

type StaleSummary struct {
	ThresholdDays int           `json:"threshold_days"`
	Total         int           `json:"total"`
	Active        int           `json:"active"`
	Clean         int           `json:"clean"`
	NeedsReview   int           `json:"needs_review"`
	Broken        int           `json:"broken"`
	Statuses      []StaleStatus `json:"statuses"`
}

StaleSummary groups analyzed sessions for CLI/API/UI consumers.

func AnalyzeStaleSessions added in v0.4.0

func AnalyzeStaleSessions(store *SessionStore, threshold time.Duration) StaleSummary

func AnalyzeStaleSessionsWithOptions added in v0.4.0

func AnalyzeStaleSessionsWithOptions(store *SessionStore, opts StaleAnalysisOptions) StaleSummary

type TargetMeta added in v0.4.0

type TargetMeta struct {
	Type          string       `json:"type,omitempty"`           // "host", "docker", future: "gatepost", "vm"
	ContainerID   string       `json:"container_id,omitempty"`   // Docker container ID
	ContainerName string       `json:"container_name,omitempty"` // Docker container name
	NetworkName   string       `json:"network_name,omitempty"`   // Docker network name
	Image         string       `json:"image,omitempty"`          // Image used
	Gatepost      GatepostMeta `json:"gatepost,omitempty"`       // Gatepost runtime metadata when target is gatepost
}

TargetMeta describes the execution environment for a session. Zero value (empty Type) is treated as "host" everywhere.

type TmuxpData

type TmuxpData struct {
	Name           string
	Path           string
	Ports          map[string]int    // service name -> port number
	Routes         map[string]string // service name -> local hostname (*.localhost)
	ExternalRoutes map[string]string // service name -> external hostname (*.domain.com), if CF configured
}

type WorktreeInfo

type WorktreeInfo struct {
	Path   string
	Branch string
	Head   string
}

func ListWorktrees

func ListWorktrees(repoPath string) ([]WorktreeInfo, error)

ListWorktrees returns all git worktrees in the repository

Jump to

Keyboard shortcuts

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