livesession

package
v1.0.2 Latest Latest
Warning

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

Go to latest
Published: Jul 6, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package livesession implements the LiveSession use case.

LiveSession composes a SessionSource and a Clock to build a complete view of a project's sessions and the focused (most-recently-active) session's events. It is the primary data source for the clyde TUI (Phases A–J).

The key difference from WatchSession:

  • Returns ALL sessions as []session.Summary (for a session-list panel).
  • Returns ALL visible events of the focused session (no top-N truncation).
  • Builds AgentTimelines: main session + any subagents, each with their tool calls matched to tool_results for duration and state.

Event ordering: ascending by Timestamp (chronological), consistent with the append semantics of Claude Code JSONL files.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type AgentTimeline

type AgentTimeline struct {
	// AgentID is the session ID for the main agent, or the subagent's agent ID
	// (e.g. "agent-a09b7f25bb46ce5bc") for subagents.
	AgentID string

	// AgentName is the human-readable name. "main session" for the main session;
	// derived from meta.json description or a shortened AgentID for subagents.
	AgentName string

	// IsSubagent is true for subagent timelines.
	IsSubagent bool

	// ParentID is the parent session ID. Empty for the main session.
	ParentID string

	// Events holds all visible events for this agent in ascending chronological
	// order.
	Events []event.Event

	// Calls is the list of tool calls extracted from Events, with each call
	// matched to its tool_result where possible.
	Calls []ToolCall

	// Active is true when the agent is currently running (has at least one
	// unmatched tool_use, or the last event is an open assistant turn).
	Active bool
}

AgentTimeline is the events and tool calls for a single agent (main session or a subagent).

type CacheStats

type CacheStats struct {
	// HitRatio is the aggregate share in [0, 1] across all observed turns.
	HitRatio float64

	// FromCache is the total tokens served from cache across the session.
	FromCache int64

	// Recomputed is total Input + CacheCreation tokens (everything not
	// served from cache).
	Recomputed int64

	// BiggestMissTokens is the largest single-turn (Input + CacheCreation)
	// figure seen this session — the worst cache-bust moment.
	BiggestMissTokens int64

	// BiggestMissAt is the timestamp of the worst cache-bust turn.
	BiggestMissAt time.Time

	// Trend is the per-turn hit-ratio history (oldest → newest), capped at
	// the last 10 turns. Powers the sparkline.
	Trend []float64

	// TurnCount is the number of assistant turns observed (Trend may be
	// shorter when the cap kicks in).
	TurnCount int
}

CacheStats summarizes prompt-cache efficiency over the focused session.

The hit ratio is the share of tokens served from the prompt cache, vs tokens re-charged as fresh input or new cache writes:

HitRatio = CacheRead / (CacheRead + Input + CacheCreation)

Tracking this matters because cache hits are MUCH cheaper / faster than recomputed input. A low ratio on a long session usually signals prompt instability that breaks caching.

type CallState

type CallState int

CallState describes the state of a tool call.

const (
	CallDone   CallState = iota // completed call
	CallActive                  // currently running (no matching tool_result yet)
	CallFailed                  // completed with an error in the tool_result
)

Call state constants.

type DiffHunk

type DiffHunk struct {
	// Header is the raw @@ line.
	Header string

	OldStart int
	OldCount int
	NewStart int
	NewCount int

	// Lines are the individual diff lines (context, add, remove).
	Lines []DiffHunkLine
}

DiffHunk is a single changed region in a unified diff. It mirrors git.Hunk without importing the adapters/git package from the application layer (hexagonal discipline: application layer must not depend on a concrete adapter).

type DiffHunkLine

type DiffHunkLine struct {
	// Type is ' ' for context, '+' for added, '-' for removed.
	Type rune
	// Text is the line content without the leading +/- marker.
	Text string
}

DiffHunkLine is a single line within a DiffHunk.

type FileNode

type FileNode struct {
	Name     string
	IsDir    bool
	Path     string
	Children []*FileNode
}

FileNode is a single node in the filesystem tree returned by the fsexplorer adapter. Mirrors fsexplorer.Node without importing the adapter package (keep the application layer free of concrete adapter dependencies).

type FileTreeSource

type FileTreeSource interface {
	WalkToView(cwd string) (*FileNode, error)
}

FileTreeSource is the port for filesystem tree walking. Adapters that implement this live in internal/adapters/fsexplorer.

type GitFileStatus

type GitFileStatus struct {
	Path   string
	Status rune // 'M', 'A', 'D', 'R', '?', …
	Staged bool
}

