core

package
v0.7.2 Latest Latest
Warning

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

Go to latest
Published: Mar 12, 2026 License: MIT Imports: 15 Imported by: 0

Documentation

Index

Constants

View Source
const (
	MinWindowMinutes = 10
	MaxWindowMinutes = 480
)

Window minutes bounds.

View Source
const ActivityTimeout = 30 * time.Second

ActivityTimeout is the duration a tool-based activity stays visible after the tool finishes, unless replaced by a newer activity.

View Source
const WaitingGrace = 10 * time.Second

WaitingGrace is the minimum time StatusWaitingForUser must be stable before displaying ActivityWaiting. Claude sometimes writes a text-only assistant message before immediately continuing with a tool_use message (~2s later), which would otherwise cause a brief false "waiting" flash.

View Source
const WaitingTimeout = 2 * time.Minute

WaitingTimeout is how long "waiting" stays visible before falling back to idle.

Variables

AllActivities returns all ActivityKind values in display order (empty = all).

View Source
var SpinnerFrames = []rune{'⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'}

SpinnerFrames contains the Braille spinner animation frames.

Functions

func BucketTimestamps

func BucketTimestamps(timestamps []time.Time, window time.Duration, width int) []int

BucketTimestamps groups timestamps into fixed-width buckets for sparkline display. Returns a slice of counts per bucket.

func Clamp

func Clamp(lo, hi, v int) int

Clamp bounds an integer to [lo, hi].

func ConfigDir

func ConfigDir() string

ConfigDir returns the config directory path (~/.config/lazyagent).

func ConfigPath

func ConfigPath() string

ConfigPath returns the full path to the config file.

func EffectiveCost

func EffectiveCost(model string, costUSD float64, inputTokens, outputTokens, cacheCreation, cacheRead int) float64

EffectiveCost returns CostUSD if non-zero, otherwise estimates from tokens.

func EstimateCost

func EstimateCost(model string, inputTokens, outputTokens, cacheCreation, cacheRead int) float64

EstimateCost estimates API cost based on model and token counts. Supports Anthropic (Claude), Google (Gemini), and OpenAI (GPT) model families.

func FormatCost

func FormatCost(usd float64) string

FormatCost formats a USD cost for display.

func FormatDuration

func FormatDuration(d time.Duration) string

FormatDuration converts a duration to a human-readable "Xs ago" string.

func FormatTokens

func FormatTokens(n int) string

FormatTokens formats a token count for display (e.g., 1200 → "1.2k").

func IsActiveActivity

func IsActiveActivity(a ActivityKind) bool

IsActiveActivity returns true for any activity that represents ongoing work (i.e. everything except idle and waiting).

func PadRight

func PadRight(s string, n int) string

PadRight pads a string with spaces to reach visual width n (rune count), or truncates if longer.

func RenderSparkline

func RenderSparkline(timestamps []time.Time, window time.Duration, width int) string

RenderSparkline renders bucketed data as a Unicode sparkline string.

func SaveConfig

func SaveConfig(cfg Config) error

SaveConfig writes the config to disk.

func ShortName

func ShortName(path string, maxLen int) string

ShortName truncates a file path intelligently, showing "…/parent/child" when needed. maxLen is measured in runes (visual width for monospace display).

func SortSessions

func SortSessions(sessions []*model.Session)

SortSessions sorts sessions by last activity (most recent first).

Types

type ActivityEntry

type ActivityEntry struct {
	Kind     ActivityKind
	LastSeen time.Time
}

ActivityEntry holds a session's current sticky activity state.

type ActivityKind

type ActivityKind string

ActivityKind is the human-readable label shown in the session list.

const (
	ActivityIdle       ActivityKind = "idle"
	ActivityWaiting    ActivityKind = "waiting"
	ActivityThinking   ActivityKind = "thinking"
	ActivityCompacting ActivityKind = "compacting"
	ActivityReading    ActivityKind = "reading"
	ActivityWriting    ActivityKind = "writing"
	ActivityRunning    ActivityKind = "running"
	ActivitySearching  ActivityKind = "searching"
	ActivityBrowsing   ActivityKind = "browsing"
	ActivitySpawning   ActivityKind = "spawning"
)

func NextActivityFilter

func NextActivityFilter(current ActivityKind) ActivityKind

NextActivityFilter cycles to the next activity filter in AllActivities.

func ResolveActivity

func ResolveActivity(s *model.Session, now time.Time) ActivityKind

ResolveActivity determines the display activity for a session.

Priority:

  1. Compacting (summary entry written recently).
  2. Most recent tool in RecentTools within ActivityTimeout.
  3. StatusWaitingForUser within WaitingTimeout (with grace period).
  4. LastActivity older than ActivityTimeout → idle.
  5. Current JSONL status → thinking if Claude is processing, idle otherwise.

func ToolActivity

func ToolActivity(tool string) ActivityKind

ToolActivity maps a tool name to an activity kind. Supports both Claude Code (PascalCase) and pi (snake_case) tool names.

type ActivityTracker

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

ActivityTracker manages sticky activity states with grace period logic.

