Documentation
¶
Index ¶
- Constants
- Variables
- func AllocatePortsLegacy() (fePort, apiPort int, err error)
- func AttachEditorToSession(sessionName, path string) error
- func AttachReadyTmuxSession(sessionName string) error
- func AttachTmuxSession(sessionName string) error
- func BranchExists(repoPath, branchName string) (bool, error)
- func BuildReviewPrompt(sess *Session, review *SessionReview) string
- func ClearAttentionFlag(sessionName string) error
- func ClearRegistry() error
- func ClearSessionReview(name string) error
- func CopyBootstrapFiles(projectRoot, worktreePath string, bootstrapFiles []string) error
- func CreateWorktree(repoPath, name string, detach bool) (string, error)
- func DeriveInstanceID(name, path string, createdAt time.Time) string
- func EnsureLocalOnlyTmuxSession(name string, sess *Session) error
- func EnsureTmuxSession(sessionName, worktreePath string) error
- func EnsureTmuxSessionInContainer(sessionName, containerName string, sess *Session) error
- func FetchOrigin(repoPath string) error
- func GenerateEnvrc(worktreePath string, data EnvrcData) error
- func GenerateTmuxpConfig(worktreePath string, data TmuxpData, projectPath string) error
- func GetCurrentSessionName() string
- func GetEditorCommand() string
- func GetProjectRoot() (string, error)
- func IsEditorAvailable() bool
- func IsProcessRunning(pid int) bool
- func IsTmuxRunning() bool
- func IsValidDisplayName(dn string) bool
- func IsValidSessionName(name string) bool
- func IsWorktreeCheckedOut(repoPath, branchName string) (bool, string, error)
- func LaunchEditor(path string) (int, error)
- func LaunchEditorForSession(sessionName, path string) error
- func LaunchTmuxSession(worktreePath, sessionName string) error
- func LocalOnlyTmuxTag(name string) (value string, present bool, err error)
- func MarkReviewed(name string, at time.Time) error
- func MatchesBoundInstance(s *Session, boundID string, boundCreatedAt time.Time) bool
- func NewInstanceID() string
- func PersistSessionReview(name string, review *SessionReview) error
- func PruneWorktrees(repoPath string) error
- func PullFromOrigin(repoPath, branch string) error
- func ReleaseManagedAgent(name, agentID string) error
- func RemoteBranchExists(repoPath, branchName string) (bool, error)
- func RemoveSession(name string, sess *Session) error
- func RemoveSessionReviewDetails(name string) error
- func ResolveReviewBase(repoPath, requested string) (string, error)
- func ReviewIsStale(sess *Session) bool
- func RunCleanupCommand(sess *Session) error
- func RunCleanupCommandForShell(sess *Session) error
- func SaveSessionReviewDetails(name string, review *SessionReview) error
- func SessionsMetadataFingerprint() string
- func SetAttentionFlag(sessionName, reason string) error
- func SetAttentionFlagWithSource(sessionName, reason, source string) error
- func StaleThresholdDuration(days int) (time.Duration, error)
- func StartReadyTmuxSession(sessionName string) (func() error, error)
- func TerminateEditor(sessionName string) error
- func TmuxHasSession(name string) bool
- func ValidInstanceID(id string) bool
- func ValidatePort(port int) error
- func WorktreeExists(repoPath, worktreePath string) (bool, error)
- type EnvrcData
- type GatepostMeta
- type LocalOnlyMeta
- type LocalOnlyRequest
- type PortAllocation
- type ReviewOptions
- type Session
- type SessionReview
- func CompactSessionReview(review *SessionReview) *SessionReview
- func LoadSessionReviewDetails(name string) (*SessionReview, error)
- func MergeReviewDetails(summary, details *SessionReview) *SessionReview
- func RefreshSessionReviewStale(name string, sess *Session) (*SessionReview, error)
- func ReviewSession(sess *Session, opts ReviewOptions) (*SessionReview, error)
- func RunReviewHarness(ctx context.Context, sess *Session, review *SessionReview, harness string, ...) (*SessionReview, error)
- type SessionStatusSummary
- type SessionStore
- func (s *SessionStore) AddSession(name, branch, path string, ports map[string]int) error
- func (s *SessionStore) AddSessionWithProject(name, branch, path string, ports map[string]int, ...) error
- func (s *SessionStore) AssignSlot(name string) (int, error)
- func (s *SessionStore) GetSession(name string) (*Session, bool)
- func (s *SessionStore) GetSessionForSlot(slot int) string
- func (s *SessionStore) GetSlotForSession(name string) int
- func (s *SessionStore) MarkActive(name string, at time.Time) (int, error)
- func (s SessionStore) MarshalJSON() ([]byte, error)
- func (s *SessionStore) Mutate(fn func(*SessionStore) error) error
- func (s *SessionStore) Overwrite() error
- func (s *SessionStore) ReconcileSlots()
- func (s *SessionStore) RecordAttach(name string) error
- func (s *SessionStore) RemoveSession(name string) error
- func (s *SessionStore) SetPinned(name string, pinned bool) error
- func (s *SessionStore) UnmarshalJSON(data []byte) error
- func (s *SessionStore) UpdateSession(name string, updateFn func(*Session)) error
- type StaleAnalysisMode
- type StaleAnalysisOptions
- type StaleStatus
- type StaleSummary
- type TargetMeta
- type TmuxpData
- type WorktreeInfo
Constants ¶
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" )
const ( StaleCategoryActive = "active" StaleCategoryClean = "stale-clean" StaleCategoryNeedsReview = "stale-needs-review" StaleCategoryBroken = "broken" )
const ( SessionStatusAttention = "attention" SessionStatusUnseenArtifact = "unseen_artifact" SessionStatusBrokenOrStale = "broken_or_stale" SessionStatusDirty = "dirty" SessionStatusActive = "active" SessionStatusCleanupCandidate = "cleanup_candidate" SessionStatusIdle = "idle" )
const DefaultStaleThreshold = 14 * 24 * time.Hour
const DefaultTmuxHistoryLimit = 50000
const DefaultTmuxMouse = "off"
const LocalOnlyOwnerPiMCP = "devx-pi-mcp"
LocalOnlyOwnerPiMCP is the only owner allowed to create local-only sessions.
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.
const MaxDisplayNameLen = 100
MaxDisplayNameLen is the maximum length of a session display name.
const MaxSessionNameLen = 100
MaxSessionNameLen is the maximum allowed length for a session name. The TUI input and the validation regex both enforce this limit.
const MaxStaleThresholdDays = 3650
Variables ¶
var ErrAdoptNotAllowed = errors.New("session cannot be adopted")
ErrAdoptNotAllowed is returned when a session cannot be adopted for an agent.
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.
var ErrSessionNotFound = errors.New("session not found")
Functions ¶
func AllocatePortsLegacy ¶
AllocatePortsLegacy allocates two unique ports for frontend and API (backwards compatibility)
func AttachEditorToSession ¶
AttachEditorToSession handles editor attachment logic for session attach
func AttachReadyTmuxSession ¶ added in v0.4.0
AttachReadyTmuxSession performs a complete already-ensured handoff.
func AttachTmuxSession ¶
AttachTmuxSession attaches to an existing tmux session
func BranchExists ¶
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 ¶
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 CopyBootstrapFiles ¶
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 ¶
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
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
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
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
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
FetchOrigin fetches remote refs from origin, pruning deleted branches. Failure is non-fatal (caller warns and continues).
func GenerateEnvrc ¶
GenerateEnvrc creates an .envrc file in the worktree directory
func GenerateTmuxpConfig ¶
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 ¶
GetProjectRoot finds the git repository root directory
func IsEditorAvailable ¶
func IsEditorAvailable() bool
IsEditorAvailable checks if the configured editor command is available
func IsProcessRunning ¶
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
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
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 ¶
IsWorktreeCheckedOut checks if a branch is already checked out in a worktree
func LaunchEditor ¶
LaunchEditor launches the configured editor with the given path It runs asynchronously and returns the process PID
func LaunchEditorForSession ¶
LaunchEditorForSession launches the editor for a session and updates the session metadata
func LaunchTmuxSession ¶
LaunchTmuxSession launches a tmux session using tmuxp
func LocalOnlyTmuxTag ¶ added in v0.4.0
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
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
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 ¶
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 ¶
PullFromOrigin pulls the latest changes from origin for the specified branch
func ReleaseManagedAgent ¶ added in v0.4.0
ReleaseManagedAgent clears the adoption marker if it still names agentID.
func RemoteBranchExists ¶ added in v0.3.0
RemoteBranchExists checks if a branch exists on origin.
func RemoveSession ¶
RemoveSession removes a single session completely (helper for commands)
func RemoveSessionReviewDetails ¶ added in v0.4.0
func ResolveReviewBase ¶ added in v0.4.0
func ReviewIsStale ¶ added in v0.4.0
func RunCleanupCommand ¶
RunCleanupCommand executes the configured cleanup command with session environment variables
func RunCleanupCommandForShell ¶
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 ¶
SetAttentionFlag sets the attention flag for a session.
func SetAttentionFlagWithSource ¶ added in v0.4.0
SetAttentionFlagWithSource sets the attention flag with a structured source.
func StaleThresholdDuration ¶ added in v0.4.0
func StartReadyTmuxSession ¶ added in v0.4.0
StartReadyTmuxSession starts the terminal handoff and returns a waiter. Callers can safely persist open-side effects after this function succeeds.
func TerminateEditor ¶
TerminateEditor terminates the editor process for a session
func TmuxHasSession ¶ added in v0.4.0
TmuxHasSession reports whether a tmux session with exactly this name exists.
func ValidInstanceID ¶ added in v0.4.0
ValidInstanceID reports whether id is a well-formed session instance id.
func WorktreeExists ¶
WorktreeExists checks if a worktree exists at the specified path
Types ¶
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
LocalOnlyRequest describes a local-only session to create (or resume).
type PortAllocation ¶
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 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
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
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
IsContainerized returns true if the session runs inside a container.
func (*Session) IsLocalOnly ¶ added in v0.4.0
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
Label returns the display name if set, otherwise the session name.
func (Session) MarshalJSON ¶ added in v0.4.0
MarshalJSON encodes the record plus any preserved unknown members.
func (*Session) TargetType ¶ added in v0.4.0
TargetType returns the effective target type, defaulting to "host".
func (*Session) UnmarshalJSON ¶ added in v0.4.0
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
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 WorktreeInfo ¶
func ListWorktrees ¶
func ListWorktrees(repoPath string) ([]WorktreeInfo, error)
ListWorktrees returns all git worktrees in the repository