GitFileStatus describes a single file entry from `git status --porcelain`. Mirrors git.FileStatus without importing the adapter package.

type GitSource

type GitSource interface {
	StatusView(cwd string) ([]GitFileStatus, error)
}

GitSource is the port for git status. Adapters that implement this live in internal/adapters/git.

type LSP

type LSP struct {
	// Name is the language server identifier, e.g. "gopls", "tsserver".
	Name string

	// Active is true when the binary is installed and on PATH.
	Active bool

	// ClaudeEnabled is true when Claude Code's enabledPlugins map references
	// this LSP (i.e. claude is actually using it). Combined with Active, the
	// TUI distinguishes installed-and-wired (green) from installed-but-not-
	// wired (amber) so the user can see when claude code missed an LSP they
	// have available.
	ClaudeEnabled bool
}

LSP represents a single language server in the servers panel view.

type LiveSession

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

LiveSession is the use case that provides a full live view of a project's most-recently-active session. Construct via New or NewWithSubagents.

func New

func New(src ports.SessionSource, clk ports.Clock) *LiveSession

New constructs a LiveSession with the given SessionSource and Clock. Subagent reading is disabled — use NewWithSubagents to enable it.

func NewWithSubagents

func NewWithSubagents(src ports.SessionSource, clk ports.Clock, subSrc ports.SubagentSource) *LiveSession

NewWithSubagents constructs a LiveSession with subagent support enabled. The subSrc is used to discover and read subagent JSONL files.

func (*LiveSession) Snapshot

func (l *LiveSession) Snapshot(ctx context.Context, p project.Project) (View, error)

Snapshot executes the use case for the given project, focusing the most-recently-active session. Equivalent to SnapshotForSession with an empty session ID.

func (*LiveSession) SnapshotAggregated

func (l *LiveSession) SnapshotAggregated(ctx context.Context, p project.Project) (View, error)

SnapshotAggregated returns a View whose Events stream is the time-merged union of every recent session in cwd, with one main-session AgentTimeline per contributing session. Used by the Σ all tab in the TUI so the activity / bash / diff panels show a true cwd-wide aggregate instead of duplicating tab[0]'s content.

FocusedID is anchored on the most-recently-active session so panels that need a single anchor (usage headline, current model, cache stats per session) keep working. CwdCacheStats already aggregates cache across sessions, so the cache panel already has the right number to show on Σ.

Cost: one extra Events read per non-anchor session (capped at maxSessionStatsPerProject). Tolerable on the Σ tab since the user explicitly opted into it; not on the per-session tabs.

func (*LiveSession) SnapshotForSession

func (l *LiveSession) SnapshotForSession(ctx context.Context, p project.Project, focusedID session.ID) (View, error)

SnapshotForSession executes the use case for the given project, focusing the session whose ID matches focusedID. Pass an empty focusedID to focus the most-recently-active session (default behavior).

It discovers all sessions, retrieves the focused session's events, builds tool-call timelines (including subagents), and returns a View.

When focusedID is non-empty but no session matches, falls back to the most-recently-active session — this keeps the TUI usable when the user's last-focused session has since been deleted or renamed.

Returns an empty view (no error) when no sessions exist for the project. Returns an empty view (no error) when the project directory is missing.

func (*LiveSession) WithExplorer

func (l *LiveSession) WithExplorer(gitSrc GitSource, fsSrc FileTreeSource) *LiveSession

WithExplorer returns a new LiveSession that also populates FileTree and ModifiedFiles on every Snapshot call. gitSrc or fsSrc may be nil to skip that half individually; both nil is a no-op equivalent to not calling this.

func (*LiveSession) WithGlobalSessions

func (l *LiveSession) WithGlobalSessions(globalSrc ports.GlobalSessionSource) *LiveSession

WithGlobalSessions returns a new LiveSession that also aggregates usage across ALL Claude Code projects (not just the current project) for the 5h and 7d time windows. Pass nil to clear a previously set source.

func (*LiveSession) WithLSPs

func (l *LiveSession) WithLSPs(lspSrc ports.LSPSource) *LiveSession

WithLSPs returns a new LiveSession that populates View.LSPs on every Snapshot call from the given LSPSource. Pass nil to clear.

func (*LiveSession) WithMCPs

func (l *LiveSession) WithMCPs(mcpSrc ports.MCPSource) *LiveSession

WithMCPs returns a new LiveSession that also populates View.MCPs on every Snapshot call from the given MCPSource. Pass nil to clear a previously set source.

