tui

package
v0.0.0-...-187d9d3 Latest Latest
Warning

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

Go to latest
Published: May 30, 2026 License: MIT Imports: 56 Imported by: 0

Documentation

Overview

Package tui implements bee's interactive Bubbletea interface.

Startup banner art — minimal sigils, no emoji.

Package tui implements the bubbletea-driven interactive UI for bee.

Visual primitives live here: hex glyphs and the honey palette. Slice 3A composes Hive + Workspace via NewHive / NewWorkspace factories.

Inline ! / !! shell exec from the editor. The default bang behavior is configurable (cfg.ShellBangSilent — silent by default). `!!cmd` always runs in the opposite mode, so users can override per-invocation either way. Execution goes through the same shell tool the model uses so the permission/sandbox model stays consistent.

Package tui implements bee's interactive Bubbletea interface.

Palette follows the charmbracelet/crush approach: a layered neutral scale (multiple foreground subtleties × multiple background layers) with a single brand accent. Bee swaps crush's purple for honey amber. Hex values are inlined so we don't take a charmtone dependency.

Index

Constants

View Source
const (
	HexFilled      = "⬢"
	HexHollow      = "⬢"
	ColorHoneyGold = "#F2B233"
	ColorAmber     = "#E08A1E"
	ColorDim       = "#5F5F5F"
	ColorAccent    = "#FFE066"
	ColorDanger    = "#D9534F"
	ColorAddFg     = "#7FBF6B"
	ColorDelFg     = "#D9534F"
	ColorMuted     = "#888888"
)

Hex glyphs (PLAN §8b.1) and honey palette.

View Source
const IntroStyleDefault = IntroStyleBloom

IntroStyleDefault is the value used when BEE_BANNER is unset.

Variables

View Source
var (
	StyleActive   = fg(ColorHoneyGold).Bold(true)
	StyleAwaiting = fg(ColorAccent).Bold(true)
	StyleIdle     = fg(ColorAmber)
	StyleDone     = fg(ColorDim)
	StyleFailed   = fg(ColorDanger).Bold(true)
	StyleLabel    = fg(ColorMuted)
)

Pre-built styles. Public so 3A may compose without redefining.

View Source
var Commit = ""