func NewActivityTracker

func NewActivityTracker() *ActivityTracker

NewActivityTracker creates a new ActivityTracker.

func (*ActivityTracker) Get

func (t *ActivityTracker) Get(sessionID string) ActivityKind

Get returns the current sticky activity for a session.

func (*ActivityTracker) Update

func (t *ActivityTracker) Update(sessions []*model.Session, now time.Time)

Update resolves and stores the current activity for each session. Applies a grace period before showing ActivityWaiting to avoid false positives.

type Config

type Config struct {
	WindowMinutes  int             `json:"window_minutes"`
	DefaultFilter  string          `json:"default_filter"`
	Editor         string          `json:"editor"`
	LaunchAtLogin  bool            `json:"launch_at_login"`
	Notifications  bool            `json:"notifications"`
	NotifyAfterSec int             `json:"notify_after_sec"`
	Agents         map[string]bool `json:"agents"`
}

Config holds application settings shared by TUI and GUI.

func DefaultConfig

func DefaultConfig() Config

DefaultConfig returns a Config with sensible defaults.

func LoadConfig

func LoadConfig() Config

LoadConfig reads the config file, creating it with defaults if missing.

func (Config) AgentEnabled

func (c Config) AgentEnabled(name string) bool

AgentEnabled returns whether an agent is enabled in config. Defaults to true if the agent key is missing from the map.

type CursorProvider

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

CursorProvider discovers Cursor sessions from store.db files.

func NewCursorProvider

func NewCursorProvider() *CursorProvider

NewCursorProvider creates a CursorProvider.

func (*CursorProvider) DiscoverSessions

func (p *CursorProvider) DiscoverSessions() ([]*model.Session, error)

func (*CursorProvider) RefreshInterval

func (p *CursorProvider) RefreshInterval() time.Duration

func (*CursorProvider) UseWatcher

func (p *CursorProvider) UseWatcher() bool

func (*CursorProvider) WatchDirs

func (p *CursorProvider) WatchDirs() []string

type LiveProvider

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

LiveProvider discovers real Claude Code sessions from disk.

func NewLiveProvider

func NewLiveProvider() *LiveProvider

NewLiveProvider creates a LiveProvider with mtime-based caches.

func (*LiveProvider) DiscoverSessions

func (p *LiveProvider) DiscoverSessions() ([]*model.Session, error)

func (*LiveProvider) RefreshInterval

func (p *LiveProvider) RefreshInterval() time.Duration

func (*LiveProvider) UseWatcher

func (p *LiveProvider) UseWatcher() bool

func (*LiveProvider) WatchDirs

func (p *LiveProvider) WatchDirs() []string

type MultiProvider

type MultiProvider struct {
	Providers []SessionProvider
}

MultiProvider merges sessions from multiple providers.

func (MultiProvider) DiscoverSessions

func (m MultiProvider) DiscoverSessions() ([]*model.Session, error)

func (MultiProvider) RefreshInterval

func (m MultiProvider) RefreshInterval() time.Duration

func (MultiProvider) UseWatcher

func (m MultiProvider) UseWatcher() bool

func (MultiProvider) WatchDirs

func (m MultiProvider) WatchDirs() []string

type OpenCodeProvider

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

OpenCodeProvider discovers OpenCode sessions from SQLite.

func NewOpenCodeProvider

func NewOpenCodeProvider() *OpenCodeProvider

NewOpenCodeProvider creates an OpenCodeProvider.

func (*OpenCodeProvider) DiscoverSessions

func (p *OpenCodeProvider) DiscoverSessions() ([]*model.Session, error)

func (*OpenCodeProvider) RefreshInterval

func (p *OpenCodeProvider) RefreshInterval() time.Duration

func (*OpenCodeProvider) UseWatcher

func (p *OpenCodeProvider) UseWatcher() bool

func (*OpenCodeProvider) WatchDirs

func (p *OpenCodeProvider) WatchDirs() []string

type PiProvider

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

PiProvider discovers pi coding agent sessions from disk.

func NewPiProvider

func NewPiProvider() *PiProvider

NewPiProvider creates a PiProvider with an mtime-based cache.

func (*PiProvider) DiscoverSessions

func (p *PiProvider) DiscoverSessions() ([]*model.Session, error)

func (*PiProvider) RefreshInterval

func (p *PiProvider) RefreshInterval() time.Duration

func (*PiProvider) UseWatcher

func (p *PiProvider) UseWatcher() bool

func (*PiProvider) WatchDirs

func (p *PiProvider) WatchDirs() []string

type ProjectWatcher

type ProjectWatcher struct {
	Events <-chan struct{}
	// contains filtered or unexported fields
}

ProjectWatcher watches ~/.claude/projects for JSONL changes using FSEvents. It debounces rapid writes so that a burst of JSONL lines triggers one reload.

func NewProjectWatcher

func NewProjectWatcher(dirs ...string) (*ProjectWatcher, error)

NewProjectWatcher starts an FSEvents watcher on the given directories. Returns nil (no error) if none of the directories exist.

