Documentation
¶
Index ¶
- Constants
- Variables
- func ApplyPreferredTheme()
- func PartitionSessionsByRecency(sessions []agent.SessionInfo) (recent, older []agent.SessionInfo)
- func PartitionWorktreesByActivityWindow(worktrees []worktreeNode, cwdLocalPath string) (recent, older []worktreeNode)
- func TimeAgo(t time.Time) string
- type ColorScheme
- type ConnectModel
- type ConnectResult
- type ImportSessionsRequestedMsg
- type InboxModel
- type ProviderAuthCaller
- type SessionPickerModel
- type SessionPickerResult
- type SessionTaskModel
- type SessionViewModel
- func (m *SessionViewModel) DraftText() string
- func (m *SessionViewModel) Init() tea.Cmd
- func (m *SessionViewModel) RestoreDraft(text string)
- func (m *SessionViewModel) SetEventChannel(ch <-chan agent.Event, cancel context.CancelFunc)
- func (m *SessionViewModel) Update(msg tea.Msg) (tea.Model, tea.Cmd)
- func (m *SessionViewModel) View() tea.View
- type SettingsRequestedMsg
- type SidebarModel
- func (m *SidebarModel) AdvanceTitleAnimations()
- func (m *SidebarModel) CursorOnCloud() bool
- func (m *SidebarModel) CursorOnHome() bool
- func (m *SidebarModel) CursorOnImport() bool
- func (m *SidebarModel) CursorOnSettings() bool
- func (m *SidebarModel) CursorWorktreePath() string
- func (m *SidebarModel) Focused() bool
- func (m *SidebarModel) HandleWheel(button tea.MouseButton) bool
- func (m *SidebarModel) Init() tea.Cmd
- func (m *SidebarModel) NodeAtRow(y int) int
- func (m *SidebarModel) SelectedBranchInfo() *host.BranchInfo
- func (m *SidebarModel) SelectedSessionID() string
- func (m *SidebarModel) SetActiveSessionID(id string)
- func (m *SidebarModel) SetCloudSpinnerFrame(frame string)
- func (m *SidebarModel) SetCloudStatus(s cloudAuthStatus)
- func (m *SidebarModel) SetCursor(idx int)
- func (m *SidebarModel) SetExpanded(seed map[string]bool)
- func (m *SidebarModel) SetFocused(focused bool)
- func (m *SidebarModel) SetHomeActive(active bool)
- func (m *SidebarModel) SetSessions(sessions []agent.SessionInfo)
- func (m *SidebarModel) SetSize(width, height int)
- func (m *SidebarModel) SnapshotExpanded() map[string]bool
- func (m *SidebarModel) Update(msg tea.Msg) tea.Cmd
- func (m *SidebarModel) View() string
- type TaskOptions
- type TaskResult
Constants ¶
const MaxRecentSessionsBeforeBucket = 5
MaxRecentSessionsBeforeBucket is how many of the most-recent sessions inside an expanded worktree stay visible before the rest collapse into a per-worktree "+ show more" bucket. Sessions don't follow the week-window worktree rule because a single worktree often accumulates many sessions across multiple days; a count cap keeps the list short.
const RecentWindowDays = 7
RecentWindowDays is the rolling window — anchored on the most-recent worktree's activity — within which a worktree stays visible. Wide enough that creating a fresh session "today" doesn't suddenly hide everything you touched earlier in the week, narrow enough that projects untouched for over a week fall away. If you go heads-down on a single repo for a week, only that one ends up visible — which matches the mental "this is my current focus" model.
Variables ¶
var ErrSessionTaskTimeout = errors.New("agent task timed out")
ErrSessionTaskTimeout classifies an inline task that exceeded its bound.
Functions ¶
func ApplyPreferredTheme ¶
func ApplyPreferredTheme()
ApplyPreferredTheme loads and applies the persisted TUI color scheme. Missing or unreadable preferences use the default scheme.
func PartitionSessionsByRecency ¶
func PartitionSessionsByRecency(sessions []agent.SessionInfo) (recent, older []agent.SessionInfo)
PartitionSessionsByRecency keeps the first MaxRecentSessionsBeforeBucket sessions visible and folds the rest into a per-worktree overflow bucket. Sorted-newest-first input is assumed.
func PartitionWorktreesByActivityWindow ¶
func PartitionWorktreesByActivityWindow(worktrees []worktreeNode, cwdLocalPath string) (recent, older []worktreeNode)
PartitionWorktreesByActivityWindow keeps every worktree whose latest activity sits within RecentWindowDays of the most-recently-active worktree. The cwd's worktree is always kept visible regardless of age — opening the TUI from a folder is the strongest possible signal that you care about whatever sessions live there. Everything else moves into the top-level overflow bucket.
The caller is responsible for having sorted the input by latest activity descending; the head of the slice anchors the window. cwdLocalPath may be empty (no canonical cwd repo resolved); in that case only the window filter applies.
Types ¶
type ColorScheme ¶
type ColorScheme struct {
Name string `json:"name"`
Primary string `json:"primary"`
Secondary string `json:"secondary"`
Success string `json:"success"`
Warning string `json:"warning"`
Danger string `json:"danger"`
Muted string `json:"muted"`
Text string `json:"text"`
Dim string `json:"dim"`
Draft string `json:"draft"`
}
ColorScheme is a named palette. All color fields are hex strings (e.g. "#7C3AED") so the struct is trivially JSON-serializable and easy to read/edit.
type ConnectModel ¶
type ConnectModel struct {
// contains filtered or unexported fields
}
ConnectModel drives `clank connect` end to end.
func NewConnectModel ¶
func NewConnectModel(caller ProviderAuthCaller, backend agent.BackendType) *ConnectModel
NewConnectModel returns the connect program. A non-empty backend jumps straight into that backend's provider flow; an empty one shows the backend picker first.
func (*ConnectModel) Init ¶
func (m *ConnectModel) Init() tea.Cmd
func (*ConnectModel) Result ¶
func (m *ConnectModel) Result() ConnectResult
Result reports what the run achieved. Read after the program exits.
IsConnected comes from the auth flow's own terminal state, not from the message that dismisses it: the credential is written before the success screen appears, so quitting at that screen instead of pressing a key still connected the provider.
func (*ConnectModel) View ¶
func (m *ConnectModel) View() tea.View
View renders inline (no alt screen) so the connect flow stays in the terminal's scrollback alongside whatever ran before it — `clank preview` prints around this.
type ConnectResult ¶
type ConnectResult struct {
Backend agent.BackendType
IsConnected bool
}
ConnectResult is what the CLI reads off the model after the program exits. Backend is set as soon as the user picks one, so a canceled run still reports what they were connecting.
type ImportSessionsRequestedMsg ¶
type ImportSessionsRequestedMsg struct{}
ImportSessionsRequestedMsg is emitted when the user activates the "↓ Import Sessions" footer entry in the sidebar.
type InboxModel ¶
type InboxModel struct {
// contains filtered or unexported fields
}
InboxModel is the top-level Bubble Tea model for the agent inbox. It uses a sidebar + main layout: sidebar shows branches, main area shows sessions. In narrow terminals, only the session pane is shown.
func NewInboxModel ¶
func NewInboxModel(client *daemonclient.Client) *InboxModel
NewInboxModel creates the inbox TUI connected to the given daemon client.
func (*InboxModel) Init ¶
func (m *InboxModel) Init() tea.Cmd
func (*InboxModel) View ¶
func (m *InboxModel) View() tea.View
type ProviderAuthCaller ¶
type ProviderAuthCaller interface {
ListAuthProviders(ctx context.Context, backend agent.BackendType) ([]agent.ProviderAuthInfo, error)
StartAuthDeviceFlow(ctx context.Context, providerID string) (agent.DeviceFlowStart, error)
SubmitAuthAPIKey(ctx context.Context, providerID, key string, metadata map[string]string) (agent.DeviceFlowStart, error)
StartAuthOAuthCodeFlow(ctx context.Context, providerID string) (agent.DeviceFlowStart, error)
SubmitAuthCode(ctx context.Context, providerID, flowID, code string) error
AuthFlowStatus(ctx context.Context, providerID, flowID string) (agent.DeviceFlowStatus, error)
CancelAuthFlow(ctx context.Context, providerID, flowID string) error
}
ProviderAuthCaller is the call surface the modal needs to drive an auth flow against a host. Two implementations exist today:
- daemonclient.HostClient via hub.Host(hostname), used by the Settings entry to target the local clank-host through the hub, and by `clank connect` outside the inbox entirely.
- cloud.AuthCaller, used by the Cloud panel's "Connect provider (in sandbox)" entry to talk directly to the active remote gateway with the user's OAuth bearer.
Mirrors the names on daemonclient.HostClient so existing call sites satisfy the interface without changes.
type SessionPickerModel ¶
type SessionPickerModel struct {
// contains filtered or unexported fields
}
SessionPickerModel drives the attach-session picker end to end.
func NewSessionPickerModel ¶
func NewSessionPickerModel(client *daemonclient.Client, projectDir string) *SessionPickerModel
NewSessionPickerModel returns the picker program. projectDir seeds the rediscover action's backend scan.
func (*SessionPickerModel) Init ¶
func (m *SessionPickerModel) Init() tea.Cmd
func (*SessionPickerModel) Result ¶
func (m *SessionPickerModel) Result() SessionPickerResult
Result reports what the run chose. Read after the program exits.
func (*SessionPickerModel) View ¶
func (m *SessionPickerModel) View() tea.View
type SessionPickerResult ¶
SessionPickerResult is what the CLI reads off the model after the program exits. No SessionID means the user canceled (esc/ctrl+c) and the preview run should stop — --attach was explicit, so there is no silent fall-through to a fresh session.
type SessionTaskModel ¶
type SessionTaskModel struct {
// contains filtered or unexported fields
}
SessionTaskModel is a non-fullscreen, non-composing presentation of the existing session model. It retains the session event and permission paths.
func NewSessionTaskModel ¶
func NewSessionTaskModel(client *daemonclient.Client, sessionID string, options TaskOptions) (*SessionTaskModel, error)
NewSessionTaskModel creates an inline view that exits when one turn settles.
func (*SessionTaskModel) Init ¶
func (m *SessionTaskModel) Init() tea.Cmd
func (*SessionTaskModel) Result ¶
func (m *SessionTaskModel) Result() TaskResult
Result returns the terminal status after the program exits.
func (*SessionTaskModel) SetEventChannel ¶
func (m *SessionTaskModel) SetEventChannel(ch <-chan agent.Event, cancel context.CancelFunc)
SetEventChannel provides the same race-free preconnected event stream used by the full session view.
func (*SessionTaskModel) View ¶
func (m *SessionTaskModel) View() tea.View
type SessionViewModel ¶
type SessionViewModel struct {
// contains filtered or unexported fields
}
SessionViewModel shows a single agent session with streaming output. It also handles the "composing" mode where no session exists yet — the user types their first prompt and the session is created on send.
func NewSessionViewComposing ¶
func NewSessionViewComposing(client *daemonclient.Client, projectDir string) *SessionViewModel
NewSessionViewComposing creates a SessionViewModel in composing mode. No daemon session exists yet — the user writes their first prompt here.
The gitRef is built from projectDir (LocalPath) plus the stamped worktree ID, if any (read via agent.ReadLocalWorktreeID), so the on-demand config-options probe can target it. Without a stamp the ref is local-only and any cross-host operations will fail at launch.
func NewSessionViewModel ¶
func NewSessionViewModel(client *daemonclient.Client, sessionID string) *SessionViewModel
NewSessionViewModel creates a session detail TUI for an existing session.
func (*SessionViewModel) DraftText ¶
func (m *SessionViewModel) DraftText() string
DraftText returns the current unsent text in the input textarea.
func (*SessionViewModel) Init ¶
func (m *SessionViewModel) Init() tea.Cmd
func (*SessionViewModel) RestoreDraft ¶
func (m *SessionViewModel) RestoreDraft(text string)
RestoreDraft sets the textarea content to the given draft text and activates the input so the user can continue typing immediately.
func (*SessionViewModel) SetEventChannel ¶
func (m *SessionViewModel) SetEventChannel(ch <-chan agent.Event, cancel context.CancelFunc)
SetEventChannel provides a pre-connected SSE event channel and cancel func. When set, Init() skips subscribing and immediately starts reading events. This avoids the race where CreateSession emits events before the TUI subscribes.
func (*SessionViewModel) View ¶
func (m *SessionViewModel) View() tea.View
type SettingsRequestedMsg ¶
type SettingsRequestedMsg struct{}
SettingsRequestedMsg is emitted by the inbox when the user activates the "⚙ Settings" footer entry in the sidebar.
type SidebarModel ¶
type SidebarModel struct {
// contains filtered or unexported fields
}
SidebarModel renders the sidebar tree and tracks cursor/expand state.
func NewSidebarModel ¶
func NewSidebarModel(client *daemonclient.Client, hostname string, gitRef agent.GitRef, projectDir string) SidebarModel
NewSidebarModel creates a sidebar for the given repo identity. projectDir is retained for display purposes only.
func (*SidebarModel) AdvanceTitleAnimations ¶
func (m *SidebarModel) AdvanceTitleAnimations()
AdvanceTitleAnimations steps every active typewriter forward by titleAnimationCharsPerTick runes. Completed animations are dropped so subsequent frames render the full title without the cursor glyph. Cheap to call every spinner tick even when nothing is animating.
func (*SidebarModel) CursorOnCloud ¶
func (m *SidebarModel) CursorOnCloud() bool
CursorOnCloud reports whether the cursor is on the cloud row.
func (*SidebarModel) CursorOnHome ¶
func (m *SidebarModel) CursorOnHome() bool
CursorOnHome reports whether the cursor is on the Home entry.
func (*SidebarModel) CursorOnImport ¶
func (m *SidebarModel) CursorOnImport() bool
CursorOnImport reports whether the cursor is on the import row.
func (*SidebarModel) CursorOnSettings ¶
func (m *SidebarModel) CursorOnSettings() bool
CursorOnSettings reports whether the cursor is on the settings row.
func (*SidebarModel) CursorWorktreePath ¶
func (m *SidebarModel) CursorWorktreePath() string
CursorWorktreePath returns the LocalPath of the worktree the cursor is currently on (or whose session the cursor is on). Empty means the cursor isn't anywhere worktree-shaped (Older buckets, footer rows). Callers fall back to the cwd's worktree in that case.
Used by the unified "n" gesture to prefill the compose view's target worktree from context.
func (*SidebarModel) Focused ¶
func (m *SidebarModel) Focused() bool
Focused reports whether the sidebar has keyboard focus.
func (*SidebarModel) HandleWheel ¶
func (m *SidebarModel) HandleWheel(button tea.MouseButton) bool
HandleWheel moves the sidebar cursor by one row in the direction of the wheel button, clamped to the list bounds. Returns whether the cursor actually moved.
Wheel scroll moves cursor by 1 row per tick (matching modelpicker's list semantics), independent of the chat's wheelScrollLines step size — sidebar rows are taller and a per-tick row move keeps the gesture predictable. No wraparound: wheel scroll past the ends stops, while keyboard up/down (handleKey) wraps because that's an explicit gesture.
func (*SidebarModel) Init ¶
func (m *SidebarModel) Init() tea.Cmd
Init is a no-op; the sidebar is populated via SetSessions.
func (*SidebarModel) NodeAtRow ¶
func (m *SidebarModel) NodeAtRow(y int) int
NodeAtRow maps a sidebar-local screen row (mouse Y — the sidebar occupies the left columns starting at row 0) to the flat node index rendered there, or -1 when the row is a border / blank / separator or out of range. Reads the map cached by the last View().
func (*SidebarModel) SelectedBranchInfo ¶
func (m *SidebarModel) SelectedBranchInfo() *host.BranchInfo
SelectedBranchInfo always returns nil; merge overlay disabled until sessions carry git branch metadata.
func (*SidebarModel) SelectedSessionID ¶
func (m *SidebarModel) SelectedSessionID() string
SelectedSessionID returns the session id under the cursor, or "" when the cursor isn't on a session row.
func (*SidebarModel) SetActiveSessionID ¶
func (m *SidebarModel) SetActiveSessionID(id string)
SetActiveSessionID stamps the session currently rendered in the right pane. The sidebar uses it to paint a left-edge rail next to that session's row, so the user can see "what's open" independent of where their arrow-key cursor sits. Pass "" to clear.
func (*SidebarModel) SetCloudSpinnerFrame ¶
func (m *SidebarModel) SetCloudSpinnerFrame(frame string)
SetCloudSpinnerFrame feeds the current spinner glyph from the inbox.
func (*SidebarModel) SetCloudStatus ¶
func (m *SidebarModel) SetCloudStatus(s cloudAuthStatus)
SetCloudStatus updates the cloud connection indicator shown next to the "☁ Cloud" footer row.
func (*SidebarModel) SetCursor ¶
func (m *SidebarModel) SetCursor(idx int)
SetCursor moves the cursor to the given flat index, clamped to the list. Used by mouse-click selection to jump straight to a row.
func (*SidebarModel) SetExpanded ¶
func (m *SidebarModel) SetExpanded(seed map[string]bool)
SetExpanded seeds the persisted user-toggle map (e.g. from Preferences.SidebarExpanded). Older buckets always start collapsed regardless of what was persisted — see sanitizeExpanded for the reset rules. Auto-defaults (visible worktrees auto-expand) are applied during rebuildFlat, not stored here. Safe to call before SetSessions.
func (*SidebarModel) SetFocused ¶
func (m *SidebarModel) SetFocused(focused bool)
SetFocused sets whether the sidebar has keyboard focus.
func (*SidebarModel) SetHomeActive ¶
func (m *SidebarModel) SetHomeActive(active bool)
SetHomeActive marks whether the welcome/home screen is the one currently shown in the right pane. The sidebar uses it to keep the Home row highlighted (via a left-edge rail) even when the sidebar itself is unfocused, mirroring the active-session rail.
func (*SidebarModel) SetSessions ¶
func (m *SidebarModel) SetSessions(sessions []agent.SessionInfo)
SetSessions rebuilds the tree from the provided sessions. Cached so toggle operations can re-flatten without re-fetching.
func (*SidebarModel) SetSize ¶
func (m *SidebarModel) SetSize(width, height int)
SetSize sets the sidebar dimensions.
func (*SidebarModel) SnapshotExpanded ¶
func (m *SidebarModel) SnapshotExpanded() map[string]bool
SnapshotExpanded returns a shallow copy of the explicit user toggle map. Auto-defaults (visible worktrees) are deliberately NOT included — they're computed every launch, persisting them would make a future default change invisible to existing users.
func (*SidebarModel) Update ¶
func (m *SidebarModel) Update(msg tea.Msg) tea.Cmd
Update handles messages for the sidebar.
func (*SidebarModel) View ¶
func (m *SidebarModel) View() string
View renders the sidebar by emitting one or more terminal rows per sidebarNode. Worktree and bucket rows render on a single line; session rows render on two (title + relative time). The cursor's row is highlighted with the standard "> " selection prefix.
type TaskOptions ¶
TaskOptions defines the bounded inline presentation for one agent turn.
type TaskResult ¶
type TaskResult struct {
Status agent.SessionStatus
Err error
}
TaskResult describes why an inline session task stopped.
Source Files
¶
- actionmenu.go
- breakpoints.go
- clipimg_other.go
- cloud_status.go
- cloudurl_picker.go
- cloudview.go
- confirmdialog.go
- connect.go
- folderpicker.go
- importsessions.go
- inbox.go
- inbox_cloud.go
- inbox_settings.go
- inbox_sse.go
- keys.go
- markdown.go
- mergeoverlay.go
- modelpicker.go
- nativecli.go
- overlay.go
- providerauth.go
- selection.go
- session_task.go
- session_task_view.go
- sessionpicker.go
- sessionrow.go
- sessions_cache.go
- sessionview.go
- sessionview_attachments.go
- sessionview_compose.go
- sessionview_compose_focus.go
- sessionview_paging.go
- settingsview.go
- sidebar.go
- sidebar_flatten.go
- sidebar_grouping.go
- sidebar_mouse.go
- sidebar_navigate.go
- sidebar_node.go
- sidebar_render.go
- sidebar_title_animation.go
- sidebar_tree.go
- statusicon.go
- styles.go
- theme.go
- theme_schemes.go
- themepicker.go
- voice.go
- welcome_actions.go
- worktreepicker.go