Commit is the build-time short sha of the running binary. cmd/bee sets it at process start; "" or "dev" disables the upstream probe (developer builds shouldn't auto-prompt against main).

View Source
var Version = "0.1.0"

Version is the bee build version surfaced in the intro placeholder after the startup animation finishes. cmd/bee sets it at process start so the linker-injected build tag flows through. Default kept in sync with main.

Functions

func AppendHistory

func AppendHistory(text string)

AppendHistory atomically appends a single entry to ~/.bee/history. Skips empty / whitespace-only lines. Trims to historyMax if the file gets large.

func BrailleSparkline

func BrailleSparkline(vals []float64, cells int) string

BrailleSparkline returns a one-line braille sparkline of vals normalized to [0, h] pixels. width is in braille cells (each cell encodes 2 samples × 4 vertical levels). Empty input returns "".

func CompletionCandidates

func CompletionCandidates(dir, prefix string) []string

CompletionCandidates returns names in dir starting with prefix.

func FuzzyFiles

func FuzzyFiles(root, needle string) []string

FuzzyFiles returns paths under root containing needle (case-insensitive). Skips hidden .folders, node_modules, vendor, worktrees. Caps at fuzzyMax results.

func HexRow

func HexRow(states []BeeState, names []string, width int) string

HexRow renders a strip of hexagons + names, capped to width cells.

func HighlightCode

func HighlightCode(content, lang string) string

HighlightCode returns content with ANSI syntax-highlight escapes wrapped around tokens. lang is a chroma lexer name ("go", "javascript", "bash", "diff"…) or "" to auto-detect by content. On any failure it returns the input unchanged — never errors out of a render path.

func HighlightLineByPath

func HighlightLineByPath(line, path string) string

HighlightLineByPath highlights a single line using the lexer matching the given file path's extension. Used by per-line render paths (diff bodies, edit previews) that hand chroma one logical line at a time.

func InstallModifyOtherKeys

func InstallModifyOtherKeys(out io.Writer) (io.Reader, func())

InstallModifyOtherKeys turns on xterm modifyOtherKeys level 1 on the provided writer (typically os.Stdout) and wraps os.Stdin in a translator that decodes the resulting CSI sequences into the bytes bubbletea's parser recognises. The returned io.Reader is suitable for tea.WithInput. The returned cleanup func writes the disable sequence — defer it before tea.Program.Run returns so the terminal is left in a sane state.

When stdout is not a TTY the function is a no-op and returns os.Stdin unwrapped + a no-op cleanup; piped invocations stay clean.

func LoadHistory

func LoadHistory() []string

LoadHistory reads ~/.bee/history newest-first, dedupes consecutive entries.

func LongestCommonPrefix

func LongestCommonPrefix(ss []string) string

LongestCommonPrefix returns the longest string that is a prefix of every input.

func PersistPick

func PersistPick(path string, provider, model string) error

PersistPick rewrites ~/.bee/config.toml so the next launch defaults to the chosen provider+model.

Trade-off: we do NOT recreate the live Engine mid-session. The choice is durable, but takes effect on the next bee run. Live swap would require draining tool-call state cleanly in loop/turn.go.

func PersistSetting

func PersistSetting(path string, key string, value any) error

PersistSetting rewrites ~/.bee/config.toml setting top-level key=value while preserving every other field. Used by /settings to make verbosity / thought visibility toggles survive across launches. key must be a top-level TOML key (no dotted paths). value must be a TOML-encodable scalar.

func ReadClipboardImage

func ReadClipboardImage() ([]byte, error)

ReadClipboardImage returns the raw image bytes from the system clipboard or an error if no image is available (or the clipboard backend is missing).

func RenderBanner

func RenderBanner(version, model string) string

RenderBanner legacy entry — delegates to hex variant. model arg accepted for api compatibility but ignored; the live top status bar already shows `provider/model cwd`, so the splash stays trim.

func RenderBannerCompact

func RenderBannerCompact(version, model string) string

RenderBannerCompact returns a single-line banner for headless mode. model arg accepted for api compatibility but not rendered (same rationale as the full banner — status bar already carries it).

func RenderBannerVariant

func RenderBannerVariant(v BannerVariant, version, model string) string

RenderBannerVariant returns a styled startup banner. version optional. model arg accepted for api compatibility but no longer rendered — model identity already lives on the persistent top status bar, so the splash stays minimal (sigil + "bee <version>").

func Run

func Run(ctx context.Context, eng *loop.Engine) error

Run builds and runs the bubbletea program with the given engine. Blocks until the program exits (Ctrl+C or tea.Quit). Uses the default (built-in) slash command set.

func RunSeeded

func RunSeeded(ctx context.Context, eng *loop.Engine, reg *commands.Registry, km KeyMap, app *Approver, seed string) error

RunSeeded is RunWithCommandsKeyMapApprover plus an optional seed prompt that auto-submits one turn on startup (skill dispatch into the TUI). Pass "" for no auto-submit.

func RunSeededAsker

func RunSeededAsker(ctx context.Context, eng *loop.Engine, reg *commands.Registry, km KeyMap, app *Approver, asker *Asker, seed string) error

RunSeededAsker is RunSeeded plus the ask_user picker adapter. Pass nil to leave ask_user auto-resolving to the recommended option.

func RunWithCommands

func RunWithCommands(ctx context.Context, eng *loop.Engine, reg *commands.Registry) error

RunWithCommands is Run with a caller-provided command registry. Pass nil to get the built-in set. Uses DefaultKeyMap — callers wanting user overrides should use RunWithCommandsAndKeyMap.

func RunWithCommandsAndKeyMap

func RunWithCommandsAndKeyMap(ctx context.Context, eng *loop.Engine, reg *commands.Registry, km KeyMap) error

RunWithCommandsAndKeyMap is RunWithCommands plus a caller-supplied keymap. Pass DefaultKeyMap() to keep stock bindings.

func RunWithCommandsKeyMapApprover

func RunWithCommandsKeyMapApprover(ctx context.Context, eng *loop.Engine, reg *commands.Registry, km KeyMap, app *Approver) error

RunWithCommandsKeyMapApprover is RunWithCommandsAndKeyMap plus the channel approver that surfaces dangerous-command prompts in the modal. Pass nil for the legacy no-gating behavior.

Types

type AgentRow

type AgentRow struct {
	SessionID    string
	State        bgreg.State
	Task         string
	LastResponse string
	Updated      time.Time
}

type AgentView

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

AgentView is the multi-bee management pane (Left arrow / Ctrl+H). List + peek + inline reply. Refreshes every tick so live bg bees update.

func NewAgentView

func NewAgentView() *AgentView

func (*AgentView) Close

func (a *AgentView) Close()

func (*AgentView) Init

func (a *AgentView) Init() tea.Cmd

func (*AgentView) IsOpen

func (a *AgentView) IsOpen() bool

func (*AgentView) Open

func (a *AgentView) Open()

func (*AgentView) Refresh

func (a *AgentView) Refresh()

func (*AgentView) Render

func (a *AgentView) Render(width, height int) string

func (*AgentView) Rows

func (a *AgentView) Rows() []AgentRow

func (*AgentView) SubmitReply

func (a *AgentView) SubmitReply(text string) error

func (*AgentView) Update

func (a *AgentView) Update(msg tea.Msg) (*AgentView, tea.Cmd)

type ApprovalAskMsg

type ApprovalAskMsg struct {
	UseID  string
	Cmd    string
	Key    string
	Reason string
}

ApprovalAskMsg asks the TUI to surface the modal for a flagged command.

type ApprovalDecision

type ApprovalDecision string

ApprovalDecision is the user's verdict on a permission request.

const (
	ApprovalAllow   ApprovalDecision = "allow"   // run once
	ApprovalSession ApprovalDecision = "session" // run + cache for session
	ApprovalAlways  ApprovalDecision = "always"  // run + persist to config
	ApprovalDeny    ApprovalDecision = "deny"
)

type ApprovalDecisionMsg

type ApprovalDecisionMsg struct {
	UseID    string
	Decision ApprovalDecision
}

ApprovalDecisionMsg is the tea.Msg published once the user chooses. Engine subscribes via the channel from RegisterApproval.

type ApprovalModel

type ApprovalModel struct {
	Active  bool
	Request ApprovalRequest
	// contains filtered or unexported fields
}

ApprovalModel is a self-contained component embedded in the main Model. When Active is false it renders nothing.

func NewApprovalModel

func NewApprovalModel(styles Styles, keys KeyMap) ApprovalModel

NewApprovalModel returns a fresh, inactive modal.

func (*ApprovalModel) Hide

func (m *ApprovalModel) Hide()

Hide closes the modal without publishing a decision.

func (*ApprovalModel) SetOutput

func (m *ApprovalModel) SetOutput(ch chan<- ApprovalDecisionMsg)

SetOutput wires the engine-facing channel. Pass nil to detach.

func (*ApprovalModel) Show

func (m *ApprovalModel) Show(req ApprovalRequest)

Show opens the modal for the given request.

func (ApprovalModel) Update

func (m ApprovalModel) Update(msg tea.Msg) (ApprovalModel, tea.Cmd)

Update handles modal key events. Returns the updated model + an optional cmd that publishes the decision message to the program. Caller forwards the cmd.

func (ApprovalModel) View

func (m ApprovalModel) View() string

View renders the modal box. The parent overlays it on the main view.

type ApprovalRequest

type ApprovalRequest struct {
	ToolName string
	Action   string // human-readable: "run shell: rm -rf /tmp/x"
	Reason   string // why the cmd was flagged, e.g. "recursive delete"
	Key      string // safety.DangerousPattern key, for session + persistent cache
	UseID    string // request id, echoed back in the decision
}

ApprovalRequest is what the Engine (eventually) hands to the modal.

type Approver

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

Approver implements approval.Approver by routing requests through the TUI.

Call site lives in shell.Tool (or any other tool) which runs on the engine goroutine. Request sends an ApprovalAskMsg to the bubbletea program, then blocks on a per-request reply channel. The Model handles the msg by Show()ing the modal; once the user picks, the resulting ApprovalDecisionMsg is fed back through Resolve which unblocks the caller.

Construct with NewApprover; call SetProgram after tea.NewProgram returns its handle. Until SetProgram is called every Request returns Deny so the engine can't accidentally race the TUI startup.

func NewApprover

func NewApprover() *Approver

NewApprover returns an unwired approver. Call SetProgram to attach the tea program once tea.NewProgram has returned.

func (*Approver) Request

func (a *Approver) Request(ctx context.Context, cmd, key, desc string) (approval.Decision, error)

Request blocks until the user picks a decision in the TUI modal. Returns Deny if the program is unset or the context is cancelled.

func (*Approver) Resolve

func (a *Approver) Resolve(useID string, d ApprovalDecision)

Resolve delivers a user decision back to the blocked Request call. Called by the Model when an ApprovalDecisionMsg arrives. Unknown ids are dropped.

func (*Approver) SetProgram

func (a *Approver) SetProgram(p *tea.Program)

SetProgram wires the tea.Program handle. Safe to call before or after the program is running.

type AskAnswerMsg

type AskAnswerMsg struct {
	UseID  string
	Answer ask.Answer
}

AskAnswerMsg is published once the user picks. The Model forwards it to Asker.Resolve to unblock the tool.

type AskModel

type AskModel struct {
	Active bool
	// contains filtered or unexported fields
}

AskModel is the ask_user picker: a vertical list of options plus an optional "type my own answer" row. Self-contained component embedded in the main Model; renders nothing when inactive. Communicates the pick back through the engine-facing channel, mirroring ApprovalModel.

func NewAskModel

func NewAskModel(styles Styles) AskModel

NewAskModel returns a fresh, inactive picker.

func (*AskModel) Hide

func (m *AskModel) Hide()

Hide closes the picker without publishing an answer.

func (*AskModel) SetOutput

func (m *AskModel) SetOutput(ch chan<- AskAnswerMsg)

SetOutput wires the engine-facing channel. Pass nil to detach.

func (*AskModel) SetWidth

func (m *AskModel) SetWidth(w int)

SetWidth records the terminal width so View can bound the modal.

func (*AskModel) Show

func (m *AskModel) Show(useID string, q ask.Question)

Show opens the picker for a question, defaulting focus to the recommended option so enter accepts it immediately.

func (AskModel) Update

func (m AskModel) Update(msg tea.Msg) (AskModel, tea.Cmd)

Update handles picker key events. Returns the model + an optional cmd that publishes the answer. Caller forwards the cmd.

func (AskModel) View

func (m AskModel) View() string

View renders the picker box. The parent overlays it on the main view.

type AskShowMsg

type AskShowMsg struct {
	UseID    string
	Question ask.Question
}

AskShowMsg asks the TUI to surface the picker for a question.

type Asker

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

Asker implements ask.Asker by routing questions through the TUI picker.

The ask_user tool runs on the engine goroutine: Ask sends an AskShowMsg to the bubbletea program, then blocks on a per-request reply channel. The Model shows the picker; once the user chooses, the AskAnswerMsg is fed back through Resolve which unblocks the caller.

Construct with NewAsker; call SetProgram after tea.NewProgram returns. Until then every Ask auto-resolves via ask.Static so the loop never wedges.

func NewAsker

func NewAsker() *Asker

NewAsker returns an unwired asker. Call SetProgram to attach the tea program.

func (*Asker) Ask

func (a *Asker) Ask(ctx context.Context, q ask.Question) (ask.Answer, error)

Ask blocks until the user answers in the TUI picker. Falls back to the recommended option (ask.Static) if the program is unset, and on context cancellation returns a dismissed answer.

func (*Asker) Resolve

func (a *Asker) Resolve(useID string, ans ask.Answer)

Resolve delivers a user answer back to the blocked Ask call. Called by the Model when an AskAnswerMsg arrives. Unknown ids are dropped.

func (*Asker) SetProgram

func (a *Asker) SetProgram(p *tea.Program)

SetProgram wires the tea.Program handle. Safe to call before or after the program is running.

type AtPickerDismissedMsg

type AtPickerDismissedMsg struct{}

AtPickerDismissedMsg is emitted when the user escapes the picker.

type AtPickerModel

type AtPickerModel struct {
	Active bool
	// contains filtered or unexported fields
}

AtPickerModel is the @-triggered fuzzy file picker. Renders inline above the input bar — same dense strip as the slash palette.

func NewAtPicker

func NewAtPicker(root string) AtPickerModel

NewAtPicker returns an inactive picker rooted at root.

func (*AtPickerModel) SetWidth

func (p *AtPickerModel) SetWidth(w int)

SetWidth tells the picker how wide a row may be.

func (AtPickerModel) Update

func (p AtPickerModel) Update(msg tea.Msg) (AtPickerModel, tea.Cmd)

Update handles picker key events.

func (AtPickerModel) View

func (p AtPickerModel) View() string

View renders the picker as a dense strip above the input bar.

type AtPickerSelectMsg

type AtPickerSelectMsg struct{ Path string }

AtPickerSelectMsg is emitted when the user picks a path.

type AttachSessionMsg

type AttachSessionMsg struct{ ID string }

type BannerVariant

type BannerVariant int

BannerVariant selects which startup banner art to render. random picks one per launch so a new shell feels alive without committing to one aesthetic.

const (
	BannerHex    BannerVariant = iota // diamond sigil (default)
	BannerSwarm                       // small constellation
	BannerComb                        // honeycomb sliver
	BannerFlower                      // radial sigil
)

func ParseBannerVariant

func ParseBannerVariant(s string) BannerVariant

ParseBannerVariant maps BEE_BANNER values to a variant. "random" / "" / unknown returns a pseudo-random pick seeded from the clock.

type Bee

type Bee struct {
	Name      string
	State     BeeState
	Model     string
	SessionID string
	StartedAt time.Time
}

Bee is one entry in the hive — either a live in-process session or a historical session pulled from disk via session.List().

type BeeState

type BeeState int

BeeState is the lifecycle of one bee (session).

const (
	Active BeeState = iota
	Awaiting
	Idle
	Done
	Failed
)

func (BeeState) String

func (s BeeState) String() string

type CloseAgentViewMsg

type CloseAgentViewMsg struct{}

type CostPane

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

CostPane is the Ctrl+Y modal: session total, recent-turn sparkline, and a filterable breakdown by model / provider.

func NewCostPane

func NewCostPane(t *cost.Tracker) *CostPane

NewCostPane returns a closed pane wired to the given tracker. Tracker may be nil — then the pane renders an empty state.

func (*CostPane) Open

func (c *CostPane) Open() bool

Open reports modal visibility.

func (*CostPane) Update

func (c *CostPane) Update(msg tea.Msg) (*CostPane, tea.Cmd)

Update reacts to keys while open. Tab cycles filter dimension; j/k cycle the active filter value; esc closes.

func (*CostPane) View

func (c *CostPane) View(width, height int) string

View renders the modal. Empty tracker → friendly stub; otherwise summary + sparkline + breakdown tables.

type DrawilleCanvas

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

DrawilleCanvas is a binary pixel buffer that renders as braille text. Out-of-bounds pixel writes are silently clipped so sprite painters can overflow the edge without bounds checks.

func NewDrawilleCanvas

func NewDrawilleCanvas(w, h int) *DrawilleCanvas

NewDrawilleCanvas allocates a canvas of the given pixel dimensions.

func (*DrawilleCanvas) Clear

func (c *DrawilleCanvas) Clear()

Clear resets all pixels to off.

func (*DrawilleCanvas) DrawSprite

func (c *DrawilleCanvas) DrawSprite(sprite []byte, w, h, ox, oy int)

DrawSprite paints a row-major binary sprite onto the canvas at (ox, oy). Pixels outside the canvas are clipped. Non-zero sprite bytes light up.

func (*DrawilleCanvas) Height

func (c *DrawilleCanvas) Height() int

Height returns canvas height in pixels.

func (*DrawilleCanvas) SetPixel

func (c *DrawilleCanvas) SetPixel(x, y int, on bool)

SetPixel turns one pixel on (true) or off (false). Out-of-bounds is a no-op so animations can sweep sprites past the edge cleanly.

func (*DrawilleCanvas) ToBraille

func (c *DrawilleCanvas) ToBraille() string

ToBraille renders the canvas as multi-line braille text. Lines are separated by \n; each line is exactly cellsW runes wide.

func (*DrawilleCanvas) Width

func (c *DrawilleCanvas) Width() int

Width returns canvas width in pixels.

type EffortPane

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

EffortPane is a modal picker for reasoning effort. Arrow keys pick, enter sets, esc closes without change.

func NewEffortPane

func NewEffortPane() *EffortPane

NewEffortPane returns a closed effort picker.

func (*EffortPane) Open

func (p *EffortPane) Open() bool

Open reports visibility.

func (*EffortPane) SetCurrent

func (p *EffortPane) SetCurrent(v string)

SetCurrent updates the stored current value (called after commit).

func (*EffortPane) Show

func (p *EffortPane) Show(current string)

Show opens the picker with the current effort highlighted.

func (*EffortPane) Update

func (p *EffortPane) Update(msg tea.Msg) (*EffortPane, tea.Cmd)

Update handles key events.

func (*EffortPane) View

func (p *EffortPane) View(width, height int) string

View renders the modal.

type HistoryDismissedMsg

type HistoryDismissedMsg struct{}

HistoryDismissedMsg signals the picker closed without a pick.

type HistoryPickerModel

type HistoryPickerModel struct {
	Active bool
	// contains filtered or unexported fields
}

HistoryPickerModel is the fzf-style reverse history search picker, rendered inline above the input bar in the same dense palette style as /model.

func NewHistoryPicker

func NewHistoryPicker() HistoryPickerModel

NewHistoryPicker returns an inactive picker. Entries load lazily on Show.

func (*HistoryPickerModel) SetWidth

func (p *HistoryPickerModel) SetWidth(w int)

SetWidth records terminal width so rows truncate cleanly. Mirrors palette/picker.

func (*HistoryPickerModel) Show

func (p *HistoryPickerModel) Show(initial string)

Show activates the picker, reloads history from disk, and resets the cursor.

func (HistoryPickerModel) Update

Update handles picker key events.

func (HistoryPickerModel) View

func (p HistoryPickerModel) View() string

View renders the picker as a borderless dense strip — same aesthetic as the slash palette + /model picker. Crumb, filter input, palette rows, hint.

type HistorySelectMsg

type HistorySelectMsg struct{ Text string }

HistorySelectMsg pastes the chosen entry into the main input.

type Hive

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

Hive is the bubbletea component that owns the hex strip and the full `Ctrl+H` view. It does not spawn bees itself (Wave 4); for v0.1 the data list is populated from session.List() plus whatever the host model registers via Set / Upsert.

func NewHive

func NewHive() *Hive

NewHive returns a Hive seeded with on-disk sessions (best-effort). 3A constructs this via `NewHive()` and embeds it into its Model.

func (*Hive) Bees

func (h *Hive) Bees() []Bee

Bees returns a copy of the current bee list (for callers / tests).

func (*Hive) Expanded

func (h *Hive) Expanded() bool

Expanded reports whether the full view is open.

func (*Hive) Init

func (h *Hive) Init() tea.Cmd

Init satisfies tea.Model.

func (*Hive) Render

func (h *Hive) Render(width int) string

Render returns the one-line hex strip. Active first, awaiting next, then idle, then done. Truncates to maxStrip entries; further capped by width.

func (*Hive) RenderFull

func (h *Hive) RenderFull(width, height int) string

RenderFull renders the Ctrl+H full hive view: a 3-wide hex grid of active bees followed by a list of recent sessions.

func (*Hive) Set

func (h *Hive) Set(bees []Bee)

Set replaces the bee list (used by 3A or hive spawner).

func (*Hive) Update

func (h *Hive) Update(msg tea.Msg) (*Hive, tea.Cmd)

Update handles toggle messages for the full view. The host model owns the keybinding (Ctrl+H) and forwards a ToggleHiveMsg.

func (*Hive) Upsert

func (h *Hive) Upsert(b Bee)

Upsert inserts or updates a bee by SessionID (or Name fallback).

type IntroFrame

type IntroFrame struct {
	Text     string
	Subtitle string
}

IntroFrame is one rendered frame of the startup animation.

type IntroStyle

type IntroStyle int

IntroStyle controls which animation plays on startup.

const (
	IntroStyleRandom    IntroStyle = iota // pick one of the concrete styles per launch
	IntroStyleLifecycle                   // egg → larva → pupa → flight
	IntroStyleSwarm                       // swarm of dots
	IntroStyleHex                         // hex outline orbit
	IntroStyleDance                       // waggle dance figure-8
	IntroStyleDrip                        // honey drop + ripple
	IntroStyleBloom                       // pollen converge → hex frame + bee → pulse rings
	IntroStyleConstell                    // constellation: dots twinkle into hex tessellation
	IntroStyleRain                        // honey-drop rain at staggered columns
	IntroStyleSpiral                      // single particle traces inward spiral with trail
	IntroStyleWave                        // sine wave sweep with crest cluster
	IntroStyleOrbit                       // three particles orbit a center at different radii
)

func ParseIntroStyle

func ParseIntroStyle(s string) IntroStyle

ParseIntroStyle maps BEE_BANNER values to a style.

type KeyMap

type KeyMap struct {
	Submit         key.Binding
	Quit           key.Binding
	Cancel         key.Binding
	ProviderPick   key.Binding
	WorkspaceTog   key.Binding
	HiveOpen       key.Binding
	SessionTree    key.Binding
	CostOpen       key.Binding
	SlashPalette   key.Binding
	HistorySearch  key.Binding
	CavemanCycle   key.Binding
	ThinkingCycle  key.Binding
	ModeCycle      key.Binding
	ApproveAllow   key.Binding
	ApproveSession key.Binding
	ApproveAlways  key.Binding
	ApproveDeny    key.Binding
	// SteerNow: enter while streaming — injects a mid-turn user steer.
	// shares the "enter" key with Submit; dispatch is state-dependent.
	SteerNow key.Binding
	// FollowUp: alt+enter queues a follow-up that fires after the current
	// turn finishes (works in idle or streaming).
	FollowUp key.Binding
	// ImagePaste: ctrl+i stages an image from the system clipboard for the
	// next submit. bubbletea's raw-paste support is unreliable in many
	// terminals, hence the explicit chord.
	ImagePaste key.Binding
}

KeyMap centralises every binding the TUI listens to. Other slices (workspace, hive, provider picker) just consume the same struct.

func DefaultKeyMap

func DefaultKeyMap() KeyMap

DefaultKeyMap returns the default keyboard chord set.

func LoadKeyMap

func LoadKeyMap(home string) KeyMap

LoadKeyMap returns DefaultKeyMap merged with overrides from <home>/keybindings.json. Missing or malformed file returns defaults silently. Unknown field names are ignored so users can pin to old configs safely.

type LoaderStyle

type LoaderStyle int

LoaderStyle selects which braille animation runs while waiting on the first token. Default is the phased pipeline (chill → swarm → orbit → ripple → starfield) which evolves the longer the wait runs. Named values pin a single painter.

const (
	LoaderStyleDefault   LoaderStyle = iota // phased: pulse → swarm → orbit → ripple → starfield
	LoaderStylePulse                        // centered bee, gentle wing flap
	LoaderStyleSwarm                        // multi-particle swarm, scales with width
	LoaderStyleWave                         // layered sine waves
	LoaderStyleComet                        // bright head + decaying tail
	LoaderStyleHex                          // rotating hexagonal outline
	LoaderStyleRipple                       // concentric ellipses expanding
	LoaderStyleRain                         // falling drops
	LoaderStyleOrbit                        // particles on elliptical orbit
	LoaderStyleBreath                       // bar expanding/contracting from center
	LoaderStyleStars                        // drifting starfield
	LoaderStyleForage                       // bees leave hive, drift, return
	LoaderStyleFigure8                      // waggle-dance lemniscate
	LoaderStyleVortex                       // 3 nested rotating rings
	LoaderStyleGust                         // swarm in wind with gust spikes
	LoaderStyleScatter                      // alarm dispersal + regroup
	LoaderStyleFlock                        // 3 cohesive bee clusters
	LoaderStyleDNA                          // double helix
	LoaderStyleMatrix                       // variable-speed vertical streams
	LoaderStyleHeartbeat                    // EKG flatline + spike
	LoaderStyleLightning                    // sudden bolt + decay
	LoaderStyleSnake                        // segments chasing head
	LoaderStyleFireworks                    // radiating bursts with gravity
	LoaderStyleDrunk                        // bee wobbles, drank fermented honey
	LoaderStyleJar                          // bee trapped, bouncing off jar walls
	LoaderStyleConga                        // bee conga line, undulating march
	LoaderStyleQueen                        // queen + 4 attendants procession
	LoaderStyleDrip                         // fat honey droplet + accumulating pool
	LoaderStyleMarathon                     // bees racing toward finish line
)

func ParseLoaderStyle

func ParseLoaderStyle(s string) LoaderStyle

ParseLoaderStyle maps BEE_LOADER values to a style. Unset / "random" / unknown → phased default. Legacy aliases (swarm/comb/dance/drip) map to their nearest braille equivalent so old configs keep working.

type LoginPane

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

LoginPane is the interactive /login modal. Lists providers vertically; arrow keys move; enter triggers OAuth or (for non-oauth providers with an env_key) switches to an inline text input for the api key; d/x removes the saved token AND any saved key file; r refreshes status; esc closes.

func NewLoginPane

func NewLoginPane(s commands.Side) *LoginPane

NewLoginPane returns a closed pane bound to the TUI side. side may be nil; the pane renders an empty state in that case.

func (*LoginPane) Open

func (p *LoginPane) Open() bool

Open reports visibility.

func (*LoginPane) SelectProvider

func (p *LoginPane) SelectProvider(name string)

SelectProvider points the cursor at the named provider AND, if the provider has an api-key (non-oauth) auth scheme, jumps straight into the key-input sub-mode. Used by the picker's auth-error escape hatch so the user lands directly on the relevant prompt.

func (*LoginPane) Show

func (p *LoginPane) Show()

Show opens the pane and refreshes status from the side.

func (*LoginPane) Update

func (p *LoginPane) Update(msg tea.Msg) (*LoginPane, tea.Cmd)

Update handles toggle/key/action messages. Returns the pane (callers reassign) and an optional tea.Cmd for async work.

func (*LoginPane) View

func (p *LoginPane) View(width, height int) string

View renders the modal. width/height match the host frame; boxModal applies the rounded border + padding.

type Model

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

Model is the bubbletea root model for bee's interactive REPL.

func NewModel

func NewModel(eng *loop.Engine, cwd, modelName, scope string, lvl caveman.Level) Model

NewModel constructs an idle TUI model. eng may be nil for unit tests. A built-in slash command registry is created and seeded — callers that want a custom set should call WithCommands on the returned Model.

func (Model) Init

func (m Model) Init() tea.Cmd

Init satisfies tea.Model. Returns the blink cmd so the cursor pulses, plus the stream pump when a delta channel is wired and a flush of any resumed-session messages so they land in native scrollback at startup.

func (Model) Update

func (m Model) Update(msg tea.Msg) (resultModel tea.Model, resultCmd tea.Cmd)

Update is the bubbletea main switch.

func (Model) View

func (m Model) View() string

View renders the live region only — top bar, streaming partial (if any), error line (if any), input row, and key hints. Finalized messages live in the terminal's native scrollback via tea.Println; we never repaint past turns. The live region grows while streaming, shrinks when idle.

func (Model) WithApprover

func (m Model) WithApprover(a *Approver) Model

WithApprover attaches the channel adapter that routes dangerous-command prompts through the TUI modal. The shell tool holds the same handle and blocks on Request until Resolve fires.

func (Model) WithAsker

func (m Model) WithAsker(a *Asker) Model

WithAsker attaches the channel adapter that routes ask_user questions through the TUI picker. The ask_user tool holds the same handle and blocks on Ask until Resolve fires.

func (Model) WithCommands

func (m Model) WithCommands(r *commands.Registry) Model

WithCommands swaps in a caller-provided registry. The palette is rebuilt against it so Ctrl+K shows the new set. Skills source is preserved.

func (Model) WithCompact

func (m Model) WithCompact(v bool) Model

WithCompact seeds compact-mode rendering. Env/config-driven path.

func (Model) WithCostTracker

func (m Model) WithCostTracker(t *cost.Tracker) Model

WithCostTracker wires the engine's cost.Tracker into the model so the top bar and the /cost pane can read it.

func (Model) WithHighlight

func (m Model) WithHighlight(v bool) Model

WithHighlight seeds chroma syntax-highlighting state. Config-driven path.

func (Model) WithInitialMessages

func (m Model) WithInitialMessages(msgs []types.Message) Model

WithInitialMessages preloads scrollback. Used by `bee back <id>` to restore a prior session into the TUI on launch. The messages get flushed to terminal scrollback via tea.Println from Init().

func (Model) WithIntro

func (m Model) WithIntro(style IntroStyle) Model

WithIntro enables the non-blocking startup animation. Frames are built lazily on the first tick once width is known. BEE_NO_INTRO=1 disables.

func (Model) WithKeyMap

func (m Model) WithKeyMap(km KeyMap) Model

WithKeyMap swaps in a caller-provided keymap. Used to fold in user overrides from ~/.bee/keybindings.json without changing NewModel's signature. Approval modal is rebuilt because it holds its own copy of the keys.

func (Model) WithLiveMsgCh

func (m Model) WithLiveMsgCh(ch chan types.Message) Model

WithLiveMsgCh wires a live-message channel from the engine into the TUI. The same channel must be set on Engine.LiveMsgCh so assistant + tool messages render as they're persisted, not only at Run completion.

func (Model) WithSeedPrompt

func (m Model) WithSeedPrompt(text string) Model

WithSeedPrompt arms a one-shot auto-submit fired from Init. Used by skill dispatch to start a turn live in the TUI (e.g. "/research <topic>").

func (Model) WithShellBangSilent

func (m Model) WithShellBangSilent(v bool) Model

WithShellBangSilent seeds the bang default behavior. Config-driven path.

func (Model) WithShowBanner

func (m Model) WithShowBanner(v bool) Model

WithShowBanner seeds the intro-animation flag. Toggling at runtime only affects the NEXT launch — the startup animation is one-shot.

func (Model) WithShowBee

func (m Model) WithShowBee(v bool) Model

WithShowBee seeds top-bar bee-glyph visibility. Config-driven path.

func (Model) WithShowContextBar

func (m Model) WithShowContextBar(v bool) Model

WithShowContextBar seeds context-bar visibility. Config-driven path.

func (Model) WithShowContextPct

func (m Model) WithShowContextPct(v bool) Model

WithShowContextPct seeds top-bar percent-label visibility.

func (Model) WithShowCwd

func (m Model) WithShowCwd(v bool) Model

WithShowCwd seeds top-bar cwd visibility.

func (Model) WithShowEffort

func (m Model) WithShowEffort(v bool) Model

WithShowEffort seeds top-bar effort-badge visibility.

func (Model) WithShowGitBranch

func (m Model) WithShowGitBranch(v bool) Model

WithShowGitBranch seeds top-bar git-branch chip visibility.

func (Model) WithShowLoader

func (m Model) WithShowLoader(v bool) Model

WithShowLoader seeds the streaming-loader visibility. Config-driven path.

func (Model) WithShowModel

func (m Model) WithShowModel(v bool) Model

WithShowModel seeds top-bar model-name visibility.

func (Model) WithShowNudges

func (m Model) WithShowNudges(v bool) Model

WithShowNudges seeds nudge-visibility from config. Default false hides the loop's [nudge] recovery turns; setting true reveals them.

func (Model) WithShowRecap

func (m Model) WithShowRecap(v bool) Model

WithShowRecap seeds the post-turn recap toggle from config. Default false so recaps are explicitly opt-in (extra tokens per turn).

func (Model) WithShowThoughts

func (m Model) WithShowThoughts(v bool) Model

WithShowThoughts seeds chain-of-thought visibility. Config-driven path.

func (Model) WithShowTotalTokens

func (m Model) WithShowTotalTokens(v bool) Model

WithShowTotalTokens seeds top-bar session-tokens chip visibility.

func (Model) WithShowTurnTimer

func (m Model) WithShowTurnTimer(v bool) Model

WithShowTurnTimer seeds top-bar turn-timer chip visibility.

func (Model) WithSkills

func (m Model) WithSkills(sk SkillsLister) Model

WithSkills wires a skills source into the palette so the picker can list commands and skills side-by-side. *skills.Registry already satisfies SkillsLister, so callers usually pass their loaded registry directly.

func (Model) WithStreamCh

func (m Model) WithStreamCh(ch chan string) Model

WithStreamCh wires a text-delta channel from the engine into the TUI. The same channel must be set on Engine.StreamCh so deltas flow.

func (Model) WithThinkCh

func (m Model) WithThinkCh(ch chan string) Model

WithThinkCh wires a reasoning-delta channel from the engine into the TUI so chain-of-thought renders live during streaming. Same channel must be set on Engine.ThinkCh so deltas flow.

func (Model) WithVerbose

func (m Model) WithVerbose(v bool) Model

WithVerbose seeds verbose tool-output rendering. CLI flag/env var path.

func (Model) WithWarnCh

func (m Model) WithWarnCh(ch chan string) Model

WithWarnCh wires the engine's transient-notice channel into the TUI so stream hiccups + retries surface as a fading line in chrome.

type ModelLister

type ModelLister func(ctx context.Context, name string, cfg config.ProviderConfig) ([]llm.Model, error)

ModelLister is the seam the picker uses to fetch a provider's catalogue.

type OpenAgentViewMsg

type OpenAgentViewMsg struct{}

type PaletteDismissedMsg

type PaletteDismissedMsg struct{}

PaletteDismissedMsg is emitted when the user presses esc.

type PaletteEntry

type PaletteEntry struct {
	Name        string
	Description string
	Kind        PaletteEntryKind
}

PaletteEntry is one row in the palette: either a slash command or a skill.

type PaletteEntryKind

type PaletteEntryKind int

PaletteEntryKind distinguishes between a slash command and a skill in the merged palette pool.

const (
	EntryCommand PaletteEntryKind = iota
	EntrySkill
)

type PaletteModel

type PaletteModel struct {
	Active bool
	// contains filtered or unexported fields
}

PaletteModel is the fzf-style picker. It merges slash commands and skills into one pool, fuzzy-matches against typed input, and renders highlighted matched runes.

func NewPalette

func NewPalette(cmds *commands.Registry, sk SkillsLister) PaletteModel

NewPalette returns an inactive palette bound to the given registry and optional skills source. Either side may be nil.

func (*PaletteModel) Bump

func (p *PaletteModel) Bump(name string)

Bump records that name was just dispatched so future palette openings rank it higher. Called by the slash dispatcher for both commands and skills.

func (*PaletteModel) SetFilter

func (p *PaletteModel) SetFilter(s string)

SetFilter mirrors the filter from the main input bar — typing lives there now, palette just shows the ranked list. Resets selection on change.

func (*PaletteModel) SetWidth

func (p *PaletteModel) SetWidth(w int)

SetWidth tells the palette how wide a row may be. Set from the app's WindowSizeMsg handler so rows truncate cleanly on narrow layouts.

func (*PaletteModel) Show

func (p *PaletteModel) Show(initial string)

Show activates the palette, rebuilds the entry pool, and applies an initial filter. The initial string pre-fills the filter — used when the user typed "/hlp" in the main bar and we open the palette pre-filtered.

func (PaletteModel) Update

func (p PaletteModel) Update(msg tea.Msg) (PaletteModel, tea.Cmd)

Update handles palette key events. Returns the updated palette and an optional cmd to forward (PaletteSelectMsg or PaletteDismissedMsg).

func (PaletteModel) View

func (p PaletteModel) View() string

View renders the palette as a borderless, dense strip designed to sit directly above the input bar. Width is taken from SetWidth — falls back to a sensible default when unset (e.g. tests).

type PaletteSelectMsg

type PaletteSelectMsg struct {
	Name string
	Kind PaletteEntryKind
}

PaletteSelectMsg carries the chosen entry. Parent decides how to dispatch (command vs skill).

type PickedMsg

type PickedMsg struct{ Provider, Model string }

PickedMsg is published when the user selects a provider+model combo.

type Picker

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

Picker is the fzf-style two-stage selector: filter providers → filter that provider's models. Looks and types like the `/` palette.

func NewPicker

func NewPicker(cfg config.Config) *Picker

NewPicker builds the picker in its inactive state.

func (*Picker) Active

func (p *Picker) Active() bool

Active reports whether the picker is open.

func (*Picker) Hide

func (p *Picker) Hide()

Hide closes the picker without emitting a PickedMsg.

func (*Picker) SetLister

func (p *Picker) SetLister(l ModelLister)

SetLister overrides the model-fetch function. Tests use this.

func (*Picker) SetSize

func (p *Picker) SetSize(w, _ int)

SetSize records the available width so rows can truncate cleanly.

func (*Picker) Show

func (p *Picker) Show() tea.Cmd

Show opens the picker on the provider stage and kicks off an async load for the highlighted provider so models are ready by the time the user advances to stage 2.

func (*Picker) Update

func (p *Picker) Update(msg tea.Msg) (*Picker, tea.Cmd)

Update handles key events + async messages.

func (*Picker) View

func (p *Picker) View() string

View renders the picker as a borderless dense strip — same aesthetic as the slash-command palette. fzf-style filter input, matched-rune highlights, two-stage flow (provider → model).

type PickerDismissedMsg

type PickerDismissedMsg struct{}

PickerDismissedMsg is published when the user hits Esc without picking.

type PickerLoginRequestedMsg

type PickerLoginRequestedMsg struct{ Provider string }

PickerLoginRequestedMsg is published when the user hits `l` from the picker's auth-error stage, asking the app to open the LoginPane on the failing provider.

type ResumeDismissedMsg

type ResumeDismissedMsg struct{}

ResumeDismissedMsg fires when the user closes without selecting.

type ResumeEntry

type ResumeEntry struct {
	ID      string
	Created time.Time
	Preview string
}

ResumeEntry is one row in the resume picker.

type ResumePicker

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

ResumePicker is the modal that lists past sessions newest-first and lets the user pick one with arrow keys + Enter. Esc/q dismisses.

func NewResumePicker

func NewResumePicker() *ResumePicker

NewResumePicker returns an inactive picker.

func (*ResumePicker) Entries

func (p *ResumePicker) Entries() []ResumeEntry

Entries exposes the current list (for tests + view).

func (*ResumePicker) Hide

func (p *ResumePicker) Hide()

Hide closes the modal without selecting.

func (*ResumePicker) Init

func (p *ResumePicker) Init() tea.Cmd

Init satisfies tea.Model.

func (*ResumePicker) Open

func (p *ResumePicker) Open() bool

Open reports modal visibility.

func (*ResumePicker) Selected

func (p *ResumePicker) Selected() int

Selected returns the cursor index.

func (*ResumePicker) SetEntries

func (p *ResumePicker) SetEntries(e []ResumeEntry)

SetEntries lets tests inject a deterministic list.

func (*ResumePicker) Show

func (p *ResumePicker) Show()

Show loads sessions from disk and opens the modal.

func (*ResumePicker) Update

func (p *ResumePicker) Update(msg tea.Msg) (*ResumePicker, tea.Cmd)

Update handles key events while open.

func (*ResumePicker) View

func (p *ResumePicker) View(width, height int) string

View renders the picker. Title + list + footer hint.

type ResumeSelectMsg

type ResumeSelectMsg struct{ ID string }

ResumeSelectMsg carries the chosen session id back to the host.

type SessionCloneMsg

type SessionCloneMsg struct{}

SessionCloneMsg requests a clone of the entire current session.

type SessionForkMsg

type SessionForkMsg struct{ FromID string }

SessionForkMsg requests a fork at FromID (or full if empty).

type SessionSwitchMsg

type SessionSwitchMsg struct{ LeafID string }

SessionSwitchMsg requests the host swap the active leaf to LeafID.

type SessionTree

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

SessionTree is the Ctrl+T modal — renders the parent-pointer message tree for one session, highlighting the active branch. Supports cursor nav with Up/Down, Enter to switch active leaf, F to fork, C to clone, Esc to close.

func NewSessionTree

func NewSessionTree() *SessionTree

NewSessionTree constructs an empty tree modal.

func (*SessionTree) Init

func (t *SessionTree) Init() tea.Cmd

Init satisfies tea.Model.

func (*SessionTree) LoadMessages

func (t *SessionTree) LoadMessages(msgs []types.Message, currentLeafID string)

LoadMessages rebuilds the tree from a flat message slice.

func (*SessionTree) Open

func (t *SessionTree) Open() bool

Open reports modal visibility.

func (*SessionTree) Selected

func (t *SessionTree) Selected() string

Selected returns the id of the cursor-highlighted node (empty if none).

func (*SessionTree) SetRoot

func (t *SessionTree) SetRoot(root *types.MessageNode, currentLeafID string)

SetRoot lets a caller pass an already-built tree.

func (*SessionTree) Update

func (t *SessionTree) Update(msg tea.Msg) (*SessionTree, tea.Cmd)

Update reacts to ToggleSessionTreeMsg and (when open) key events.

func (*SessionTree) View

func (t *SessionTree) View(width, height int) string

View renders the tree. If no tree loaded, prints a friendly stub.

type SettingsPane

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

SettingsPane is a modal toggling persistent TUI settings. Arrow keys move cursor, enter/space flips the focused row, anything else types into the fuzzy filter. Each flip applies live and writes to ~/.bee/config.toml so the next launch picks the same values up.

func NewSettingsPane

func NewSettingsPane() *SettingsPane

NewSettingsPane returns a closed settings pane.

func (*SettingsPane) Open

func (p *SettingsPane) Open() bool

Open reports visibility.

func (*SettingsPane) Show

func (p *SettingsPane) Show(s SettingsSnapshot)

Show opens the pane seeded with the live values.

func (*SettingsPane) Update

func (p *SettingsPane) Update(msg tea.Msg) (*SettingsPane, tea.Cmd)

Update handles key events.

func (*SettingsPane) View

func (p *SettingsPane) View(width, height int) string

View renders the modal.

type SettingsSnapshot

type SettingsSnapshot struct {
	Verbose         bool
	ShowThoughts    bool
	ShowNudges      bool
	ShowRecap       bool
	Compact         bool
	ShowContextBar  bool
	Highlight       bool
	ShellBangSilent bool
	ShowBee         bool
	ShowContextPct  bool
	ShowModel       bool
	ShowCwd         bool
	ShowEffort      bool
	ShowTurnTimer   bool
	ShowGitBranch   bool
	ShowTotalTokens bool
	ShowBanner      bool
	ShowLoader      bool
}

SettingsSnapshot is the live values handed to Show. Grouped into a struct because the top-bar toggles pushed the positional-arg list past readable.

type SkillsLister

type SkillsLister interface {
	List() []skills.Skill
	Get(name string) (skills.Skill, bool)
}

SkillsLister is the seam the palette uses to fetch skills. Tests inject a stub; *skills.Registry already satisfies it. Get is also used by the slash dispatcher to resolve "/<name>" against the skill registry when no built-in command matches.

type State

type State int

State is the high-level TUI mode. Most input is gated on it.

const (
	StateIdle State = iota
	StateStreaming
	StateAwaitingApproval
	StateError
)

type StreamRenderer

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

StreamRenderer turns Messages and live deltas into styled strings. It is an append-only view buffer — callers feed it events and read View().

func NewStreamRenderer

func NewStreamRenderer(styles Styles, width int) *StreamRenderer

NewStreamRenderer builds a renderer. width is the wrap target; pass 0 for glamour's default (80). Loader style is taken from BEE_LOADER (swarm / comb / dance / drip); unset / "random" → random pick at construction.

func (*StreamRenderer) ClipStreamingTail

func (r *StreamRenderer) ClipStreamingTail(rendered string, maxRows int) string

ClipStreamingTail keeps the last maxRows visual rows of a rendered streaming chunk, prepending a `… +N lines above` header when content was dropped. Visual rows are computed against r.width so soft-wrapped long lines count correctly; bubbletea's inline renderer cannot reach above the cursor, so without this the head of a long partial gets clipped out of sight while it grows. maxRows <= 0 is a no-op (caller has no budget info). With progressive flush active, complete leading lines get pushed to scrollback before this fires — clipping only trims the unflushed tail.

func (*StreamRenderer) RenderCompacting

func (r *StreamRenderer) RenderCompacting(frame int) string

RenderCompacting draws the /compact-specific loader. Three braille swarm variants reuse the same particle/sine techniques as the "generating" loaders so memory-being-squeezed reads as live bees, not a static bar. The variant is rolled on frame 0 per run.

func (*StreamRenderer) RenderMessage

func (r *StreamRenderer) RenderMessage(m types.Message) string

RenderMessage formats a single message for the scrollback. Glyph and the first body line share one row; continuation lines indent under the body column. Dense by design — `▸ yo yo` reads as one unit.

Each ContentBlock renders independently; results are right-trimmed and joined on a single newline so neighbouring blocks never collide on the same row (the original concat-without-separator caused text to share a line with the following tool card). Interior blank runs are collapsed so glamour padding or stray `\n\n\n` from the model can't spill hundreds of empty rows into terminal scrollback.

func (*StreamRenderer) RenderStreaming

func (r *StreamRenderer) RenderStreaming(partial string, frame int) string

RenderStreaming returns the partial-text view while the model emits deltas. frame drives both the pre-token loader animation (empty partial) and the trailing caret animation (non-empty partial) — see animatedCaret for the rationale: a static caret looked "stopped" during in-stream pauses (reasoning, slow tool-call generation, network stalls between deltas).

The partial is rendered as RAW text (not glamour-markdown). Re-rendering a growing buffer through glamour on every delta reflows word-wrap and shifts indent as markdown tokens (`-`, `*`, ```` ``` ````) come into being mid- stream — visually the text "jumps" and indentation breaks. Markdown styling is applied once the turn finishes in RenderMessage. Continuation lines are indented 2 cols so they align under the body column, not the role glyph.

func (*StreamRenderer) RenderStreamingChunk

func (r *StreamRenderer) RenderStreamingChunk(chunk string, styleMarkdown bool) string

RenderStreamingChunk formats a settled head of a streaming partial for emission to terminal scrollback via tea.Println. Mirrors RenderStreaming's gutter treatment but drops the trailing caret (the cursor isn't here anymore) and the leading blank row (rest of the partial keeps streaming in the live region right below). Used by the progressive-flush path so the head of a long response stays readable while the tail keeps growing.

styleMarkdown=true routes the chunk through glamour so prose paragraphs keep their headings, lists, bold, and link styling once they hit scroll- back. Callers pass false when the chunk straddles an open ``` fence — partial code blocks render unpredictably through glamour, and raw output preserves any inline ANSI the model already painted (git log colors, chroma highlight, etc).

func (*StreamRenderer) RenderThinkingPartial

func (r *StreamRenderer) RenderThinkingPartial(s string) string

RenderThinkingPartial is the live-streaming variant of renderThinking used by the in-flight view region. Same dim/italic styling so the live block visually matches the finalized scrollback render once the turn commits. Empty result when thoughts are hidden or no content remains after sanitize.

func (*StreamRenderer) SetCompact

func (r *StreamRenderer) SetCompact(v bool)

SetCompact toggles compact mode. When true, RenderMessage and friends emit the dense pre-pi layout (no outer gutter, no inter-turn blank line, no user bg-tint, no OSC 133 prompt zones). Default false = clean mode.

func (*StreamRenderer) SetHighlight

func (r *StreamRenderer) SetHighlight(v bool)

SetHighlight toggles chroma syntax-highlighting across diff/file/bash previews. Off returns raw content; on (default) emits ANSI-colored tokens.

func (*StreamRenderer) SetLoaderStyle

func (r *StreamRenderer) SetLoaderStyle(s LoaderStyle)

SetLoaderStyle picks which pre-token loader animation to render.

func (*StreamRenderer) SetShowLoader

func (r *StreamRenderer) SetShowLoader(v bool)

SetShowLoader toggles the streaming "generating" animation. Off swaps the braille loader/caret for a static ⬢ marker so the row still signals activity without motion.

func (*StreamRenderer) SetShowNudges

func (r *StreamRenderer) SetShowNudges(v bool)

SetShowNudges toggles rendering of synthetic `[nudge]` user messages. Off (default) collapses them out of scrollback; the loop still injects them so the provider sees the same conversation.

func (*StreamRenderer) SetShowThoughts

func (r *StreamRenderer) SetShowThoughts(v bool)

SetShowThoughts toggles BlockThinking chain-of-thought rendering. Off hides reasoning blocks entirely from scrollback; on (default) shows them dimmed and italicized.

func (*StreamRenderer) SetVerbose

func (r *StreamRenderer) SetVerbose(v bool)

SetVerbose toggles full tool-output rendering. Compact (default) keeps the preview at one line; verbose lets the whole output through.

type Styles

type Styles struct {
	TopBar     lipgloss.Style // dim chrome — bee glyph carries the accent
	BottomBar  lipgloss.Style
	Scope      lipgloss.Style
	RoleYou    lipgloss.Style
	RoleBee    lipgloss.Style
	RoleTool   lipgloss.Style
	ToolCard   lipgloss.Style
	ToolName   lipgloss.Style // lilac, bold — distinguishes from honey AI + blue user
	ToolArgs   lipgloss.Style
	ToolPrev   lipgloss.Style
	ToolRail   lipgloss.Style // lilac left rail beside tool-output lines
	DiffAdd    lipgloss.Style // green `+` line for inserted text in edit previews
	DiffDel    lipgloss.Style // red `-` line for removed text in edit previews
	DiffAddBg  lipgloss.Style // pale green wash behind whole `+` diff row
	DiffDelBg  lipgloss.Style // pale red wash behind whole `-` diff row
	DiffPath   lipgloss.Style // bold path header above diff body
	DiffMeta   lipgloss.Style // dimmed meta line (occurrence, anchors, hunk hdrs)
	Thought    lipgloss.Style // grayed italic — model's chain-of-thought
	Modal      lipgloss.Style
	ModalTitle lipgloss.Style
	Button     lipgloss.Style
	ButtonHot  lipgloss.Style
	Error      lipgloss.Style
	ErrorCmd   lipgloss.Style // failed-bash command rendered on red bg highlight
	Warn       lipgloss.Style // refused/denied body text (permission blocked, not broken)
	WarnCmd    lipgloss.Style // refused command rendered on yellow bg highlight
	WarnBadge  lipgloss.Style // pill badge for the escalate card title
	WarnRail   lipgloss.Style // mustard left rail beside escalate body lines
	Dim        lipgloss.Style
	Body       lipgloss.Style // base prose
	UserBubble lipgloss.Style // (legacy) full-width warm tint — retained for callers
	UserRail   lipgloss.Style // blue left rail beside user-turn lines
	UserBody   lipgloss.Style // bold blue prose for the user-turn body
}

Styles bundles every reusable lipgloss style.

func DefaultStyles

func DefaultStyles() Styles

DefaultStyles returns the layered honey-on-charmtone palette.

type ToggleCostPaneMsg

type ToggleCostPaneMsg struct{}

ToggleCostPaneMsg flips the pane visibility.

type ToggleHiveMsg

type ToggleHiveMsg struct{}

ToggleHiveMsg flips the full-screen hive view.

type ToggleLoginPaneMsg

type ToggleLoginPaneMsg struct{}

ToggleLoginPaneMsg flips visibility.

type ToggleResumePickerMsg

type ToggleResumePickerMsg struct{}

ToggleResumePickerMsg flips visibility.

type ToggleSessionTreeMsg

type ToggleSessionTreeMsg struct{}

ToggleSessionTreeMsg flips visibility.

type ToggleWorkspaceMsg

type ToggleWorkspaceMsg struct{}

ToggleWorkspaceMsg flips visibility.

type ToolsPane

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

ToolsPane is a modal listing every registered tool with a toggle. Arrow keys move the cursor; enter/space flips the focused row. Each flip applies live and persists to ~/.bee/config.toml under disabled_tools. Mirrors the SettingsPane shape so users see the same modal grammar.

func NewToolsPane

func NewToolsPane() *ToolsPane

NewToolsPane returns a closed tools pane.

func (*ToolsPane) Open

func (p *ToolsPane) Open() bool

Open reports visibility.

func (*ToolsPane) Show

func (p *ToolsPane) Show(rows []commands.ToolInfo)

Show opens the pane seeded with the live tool list.

func (*ToolsPane) Update

func (p *ToolsPane) Update(msg tea.Msg) (*ToolsPane, tea.Cmd)

Update handles key events.

func (*ToolsPane) View

func (p *ToolsPane) View(width, height int) string

View renders the modal.

type UpdateDecision

type UpdateDecision int

UpdateDecision is the user's verdict on an "update available" prompt.

const (
	UpdateLater    UpdateDecision = iota // close modal; re-check next interval
	UpdateNow                            // apply now (this session)
	UpdateAlways                         // persist update_check=auto + apply now
	UpdateNeverAsk                       // persist update_check=off + stop probing
)

type UpdatePrompt

type UpdatePrompt struct {
	Active bool
	Info   update.Info
	// contains filtered or unexported fields
}

UpdatePrompt is the four-button modal surfaced when Probe finds main ahead.

func NewUpdatePrompt

func NewUpdatePrompt(styles Styles) UpdatePrompt

NewUpdatePrompt returns an inactive prompt.

func (*UpdatePrompt) Hide

func (p *UpdatePrompt) Hide()

Hide closes without publishing a decision.

func (*UpdatePrompt) Show

func (p *UpdatePrompt) Show(info update.Info)

Show opens the modal with the probed info.

func (UpdatePrompt) Update

func (p UpdatePrompt) Update(msg tea.Msg) (UpdatePrompt, tea.Cmd)

Update handles modal key events. Returns the updated prompt + an optional cmd carrying the decision; caller forwards the cmd. Esc dismisses as "later".

func (UpdatePrompt) View

func (p UpdatePrompt) View() string

View renders the modal. Caller overlays it on the main view.

type Workspace

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

Workspace is the right-pane file/diff preview. Toggled by Ctrl+W in 3A. SetFile loads file contents; SetDiff overlays a unified-diff annotation (additions green, deletions red, context dim). Both are optional — calling SetDiff without SetFile renders the diff alone.

func NewWorkspace

func NewWorkspace() *Workspace

NewWorkspace constructs a Workspace. 3A embeds this in its top-level Model.

func (*Workspace) ClearDiff

func (w *Workspace) ClearDiff()

ClearDiff drops the overlay.

func (*Workspace) Init

func (w *Workspace) Init() tea.Cmd

Init satisfies tea.Model.

func (*Workspace) Path

func (w *Workspace) Path() string

Path returns the currently bound file path.

func (*Workspace) SetDiff

func (w *Workspace) SetDiff(unified string) error

SetDiff parses a unified-diff and stores the first file's fragments. If the diff is empty or malformed it returns an error.

func (*Workspace) SetFile

func (w *Workspace) SetFile(path string) error

SetFile reads path into the buffer. Stat errors propagate.

func (*Workspace) SetVisible

func (w *Workspace) SetVisible(v bool)

SetVisible forces a state (for direct host control).

func (*Workspace) Update

func (w *Workspace) Update(msg tea.Msg) (*Workspace, tea.Cmd)

Update reacts to ToggleWorkspaceMsg. Host model owns Ctrl+W binding.

func (*Workspace) View

func (w *Workspace) View(width, height int) string

View renders the pane with a top label `path · <type>`. width/height constrain the box; content overflow truncated by lines.

func (*Workspace) Visible

func (w *Workspace) Visible() bool

Visible reports current panel state.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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