// Package tui is a full-screen terminal front end built on Bubble Tea.
//
// It observes the same agent.Event stream the plain renderer does and answers
// the same approval.Prompt signature, so the dependency direction is unchanged:
// tui imports agent, never the reverse, and the eval runner still drives the
// loop with no terminal attached.
package tui
import "github.com/charmbracelet/lipgloss"
// The palette is warm rather than neutral: one coral accent carries the
// identity and everything else is a grey at some distance from the text
// colour. Every colour is adaptive, because a palette tuned only for a dark
// terminal is the usual way a hand-rolled TUI becomes unreadable on a light
// one.
var (
colCoral = lipgloss.AdaptiveColor{Light: "#b4532f", Dark: "#d97757"}
colText = lipgloss.AdaptiveColor{Light: "#1c1b1a", Dark: "#e8e6e3"}
colUser = lipgloss.AdaptiveColor{Light: "#4b4945", Dark: "#b3ada4"}
colDim = lipgloss.AdaptiveColor{Light: "#6f6a66", Dark: "#8a847d"}
colFaint = lipgloss.AdaptiveColor{Light: "#c9c4be", Dark: "#3f3b38"}
colOK = lipgloss.AdaptiveColor{Light: "#2f7d46", Dark: "#5dbb7a"}
colErr = lipgloss.AdaptiveColor{Light: "#b3261e", Dark: "#eb6f6f"}
colWarn = lipgloss.AdaptiveColor{Light: "#8a5a00", Dark: "#e0a458"}
colBlue = lipgloss.AdaptiveColor{Light: "#2f5fa8", Dark: "#7aa2e3"}
colPillBg = lipgloss.AdaptiveColor{Light: "#ebe7e2", Dark: "#2b2825"}
)
var (
styText = lipgloss.NewStyle().Foreground(colText)
styDim = lipgloss.NewStyle().Foreground(colDim)
styFaint = lipgloss.NewStyle().Foreground(colFaint)
styCoral = lipgloss.NewStyle().Foreground(colCoral)
styBold = lipgloss.NewStyle().Bold(true)
styErr = lipgloss.NewStyle().Foreground(colErr)
styWarn = lipgloss.NewStyle().Foreground(colWarn)
styOK = lipgloss.NewStyle().Foreground(colOK)
// The transcript's grammar: every turn of events opens with a dot, and
// anything hanging off it is indented under that dot.
styUserMark = lipgloss.NewStyle().Foreground(colDim)
styUserText = lipgloss.NewStyle().Foreground(colUser)
styToolDot = lipgloss.NewStyle().Foreground(colCoral)
styTextDot = lipgloss.NewStyle().Foreground(colText)
styErrDot = lipgloss.NewStyle().Foreground(colErr)
styToolName = lipgloss.NewStyle().Foreground(colText).Bold(true)
styToolArgs = lipgloss.NewStyle().Foreground(colDim)
styResult = lipgloss.NewStyle().Foreground(colDim)
styDiffAdd = lipgloss.NewStyle().Foreground(colOK)
styDiffDel = lipgloss.NewStyle().Foreground(colErr)
styDiffHunk = lipgloss.NewStyle().Foreground(colCoral)
styDiffHead = lipgloss.NewStyle().Foreground(colDim).Bold(true)
styName = lipgloss.NewStyle().Foreground(colBlue).Background(colPillBg).Padding(0, 1)
styPill = lipgloss.NewStyle().Foreground(colDim).Background(colPillBg).Padding(0, 1)
styKey = lipgloss.NewStyle().Foreground(colCoral).Bold(true)
styHeading = lipgloss.NewStyle().Foreground(colCoral).Bold(true)
// The input frame is the only always-present chrome, so it carries the
// mode: coral when it is yours to type into, faint while the agent has it.
styBoxFocus = lipgloss.NewStyle().
Border(lipgloss.RoundedBorder()).
BorderForeground(colCoral).
Padding(0, 1)
styBoxBlur = lipgloss.NewStyle().
Border(lipgloss.RoundedBorder()).
BorderForeground(colFaint).
Padding(0, 1)
// The approval box is the one place the UI is allowed to shout: it is the
// only moment a human has to decide something.
styModal = lipgloss.NewStyle().
Border(lipgloss.RoundedBorder()).
BorderForeground(colCoral).
Padding(0, 1)
)