Documentation
¶
Overview ¶
Package conversations provides the content search functionality for cross-conversation search (searching message content across sessions).
Package conversations provides content search execution for cross-conversation search.
Package conversations provides content search keyboard handling for cross-conversation search (td-6ac70a).
Package conversations provides the content search modal UI for cross-conversation search (searching message content across sessions).
Package conversations implements a multi-pane session and message viewer with search, filtering, pagination, content export, and per-session analytics.
Index ¶
- Constants
- func CopyToClipboard(content string) error
- func ExportSessionAsMarkdown(session *adapter.Session, messages []adapter.Message) string
- func ExportSessionToFile(session *adapter.Session, messages []adapter.Message, workDir string) (string, error)
- func RunContentSearch(query string, sessions []adapter.Session, adapters map[string]adapter.Adapter, ...) tea.Cmd
- func UpdateSessionSummary(summary *SessionSummary, newMessages []adapter.Message, ...)
- type AdapterBatchMsg
- type CoalescedRefreshMsg
- type ContentSearchDebounceMsg
- type ContentSearchResultsMsg
- type ContentSearchState
- func (s *ContentSearchState) ClampCursor()
- func (s *ContentSearchState) CollapseAll()
- func (s *ContentSearchState) EnsureCursorVisible(viewportHeight int)
- func (s *ContentSearchState) ExpandAll()
- func (s *ContentSearchState) FirstMatchInSession(sessionIdx int) int
- func (s *ContentSearchState) FlatItem(idx int) (sessionIdx, msgIdx, matchIdx int, isSession, isMessage bool)
- func (s *ContentSearchState) FlatLen() int
- func (s *ContentSearchState) GetSelectedResult() (*adapter.Session, *adapter.MessageMatch, *adapter.ContentMatch)
- func (s *ContentSearchState) MoveToSession()
- func (s *ContentSearchState) NextMatchIndex(from int) int
- func (s *ContentSearchState) PrevMatchIndex(from int) int
- func (s *ContentSearchState) Reset()
- func (s *ContentSearchState) SessionCount() int
- func (s *ContentSearchState) ToggleCollapse() bool
- func (s *ContentSearchState) TotalMatches() int
- type DateRange
- type ErrorMsg
- type EventCoalescer
- func (c *EventCoalescer) Add(sessionID string, epoch uint64)
- func (c *EventCoalescer) ShouldAutoReload(sessionID string) bool
- func (c *EventCoalescer) Stop()
- func (c *EventCoalescer) UpdateSessionSize(sessionID string, size int64)
- func (c *EventCoalescer) UpdateSessionSizes(sessions []adapter.Session)
- type FocusPane
- type GlamourRenderer
- type GroupSummary
- type LoadSettledMsg
- type LoadingStartedMsg
- type MessageReloadMsg
- type MessagesLoadedMsg
- type Plugin
- func (p *Plugin) Commands() []plugin.Command
- func (p *Plugin) ConsumesTextInput() bool
- func (p *Plugin) Diagnostics() []plugin.Diagnostic
- func (p *Plugin) FocusContext() string
- func (p *Plugin) ID() string
- func (p *Plugin) Icon() string
- func (p *Plugin) Init(ctx *plugin.Context) error
- func (p *Plugin) IsFocused() bool
- func (p *Plugin) Name() string
- func (p *Plugin) SetFocused(f bool)
- func (p *Plugin) Start() tea.Cmd
- func (p *Plugin) Stop()
- func (p *Plugin) Update(msg tea.Msg) (plugin.Plugin, tea.Cmd)
- func (p *Plugin) View(width, height int) string
- type PreviewLoadMsg
- type SearchFilters
- func (f *SearchFilters) HasAdapter(adapterID string) bool
- func (f *SearchFilters) HasCategory(cat string) bool
- func (f *SearchFilters) HasModel(model string) bool
- func (f *SearchFilters) IsActive() bool
- func (f *SearchFilters) Matches(session adapter.Session) bool
- func (f *SearchFilters) SetDateRange(preset string)
- func (f *SearchFilters) String() string
- func (f *SearchFilters) ToggleAdapter(adapterID string)
- func (f *SearchFilters) ToggleCategory(cat string)
- func (f *SearchFilters) ToggleModel(model string)
- type SessionGroup
- type SessionSearchResult
- type SessionSummary
- type SessionsLoadedMsg
- type SessionsRefreshedMsg
- type Turn
- type View
- type WatchEventMsg
- type WatchStartedMsg
Constants ¶
const ( // Hybrid content display thresholds ShortMessageCharLimit = 500 // Messages shorter than this display inline ShortMessageLineLimit = 13 // Messages with fewer lines display inline CollapsedPreviewChars = 300 // Preview length for collapsed messages )
Variables ¶
This section is empty.
Functions ¶
func CopyToClipboard ¶
CopyToClipboard copies content to the system clipboard.
func ExportSessionAsMarkdown ¶
ExportSessionAsMarkdown converts a session and its messages to markdown format.
func ExportSessionToFile ¶
func ExportSessionToFile(session *adapter.Session, messages []adapter.Message, workDir string) (string, error)
ExportSessionToFile writes a session to a markdown file.
func RunContentSearch ¶
func RunContentSearch(query string, sessions []adapter.Session, adapters map[string]adapter.Adapter, opts adapter.SearchOptions, epoch uint64) tea.Cmd
RunContentSearch executes search across all sessions using their adapters. Returns a tea.Cmd that produces ContentSearchResultsMsg when complete. Search runs in parallel with concurrency limit, timeout, and match cap. Performance optimizations (td-80cbe1):
- Concurrency scales with CPU count
- Sessions sorted by UpdatedAt (recent first for early results)
- Empty sessions skipped
func UpdateSessionSummary ¶
func UpdateSessionSummary(summary *SessionSummary, newMessages []adapter.Message, modelCounts map[string]int, fileSet map[string]bool)
UpdateSessionSummary incrementally updates an existing summary with new messages. It avoids re-scanning all messages by only processing the new ones. Note: primary model may change if new messages use a different model more frequently.
Types ¶
type AdapterBatchMsg ¶
type AdapterBatchMsg struct {
Epoch uint64
Sessions []adapter.Session
Final bool // true when all adapters are done
WorktreePaths []string
WorktreeNames map[string]string
}
AdapterBatchMsg delivers sessions from a single adapter incrementally (td-7198a5).
func (AdapterBatchMsg) GetEpoch ¶
func (m AdapterBatchMsg) GetEpoch() uint64
GetEpoch implements plugin.EpochMessage.
type CoalescedRefreshMsg ¶
type CoalescedRefreshMsg struct {
Epoch uint64 // Epoch when request was issued (for stale detection)
SessionIDs []string // Specific sessions to refresh (if not RefreshAll)
RefreshAll bool // If true, ignore SessionIDs and do full refresh
}
CoalescedRefreshMsg is sent when the coalesce window closes.
func (CoalescedRefreshMsg) GetEpoch ¶
func (m CoalescedRefreshMsg) GetEpoch() uint64
GetEpoch implements plugin.EpochMessage.
type ContentSearchDebounceMsg ¶
type ContentSearchDebounceMsg struct {
Version int // Must match DebounceVersion to be valid
Query string // Query to search for
}
ContentSearchDebounceMsg is sent after debounce delay to trigger search.
type ContentSearchResultsMsg ¶
type ContentSearchResultsMsg struct {
Epoch uint64 // Epoch when request was issued (for stale detection)
Results []SessionSearchResult // Search results by session
Error error // Error if search failed
Query string // The query these results are for (td-5b9928)
TotalMatches int // Total matches found before truncation (td-8e1a2b)
Truncated bool // True if results were truncated (td-8e1a2b)
}
ContentSearchResultsMsg carries search results back to the plugin.
func (ContentSearchResultsMsg) GetEpoch ¶
func (m ContentSearchResultsMsg) GetEpoch() uint64
GetEpoch implements plugin.EpochMessage.
type ContentSearchState ¶
type ContentSearchState struct {
Query string // Current search query
Results []SessionSearchResult // Sessions with matching messages
UseRegex bool // Treat query as regex
CaseSensitive bool // Case-sensitive matching
Cursor int // Flat index into hierarchical results
ScrollOffset int // Scroll offset for viewport
IsSearching bool // True while search is in progress
Error string // Error message if search failed
DebounceVersion int // For debouncing search requests
TotalFound int // Total matches found before truncation (td-8e1a2b)
Truncated bool // True if results were truncated (td-8e1a2b)
Skeleton ui.Skeleton // Animated skeleton loader for search in progress (td-e740e4)
}
ContentSearchState holds cross-conversation search state.
func NewContentSearchState ¶
func NewContentSearchState() *ContentSearchState
NewContentSearchState creates a new content search state with defaults.
func (*ContentSearchState) ClampCursor ¶
func (s *ContentSearchState) ClampCursor()
ClampCursor ensures cursor is within valid bounds.
func (*ContentSearchState) CollapseAll ¶
func (s *ContentSearchState) CollapseAll()
CollapseAll collapses all sessions.
func (*ContentSearchState) EnsureCursorVisible ¶
func (s *ContentSearchState) EnsureCursorVisible(viewportHeight int)
EnsureCursorVisible adjusts ScrollOffset to ensure the cursor is visible. viewportHeight is the number of visible rows.
func (*ContentSearchState) ExpandAll ¶
func (s *ContentSearchState) ExpandAll()
ExpandAll expands all sessions.
func (*ContentSearchState) FirstMatchInSession ¶
func (s *ContentSearchState) FirstMatchInSession(sessionIdx int) int
FirstMatchInSession returns the flat index of the first match in the given session. Returns -1 if session is collapsed or has no matches.
func (*ContentSearchState) FlatItem ¶
func (s *ContentSearchState) FlatItem(idx int) (sessionIdx, msgIdx, matchIdx int, isSession, isMessage bool)
FlatItem maps a flat index to the hierarchical position. Returns (sessionIdx, msgIdx, matchIdx, isSession, isMessage). - If isSession is true, this is a session row (msgIdx and matchIdx are -1). - If isMessage is true, this is a message row (matchIdx is -1). - Otherwise, this is a match row. Returns (-1, -1, -1, false, false) if idx is out of range.
func (*ContentSearchState) FlatLen ¶
func (s *ContentSearchState) FlatLen() int
FlatLen returns the total number of items in the flattened view. The hierarchy is: Session -> Message -> Match When a session is collapsed, its messages and matches are hidden.
func (*ContentSearchState) GetSelectedResult ¶
func (s *ContentSearchState) GetSelectedResult() (*adapter.Session, *adapter.MessageMatch, *adapter.ContentMatch)
GetSelectedResult returns the currently selected item based on cursor position. Returns (session, messageMatch, contentMatch) where some may be nil depending on selection type: - Session row: session is set, others are nil - Message row: session and messageMatch are set, contentMatch is nil - Match row: all three are set Returns (nil, nil, nil) if cursor is out of range.
func (*ContentSearchState) MoveToSession ¶
func (s *ContentSearchState) MoveToSession()
MoveToSession moves the cursor to the session containing the current selection. Useful for navigating "up" in the hierarchy.
func (*ContentSearchState) NextMatchIndex ¶
func (s *ContentSearchState) NextMatchIndex(from int) int
NextMatchIndex finds the next actual match (not session or message row) from the given index. Returns the flat index of the next match, or -1 if none found.
func (*ContentSearchState) PrevMatchIndex ¶
func (s *ContentSearchState) PrevMatchIndex(from int) int
PrevMatchIndex finds the previous actual match (not session or message row) from the given index. Returns the flat index of the previous match, or -1 if none found.
func (*ContentSearchState) Reset ¶
func (s *ContentSearchState) Reset()
Reset clears the search state.
func (*ContentSearchState) SessionCount ¶
func (s *ContentSearchState) SessionCount() int
SessionCount returns the number of sessions with matches.
func (*ContentSearchState) ToggleCollapse ¶
func (s *ContentSearchState) ToggleCollapse() bool
ToggleCollapse toggles the collapsed state of the session at the current cursor. Returns true if toggle was performed (cursor was on a session row).
func (*ContentSearchState) TotalMatches ¶
func (s *ContentSearchState) TotalMatches() int
TotalMatches returns the total count of content matches across all results.
type DateRange ¶
type DateRange struct {
Preset string // "today", "yesterday", "week", "month", "all"
Start time.Time // For custom range
End time.Time
}
DateRange represents a date range filter.
type EventCoalescer ¶
type EventCoalescer struct {
// contains filtered or unexported fields
}
EventCoalescer batches rapid watch events into single refreshes. When events arrive faster than the coalesce window, they are accumulated and a single refresh is triggered after the window closes. td-190095: Uses dynamic window based on largest pending session's size.
func NewEventCoalescer ¶
func NewEventCoalescer(window time.Duration, msgChan chan<- CoalescedRefreshMsg) *EventCoalescer
NewEventCoalescer creates a coalescer with the given window duration. msgChan receives CoalescedRefreshMsg when the coalesce window closes.
func (*EventCoalescer) Add ¶
func (c *EventCoalescer) Add(sessionID string, epoch uint64)
Add queues a sessionID for refresh. Empty string triggers full refresh. Uses dynamic window based on largest pending session (td-190095). The epoch parameter tracks the project context for stale detection.
func (*EventCoalescer) ShouldAutoReload ¶
func (c *EventCoalescer) ShouldAutoReload(sessionID string) bool
ShouldAutoReload returns whether auto-reload is enabled for a session. Sessions larger than HugeSessionThreshold (500MB) disable auto-reload.
func (*EventCoalescer) Stop ¶
func (c *EventCoalescer) Stop()
Stop cancels any pending flush. Call when plugin is shutting down.
func (*EventCoalescer) UpdateSessionSize ¶
func (c *EventCoalescer) UpdateSessionSize(sessionID string, size int64)
UpdateSessionSize records the file size for a session (td-190095). Call this after loading sessions to enable dynamic debounce.
func (*EventCoalescer) UpdateSessionSizes ¶
func (c *EventCoalescer) UpdateSessionSizes(sessions []adapter.Session)
UpdateSessionSizes updates sizes for multiple sessions at once.
type GlamourRenderer ¶
GlamourRenderer is an alias to the shared markdown renderer.
func NewGlamourRenderer ¶
func NewGlamourRenderer() (*GlamourRenderer, error)
NewGlamourRenderer creates a new renderer instance.
type GroupSummary ¶
GroupSummary holds aggregate stats for a session group.
type LoadSettledMsg ¶
type LoadSettledMsg struct {
Token int // Must match loadSettleToken to be valid
}
LoadSettledMsg signals that session loading has settled (no new arrivals).
type LoadingStartedMsg ¶
type LoadingStartedMsg struct {
Epoch uint64
}
LoadingStartedMsg signals that adapter goroutines have been launched (td-7198a5).
func (LoadingStartedMsg) GetEpoch ¶
func (m LoadingStartedMsg) GetEpoch() uint64
GetEpoch implements plugin.EpochMessage.
type MessageReloadMsg ¶
type MessageReloadMsg struct {
Epoch uint64 // Epoch when request was issued (for stale detection)
Token int
SessionID string
}
func (MessageReloadMsg) GetEpoch ¶
func (m MessageReloadMsg) GetEpoch() uint64
GetEpoch implements plugin.EpochMessage.
type MessagesLoadedMsg ¶
type MessagesLoadedMsg struct {
Epoch uint64 // Epoch when request was issued (for stale detection)
SessionID string
Messages []adapter.Message
TotalCount int // Total message count before truncation (td-313ea851)
Offset int // Offset into the message list (td-313ea851)
}
func (MessagesLoadedMsg) GetEpoch ¶
func (m MessagesLoadedMsg) GetEpoch() uint64
GetEpoch implements plugin.EpochMessage.
type Plugin ¶
type Plugin struct {
// contains filtered or unexported fields
}
Plugin implements the conversations plugin.
func (*Plugin) ConsumesTextInput ¶
ConsumesTextInput reports whether conversation UI currently has a focused text-entry flow where app shortcuts should not intercept characters.
func (*Plugin) Diagnostics ¶
func (p *Plugin) Diagnostics() []plugin.Diagnostic
Diagnostics returns plugin health info.
func (*Plugin) FocusContext ¶
FocusContext returns the current focus context.
type PreviewLoadMsg ¶
type PreviewLoadMsg struct {
Epoch uint64 // Epoch when request was issued (for stale detection)
Token int
SessionID string
}
func (PreviewLoadMsg) GetEpoch ¶
func (m PreviewLoadMsg) GetEpoch() uint64
GetEpoch implements plugin.EpochMessage.
type SearchFilters ¶
type SearchFilters struct {
Query string // Text search
Adapters []string // ["claude-code", "codex"]
Models []string // ["opus", "sonnet", "haiku"]
Categories []string // ["interactive", "cron", "system"]
DateRange DateRange // today, week, custom
MinTokens int // Sessions with > N tokens
MaxTokens int // Sessions with < N tokens
ActiveOnly bool // Only currently active
HasFiles []string // Sessions that touched these files
}
SearchFilters holds multi-dimensional filter criteria.
func (*SearchFilters) HasAdapter ¶
func (f *SearchFilters) HasAdapter(adapterID string) bool
HasAdapter returns true if the adapter is in the filter list.
func (*SearchFilters) HasCategory ¶
func (f *SearchFilters) HasCategory(cat string) bool
HasCategory returns true if the category is in the filter list.
func (*SearchFilters) HasModel ¶
func (f *SearchFilters) HasModel(model string) bool
HasModel returns true if the model is in the filter list.
func (*SearchFilters) IsActive ¶
func (f *SearchFilters) IsActive() bool
IsActive returns true if any filter is active.
func (*SearchFilters) Matches ¶
func (f *SearchFilters) Matches(session adapter.Session) bool
Matches checks if a session matches all filter criteria.
func (*SearchFilters) SetDateRange ¶
func (f *SearchFilters) SetDateRange(preset string)
SetDateRange sets the date range preset.
func (*SearchFilters) String ¶
func (f *SearchFilters) String() string
String formats active filters for display.
func (*SearchFilters) ToggleAdapter ¶
func (f *SearchFilters) ToggleAdapter(adapterID string)
ToggleAdapter toggles an adapter in the filter list.
func (*SearchFilters) ToggleCategory ¶
func (f *SearchFilters) ToggleCategory(cat string)
ToggleCategory toggles a category in the filter list.
func (*SearchFilters) ToggleModel ¶
func (f *SearchFilters) ToggleModel(model string)
ToggleModel toggles a model in the filter list.
type SessionGroup ¶
type SessionGroup struct {
Label string // "Today", "Yesterday", "This Week", "Older"
Sessions []adapter.Session // Sessions in this group
Summary GroupSummary // Aggregate stats
}
SessionGroup represents a group of sessions by time period.
func GroupSessionsByTime ¶
func GroupSessionsByTime(sessions []adapter.Session) []SessionGroup
GroupSessionsByTime organizes sessions into time-based groups.
type SessionSearchResult ¶
type SessionSearchResult struct {
Session adapter.Session // The session containing matches
Messages []adapter.MessageMatch // Messages with matches (from adapter search)
Collapsed bool // True if session is collapsed in view
}
SessionSearchResult represents a session with matching messages.
type SessionSummary ¶
type SessionSummary struct {
FilesTouched []string // Unique files from tool uses
FileCount int // Number of unique files
TotalTokensIn int // Sum of input tokens
TotalTokensOut int // Sum of output tokens
TotalCacheRead int // Sum of cache read tokens
TotalCacheWrite int // Sum of cache write tokens
TotalCost float64 // Estimated cost in dollars
Duration time.Duration // Session duration
PrimaryModel string // Most used model
MessageCount int // Total messages
ToolCounts map[string]int // Tool name -> count
}
SessionSummary holds aggregated statistics for a session.
func ComputeSessionSummary ¶
func ComputeSessionSummary(messages []adapter.Message, duration time.Duration) SessionSummary
ComputeSessionSummary aggregates statistics from messages.
type SessionsLoadedMsg ¶
type SessionsLoadedMsg struct {
Epoch uint64 // Epoch when request was issued (for stale detection)
Sessions []adapter.Session
// Worktree cache data (td-0e43c080: computed in cmd, stored in Update)
WorktreePaths []string
WorktreeNames map[string]string
}
Message types
func (SessionsLoadedMsg) GetEpoch ¶
func (m SessionsLoadedMsg) GetEpoch() uint64
GetEpoch implements plugin.EpochMessage.
type SessionsRefreshedMsg ¶
type SessionsRefreshedMsg struct {
Epoch uint64
Refreshed []adapter.Session // Only the sessions that were successfully refreshed
}
SessionsRefreshedMsg carries only refreshed sessions as a delta update. Unlike SessionsLoadedMsg which replaces the entire session list, this merges into the current list to avoid overwriting concurrent updates from loadSessions.
func (SessionsRefreshedMsg) GetEpoch ¶
func (m SessionsRefreshedMsg) GetEpoch() uint64
GetEpoch implements plugin.EpochMessage.
type Turn ¶
type Turn struct {
Role string // "user" or "assistant"
Messages []adapter.Message // All messages in this turn
StartIndex int // Index of first message in original slice
TotalTokensIn int // Sum of input tokens
TotalTokensOut int // Sum of output tokens
ThinkingTokens int // Sum of thinking block tokens
ToolCount int // Number of tool uses
}
Turn represents a sequence of consecutive messages from the same role. In Claude Code, a single "turn" may contain multiple JSONL messages: - User turn: system reminders, command output, actual user text - Assistant turn: thinking blocks, tool calls, text responses
func AppendMessagesToTurns ¶
AppendMessagesToTurns incrementally adds new messages to existing turns. It handles the case where the first new message may extend the last turn. Returns the updated turns slice (may modify the last element in place).
func GroupMessagesIntoTurns ¶
GroupMessagesIntoTurns groups consecutive messages by role into turns.
func (*Turn) FirstTimestamp ¶
FirstTimestamp returns the timestamp of the first message in the turn.
type WatchEventMsg ¶
type WatchEventMsg struct {
Epoch uint64 // Epoch when request was issued (for stale detection)
SessionID string // ID of the session that changed (empty for periodic refresh)
}
func (WatchEventMsg) GetEpoch ¶
func (m WatchEventMsg) GetEpoch() uint64
GetEpoch implements plugin.EpochMessage.