func (*LiveSession) WithProcesses

func (l *LiveSession) WithProcesses(procSrc ports.ProcessSource) *LiveSession

WithProcesses returns a new LiveSession that consults the given ProcessSource on every Snapshot to mark sessions as live when their `claude` process is running, even if the JSONL is mtime-stale. The per-cwd session set is unchanged — process info enriches IsLive but never adds sessions from outside the current project. Pass nil to clear (falls back to mtime-only liveness, the v0.6 behavior).

type MCP

type MCP struct {
	// Name is the plugin identifier, e.g. "engram@engram".
	Name string

	// Enabled is true when the plugin is enabled in the settings file.
	Enabled bool

	// ToolCount is the number of tools exposed by this server.
	// 0 when live ping is unavailable (V1).
	ToolCount int
}

MCP represents a single MCP server entry in the servers panel view.

type SessionStat

type SessionStat struct {
	// ID is the session identifier (matches the JSONL filename).
	ID session.ID

	// Label is a short human-readable hint for the tab — typically a
	// truncated first user prompt. Falls back to ID prefix when no
	// prompt was extracted.
	Label string

	// LastActivity mirrors session.Summary.LastActivity. Used by the TUI
	// to filter zombies (older than now-1h) out of the leaderboard.
	LastActivity time.Time

	// LatestUsage is the usage from the most recent assistant event in this
	// session. Drives ContextPct.
	LatestUsage usage.Usage

	// ContextPct is the model-context fill percentage in [0, 100],
	// computed via pricing.CompactionPercent against the session's model.
	// This is the actionable "is this session about to compact?" signal.
	ContextPct int

	// SessionTokens is the total tokens used by the session
	// (pricing.TotalTokens of the running sum). Powers the Σ aggregate
	// view for the current cwd.
	SessionTokens int64

	// Active is true when the focused session has an open assistant turn
	// (running tool call). Only set for the focused session — derived from
	// timeline state, which is populated from the focused session's events.
	Active bool

	// IsLive is true when the session was written to recently — its JSONL
	// was modified within the live-activity window of the snapshot's clock.
	// Recency is a reliable signal that claude code itself still has the
	// session open, regardless of which session the user has focused in
	// clyde. Closed/idle sessions read as IsLive=false.
	IsLive bool
}

SessionStat is a per-session summary computed at Snapshot time. It carries everything the TUI needs to render the session-tab strip and the usage-panel leaderboard without extra I/O.

One SessionStat per session JSONL in the current project's cwd, ordered by LastActivity desc.

type ToolCall

type ToolCall struct {
	// ToolUseID is the unique identifier from the tool_use content block.
	ToolUseID string

	// Tool is the tool name (e.g. "Read", "Bash", "Edit").
	Tool string

	// KeyArg is the primary argument extracted from the summary string
	// (the part after "Tool: Read " in a summary like "Tool: Read /some/path").
	KeyArg string

	// Duration is the time between tool_use and matching tool_result.
	// Zero if no tool_result has been found yet (call is active).
	Duration time.Duration

	// State is the current state of the tool call.
	State CallState

	// StartTime is the timestamp of the tool_use event.
	StartTime time.Time
}

ToolCall is a single tool invocation extracted from an AgentTimeline. It carries the matched tool_use and tool_result data for display.

type View