func (*ProjectWatcher) Close

func (w *ProjectWatcher) Close()

Close signals the watcher goroutine to stop and releases resources.

type SessionDetailView

type SessionDetailView struct {
	model.Session
	Activity ActivityKind
}

SessionDetailView is the full struct for a detail panel.

type SessionManager

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

SessionManager manages session discovery, file watching, and activity tracking.

func NewSessionManager

func NewSessionManager(windowMinutes int, provider SessionProvider) *SessionManager

NewSessionManager creates a new SessionManager with the given provider.

func (*SessionManager) ActivityFilter

func (m *SessionManager) ActivityFilter() ActivityKind

ActivityFilter returns the current activity filter.

func (*SessionManager) ActivityFor

func (m *SessionManager) ActivityFor(sessionID string) ActivityKind

ActivityFor returns the current activity for a session.

func (*SessionManager) QuerySessions

func (m *SessionManager) QuerySessions(search string, filter ActivityKind) []*model.Session

QuerySessions returns sessions filtered by explicit parameters without using the manager's internal filter/search state. Safe for concurrent API use. Empty search/filter means no filtering.

func (*SessionManager) Reload

func (m *SessionManager) Reload() error

Reload discovers sessions via the provider and updates activity states.

func (*SessionManager) SessionDetail

func (m *SessionManager) SessionDetail(id string) *SessionDetailView

SessionDetail returns the full detail view for a session.

func (*SessionManager) SessionName

func (m *SessionManager) SessionName(sessionID string) string

SessionName returns the custom name for a session, or empty string.

func (*SessionManager) Sessions

func (m *SessionManager) Sessions() []*model.Session

Sessions returns all raw sessions (unfiltered).

func (*SessionManager) SetActivityFilter

func (m *SessionManager) SetActivityFilter(filter ActivityKind)

SetActivityFilter sets the activity filter.

func (*SessionManager) SetSearchQuery

func (m *SessionManager) SetSearchQuery(query string)

SetSearchQuery sets the search query.

func (*SessionManager) SetSessionName

func (m *SessionManager) SetSessionName(sessionID, name string) error

SetSessionName stores a custom name for a session.

func (*SessionManager) SetWindowMinutes

func (m *SessionManager) SetWindowMinutes(minutes int)

SetWindowMinutes sets the time window filter, clamped to [MinWindowMinutes, MaxWindowMinutes].

func (*SessionManager) StartWatcher

func (m *SessionManager) StartWatcher() error

StartWatcher starts the file system watcher if the provider supports it.

func (*SessionManager) StopWatcher

func (m *SessionManager) StopWatcher()

StopWatcher stops the file system watcher.

func (*SessionManager) UpdateActivities

func (m *SessionManager) UpdateActivities() bool

UpdateActivities refreshes activity states without reloading from disk. Returns true if any activity state changed. If the provider specifies a RefreshInterval, sessions are re-discovered periodically. Also refreshes session names from disk if modified externally.

func (*SessionManager) VisibleSessions

func (m *SessionManager) VisibleSessions() []*model.Session

VisibleSessions returns sessions filtered by the manager's internal state (time window, activity filter, search query). Used by TUI and tray.

func (*SessionManager) WatcherEvents

func (m *SessionManager) WatcherEvents() <-chan struct{}

WatcherEvents returns the channel for file change notifications, or nil.

func (*SessionManager) WindowMinutes

func (m *SessionManager) WindowMinutes() int

WindowMinutes returns the current time window.

type SessionNames

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

SessionNames manages user-defined aliases for sessions. Stored in ~/.config/lazyagent/session-names.json.

func NewSessionNames

func NewSessionNames() *SessionNames

NewSessionNames creates a new SessionNames and loads from disk.

func (*SessionNames) Get

func (sn *SessionNames) Get(sessionID string) string

Get returns the custom name for a session, or empty string.

func (*SessionNames) Refresh

func (sn *SessionNames) Refresh() bool

Refresh re-reads the file from disk if it was modified externally. Returns true if the file was actually reloaded.

func (*SessionNames) Set

func (sn *SessionNames) Set(sessionID, name string) error

Set stores a custom name for a session and persists to disk. Empty name removes the alias.

type SessionProvider

type SessionProvider interface {
	// DiscoverSessions returns all available sessions.
	DiscoverSessions() ([]*model.Session, error)
	// UseWatcher returns whether a file system watcher should be started.
	UseWatcher() bool
	// RefreshInterval returns how often UpdateActivities should re-discover sessions,
	// or 0 to never re-discover (only on explicit Reload or watcher events).
	RefreshInterval() time.Duration
	// WatchDirs returns directories to watch for file system changes.
	WatchDirs() []string
}

SessionProvider abstracts how sessions are discovered.

func BuildProvider

func BuildProvider(agentMode string, cfg Config) SessionProvider

BuildProvider creates a SessionProvider based on agent mode and config. When agentMode is "all", it reads the agents config to decide which providers to include. A specific agentMode (e.g. "claude") overrides the config.

Jump to

Keyboard shortcuts

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