Documentation
¶
Index ¶
- Constants
- Variables
- func CommandPaletteCategoryBadge(category string) string
- func CommandPaletteIdleBadge(needsIdle bool) string
- func CommandPaletteKindBadge(kind string) string
- func DrawBox(lines []string, innerWidth, fixedRows int) string
- func FormatProgressLine(progress *agentcore.ProgressPayload) string
- func FormatSubagentOutput(result json.RawMessage) string
- func FormatTokens(n int) string
- func FormatToolArgs(args json.RawMessage) string
- func FormatToolHeader(tool string, args json.RawMessage) string
- func FormatToolOutput(text string, maxVisible int, styles ...lipgloss.Style) string
- func FormatToolResult(result json.RawMessage, isError bool) string
- func RenderEditResult(result json.RawMessage) string
- func RenderLsResult(result json.RawMessage) (dirPath string, body string)
- func RenderReadResult(result json.RawMessage) string
- func RenderReadSummary(result json.RawMessage) string
- func RenderStreamingOutput(full string, maxLines int) string
- func RenderToolHeader(tool string, args json.RawMessage) string
- func RenderWriteResult(result json.RawMessage) string
- func SendCommandResult(text string) tea.Cmd
- func TasksTickCmd() tea.Cmd
- func TruncateLines(s string, maxLines int) string
- type AgentEventMsg
- type AskUserMsg
- type BtwResultMsg
- type CommandResultMsg
- type CompletionItem
- type Config
- type Deps
- type Driver
- type HideCompletedTasksMsg
- type ImageAttachedMsg
- type InfoOverlayFrame
- type InfoOverlayTab
- type InfoPanel
- type MCPReadyMsg
- type Model
- func (m *Model) Emit(body string) tea.Cmd
- func (m *Model) HandleAgentEvent(ev agentcore.Event) (tea.Model, tea.Cmd)
- func (m *Model) Init() tea.Cmd
- func (m *Model) RenderContextBar() string
- func (m *Model) RenderMarkdown(content string) string
- func (m *Model) RenderPlanBar() string
- func (m *Model) RenderPromptOutput(text string) string
- func (m *Model) RenderStatusBar() string
- func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd)
- func (m *Model) View() string
- type OverlayState
- type PasteErrorMsg
- type PasteTextMsg
- type PermissionDismissMsg
- type PermissionMsg
- type PermitChoice
- type PlanBarInfo
- type PromptMsg
- type RestoreMsg
- type RetryStatusMsg
- type State
- type SuggestionMsg
- type TaskListUpdateMsg
- type TasksRefreshMsg
Constants ¶
const ( // MaxInputLines caps the textarea height when the user types multiple lines. MaxInputLines = 8 // PaletteMaxVisible caps simultaneously visible slash-command suggestions. PaletteMaxVisible = 8 // ToolResultMaxLines caps how many lines of a tool result are shown in scrollback // before collapsing into "… +N lines". ToolResultMaxLines = 5 // ToolStreamTailLines is the window (in lines) kept visible while a tool streams // live output in the bottom-pinned area. ToolStreamTailLines = 8 )
const ConnectorPad = " "
ConnectorPad matches TreeConnector's width (3 cells) for continuation lines.
const TreeConnector = "⎿ "
TreeConnector is the Claude-Code-style result connector: U+23BF (⎿) plus two spaces for wide, legible alignment under the tool header.
Variables ¶
var ( // Bullet — green for successful tool call, red for failure, à la Claude Code. ToolIconStyle = lipgloss.NewStyle().Foreground(Success) ErrorIconStyle = lipgloss.NewStyle().Foreground(Danger) // Tool name — bold only, default foreground. Lets terminal theme show through. ToolNameStyle = lipgloss.NewStyle().Bold(true) // Tool args and result body intentionally carry no color — they inherit the // terminal's default foreground so the user's theme stays in charge. ToolArgsStyle = lipgloss.NewStyle() ToolResultStyle = lipgloss.NewStyle() ToolPathStyle = lipgloss.NewStyle().Foreground(Path) )
var ( // Assistant bullet — pure white on dark / pure black on light, bold. // Uses Strong rather than the terminal default so contrast against the // Subtle-gray thinking bullet is guaranteed under any terminal palette. AssistantIconStyle = lipgloss.NewStyle().Foreground(Strong).Bold(true) // Thinking bullet — dim gray, same family as the italic thinking body. ThinkingIconStyle = lipgloss.NewStyle().Foreground(Subtle) ThinkingBodyStyle = lipgloss.NewStyle().Foreground(Subtle).Italic(true) ReplyLabelStyle = lipgloss.NewStyle().Foreground(RoleAssistant) SystemMsgStyle = lipgloss.NewStyle().Foreground(Muted).Italic(true) QueuedMsgStyle = lipgloss.NewStyle().Foreground(Muted).Italic(true) )
var ( ErrorStyle = lipgloss.NewStyle().Foreground(Danger).Bold(true) CommandStyle = lipgloss.NewStyle().Foreground(Info) MutedStyle = lipgloss.NewStyle().Foreground(Muted) TokenStyle = lipgloss.NewStyle().Foreground(Muted) )
var ( DiffAddStyle = lipgloss.NewStyle().Foreground(Success) DiffRemoveStyle = lipgloss.NewStyle().Foreground(Danger) DiffInverseAddStyle = lipgloss.NewStyle().Foreground(Success).Reverse(true) DiffInverseRemoveStyle = lipgloss.NewStyle().Foreground(Danger).Reverse(true) )
var ( SeparatorStyle = lipgloss.NewStyle().Foreground(Separator) BoxBorderStyle = lipgloss.NewStyle().Foreground(Border) CardTitleStyle = lipgloss.NewStyle().Foreground(Title).Bold(true) CardSectionStyle = lipgloss.NewStyle().Foreground(BrandSoft).Bold(true) // ConnectorStyle dims the tree connector "⎿ " so it recedes visually. ConnectorStyle = lipgloss.NewStyle().Foreground(Subtle) )
var ( InputPanelStyle = inputPanel(InputRule) ShellInputPanelStyle = inputPanel(RoleShell) // ShellAccentStyle colors both the prompt caret "❯" and the "!" prefix // when the input is in shell mode — they share the same style by design. ShellAccentStyle = lipgloss.NewStyle().Foreground(RoleShell).Bold(true) InputHintStyle = lipgloss.NewStyle().Foreground(Muted) ImageSelectedStyle = lipgloss.NewStyle().Reverse(true) ImageTagStyle = lipgloss.NewStyle().Foreground(Brand) )
var ( WelcomeTitleStyle = lipgloss.NewStyle().Foreground(Title).Bold(true) WelcomeKickerStyle = lipgloss.NewStyle().Foreground(Brand).Bold(true) WelcomeBodyStyle = lipgloss.NewStyle().Foreground(Text) WelcomeMutedStyle = lipgloss.NewStyle().Foreground(Muted) )
var ( CommandPaletteStyle = card(BrandSoft) CommandPaletteTitleStyle = lipgloss.NewStyle().Foreground(Title).Bold(true) CommandPaletteSectionStyle = lipgloss.NewStyle().Foreground(BrandSoft).Bold(true) CommandPaletteSelectedStyle = lipgloss.NewStyle().Foreground(Brand).Bold(true) CommandPaletteItemStyle = lipgloss.NewStyle().Foreground(Text) CommandPaletteDescStyle = lipgloss.NewStyle().Foreground(Muted) CommandPaletteSelectedDescStyle = lipgloss.NewStyle().Foreground(RoleAssistant) CommandPaletteHintStyle = lipgloss.NewStyle().Foreground(Border) )
var ( ContextChipStyle = lipgloss.NewStyle().Foreground(Muted) ContextChipAccentStyle = lipgloss.NewStyle().Foreground(Brand) ContextChipPathStyle = lipgloss.NewStyle().Foreground(Path) // Transient hints like "Press Ctrl+C again to exit" or "bash mode" — muted // gray, not a loud warning. Claude Code keeps these understated. ContextChipWarnStyle = lipgloss.NewStyle().Foreground(Muted) ChoiceActiveStyle = lipgloss.NewStyle().Foreground(Accent).Bold(true) PlanBoxStyle = card(Accent) SubagentCardStyle = card(Accent) TaskCardStyle = card(Border) TaskProgressStyle = lipgloss.NewStyle().Foreground(Title) PermissionTitleStyle = lipgloss.NewStyle().Foreground(Accent).Bold(true) AskCardStyle = card(BrandSoft) TagSubtleStyle = lipgloss.NewStyle().Foreground(Text) )
var ( Strong = lipgloss.AdaptiveColor{Light: "#000000", Dark: "#FFFFFF"} // highest contrast — bullets, critical anchors Text = lipgloss.AdaptiveColor{Light: "236", Dark: "252"} // body text Muted = lipgloss.AdaptiveColor{Light: "242", Dark: "247"} // secondary labels, status Subtle = lipgloss.AdaptiveColor{Light: "246", Dark: "243"} // placeholder, thinking, hints Meta = lipgloss.AdaptiveColor{Light: "243", Dark: "246"} // line numbers, tails, dim metadata )
Foundation — text scale (recedes left-to-right: Strong > Text > Muted > Subtle > Meta).
var ( Border = lipgloss.AdaptiveColor{Light: "247", Dark: "241"} Separator = lipgloss.AdaptiveColor{Light: "248", Dark: "242"} Title = lipgloss.AdaptiveColor{Light: "235", Dark: "255"} InputRule = lipgloss.AdaptiveColor{Light: "245", Dark: "244"} )
Chrome — borders, separators, titles, rules.
var ( Brand = lipgloss.AdaptiveColor{Light: "#2B7B70", Dark: "#3FA796"} BrandSoft = lipgloss.AdaptiveColor{Light: "30", Dark: "72"} // muted teal for borders/labels )
Brand — teal, primary action.
var ( Success = lipgloss.AdaptiveColor{Light: "#2C7A39", Dark: "#4EBA65"} // pure saturated green, matches Claude Code Danger = lipgloss.AdaptiveColor{Light: "#C53030", Dark: "#E06C75"} Info = lipgloss.AdaptiveColor{Light: "#1E6FAF", Dark: "#78C6E7"} Live = lipgloss.AdaptiveColor{Light: "31", Dark: "153"} // spinner / running chrome )
Status.
var ( RoleUser = lipgloss.AdaptiveColor{Light: "31", Dark: "#9CC2F9"} RoleAssistant = lipgloss.AdaptiveColor{Light: "#3A6F6B", Dark: "#B8E1DD"} RoleShell = lipgloss.AdaptiveColor{Light: "#A04870", Dark: "#D16D9E"} )
Message roles.
var Accent = lipgloss.AdaptiveColor{Light: "#B47A2E", Dark: "#E5B567"}
Accent — amber, emphasis & tool surfaces.
var Path = lipgloss.AdaptiveColor{Light: "26", Dark: "111"} // file / path token
Highlights.
var (
SurfaceAccent = lipgloss.AdaptiveColor{Light: "254", Dark: "236"} // user echo strip
)
Surfaces — background tints (foreground colors for backgrounds).
Functions ¶
func CommandPaletteCategoryBadge ¶ added in v0.0.4
func CommandPaletteIdleBadge ¶ added in v0.0.2
func CommandPaletteKindBadge ¶ added in v0.0.2
func DrawBox ¶ added in v0.0.3
DrawBox draws a rounded border box with fixed height and gray border. innerWidth is the content width; fixedRows is the exact number of content rows (short content is padded with empty lines to keep view height stable).
func FormatProgressLine ¶
func FormatProgressLine(progress *agentcore.ProgressPayload) string
FormatProgressLine formats a structured tool progress update for display.
func FormatSubagentOutput ¶
func FormatSubagentOutput(result json.RawMessage) string
FormatSubagentOutput extracts the full output from a subagent result, appending usage stats as a footer. Returns content for card display.
func FormatTokens ¶
FormatTokens formats a token count with k/M suffix for readability. Uses floor truncation at 0.1 precision so the displayed number never overstates the real value (e.g. 1,050,000 → "1M", not "1.1M"). A trailing ".0" is omitted so whole values render as "200k" / "1M" instead of "200.0k".
func FormatToolArgs ¶
func FormatToolArgs(args json.RawMessage) string
FormatToolArgs formats tool arguments for display, truncating if needed.
func FormatToolHeader ¶ added in v0.0.2
func FormatToolHeader(tool string, args json.RawMessage) string
FormatToolHeader returns a one-line tool header like "Bash(git diff --stat)".
func FormatToolOutput ¶ added in v0.0.2
FormatToolOutput formats tool result text with tree connectors. First line gets the TreeConnector, subsequent lines get ConnectorPad alignment. Truncates to maxVisible lines with "… +N lines" hint. Optional styles override the default ToolResultStyle for line content.
func FormatToolResult ¶
func FormatToolResult(result json.RawMessage, isError bool) string
FormatToolResult extracts displayable text from a tool result. Truncation is handled by the caller (FormatToolOutput).
func RenderEditResult ¶
func RenderEditResult(result json.RawMessage) string
RenderEditResult renders the edit tool result with colored diff output. Leads with a "⎿ Added N lines, removed M lines" summary, à la Claude Code. Single-line changes (1 removed + 1 added) get intra-line highlighting where only the changed portion is rendered in inverse color.
func RenderLsResult ¶ added in v0.0.4
func RenderLsResult(result json.RawMessage) (dirPath string, body string)
RenderLsResult renders ls tool results with tree structure. Returns the directory path (for header update) and the formatted body.
func RenderReadResult ¶ added in v0.0.4
func RenderReadResult(result json.RawMessage) string
RenderReadResult renders glob tool results as a path list with colored line numbers. Handles both numbered lines (" 123\tcontent") and plain path lists.
func RenderReadSummary ¶ added in v0.1.2
func RenderReadSummary(result json.RawMessage) string
RenderReadSummary renders a one-line summary for the read tool ("Read N lines"), matching Claude Code's convention of not dumping file contents into the log.
func RenderStreamingOutput ¶
RenderStreamingOutput shows the last N lines of streaming tool output with tree connectors (TreeConnector on first line, ConnectorPad for alignment).
func RenderToolHeader ¶ added in v0.1.1
func RenderToolHeader(tool string, args json.RawMessage) string
RenderToolHeader styles the tool name while keeping the summary muted.
func RenderWriteResult ¶ added in v0.0.2
func RenderWriteResult(result json.RawMessage) string
RenderWriteResult renders the write tool result with a green preview of the written content.
func SendCommandResult ¶
SendCommandResult is a helper that wraps text into a CommandResultMsg tea.Cmd.
func TasksTickCmd ¶ added in v0.0.3
TasksTickCmd returns a tea.Cmd that fires TasksRefreshMsg after 500ms.
func TruncateLines ¶
TruncateLines truncates text to maxLines, appending "..." if truncated.
Types ¶
type AgentEventMsg ¶
AgentEventMsg bridges agentcore events into the bubbletea Elm loop.
type AskUserMsg ¶
type AskUserMsg struct {
Questions []tools.Question
RespCh chan<- *tools.AskUserResponse
}
AskUserMsg is sent by the AskUser handler to show questions in the TUI.
type BtwResultMsg ¶ added in v0.0.4
BtwResultMsg carries the result of a /btw side question back to the overlay.
type CommandResultMsg ¶
type CommandResultMsg struct {
Text string
// Inline prints the result flush against the previous scrollback block
// (no leading blank line). Use for output that should feel like a direct
// continuation — e.g. shell command output under its echoed prompt.
Inline bool
Quit bool // true for /exit
Clear bool // true for /clear
NewProvider string // non-empty if provider was switched
NewModel string // non-empty if model was switched
NewContextWindow int // non-zero if context window changed
}
CommandResultMsg carries the result of a slash command back to the model.
type CompletionItem ¶ added in v0.0.2
type CompletionItem struct {
Name string // command name without "/" (e.g. "model")
Description string
Usage string
Kind string
Category string
NeedsIdle bool
Source string
Aliases []string
AutoExecute bool
}
CompletionItem is a single command completion candidate.
type Config ¶
type Config struct {
Placeholder string
Version string
Provider string
ContextWindow int
Cwd string
GitBranch string
EnvHint string // shown below welcome when using env var credentials
History *storage.History // input history (Up/Down navigation)
InitialTasks *storage.TaskSnapshot // initial task snapshot restored before first render
RestoredMessages []agentcore.AgentMessage // messages restored from a previous session (rendered on Init)
OnKey func(m *Model, msg tea.KeyMsg) (handled bool, cmd tea.Cmd)
OnEvent func(m *Model, ev agentcore.Event) tea.Cmd
OnPaste func(m *Model) tea.Cmd // Ctrl+V: read clipboard image, return ImageAttachedMsg
OnDrop func(m *Model, text string) tea.Cmd // Drag-drop: if text is image path, return cmd; else nil
OnMCPReady func(msg MCPReadyMsg) // called when MCP servers finish connecting
OnHideCompletedTasks func(snap storage.TaskSnapshot) tea.Cmd
StatusRight func(m *Model) string
StatusMode func(m *Model) string // mode indicator for context bar (e.g. "⏵⏵ trust")
StatusPlan func(m *Model) *PlanBarInfo
Overlay func(m *Model) *OverlayState // interactive command overlay
Completions func(prefix string) []CompletionItem // slash command completions
OnBtwResult func(msg BtwResultMsg) // called when /btw side question completes
}
Config provides hooks for extending the base TUI behavior.
type Deps ¶ added in v0.1.0
type Deps struct {
Driver Driver
ModelName string
ContextWindow int
Provider string
Version string
// contains filtered or unexported fields
}
Deps holds external dependencies and static configuration for the TUI.
type Driver ¶
type Driver interface {
Prompt(text string) error
PromptWithBlocks(blocks []agentcore.ContentBlock) error
Steer(text string)
Abort()
}
Driver defines the minimal conversation operations required by the TUI.
type HideCompletedTasksMsg ¶ added in v0.1.0
type HideCompletedTasksMsg struct {
Version uint64
}
HideCompletedTasksMsg hides the task card after all tasks stayed completed for a short delay. Version prevents stale timers from hiding a newer list.
type ImageAttachedMsg ¶
type ImageAttachedMsg struct {
Block agentcore.ContentBlock // pre-built ImageBlock (base64 + mime)
}
ImageAttachedMsg notifies the Model that an image has been pasted from clipboard.
type InfoOverlayFrame ¶ added in v0.1.1
type InfoOverlayFrame struct {
Title string
Subtitle string
Tabs []InfoOverlayTab
Active int
Hint string
Width int
}
InfoOverlayFrame renders a modal-style info overlay: title + tab bar + divider + body + footer hint. Used by information commands that want to replace the input area rather than scroll past it.
frame := tui.InfoOverlayFrame{
Title: "Settings",
Tabs: []tui.InfoOverlayTab{{Name: "general", Body: renderGeneral}},
Hint: "Esc to close",
Width: width,
}
fmt.Print(frame.Render())
func (InfoOverlayFrame) Render ¶ added in v0.1.1
func (f InfoOverlayFrame) Render() string
Render produces the full styled overlay body.
type InfoOverlayTab ¶ added in v0.1.1
InfoOverlayTab describes one pane inside an InfoOverlayFrame. Body is invoked on each render so it can reflect live session state.
type InfoPanel ¶ added in v0.1.1
type InfoPanel struct {
// contains filtered or unexported fields
}
InfoPanel builds structured info displays used by /settings, /context, etc.
p := NewInfoPanel("Settings")
p.Row("Provider", "anthropic")
p.Row("Model", "claude-sonnet-4-6")
p.Section("Runtime")
p.Row("Thinking", "low")
p.Hint("Config", "~/.codebot/settings.json")
fmt.Print(p.Render())
func NewInfoPanel ¶ added in v0.1.1
NewInfoPanel creates a panel with the given title.
type MCPReadyMsg ¶ added in v0.0.3
type MCPReadyMsg struct {
Tools int // total number of tools loaded across all servers
Errors []string // connection errors (server: reason)
Instructions string // MCP server instructions to set as system suffix
}
MCPReadyMsg notifies the TUI that background MCP server connection has completed.
type Model ¶
Model is the bubbletea Model for the agent TUI. Completed content is printed to terminal scrollback via tea.Println; View() only renders the live area (status + streaming + input).
func (*Model) Emit ¶ added in v0.1.2
Emit is the single entry point for writing content to terminal scrollback. It caches the exact body given to tea.Println so handleResize can replay the entire stream after a clear. All pre-formatted paths — printBlock, printInline, and direct tea.Println calls that used to exist — funnel through here so the cache stays authoritative. Exported so the outer ui package (app.go, plan.go) can push external scrollback writes through the same cache.
func (*Model) HandleAgentEvent ¶
HandleAgentEvent processes agent events. Completed content is printed to terminal scrollback via tea.Println. In-progress content (streaming, tool output) is shown in the live View().
func (*Model) RenderContextBar ¶
RenderContextBar renders the context line below the input (env info).
func (*Model) RenderMarkdown ¶
RenderMarkdown renders a lightweight terminal-friendly markdown subset.
func (*Model) RenderPlanBar ¶
RenderPlanBar renders the plan review card (AskUser-style). Empty when inactive.
func (*Model) RenderPromptOutput ¶
RenderPromptOutput renders a user message with optional welcome banner for scrollback.
func (*Model) RenderStatusBar ¶
RenderStatusBar renders the status line above the input. Only shown while the agent is running.
type OverlayState ¶ added in v0.0.2
type OverlayState struct {
HandleKey func(msg tea.KeyMsg) (handled bool, cmd tea.Cmd)
View func(width int) string
ReplacesInput bool // when true, overlay replaces the input area instead of appearing below it
}
OverlayState bridges an interactive command overlay to the TUI.
type PasteErrorMsg ¶
type PasteErrorMsg struct {
Text string
}
PasteErrorMsg carries an error from clipboard paste or file drag-drop. Decrements Pasting counter and displays the error text.
type PasteTextMsg ¶
type PasteTextMsg struct{}
PasteTextMsg signals that Ctrl+V found no image; the textarea should paste text.
type PermissionDismissMsg ¶ added in v0.0.2
type PermissionDismissMsg struct{}
PermissionDismissMsg tells the TUI to close the permission prompt.
type PermissionMsg ¶ added in v0.0.2
type PermissionMsg struct {
Tool string
Command string
Reason string
Preview string
OutsideRoots bool // when true, only AllowOnce and Deny are shown
RespCh chan<- PermitChoice
}
PermissionMsg is sent to the TUI to show a permission confirmation prompt.
type PermitChoice ¶ added in v0.0.2
type PermitChoice int
PermitChoice is the user's response to a permission prompt.
const ( PermitChoiceDeny PermitChoice = iota PermitChoiceAllowOnce // allow this invocation only PermitChoiceAllowSession // allow for the rest of the session PermitChoiceAllowAlways // persist to project config )
type PlanBarInfo ¶
type PlanBarInfo struct {
Tag string // appended to status bar (e.g., "plan mode")
Choices []string // selectable options
Active int // active choice index
// Plan review card fields.
Prompt string // e.g., "Would you like to proceed?"
Details []string
OtherMode bool // typing custom feedback
OtherBuf string // custom feedback buffer
}
PlanBarInfo provides plan mode status for the status bar.
type PromptMsg ¶
type PromptMsg struct {
Text string
}
PromptMsg injects a message as if the user typed and sent it. The TUI renders it as a user message and forwards it to the agent.
type RestoreMsg ¶ added in v0.0.2
type RestoreMsg struct{ Msgs []agentcore.AgentMessage }
RestoreMsg is sent to replay restored session messages into scrollback.
type RetryStatusMsg ¶ added in v0.1.2
type RetryStatusMsg struct {
Text string
}
RetryStatusMsg updates the single in-place retry status shown in the live area. Empty Text clears the current retry status.
type State ¶ added in v0.1.0
type State struct {
Input textarea.Model
Spinner spinner.Model
ToolSpinner spinner.Model // breathing-dot spinner for tool execution
Streaming *strings.Builder
Thinking *strings.Builder
IsStream bool
Running bool
TurnCount int
PendingTools map[string]string // toolID -> tool name
ToolHeaders map[string]string // toolID -> formatted header (printed at end)
ToolOutputBuf map[string]*strings.Builder // toolID -> streaming output
ToolDeltaBuf map[string]*strings.Builder // toolID -> accumulated subagent delta text
ToolThinkingBuf map[string]*strings.Builder // toolID -> accumulated subagent thinking text
Width int
Height int
Ready bool
Cwd string
GitBranch string
ShowWelcome bool
EnvHint string // env var hint shown below welcome
RunStats runStats
Images []agentcore.ContentBlock // attached images (from Ctrl+V clipboard paste)
ImageCursor int // -1 = not selecting; 0+ = selected image index
Pasting int // number of async image reads in progress (clipboard paste or drag-drop)
Markdown *markdown.Renderer
AskUser *askUserState // non-nil when ask-user UI is active
Permission *permissionState // non-nil when permission prompt is active
Tasks *storage.TaskSnapshot // non-nil when task items exist; displayed above input
QueuedMsgs []string // messages queued while agent is running (display only)
RetryStatus string // single in-place retry status shown while auto-retrying
MCPLoading bool // true while MCP servers are connecting in background
// Scrollback mirrors the stream of pre-formatted bodies sent to
// tea.Println. It exists solely to cure the terminal-resize ghost /
// reflow duplication problem (重影).
//
// Precise cause: Println content, once written, is inert — bubbletea
// never redraws it, so reflow at worst re-wraps it in place without
// duplicating. The ghosts come exclusively from the live View()
// (status bar, input panel borders, streaming area). On resize the
// terminal pushes those rows up into OS scrollback to make room for
// the new viewport, but bubbletea's `linesRendered` cursor tracking
// still points at the old position — its next frame's "erase previous
// frame" sequence misses, and the pushed-up copy is marooned in
// scrollback as a ghost.
//
// Fix: on WindowSizeMsg we wipe viewport + OS scrollback (`\x1b[2J`
// + `\x1b[3J` + `\x1b[H`) to evict the ghosts, then replay this cache
// so legitimate Println history survives the nuke. Without the cache
// we'd be trading ghosts for lost conversation history. See
// handleResize for the replay path, Emit for the write path,
// handleCommandResult (msg.Clear) for the reset path.
//
// Entries are the exact string passed to tea.Println (as returned by
// formatScrollbackBlock), so joining them with "\n" and Println'ing
// once is byte-for-byte equivalent to the original per-block Println
// sequence — tea.Println splits on "\n" internally. Bounded by
// scrollbackCacheLimit; entries beyond the cap are dropped FIFO,
// which only materialises as lost history after a resize (the live
// terminal scrollback remains complete until the next resize clears
// it).
Scrollback []string
Suggestion string // prompt suggestion shown as placeholder after agent completes
QuitPending bool // true after first Ctrl+C, waiting for second to quit
// contains filtered or unexported fields
}
State holds mutable runtime state for the TUI.
type SuggestionMsg ¶ added in v0.0.4
type SuggestionMsg struct {
Text string
}
SuggestionMsg carries a prompt suggestion generated after agent completion.
type TaskListUpdateMsg ¶
type TaskListUpdateMsg struct {
Snapshot storage.TaskSnapshot
}
TaskListUpdateMsg notifies the TUI that the task list has changed.
type TasksRefreshMsg ¶ added in v0.0.3
type TasksRefreshMsg struct{}
TasksRefreshMsg is a periodic tick that triggers a re-render of the /tasks overlay.