type View struct {
	// Project is the project this view was built for.
	Project project.Project

	// Sessions is all sessions in this project, sorted by LastActivity
	// descending (most recently active first).
	Sessions []session.Summary

	// FocusedID is the ID of the most-recently-active session.
	// Zero value (empty string) means no sessions exist.
	FocusedID session.ID

	// Events holds ALL visible events of the focused session in strictly
	// ascending chronological order (oldest first). May be empty.
	//
	// "Visible" means the isVisible predicate: excludes KindOpaque events,
	// meta user events, and tool-result-only user events (ADR-007).
	Events []event.Event

	// Timelines is the list of agent timelines for the focused session.
	// [0] is always the main session (if any events exist); subsequent entries
	// are subagents in discovery order.
	Timelines []AgentTimeline

	// TotalUsage is the sum of all assistant event usage across the focused session.
	// Used by the usage panel for cost computation.
	// NOTE: do NOT use TotalUsage.CacheRead for display totals — it counts the
	// same cached content once per turn, inflating the sum massively.
	TotalUsage usage.Usage

	// LatestUsage is the usage snapshot from the most recent assistant event.
	// Use this (not TotalUsage) for compaction percentage calculation because it
	// represents the actual context size of the last API call, not a running sum.
	LatestUsage usage.Usage

	// CurrentModel is the model ID from the most recent assistant event in the
	// focused session, e.g. "claude-opus-4-7". Empty when no assistant events exist.
	CurrentModel string

	// AssistantTurns is the count of KindAssistant events in the focused session.
	// Used by the usage panel to display the "turns" metric.
	AssistantTurns int

	// LastUpdate is the UTC instant captured from Clock at the time Snapshot
	// was called.
	LastUpdate time.Time

	// EmptyReason is a human-readable explanation for why Events is empty.
	// Set when there are no sessions or the focused session has no events.
	// Empty string when Events is non-empty.
	EmptyReason string

	// MCPs is the list of configured MCP servers, populated from the Claude
	// Code settings file via the mcpconfig adapter.
	// Populated at construction time (before Snapshot); empty when no adapter
	// is provided or the settings file is unreadable.
	MCPs []MCP

	// BashLog is the chronological list of Bash tool calls across all
	// agents (main + subagents) in the focused window. Each entry carries
	// the command (KeyArg), state, start time, and duration. Populated by
	// every Snapshot call; nil when no Bash calls have been observed.
	BashLog []ToolCall

	// CacheStats summarizes prompt-cache efficiency across the focused
	// session: hit ratio, totals, biggest cache miss, and a per-turn ratio
	// trend. Powers the cache-efficiency panel.
	CacheStats CacheStats

	// CwdCacheStats is the same metric merged across every session in the
	// current cwd (within applySessionStats's iteration). The TUI shows
	// this when the user is on the Σ aggregate tab — single-session cache
	// stats would be misleading there.
	CwdCacheStats CacheStats

	// SessionStats lists every session in the current project (cwd), sorted
	// by LastActivity desc. Carries per-session context fill, label, and
	// activity flags so the title-bar tab strip and the usage-panel
	// leaderboard can render without further I/O.
	SessionStats []SessionStat

	// LSPs is the list of detected language servers.
	// Always empty in V1 — LSP detection is deferred to V2.
	LSPs []LSP

	// FileTree is the directory tree for the project's cwd, built by the
	// fsexplorer adapter.  Nil when the adapter is not wired or on error.
	FileTree *FileNode

	// ModifiedFiles is the list of files that git reports as changed in the
	// project's cwd, built by the git adapter.  Nil on error or no adapter.
	ModifiedFiles []GitFileStatus

	// DiffFile is the path of the file Claude is currently editing, extracted
	// from the most recent Edit/Write/MultiEdit tool_use event in the focused
	// session.  Empty string when no such event exists.
	DiffFile string

	// DiffHunks holds the parsed git diff hunks for DiffFile (or all changed
	// files when DiffFile is empty).  Populated by applyLiveView in the TUI
	// layer via git.Source.Diff.  Nil when running in demo mode or on error.
	DiffHunks []DiffHunk

	// Usage5h is the sum of assistant event usage across ALL Claude Code projects
	// whose sessions had LastActivity within the last 5 hours.
	// Zero value when no sessions qualify or source is unavailable.
	Usage5h usage.Usage

	// UsageWeek is the sum of assistant event usage across ALL Claude Code projects
	// whose sessions had LastActivity within the last 7 days.
	// Zero value when no sessions qualify or source is unavailable.
	UsageWeek usage.Usage

	// Sessions5hCount is the number of sessions (across all projects) that
	// contributed to Usage5h. Zero when Usage5h is empty.
	Sessions5hCount int

	// SessionsWeekCount is the number of sessions (across all projects) that
	// contributed to UsageWeek. Zero when UsageWeek is empty.
	SessionsWeekCount int

	// Reset5hAt is the time when the rolling 5-hour window resets.
	// Computed as: earliest event in the 5h window + 5h.
	// Zero when no sessions exist in the 5h window.
	Reset5hAt time.Time

	// ResetWeekAt is the time when the rolling 7-day window resets.
	// Computed as: earliest event in the 7d window + 7d.
	// Zero when no sessions exist in the 7d window.
	ResetWeekAt time.Time

	// LLMSource is the name of the LLM CLI source driving this view
	// (e.g. "claude-code", "gemini-cli"). Set by the composition root.
	LLMSource string
}

View is the output of LiveSession.Snapshot. It is a plain data value safe to pass across layer boundaries.

Jump to

Keyboard shortcuts

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