Documentation
¶
Overview ¶
Package tui provides the Bubble Tea v2 TUI adapter for clyde. Real data is wired via the LiveSession use case when --demo is not specified. Run cmd/clyde to start the TUI; pass --demo for deterministic mock mode.
Package proto provides the visual prototype of the clyde TUI. It runs on mock data only — no real adapters wired.
Index ¶
- func ComposeColumns(height int, columns ...Column) string
- func MockFileContent(path string, _ MockData) string
- func NormalizeCwd(cwd string) string
- func SupportsKittyGraphics() bool
- type AgentGroup
- type BashRow
- type BootScreen
- type Breakpoint
- type CacheStatsView
- type CallState
- type CollapseSpring
- type Column
- type CompactionState
- type Config
- type DiffKind
- type DiffLine
- type DiffSource
- type ExplorerRow
- type ExplorerSearch
- type ExplorerSearchMatch
- type ExplorerSection
- type ExplorerState
- type FileIcon
- type FrameMsg
- type FrameState
- type HookNotification
- type KeyMap
- type Layout
- type LayoutConfig
- type LayoutMode
- type MascotBaseState
- type MascotFSM
- type MascotPersona
- type MockData
- type Model
- type ModifiedFile
- type NotificationStyle
- type NowStatus
- type Palette
- type PanelCollapseState
- func (p *PanelCollapseState) Advance()
- func (p *PanelCollapseState) Collapse()
- func (p *PanelCollapseState) Expand()
- func (p *PanelCollapseState) ExpandedHeight() int
- func (p *PanelCollapseState) Height() int
- func (p *PanelCollapseState) IsCollapsed() bool
- func (p *PanelCollapseState) IsSettled() bool
- func (p *PanelCollapseState) SetExpandedHeight(h float64)
- func (p *PanelCollapseState) Toggle()
- type PanelConfig
- type PanelID
- type PanelLayout
- type PanelState
- type PanelsConfig
- type ProjectOverride
- type QuotaNotification
- type QuotaSeverity
- type Server
- type ServerStatus
- type SessionTab
- type SettingsPanelToggle
- type SettingsScope
- type Styles
- type SubStep
- type Task
- type TaskStatus
- type TerminalGraphics
- type Theme
- type ToolCall
- type TreeNode
- type UsageWindowRow
- type ViewerMode
- type ViewerViewport
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ComposeColumns ¶
ComposeColumns joins columns horizontally, padding each to its declared width and padding to `height` rows.
func MockFileContent ¶
MockFileContent returns the mock content for a given file path. Exported for use by the viewport loader in model.go.
func NormalizeCwd ¶
NormalizeCwd resolves a path to its canonical absolute form, expanding symlinks where possible. Used as the per-project lookup key so symlinked or relative paths still match their config section.
func SupportsKittyGraphics ¶
func SupportsKittyGraphics() bool
SupportsKittyGraphics returns true if the terminal supports the Kitty graphics protocol (either native Kitty or Ghostty in Kitty-compat mode).
Types ¶
type AgentGroup ¶
type AgentGroup struct {
AgentID string
AgentName string
IsSubagent bool
Calls []ToolCall
Active bool // whether this agent is currently running
}
AgentGroup groups tool calls by the agent that made them.
type BashRow ¶
type BashRow struct {
Time string // "14:32:08" — short time-of-day
Command string // "go test ./auth/..."
Duration string // "12s" / "<1s" / "" when running
State CallState // CallDone / CallActive / CallFailed
}
BashRow is one Bash command entry rendered in the bash audit panel.
type BootScreen ¶
type BootScreen struct {
// Active is true while the splash is on screen. The model gates the
// regular View() pipeline on this and routes the next FrameMsg into
// Advance(). Cleared by Dismiss() (any key) or auto-finish.
Active bool
// Tick counts FrameMsg ticks since the splash was triggered.
Tick int
}
BootScreen drives the animated startup splash. The renderer is pure: it reads the tick counter and paints whatever the current phase requires, so tests can drive it deterministically by setting Tick directly.
func (BootScreen) Advance ¶
func (b BootScreen) Advance() BootScreen
Advance returns a new BootScreen with the tick incremented and Active cleared once the auto-finish window passes.
func (BootScreen) Dismiss ¶
func (b BootScreen) Dismiss() BootScreen
Dismiss flips Active off — used when the user hits any key during boot.
type Breakpoint ¶
type Breakpoint int
Breakpoint describes the width-driven layout mode.
const ( // BreakpointNarrow is single-column stack only (< 80 cols). BreakpointNarrow Breakpoint = iota // BreakpointMedium is two-column layout (80-159 cols): // left = explorer + servers, right = now/tasks/diff/usage stacked. BreakpointMedium // BreakpointWide is the full 3-column design (160+ cols). BreakpointWide )
func DetectBreakpoint ¶
func DetectBreakpoint(width int) Breakpoint
DetectBreakpoint maps a terminal width to a Breakpoint.
type CacheStatsView ¶
type CacheStatsView struct {
HitRatio float64
FromCache int64
Recomputed int64
BiggestMissTokens int64
BiggestMissAt string // formatted "HH:MM"
Trend []float64
TurnCount int
}
CacheStatsView mirrors livesession.CacheStats for the TUI layer.
type CollapseSpring ¶
type CollapseSpring struct {
// contains filtered or unexported fields
}
CollapseSpring is a harmonica-backed spring for animating panel height. Each panel has its own CollapseSpring tracking current height, velocity, and the target height driven by collapsed/expanded state.
func NewCollapseSpring ¶
func NewCollapseSpring(h float64) CollapseSpring
NewCollapseSpring creates a spring starting at h (already settled).
func (*CollapseSpring) Advance ¶
func (cs *CollapseSpring) Advance()
Advance runs one frame of the spring simulation. At 100ms tick cadence we call this once per FrameMsg.
func (*CollapseSpring) Height ¶
func (cs *CollapseSpring) Height() int
Height returns the current integer height for rendering.
func (*CollapseSpring) IsSettled ¶
func (cs *CollapseSpring) IsSettled() bool
IsSettled reports whether the animation has converged.
func (*CollapseSpring) SetTarget ¶
func (cs *CollapseSpring) SetTarget(h float64)
SetTarget changes the target height and marks the spring as unsettled.
type CompactionState ¶
type CompactionState int
CompactionState describes how close a session is to the context window limit.
const ( // CompactionOK — tokens < 75% of context limit. No warning shown. CompactionOK CompactionState = iota // CompactionWarn — tokens 75–90% of context limit. Inline warning in usage panel. CompactionWarn // CompactionDanger — tokens > 90% of context limit. Danger indicator + notification banner. CompactionDanger )
type Config ¶
type Config struct {
Layout LayoutConfig `toml:"layout"`
Panels PanelsConfig `toml:"panels"`
Projects map[string]ProjectOverride `toml:"projects,omitempty"`
// AutoSwitchToAllOnNewSession controls what happens when a brand-new
// claude code session appears in the same cwd while clyde is running.
// When true (default), clyde flips the focused tab to Σ all so the
// user sees both sessions at a glance and can pick. When false, the
// user's currently-focused tab is preserved — useful if they're
// concentrating on one session and don't want their cursor stolen.
AutoSwitchToAllOnNewSession bool `toml:"auto_switch_to_all_on_new_session"`
// RememberLayout controls whether runtime panel-layout changes
// (collapse toggles via space, manual height resize via +/-) are
// written back to the config so the next session restores the same
// layout. When false, runtime changes stay in-session and panels
// fall back to PanelConfig.DefaultCollapsed on next launch.
RememberLayout bool `toml:"remember_layout"`
// NotificationStyle chooses the visual treatment for live hook
// prompts and compaction warnings. Defaults to fullscreen so the
// signal is impossible to miss; the user can downgrade to banner
// or disable entirely from the settings overlay.
NotificationStyle NotificationStyle `toml:"notification_style"`
// NotifyCostThresholdUSD fires a quota notification when the
// current session's accumulated cost crosses this dollar amount.
// Zero (default) disables cost-based alerts — plan-quota %
// notifications still fire on their own thresholds.
NotifyCostThresholdUSD float64 `toml:"notify_cost_threshold_usd"`
// Theme picks the active color palette. See theme.go for the registry
// of supported themes; defaults to ThemeTokyoNight. Cycled live from
// the settings overlay; the choice persists in config.toml so the
// next launch starts in the same theme.
Theme Theme `toml:"theme"`
// MascotPersona picks which character drives the now-panel mascot. The
// default ("meowl") is the cat shipped in v23+; "bowl" reverts to the
// v9–v22 rabbit; "off" hides the mascot block entirely for users who'd
// rather see the now panel as a flat status line. The legacy "kitten" /
// "bunny" values are still accepted on read and normalized to
// "meowl" / "bowl" (see MascotPersona.Normalize).
MascotPersona MascotPersona `toml:"mascot_persona"`
// BootScreenEnabled toggles the animated splash screen shown for
// ~1.5s on launch. Enabled by default; users who launch clyde a lot
// in CI scripts or back-to-back can flip it off from the settings
// overlay.
BootScreenEnabled bool `toml:"boot_screen_enabled"`
}
Config is the root config struct for the clyde TUI.
Resolution order at runtime is:
- Built-in defaults (DefaultConfig).
- Global user file (~/.config/clyde/config.toml).
- Per-project override under [projects."<absolute cwd>"] (V22+).
The global file may also contain a [projects."<cwd>"] section; the project layer is applied last via EffectiveFor.
func DefaultConfig ¶
func DefaultConfig() Config
DefaultConfig returns hardcoded defaults matching the spec.
V22 defaults: Diff is OFF (the standalone diff panel is opt-in; hunks surface inline under Edit calls in the activity panel). Every other panel is on by default.
func LoadConfig ¶
func LoadConfig() Config
LoadConfig reads the TOML config at configDir()/config.toml and merges it over the defaults. If the file doesn't exist, defaults are returned.
func (Config) EffectiveFor ¶
EffectiveFor returns a copy of the config with the per-project override for cwd applied on top of the global panel settings. cwd is normalized before lookup so symlinked or relative paths resolve to the same key.
type DiffSource ¶
type DiffSource interface {
// Diff returns parsed unified-diff hunks for the given file in cwd.
// If file is empty, all changed files are included.
// Returns (nil, nil) when cwd is not a git repo or git is unavailable.
Diff(cwd, file string) ([]livesession.DiffHunk, error)
}
DiffSource is the minimal interface for fetching git diff hunks. The concrete implementation is git.Source from the adapters/git package. Defined here (TUI layer) so model.go can hold a DiffSource without importing the adapter package directly.
type ExplorerRow ¶
type ExplorerRow struct {
// DisplayName is the rendered node name (▼ src, Sidebar.tsx, etc.)
DisplayName string
// Path is the full relative path for files, dir-name for dirs.
Path string
// IsDir signals whether this row is a directory.
IsDir bool
// IsAct flags the currently active file.
IsAct bool
// Mark is "M", "+", or "".
Mark string
// Indent prefix (│ characters).
Indent string
// DirKey is the canonical dir name used to look up collapse state.
DirKey string
}
ExplorerRow is a visible row in the interactive tree.
type ExplorerSearch ¶
type ExplorerSearch struct {
Active bool
Query string
Matches []ExplorerSearchMatch
Idx int
}
ExplorerSearch holds the search-overlay state for the explorer panel. Zero value = inactive (no overlay rendered, original tree visible).
When Active is true the explorer hides its normal tree+modified split and shows a flat list of matches scoped to the current Query. Up/Down navigate Idx through Matches; Enter opens Matches[Idx]. The cursor index auto-clamps to the match count so a query that narrows from 5 → 1 doesn't land on a stale row.
type ExplorerSearchMatch ¶
ExplorerSearchMatch is a single hit inside the explorer's search overlay. Carries enough info to render a row (display text) and to act on Enter (full path + whether it came from the modified-files window).
type ExplorerSection ¶
type ExplorerSection int
ExplorerSection identifies which of the two scrollable regions in the explorer panel currently owns the keyboard cursor.
const ( // SectionTree — cursor is in the tree below the modified-files window. SectionTree ExplorerSection = iota // SectionMod — cursor is in the modified-files window above the tree. SectionMod )
type ExplorerState ¶
type ExplorerState struct {
// contains filtered or unexported fields
}
ExplorerState holds the interactive explorer panel state. All fields are value-type — no pointers — to keep Model copyable.
func NewExplorerState ¶
func NewExplorerState(d MockData) ExplorerState
NewExplorerState builds an ExplorerState from mock data. All top-level directories start collapsed so the explorer is compact on startup; the user expands individual directories with Enter or Space.
func (*ExplorerState) HighlightedNode ¶
func (es *ExplorerState) HighlightedNode() *ExplorerRow
HighlightedNode returns a pointer to the currently highlighted row, or nil.
func (*ExplorerState) HighlightedPath ¶
func (es *ExplorerState) HighlightedPath() string
HighlightedPath returns the path of the highlighted row, normalized for mock lookup.
func (*ExplorerState) MoveDown ¶
func (es *ExplorerState) MoveDown(modCount int)
MoveDown moves the highlight one row down across the unified modified+tree cursor. ↓ at the bottom of mod crosses into the tree at row 0; ↓ at the bottom of tree clamps (no wrap).
func (*ExplorerState) MoveUp ¶
func (es *ExplorerState) MoveUp(modCount int)
MoveUp moves the highlight one row up across the unified modified+tree cursor. modCount is the number of modified files in the current view — when the cursor is at the top of the tree and any modified files exist, the cursor crosses into the modified section. Wrapping at the top of mod is intentionally disabled: knowing "I'm at the very top" is more useful than wrap-around in a small list.
func (*ExplorerState) RefreshRows ¶
func (es *ExplorerState) RefreshRows(d MockData)
RefreshRows rebuilds the visible row list from mock data (call after toggle).
func (*ExplorerState) ToggleDir ¶
func (es *ExplorerState) ToggleDir(dirKey string)
ToggleDir expands or collapses a directory by its dirKey. After the toggle, the visible row list is rebuilt from the data stored in MockData — so we need it passed in.
type FileIcon ¶
FileIcon describes a single-cell glyph plus its accent color for a file type. Glyphs are chosen from Unicode Geometric Shapes / Block Elements so they render in any modern terminal font — no Nerd Font dependency.
type FrameMsg ¶
type FrameMsg struct {
Gen uint64
}
FrameMsg is the tick message driving all frame-counter animations.
Gen identifies the tick chain that scheduled this message. The model tracks the current generation in tickGen and bumps it whenever the next interval should change (user input, animation start). A FrameMsg whose Gen does not match the current tickGen is a stale tick from a superseded chain and is silently dropped — without this, switching from idle (1Hz) to active (20Hz) would create racing parallel chains.
type FrameState ¶
type FrameState struct {
Tick uint64
// Bunny FSM — drives all mascot states and transitions.
Mascot MascotFSM
// Derived phases — recomputed on each tick.
SpinnerFrame int // 0-3 (~333ms per frame)
LiveDotDim bool // alternates every 0.8s
CursorVisible bool // alternates every 0.4s
ChevronDim bool // alternates every 0.7s
}
FrameState holds per-animation phase counters derived from a monotonic tick counter. All animations are driven by the FrameMsg tick.
func AdvanceTick ¶
func AdvanceTick(prev FrameState) FrameState
AdvanceTick returns a new FrameState with Tick incremented and all derived phases recomputed. Dividers are sized for the active tick interval so every wall-clock period below stays the same regardless of the tick rate.
func InitFrameState ¶
func InitFrameState() FrameState
InitFrameState returns an initial FrameState (tick=0).
func (FrameState) SpinnerGlyph ¶
func (f FrameState) SpinnerGlyph() string
SpinnerGlyph returns the current spinner glyph from frame counter.
type HookNotification ¶
type HookNotification struct {
// Active is true when an unanswered hook event is in flight.
Active bool
// Tool is the tool name, e.g. "Bash", "Edit".
Tool string
// KeyArg is the main argument for the tool (command, path, etc.).
KeyArg string
// Cwd is the working directory context for the call.
Cwd string
}
HookNotification holds the live hook event currently displayed in the banner. Zero value means no live event (fall through to mock data or hidden).
type KeyMap ¶
type KeyMap struct {
Quit key.Binding
Tab key.Binding
ShiftTab key.Binding
Space key.Binding
Up key.Binding
Down key.Binding
Left key.Binding
Right key.Binding
Enter key.Binding
Backspace key.Binding
Esc key.Binding
// ⌃-prefixed chords dispatched by handleCtrl.
CycleMode key.Binding // ⌃l — cycle layout mode
CollapseAll key.Binding // ⌃0 — collapse every panel except the focused one
FocusExplorer key.Binding // ⌃e — focus explorer
FocusCalls key.Binding // ⌃a — focus activity/calls
FocusDiff key.Binding // ⌃d — focus diff
// Resize bindings — grow/shrink the focused expanded panel
PanelGrow key.Binding // + or = → increase panel height by 1
PanelShrink key.Binding // - → decrease panel height by 1
// Session cycling across the footer session-tab strip ([ / ]).
SessionPrev key.Binding // [ — previous session tab
SessionNext key.Binding // ] — next session tab
// PanelJump documents the plain-letter panel jumps dispatched by
// handlePanelJumpKey (e/a/d/u/s/b/c).
PanelJump key.Binding
// Overlays.
Help key.Binding // h — per-panel help cheat-sheet
Settings key.Binding // ? — settings overlay (also cycles layout)
// Numeric tab jumps for tabs mode (1..N).
Jump1 key.Binding
Jump2 key.Binding
Jump3 key.Binding
Jump4 key.Binding
}
KeyMap is the central keybinding registry for clyde. It documents the bindings the dashboard actually dispatches — every entry here must have a live handler (handleKey/handleCtrl/handlePanelJumpKey); dead declarations mislead the help surfaces.
type Layout ¶
type Layout struct {
// Mode + breakpoint + width snapshot.
Mode LayoutMode
BP Breakpoint
Width int
// Chrome rows. NotifH only takes height when an actual hook or
// compaction warning is active; StatusH grows when help is open.
TitleH int
NotifH int
StatusH int
// Vertical budget for panels = Height - TitleH - NotifH - StatusH,
// floored at a per-mode minimum so degenerate window sizes don't
// produce negative dimensions downstream.
GridH int
// ── 2-col (BreakpointMedium with stack mode) ────────────────────
// LeftW + RightW = Width. ExplorerH and ServersH split the left
// column vertically; the right column uses panelStackHeight per
// panel (collapse spring or panelHeight()).
LeftW int
RightW int
ExplorerH int
ServersH int
// ── Multi-col (3 columns) ───────────────────────────────────────
// MultiExplorerW takes the full GridH on the left. The middle
// column stacks Now → Calls → optional Diff. The right column
// stacks Usage → Servers → optional Bash → optional Cache.
MultiExplorerW int
MultiMiddleW int
MultiRightW int
MultiNowH int
MultiCallsH int
MultiDiffH int
MultiUsageH int
MultiServersH int
MultiBashH int
MultiCacheH int
}
Layout holds the geometry derived from the current model snapshot. Never store this — always recompute via m.computeLayout() at the top of the consumer function. Stale Layouts (across model updates) are silently wrong; recomputing is cheap.
type LayoutConfig ¶
type LayoutConfig struct {
DefaultMode LayoutMode `toml:"default_mode"`
AutoSwitchThreshold int `toml:"auto_switch_threshold"`
CycleHotkey string `toml:"cycle_hotkey"`
}
LayoutConfig holds the layout section of the config.
type LayoutMode ¶
type LayoutMode string
LayoutMode is a named layout mode.
const ( LayoutStack LayoutMode = "stack" LayoutTabs LayoutMode = "tabs" LayoutMultiCol LayoutMode = "multi-col" )
Layout mode constants.
func ResolveMode ¶
func ResolveMode(preferred LayoutMode, threshold, width int) LayoutMode
ResolveMode returns the effective LayoutMode for a given terminal width, respecting the auto-switch threshold and the user's preferred mode. Multi-col requires at least 160 cols; below that it falls back to tabs.
func (LayoutMode) IsValid ¶
func (m LayoutMode) IsValid() bool
IsValid reports whether m is a recognized LayoutMode. Used when loading config to fall back to the default if an unknown string slipped in via a hand-edited TOML file (consistent with Theme / NotificationStyle / MascotPersona validation).
type MascotBaseState ¶
type MascotBaseState int
MascotBaseState identifies the named base states of the mascot FSM. Intermediate / transitional frames are encoded as additional constants.
Kitten shape reference (Stand state):
/\_/\ ← ears (row 0) ( o.o ) ← round face with eyes (row 1) /( )\ ← body / arms (row 2) _"_"_ ← paws (row 3)
Width budget: 9 chars wide on every row (lipgloss pads to the longest line anyway, but staying balanced keeps the block from drifting under the spinner column). Block height: always exactly 4 rows.
const ( MascotStand MascotBaseState = iota // default — ears up, eyes open MascotBlink // eyes closed (-.-) MascotLookLeft // eyes look left (◐.◐) MascotLookRight // eyes look right (◑.◑) MascotHappy // eyes smile up (^_^) MascotSurprised // eyes wide open (O.O) MascotSleep // eyes droop, animated zZ next to ears MascotWave // both paws up, greeting )
Base state constants. The iota starts at MascotStand.
type MascotFSM ¶
type MascotFSM struct {
// contains filtered or unexported fields
}
MascotFSM drives the mascot state machine on each 50ms tick. It holds the current playback position within an event sequence plus scheduling state for the next idle event.
func NewMascotFSM ¶
func NewMascotFSM() MascotFSM
NewMascotFSM returns an FSM ready to play. Locked at frame 0 for tests.
func (MascotFSM) Advance ¶
Advance moves the FSM one tick forward and returns a new FSM. Autonomous idle events (blink / look-around / nuzzle / stretch / cuddle / happy) and external triggers (pendingEvent set via SetExternalState / WithWorking) both fire from here.
func (MascotFSM) CurrentState ¶
func (f MascotFSM) CurrentState() MascotBaseState
CurrentState returns the rendered base state for this tick.
func (MascotFSM) HasActiveSequence ¶
HasActiveSequence reports whether the mascot is currently mid-animation (a sequence is queued and playback hasn't returned to the resting Stand state). Callers use this to decide whether to keep the frame loop in fast mode — a settled mascot at the idle cadence is one fewer reason to keep the View() rebuild rate at 20Hz.
func (MascotFSM) SetExternalState ¶
SetExternalState queues an external event kind to play on the next Advance tick. If the FSM is already mid-sequence, the new event replaces the pending event (latest-wins semantics). This is the hook for live-data triggers from model.go.
func (MascotFSM) SleepZPhase ¶
SleepZPhase returns the current zZ animation phase (0..3).
func (MascotFSM) WithWorking ¶
WithWorking returns an FSM with the working hint applied. The hint is consulted by scheduleNext + pickEvent to decide cadence and weights. Idempotent and value-typed so callers store the result.
type MascotPersona ¶
type MascotPersona string
MascotPersona picks which character drives the now-panel mascot.
Two named characters ride the same FSM:
Meowl — the v23 cat. Default. /\_/\ ears, ( o.o ) face. Bowl — the legacy v9 rabbit. (\_/) ears, (o.o) face.
"Off" hides the mascot block entirely. The TOML serialization uses the new names ("meowl" / "bowl"); the legacy "kitten" / "bunny" values are accepted on read via Normalize() so a user upgrading from an earlier dev build doesn't see their persona reset to default.
const ( MascotPersonaMeowl MascotPersona = "meowl" MascotPersonaBowl MascotPersona = "bowl" MascotPersonaOff MascotPersona = "off" )
MascotPersona constants.
func (MascotPersona) Display ¶
func (p MascotPersona) Display() string
Display returns a short human-readable label used in the settings chip.
func (MascotPersona) IsValid ¶
func (p MascotPersona) IsValid() bool
IsValid reports whether p is a recognized MascotPersona — including legacy aliases, since the LoadConfig path treats those as valid input before normalizing.
func (MascotPersona) Next ¶
func (p MascotPersona) Next() MascotPersona
Next returns the next persona in the cycle: meowl → bowl → off → meowl.
func (MascotPersona) Normalize ¶
func (p MascotPersona) Normalize() MascotPersona
Normalize collapses legacy persona names into their new equivalents. Called from LoadConfig so files written before the v23 rename keep working with the same character.
type MockData ¶
type MockData struct {
// Title bar
ProjectPath string
ProjectName string
Duration string
Tokens string
Cost string
// Explorer
ModifiedFiles []ModifiedFile
Tree []TreeNode
// Now panel
NowMode string // "writing · 47 t/s"
NowOp string // "edit auth.ts"
NowMeta string // "14 lines staged · line 46"
NowTS bool // ts done
NowLint bool // lint done
NowCompile bool // compile active (not done)
// Calls panel (replaces tasks panel in v13)
AgentGroups []AgentGroup
// Diff panel
DiffFile string // "auth.ts · +14 −3"
DiffLines []DiffLine
IsGitRepo bool // true when cwd contains a .git directory
// Usage panel
Tokens200k int // used out of 200k
TokenPct int // 23
Cost142 string // "$1.42"
Turns string // "38"
Model string // "opus 4.7"
Errors string
Warnings string
Tests string
// Multi-window usage rows with per-token-type breakdown.
// Each row shows label · in · out · cache · cost for one time window.
UsageSession UsageWindowRow // this session
Usage5h UsageWindowRow // rolling last 5 hours
UsageWeek UsageWindowRow // rolling last 7 days
// BurnRate is a derived display string shown below the usage rows:
// e.g. "~3.2k tok/min · $0.18/hr". Empty when there is too little data.
BurnRate string
// PlanTier is the human-readable subscription plan tier
// (e.g. "Max 5x", "Pro"). Empty when unknown OR when the user is
// on API auth (in which case IsAPIUser is true and renderers show
// "api" via that flag instead of trying to fake a tier here).
PlanTier string
// IsAPIUser is true when the plan-usage source returned
// ErrPlanUsageUnavailable — the user has no subscription and is
// paying per-token via API. Used to gate the cost-threshold
// notification (subscribers' "cost" is mostly cosmetic) and to
// display "api" as the tier label so the user can see at a glance
// what mode they're in.
IsAPIUser bool
// PlanUsageOffline is true when the plan-usage API is unreachable or
// the credentials are present but the request failed. Distinct from
// IsAPIUser — offline means "we expected data and didn't get it",
// API means "no subscription credentials by design".
PlanUsageOffline bool
// Servers panel
ServersOn int // 5
ServersTotal int // 7
MCPs []Server
LSPs []Server
// Bash audit panel (v22+, opt-in via settings)
BashLog []BashRow
// Cache efficiency panel (v22+, opt-in via settings)
Cache CacheStatsView
// Multi-session tab strip — one entry per session in the current cwd
// (Σ aggregate first when populated). Populated from
// livesession.View.SessionStats; empty in demo mode and when only a
// single session is recently active.
Sessions []SessionTab
// SessionTabIndex is the index of the active tab in Sessions. -1 means
// the Σ aggregate tab is active; 0..len(Sessions)-1 selects a specific
// session. Default 0 (most-recently-active session).
SessionTabIndex int
// SessionLeaderboard mirrors Sessions for the usage panel: top sessions
// by ContextPct desc, used to render per-session ctx bars when the Σ
// tab is active. Empty when the panel should render its single-session
// fallback bar.
SessionLeaderboard []SessionTab
}
MockData is the complete v3 mock dataset.
func V3MockData ¶
func V3MockData() MockData
V3MockData returns the authoritative v3 mock content matching v3-mock.html.
type Model ¶
type Model struct {
// contains filtered or unexported fields
}
Model is the root Bubble Tea v2 model for the clyde prototype.
func NewModel ¶
func NewModel() Model
NewModel constructs a Model with mock data and the Tokyo Night v4 theme. It runs in demo mode (demoMode=true): all data is from MockData, no live reads.
func NewModelLive ¶
func NewModelLive(cfg Config, layoutOverride LayoutMode, p project.Project, ls *livesession.LiveSession, hs *hookserver.Server, ds DiffSource, sourceName string) Model
NewModelLive constructs a Model wired to real Claude Code data. It runs in live mode: on Init it fires a LiveSession.Snapshot and then refreshes every liveRefreshInterval. The demo data is kept as a fallback for panels not yet wired in Phase A (explorer, servers, diff, usage details).
p is the project to watch (typically os.Getwd()). ls is the LiveSession use case already constructed with real adapters. hs is the optional hook server; pass nil to disable hook integration. ds is the optional DiffSource for Phase E; pass nil to keep mock diff data. sourceName is the LLM source name for the title bar (e.g. "claude-code").
func NewModelWithConfig ¶
func NewModelWithConfig(cfg Config, layoutOverride LayoutMode) Model
NewModelWithConfig constructs a Model with the given config and layout override. Runs in demo mode (demoMode=true).
func (Model) Init ¶
Init implements tea.Model. Starts the animation tick loop. In live mode, also fires the first snapshot immediately and starts the hook server watcher if a hook server was provided.
Boot splash is opt-out via Config.BootScreenEnabled and only activates after Init runs (i.e. tea.NewProgram(...).Run()) so unit tests that build a Model and call View() directly never see it.
func (Model) WithPlanUsageSource ¶
func (m Model) WithPlanUsageSource(src ports.PlanUsageSource) Model
WithPlanUsageSource attaches a ports.PlanUsageSource to the Model so the usage panel can show real plan-quota percentages instead of the time-elapsed approximation. Pass nil to disable (the panel falls back to the JSONL-derived display).
Returns the updated Model — the caller MUST replace its reference, matching the pattern used by NewModelLive.
type ModifiedFile ¶
ModifiedFile is a file changed during the session.
type NotificationStyle ¶
type NotificationStyle string
NotificationStyle picks the visual treatment for hook prompts and the compaction-imminent warning.
const ( NotificationFullscreen NotificationStyle = "fullscreen" NotificationBanner NotificationStyle = "banner" NotificationOff NotificationStyle = "off" )
Notification style constants.
NotificationFullscreen — animated centered overlay (default). Covers
the panel grid until dismissed; pulses to
grab attention for hook prompts.
NotificationBanner — compact 3-row banner above the status bar
(the V22 behavior, kept for users who find
fullscreen too aggressive).
NotificationOff — no UI surfacing. Hook events still block on
the server side; the user must rely on the
claude CLI's own prompt or use y/n hotkeys.
func (NotificationStyle) Display ¶
func (s NotificationStyle) Display() string
Display returns a short human-readable label used in the settings chip.
func (NotificationStyle) IsValid ¶
func (s NotificationStyle) IsValid() bool
IsValid reports whether s is a recognized NotificationStyle. Used when loading config to fall back to the default if an unknown string slipped in via a hand-edited TOML file.
func (NotificationStyle) Next ¶
func (s NotificationStyle) Next() NotificationStyle
Next returns the next style in the cycle order: fullscreen → banner → off → fullscreen. Drives the Enter handler on the settings overlay.
type NowStatus ¶
type NowStatus struct {
// Op is the concise action string shown on line 1:
// "edit auth.ts", "read main.go", "bash 'go test'", "thinking…", etc.
Op string
// Meta is the secondary detail string shown on line 2:
// elapsed time for bash, token rate for thinking, path tail for reads.
Meta string
// ModeText is the header badge text (top-right of panel border):
// "writing · NN t/s" during streaming, tool name or "idle" otherwise.
ModeText string
// MascotTrigger is the mascot event to fire on this status update.
// Valid trigger values are eventHappy, eventSurprised, eventSleep.
MascotTrigger mascotEventKind
// HasTrigger is true when MascotTrigger should be applied.
// Separates "no trigger" from eventBlink (index 0).
HasTrigger bool
}
NowStatus holds the derived display strings for the now panel. It is produced by deriveNowStatus and consumed by applyLiveView.
type Palette ¶
type Palette struct {
// Surface
Bg color.Color // terminal surface
Surface color.Color // panel bg
SurfaceAcc color.Color // focused panel interior tint
// Borders
BorderDim color.Color // default panel border
BorderAcc color.Color // active/focused panel border
// Foreground
Text color.Color // primary text
TextMid color.Color // secondary text
TextDim color.Color // metadata, labels
TextFade color.Color // gutters, disabled
// Accents
Purple color.Color // clyde brand, active substate
Pink color.Color // mascot, claude voice ONLY
Magenta color.Color // expanded-active panel borders
Cyan color.Color // paths, info
Green color.Color // live, done, success
Amber color.Color // modified, warnings
Red color.Color // removed, errors, current file
Orange color.Color // grep / find tags
}
Palette holds all semantic color roles for a theme. Every style in the UI is derived from this palette — never hardcoded hex.
func ClydeDarkPalette ¶
func ClydeDarkPalette() Palette
ClydeDarkPalette is an alias for TokyoNightPalette kept for API compat.
func PaletteFor ¶
PaletteFor returns the palette for the given theme. Falls back to Tokyo Night when the theme is unknown — keeps the UI rendering even if a user hand-edits an invalid value into config.toml.
func TokyoNightPalette ¶
func TokyoNightPalette() Palette
TokyoNightPalette returns the v4 Tokyo Night palette. Values are EXACT — do not substitute.
type PanelCollapseState ¶
type PanelCollapseState struct {
// contains filtered or unexported fields
}
PanelCollapseState holds collapse state + animation spring for one panel.
func NewPanelCollapseState ¶
func NewPanelCollapseState(startCollapsed bool, expandedH float64) PanelCollapseState
NewPanelCollapseState initializes collapse state. startCollapsed sets the initial visual state. expandedH is the full panel height in rows.
func (*PanelCollapseState) Advance ¶
func (p *PanelCollapseState) Advance()
Advance ticks the spring one frame.
func (*PanelCollapseState) Collapse ¶
func (p *PanelCollapseState) Collapse()
Collapse ensures the panel is collapsed.
func (*PanelCollapseState) Expand ¶
func (p *PanelCollapseState) Expand()
Expand ensures the panel is expanded (does not toggle if already expanded).
func (*PanelCollapseState) ExpandedHeight ¶
func (p *PanelCollapseState) ExpandedHeight() int
ExpandedHeight returns the settled expanded-height target — the height the panel reaches once the expand animation finishes. Use this (not the animated Height) when sizing things that must match the final layout, e.g. viewport scroll clamping.
func (*PanelCollapseState) Height ¶
func (p *PanelCollapseState) Height() int
Height returns the current animated height for rendering.
func (*PanelCollapseState) IsCollapsed ¶
func (p *PanelCollapseState) IsCollapsed() bool
IsCollapsed reports the logical collapsed state (not the animated state).
func (*PanelCollapseState) IsSettled ¶
func (p *PanelCollapseState) IsSettled() bool
IsSettled reports whether the wrapped spring has converged. Used by the model's adaptive frame-tick gate to decide whether the View loop can drop to idleTickInterval.
func (*PanelCollapseState) SetExpandedHeight ¶
func (p *PanelCollapseState) SetExpandedHeight(h float64)
SetExpandedHeight updates the target expanded height (e.g. on window resize).
func (*PanelCollapseState) Toggle ¶
func (p *PanelCollapseState) Toggle()
Toggle flips collapsed state and updates the spring target.
type PanelConfig ¶
type PanelConfig struct {
Enabled bool `toml:"enabled"`
DefaultCollapsed bool `toml:"default_collapsed"`
Position int `toml:"position"`
Height int `toml:"height,omitempty"`
}
PanelConfig holds per-panel display settings.
Height is the user's persisted manual resize for this panel. When RememberLayout is enabled at the Config level, +/- resize and the space-toggle write back to Height + DefaultCollapsed so the next session restores the same layout. When RememberLayout is off, Height is ignored and the panel falls back to its computed default.
type PanelID ¶
type PanelID int
PanelID identifies a focusable panel.
const ( PanelNow PanelID = iota PanelCalls PanelDiff PanelUsage PanelExplorer PanelServers // PanelBash — session-wide ledger of every Bash command claude has run, // with exit/duration. Off by default; opt-in via the settings overlay // per project. PanelBash // PanelCache — prompt-cache efficiency dashboard (hit ratio, totals, // biggest cache miss, per-turn trend sparkline). Off by default. PanelCache // PanelNone is the zero-like sentinel meaning "no panel is active". // Defined after panelCount so it's never confused with a real panel. PanelNone PanelID = -1 )
Panel ID constants. Tab cycles through these in order.
type PanelLayout ¶
type PanelLayout struct {
Height int `toml:"height,omitempty"`
DefaultCollapsed bool `toml:"default_collapsed,omitempty"`
}
PanelLayout is the per-project subset of PanelConfig that participates in RememberLayout persistence. Height==0 means "no manual override"; DefaultCollapsed defaults to false and is omitted from the TOML when it matches that zero value.
type PanelState ¶
type PanelState int
PanelState describes which visual state a panel is rendered in.
const ( // PanelStateNormal — unfocused, collapsed or expanded. PanelStateNormal PanelState = iota // PanelStatePassive — focused, expanded-passive (purple border). PanelStatePassive // PanelStateActive — focused, expanded-active (pink double border + mode badge). PanelStateActive )
type PanelsConfig ¶
type PanelsConfig struct {
Now PanelConfig `toml:"now"`
Calls PanelConfig `toml:"calls"` // v13: replaces tasks
Tasks PanelConfig `toml:"tasks"` // legacy alias — copied onto Calls in LoadConfig when [panels.calls] is absent
Diff PanelConfig `toml:"diff"`
Usage PanelConfig `toml:"usage"`
Explorer PanelConfig `toml:"explorer"`
Servers PanelConfig `toml:"servers"`
Bash PanelConfig `toml:"bash"` // v22+: session-wide bash command ledger
Cache PanelConfig `toml:"cache"` // v22+: prompt-cache efficiency dashboard
}
PanelsConfig holds all panel configs.
type ProjectOverride ¶
type ProjectOverride struct {
Panels map[string]bool `toml:"panels,omitempty"`
PanelLayouts map[string]PanelLayout `toml:"panel_layouts,omitempty"`
}
ProjectOverride is a per-project settings layer applied on top of the global config when the user is launched in that working directory.
Panels carries per-panel visibility overrides (enabled flag). PanelLayouts carries per-panel layout overrides (manual Height and DefaultCollapsed) so RememberLayout-driven persistence is scoped to the project the user actually resized panels in.
type QuotaNotification ¶
type QuotaNotification struct {
Active bool
Headline string
Detail string
Severity QuotaSeverity
}
QuotaNotification carries a derived plan-quota or cost alert.
Active is set when one of the configured thresholds has just been crossed upward; the renderers branch on Severity to pick the right chrome and copy.
resolveNotification suppresses Active while notifAck is set, so dismiss flow matches hook + compaction.
type QuotaSeverity ¶
type QuotaSeverity int
QuotaSeverity tints the chrome and chooses the title copy.
const ( // QuotaSeverityWarn is the 90% crossing — heads-up. QuotaSeverityWarn QuotaSeverity = iota // QuotaSeverityDanger is the 95% crossing — final warning. QuotaSeverityDanger )
type Server ¶
type Server struct {
Status ServerStatus
Name string
Count string // tool count for MCPs; empty for LSPs
}
Server is one entry in the servers panel.
type ServerStatus ¶
type ServerStatus int
ServerStatus is the state of an MCP/LSP server.
const ( ServerOn ServerStatus = iota // server is active ServerBusy // server is busy (amber) ServerOff // server is offline )
Server status constants.
type SessionTab ¶
type SessionTab struct {
// ID is the session identifier; empty for the synthetic Σ aggregate
// tab (which represents "all sessions in this cwd").
ID session.ID
// Label is the short text rendered inside the tab (e.g. "fix auth"
// or a 6-char session-ID prefix). For the Σ tab this is "Σ all".
Label string
// Active is true for the currently-focused tab.
Active bool
// IsAggregate is true for the leftmost Σ tab.
IsAggregate bool
// ContextPct is the model-context fill percent for this session's
// most recent assistant turn. Zero for the Σ tab.
ContextPct int
// Warning is true when the session is close to compaction
// (ContextPct > sessionCtxWarnThreshold). Drives the ⚠ glyph on
// inactive tabs so users notice the danger even when not focused on
// that session.
Warning bool
// Live is true when the session was written to recently (claude code
// still has it open). Drives the bullet glyph on the tab — orthogonal
// to Active (which is the user's focused tab in clyde). A closed /
// idle session that the user happens to have selected reads as
// "[ resume ]" without a bullet; a running session that is not the
// current tab still gets "[● label]" so the user can spot it.
Live bool
// Tokens is the total session token count (formatted in the panel
// when needed). Mostly used by the Σ leaderboard view.
Tokens int64
}
SessionTab is one tab rendered in the title-bar tab strip. Tabs cover every recently-active session in the current cwd, plus a Σ aggregate.
type SettingsPanelToggle ¶
type SettingsPanelToggle struct {
PanelID PanelID
Label string
Enabled bool
StartsCollapsed bool
IsOverride bool // true when the project layer differs from the global layer
}
SettingsPanelToggle holds the per-panel toggle state for the settings overlay.
Enabled mirrors the visibility flag (with project-scope override semantics). StartsCollapsed mirrors the global DefaultCollapsed flag — it is always edited at the global layer regardless of the current scope, since we don't support per-project default-collapsed overrides.
type SettingsScope ¶
type SettingsScope int
SettingsScope chooses which layer of the config the overlay edits.
const ( // ScopeProject — edits go to baseCfg.Projects["<cwd>"].Panels (default // when a cwd is known). Effective for ONLY this project. ScopeProject SettingsScope = iota // ScopeGlobal — edits go to baseCfg.Panels (the top-level [panels]). // Used when the user wants a setting to apply to every project that // does not explicitly override it. ScopeGlobal )
type Styles ¶
type Styles struct {
// Panel chrome (normal border)
Panel lipgloss.Style
PanelFocus lipgloss.Style // Expanded-Passive: purple border
PanelActive lipgloss.Style // Expanded-Active: pink double border
// Panel label / metadata riding the border
PanelLabel lipgloss.Style
PanelLabelFocus lipgloss.Style // purple when focused (passive)
PanelLabelActive lipgloss.Style // pink when in active mode
PanelMeta lipgloss.Style
PanelModeBadge lipgloss.Style // active-mode badge text (pink)
// Collapsed panel one-liner summary
PanelCollapsedLabel lipgloss.Style // dim when blurred
PanelCollapsedLabelFocus lipgloss.Style // purple when focused
// Title bar
TitleBar lipgloss.Style
TitleBrand lipgloss.Style // "clyde" in purple
TitlePath lipgloss.Style // dim path
TitleProjct lipgloss.Style // cyan project name
TitleLive lipgloss.Style // green "claude · live"
TitleMeta lipgloss.Style // dim meta labels
TitleValue lipgloss.Style // white values
// Explorer
SectionHeader lipgloss.Style // dim section label
SectionCount lipgloss.Style // fade count on right
FileModMark lipgloss.Style // M amber
FileAddMark lipgloss.Style // + green
FileName lipgloss.Style // mid text
FileNameAct lipgloss.Style // red — active file
FileStats lipgloss.Style // dim +/- counts
TreeDir lipgloss.Style // blue-ish dir color
TreeIndent lipgloss.Style // fade
HintKey lipgloss.Style // purple kbd hints
HintText lipgloss.Style // dim hint text
// Now panel
Mascot lipgloss.Style // pink — bunny body
MascotZZ lipgloss.Style // dim — sleep zZ annotation
NowOp lipgloss.Style // purple operation line
NowMeta lipgloss.Style // dim meta
NowCode lipgloss.Style // cyan inline code
NowDetail lipgloss.Style // dim detail (e.g. · line 46)
StatusGreen lipgloss.Style // green status dot
StatusPurpl lipgloss.Style // purple status dot/chevron
// Tasks panel
TaskDoneIcon lipgloss.Style // green ✓
TaskDoneName lipgloss.Style // muted strikethrough-ish
TaskDur lipgloss.Style // dim duration
TaskSubtitle lipgloss.Style // small dim subtitle
TaskActBorder lipgloss.Style // active task outer box
TaskActName lipgloss.Style // text active task name
TaskActDur lipgloss.Style // purple duration
TaskActOp lipgloss.Style // spinner+code line
TaskActCode lipgloss.Style // cyan code ref
TaskSubDoneIcon lipgloss.Style
TaskSubDoneName lipgloss.Style
TaskSubActIcon lipgloss.Style // purple
TaskSubActName lipgloss.Style
TaskSubPenIcon lipgloss.Style // fade
TaskSubPenName lipgloss.Style // dim
TaskPenIcon lipgloss.Style // fade □
TaskPenName lipgloss.Style // dim
ProgPct lipgloss.Style // purple %
ProgLeft lipgloss.Style // dim "N left"
ProgBarBg lipgloss.Style // dark bar bg
// Diff panel
DiffHunk lipgloss.Style // dim italic @@ line
DiffLineNum lipgloss.Style // fade line number
DiffCtx lipgloss.Style // mid context text
DiffAdd lipgloss.Style // green added text
DiffRem lipgloss.Style // red removed text
// Usage panel
UsageLabel lipgloss.Style
UsageValue lipgloss.Style
UsageModel lipgloss.Style // purple model name
UsageDivider lipgloss.Style
IssueDot lipgloss.Style // base
IssueName lipgloss.Style
IssueValue lipgloss.Style
// Servers panel
SrvSubHeader lipgloss.Style
SrvName lipgloss.Style
SrvCount lipgloss.Style
SrvOff lipgloss.Style // dim name when off
// Semantic color shortcuts (for inline dot/accent usage)
TextFade lipgloss.Style // #3b4261 gutters/disabled
Amber lipgloss.Style // #e0af68 warnings
// Notification banner
NotifIcon lipgloss.Style // purple ◆
NotifWho lipgloss.Style // pink "claude" — ONLY place pink is used on text
NotifText lipgloss.Style
NotifCmd lipgloss.Style // amber code
NotifPath lipgloss.Style // cyan path
KbdChip lipgloss.Style // keyboard chip [y]
// Status bar
StatusBar lipgloss.Style
StatusKey lipgloss.Style // purple keybind
StatusSep lipgloss.Style // fade ·
StatusVer lipgloss.Style // dim version
StatusReady lipgloss.Style // green "ready"
// Tab strip (Mode B)
TabActive lipgloss.Style // active tab — purple text
TabInactive lipgloss.Style // inactive tab — dim
TabBorder lipgloss.Style // tab separator
}
Styles holds all per-component lipgloss styles derived from a Palette. Never create lipgloss styles inline in rendering code — go through this struct so the theme stays consistent.
func (Styles) WithFadedFocus ¶
WithFadedFocus returns a copy of s with the focus-chrome foregrounds interpolated toward their dim equivalents based on alpha.
alpha=1 → unchanged (full purple/BorderAcc on focused panels) alpha=0 → focus colors collapse to dim/TextDim equivalents in between → blendColor across BorderDim↔BorderAcc and TextDim↔Purple
Only the chrome that distinguishes Passive (focused) from Normal flips — PanelStateActive / PanelLabelActive / PanelMeta etc are left alone so active mode and meta text don't get caught up in the fade.
Used by render_stack/2col/multicol when the focus-decay handoff is in flight: the previously-focused panel's border tints purple → gray over 3s and the now-panel's border tints gray → purple over the next 3s.
type Task ¶
type Task struct {
Status TaskStatus
Icon string // "✓", "▸", "□"
Name string
Duration string
Subtitle string // shown for done tasks
SubSteps []SubStep // only for active task
}
Task is a single entry in the tasks panel.
type TaskStatus ¶
type TaskStatus int
TaskStatus describes a task's completion state.
const ( TaskDone TaskStatus = iota // completed task TaskActive // currently running task TaskPending // not yet started task )
Task status constants.
type TerminalGraphics ¶
type TerminalGraphics int
TerminalGraphics describes the image rendering capability of the current terminal.
const ( // GraphicsNone — no inline image support; use ASCII fallback. GraphicsNone TerminalGraphics = iota // GraphicsKitty — Kitty graphics protocol (APC _G sequences). GraphicsKitty // GraphicsGhostty — Ghostty terminal (also supports Kitty graphics). GraphicsGhostty )
func DetectTerminalGraphics ¶
func DetectTerminalGraphics() TerminalGraphics
DetectTerminalGraphics checks the $TERM and $TERM_PROGRAM environment variables to determine whether Kitty graphics protocol is available.
Supported values:
TERM=xterm-kitty → Kitty TERM=ghostty → Ghostty (Kitty-compatible) TERM=xterm-ghostty → Ghostty TERM_PROGRAM=ghostty → Ghostty
type Theme ¶
type Theme string
Theme identifies a palette in the registry. The string value is what's persisted in config.toml so users can edit it by hand.
const ( ThemeTokyoNight Theme = "tokyo-night" ThemeCatppuccin Theme = "catppuccin" ThemeDracula Theme = "dracula" ThemeGruvbox Theme = "gruvbox" ThemeNord Theme = "nord" ThemeRosePine Theme = "rose-pine" ThemeKanagawa Theme = "kanagawa" )
Theme constants. Keep ThemeTokyoNight first — it's the historical default.
type ToolCall ¶
type ToolCall struct {
AgentID string
AgentName string
IsSubagent bool
Tool string // "Read", "Edit", "Bash", "Grep", etc.
KeyArg string // first/main argument (path, command, pattern)
Duration string // "12s", "1.4m"
State CallState // CallDone, CallActive, CallFailed
}
ToolCall is a single tool invocation within an agent session.
type TreeNode ¶
type TreeNode struct {
Indent string // indentation prefix using │ characters
Mark string // "M", "+", " "
IsDir bool // renders with dir color
IsAct bool // currently active file (red highlight)
Name string
FullPath string // optional full relative path (used by viewer for mock lookup)
}
TreeNode is a single line in the file tree view.
type UsageWindowRow ¶
type UsageWindowRow struct {
// Label is the window name shown in the left column: "session ctx", "5h usage", "weekly usage".
Label string
// Percent is the 0-100 fill ratio for this row's progress bar.
// - session row: % of model context window used (compaction risk).
// - 5h / weekly rows: % of plan quota consumed (when IsPlanQuota=true)
// OR % of time elapsed in window (when IsPlanQuota=false fallback).
Percent int
// IsPlanQuota is true when Percent comes from the Anthropic plan-usage
// API (real plan-quota %), false when it's a time-elapsed approximation
// derived from JSONL timestamps. Used by the panel to decide whether
// to show the "(plan offline)" badge.
IsPlanQuota bool
// Input is the formatted input-token count, e.g. "12k".
Input string
// Output is the formatted output-token count, e.g. "5k".
Output string
// Cache is the formatted cache-read token count, e.g. "30k".
Cache string
// Cost is the formatted USD cost, e.g. "$0.42".
Cost string
// TotalUsed is the formatted total token count for the window, e.g. "3.4M".
// Used in the two-line per-window display as the "total used" line.
TotalUsed string
// CurrentCtx is the "Nk / 1M (N%)" string for the current context window.
// Only populated for the session row (LatestUsage context, not TotalUsage).
// Empty for 5h and 7d rows.
CurrentCtx string
// ResetsIn is the human-readable countdown until the window resets,
// e.g. "3h 57m" for the 5h window, "4d 14h" for the 7d window.
// Empty when the reset time is unknown or has already passed.
ResetsIn string
// ResetAt is the wall-clock time when this window resets. Zero when
// unknown (e.g. hand-authored demo rows). Used to pick the SOONEST
// reset for the synthetic "next reset" row.
ResetAt time.Time
// ResetElapsedPct is the 0-100 percentage of TIME elapsed in this
// window (0 = just reset, 100 = about to reset). This — not Percent,
// which may hold the plan-quota % — feeds the "next reset" bar so its
// fill always matches the countdown headline.
ResetElapsedPct int
// Empty is true when all token counts are zero (nothing to display).
Empty bool
// SessionCount is the number of sessions that contributed to this row.
// Zero means "not available" (single-project fallback or this session row).
// Positive values are formatted as "(N sessions)" in the display.
SessionCount int
}
UsageWindowRow holds the pre-formatted display strings for one usage time window (session / 5h / weekly). All fields are strings to keep rendering trivial.
type ViewerMode ¶
type ViewerMode int
ViewerMode selects the viewer's interaction model.
Today only ViewerView (read-only) is implemented. ViewerEdit is reserved for a future bubbles/textarea-backed edit experience: 'i' would enter insert from view mode, ':w' would save, ':q' would quit. The field exists now so the dispatcher and the hint bar can branch on it without requiring a refactor when edit lands.
const ( // ViewerView is read-only navigation with vim bindings. ViewerView ViewerMode = iota // ViewerEdit is text editing — placeholder, not wired yet. ViewerEdit )
type ViewerViewport ¶
type ViewerViewport struct {
// contains filtered or unexported fields
}
ViewerViewport wraps the bubbles/v2/viewport model for the file viewer. xOffset is the horizontal scroll position in characters (0 = leftmost column). The bubbles viewport does not natively support horizontal scroll, so the rendering layer applies it manually before styling each line.
func NewViewerViewport ¶
func NewViewerViewport() ViewerViewport
NewViewerViewport constructs an initial ViewerViewport. SoftWrap is OFF: code reads better truncated than wrapped at narrow widths, and predictable one-source-line-per-row scrolling keeps the scrollbar honest.
func (*ViewerViewport) LoadFile ¶
func (v *ViewerViewport) LoadFile(path, cwd string, demoMode bool)
LoadFile loads content for the given file path. In demo mode it uses the mock content table; in live mode it reads from disk. cwd is used to resolve relative paths in live mode.
Source Files
¶
- boot.go
- collapse.go
- config.go
- fileicons.go
- focus.go
- frame.go
- image_render.go
- keymap.go
- keys.go
- kitty_graphics.go
- layout.go
- livedata.go
- livedata_bash.go
- livedata_cache.go
- livedata_calls.go
- livedata_diff.go
- livedata_explorer.go
- livedata_format.go
- livedata_now.go
- livedata_servers.go
- livedata_usage.go
- mascot.go
- mockdata.go
- model.go
- model_commands.go
- model_messages.go
- mouse.go
- panel_bash.go
- panel_cache.go
- panel_calls.go
- panel_common.go
- panel_diff.go
- panel_explorer.go
- panel_explorer_copy.go
- panel_explorer_search.go
- panel_height.go
- panel_help.go
- panel_notification.go
- panel_notification_fullscreen.go
- panel_notification_quota.go
- panel_now.go
- panel_servers.go
- panel_statusbar.go
- panel_titlebar.go
- panel_usage.go
- panel_viewer.go
- render_fullscreen.go
- render_multicol.go
- render_stack.go
- render_stack_2col.go
- render_tabs.go
- session_tabs.go
- settings_overlay.go
- styles.go
- syntax.go
- theme.go
- update.go
- viewer_edit.go
- viewer_edit_commands.go
- viewer_edit_model.go
- viewer_edit_select.go
- viewer_find.go
- viewer_vim.go
- viewport_sync.go