Documentation
¶
Overview ¶
Mouse tracking and context menu support for sprout IDE
Index ¶
- Constants
- func BoldText(text string) string
- func ClearLineSeq() string
- func ClearScreenSeq() string
- func ClearToEndOfLineSeq() string
- func ClearToEndOfScreenSeq() string
- func ClearToStartOfLineSeq() string
- func Colorize(text, color string) string
- func ColorizeBold(text, color string) string
- func DetectImageMagic(data []byte) (ext string, mimeType string)
- func DisableMouseTracking()
- func EnableMouseTracking()
- func FormatErrorBlock(header string, err error) string
- func FormatHunkSummary(hunk ReviewHunk) string
- func FormatYesNoPrompt(yesDefault bool) string
- func FormatYesNoPromptStdout(yesDefault bool) string
- func HideCursorSeq() string
- func HomeCursorSeq() string
- func IsLikelyMarkdown(text string) bool
- func LockOutput()
- func MoveCursorDownSeq(n int) string
- func MoveCursorLeftSeq(n int) string
- func MoveCursorSeq(x, y int) string
- func MoveCursorToColumnSeq(n int) string
- func MoveCursorUpSeq(n int) string
- func PersonaBadge(depth int, personaID string) string
- func PersonaColor(personaID string) string
- func PersonaIndent(depth int) string
- func RegisterGlobalIndicator(ind *ActivityIndicator)
- func RegisterGlobalStatusFooter(f *StatusFooter)
- func RenderColoredDiff(w io.Writer, hunk ReviewHunk)
- func ResetScrollRegionSeq() string
- func SavePastedImage(data []byte, baseDir string) (string, error)
- func SavePastedText(content, baseDir string) (string, error)
- func SetScrollRegionSeq(top, bottom int) string
- func ShouldSmartSavePaste(content string) bool
- func ShowCursorSeq() string
- func SinkFromPrintf() func(string)
- func StderrIsTerminal() bool
- func StdoutIsTerminal() bool
- func StopGlobalStatusFooter()
- func SuspendIndicator()
- func UnlockOutput()
- func WithOutput(fn func())
- type ActivityIndicator
- func (a *ActivityIndicator) Elapsed() time.Duration
- func (a *ActivityIndicator) IsActive() bool
- func (a *ActivityIndicator) Replace(line string)
- func (a *ActivityIndicator) ReplaceLast(line string)
- func (a *ActivityIndicator) ReplaceLastN(line string, n int)
- func (a *ActivityIndicator) Start(msg string)
- func (a *ActivityIndicator) Stop()
- func (a *ActivityIndicator) Update(msg string)
- type AssistantTurnRenderer
- type CIOutputHandler
- func (h *CIOutputHandler) IsCI() bool
- func (h *CIOutputHandler) IsInteractive() bool
- func (h *CIOutputHandler) PrintProgress()
- func (h *CIOutputHandler) PrintSummary()
- func (h *CIOutputHandler) Printf(format string, args ...interface{})
- func (h *CIOutputHandler) ShouldShowProgress() bool
- func (h *CIOutputHandler) UpdateMetrics(totalTokens, contextTokens, maxContextTokens, iteration int, totalCost float64)
- func (h *CIOutputHandler) Write(p []byte) (n int, err error)
- func (h *CIOutputHandler) WriteString(s string) error
- type CompletionProvider
- type ContentSource
- type ContextMenu
- func (cm *ContextMenu) AddItem(id, label, description, shortcut string, enabled bool, ...)
- func (cm *ContextMenu) ClearItems()
- func (cm *ContextMenu) Hide()
- func (cm *ContextMenu) NavigateDown()
- func (cm *ContextMenu) NavigateUp()
- func (cm *ContextMenu) Render()
- func (cm *ContextMenu) SelectCurrent() *ContextMenuItem
- func (cm *ContextMenu) SetPosition(row, col int)
- func (cm *ContextMenu) Show()
- func (cm *ContextMenu) Toggle()
- type ContextMenuItem
- type EditReviewResult
- type EscapeParser
- type Glyph
- type GroundTruthTermios
- type InputEvent
- type InputEventType
- type InputReader
- func (ir *InputReader) AddToHistory(command string)
- func (ir *InputReader) Backspace()
- func (ir *InputReader) Delete()
- func (ir *InputReader) DeleteWordBackward()
- func (ir *InputReader) GetHistory() []string
- func (ir *InputReader) HandleEvent(event *InputEvent)
- func (ir *InputReader) InsertChar(char string)
- func (ir *InputReader) KillToEndOfLine()
- func (ir *InputReader) KillToStartOfLine()
- func (ir *InputReader) MoveCursor(delta int)
- func (ir *InputReader) MoveWord(direction int)
- func (ir *InputReader) NavigateHistory(direction int)
- func (ir *InputReader) NavigateVertically(direction int)
- func (ir *InputReader) ReadLine() (string, error)
- func (ir *InputReader) Refresh()
- func (ir *InputReader) SetCompleter(c CompletionProvider)
- func (ir *InputReader) SetCursor(pos int)
- func (ir *InputReader) SetGroundTruth(gt *GroundTruthTermios)
- func (ir *InputReader) SetHistory(history []string)
- func (ir *InputReader) SetInitialContent(content string)
- func (ir *InputReader) SetPrompt(p string)
- type LineCapWriter
- type MarkdownFormatter
- type MouseButton
- type MouseEvent
- type MouseEventKind
- type MouseModifier
- type ReviewDiffLine
- type ReviewHunk
- type SelectItem
- type SelectList
- type SelectListOptions
- type StatusFooter
- type SteerInputReader
- func (r *SteerInputReader) DrainUnsentBuffer() string
- func (r *SteerInputReader) IsActive() bool
- func (r *SteerInputReader) ResetBuffer()
- func (r *SteerInputReader) SetGroundTruth(gt *GroundTruthTermios)
- func (r *SteerInputReader) Start()
- func (r *SteerInputReader) Stop()
- func (r *SteerInputReader) SubmitMode() SteerSubmitMode
- type SteerSubmitMode
- type TerminalManager
Constants ¶
const ( ColorReset = "\033[0m" ColorBold = "\033[1m" ColorDim = "\033[2m" ColorItalic = "\033[3m" ColorUnderline = "\033[4m" // Colors ColorRed = "\033[31m" ColorGreen = "\033[32m" ColorYellow = "\033[33m" ColorBlue = "\033[34m" ColorMagenta = "\033[35m" ColorCyan = "\033[36m" ColorWhite = "\033[37m" ColorGray = "\033[90m" // Bright colors ColorBrightRed = "\033[91m" ColorBrightGreen = "\033[92m" ColorBrightYellow = "\033[93m" ColorBrightBlue = "\033[94m" ColorBrightMagenta = "\033[95m" ColorBrightCyan = "\033[96m" ColorBrightWhite = "\033[97m" // Background colors BgRed = "\033[41m" BgGreen = "\033[42m" BgYellow = "\033[43m" BgBlue = "\033[44m" BgMagenta = "\033[45m" BgCyan = "\033[46m" BgGray = "\033[100m" )
ANSI color codes
const ( // Enable mouse tracking (X10 mode - button press/release only) MouseTrackingX10 = "\x1b[?9h" // Enable mouse tracking (VT200 mode - all mouse events) MouseTrackingVT200 = "\x1b[?1000h" // Enable mouse tracking with SGR extended coordinates MouseTrackingSGR = "\x1b[?1006h" // Disable all mouse tracking MouseTrackingDisable = "\x1b[?1006l\x1b[?1000l\x1b[?9l" )
Mouse tracking escape sequences
const ( SteerPromptPrefix = "⇄ steer › " QueuePromptPrefix = "⏸ queue › " )
SteerPromptPrefix is the visible glyph + space rendered at the start of the pinned input line in STEER mode. QueuePromptPrefix is the alternative shown after the user toggles via Tab. Both exposed for testing / theming.
const ( SmartPasteLineThreshold = 100 SmartPasteByteThreshold = 5 * 1024 )
SmartPasteLineThreshold and SmartPasteByteThreshold trigger the smart- paste flow when a bracketed paste's content exceeds either bound. The content is written to PastedTextDirName and a `@<relpath>` reference is inserted into the input buffer instead of the raw blob, mirroring the image-paste pattern. SP-048-4d.
const MaxPastedImageSize = 10 * 1024 * 1024
MaxPastedImageSize is the maximum size of a pasted image before rejection (10 MB).
const PastedImageDirName = ".sprout/pasted-images"
PastedImageDirName is the subdirectory (relative to CWD) where pasted images are saved.
const PastedTextDirName = ".sprout/pastes"
PastedTextDirName is the workspace-relative directory under which large text pastes are auto-saved by SavePastedText. Mirrors PastedImageDirName.
const SteerHistoryCap = 50
SteerHistoryCap bounds the in-memory steer history to a sensible session-level value. Exposed for testing / config.
Variables ¶
This section is empty.
Functions ¶
func ClearLineSeq ¶
func ClearLineSeq() string
ClearLineSeq returns the escape sequence to clear the entire current line.
func ClearScreenSeq ¶
func ClearScreenSeq() string
ClearScreenSeq returns the escape sequence to clear the entire screen.
func ClearToEndOfLineSeq ¶
func ClearToEndOfLineSeq() string
ClearToEndOfLineSeq returns the escape sequence to clear from cursor to end of line.
func ClearToEndOfScreenSeq ¶
func ClearToEndOfScreenSeq() string
ClearToEndOfScreenSeq returns the escape sequence to clear from cursor to end of screen.
func ClearToStartOfLineSeq ¶
func ClearToStartOfLineSeq() string
ClearToStartOfLineSeq returns the escape sequence to clear from start of line to cursor.
func ColorizeBold ¶
ColorizeBold wraps text with bold and a color code
func DetectImageMagic ¶
DetectImageMagic checks if data starts with a known image format signature. Returns the file extension (e.g., ".png") and MIME type (e.g., "image/png"), or empty strings if no known image format is detected.
func DisableMouseTracking ¶
func DisableMouseTracking()
DisableMouseTracking disables mouse tracking
func EnableMouseTracking ¶
func EnableMouseTracking()
EnableMouseTracking enables mouse tracking in the terminal
func FormatErrorBlock ¶
FormatErrorBlock turns an error into a CLI-renderable block.
- nil error → empty string. Callers can append it directly to a header line without an extra branch.
- Single-line error → "<header>: <err>\n", matching today's `fmt.Fprintf(os.Stderr, "[FAIL] Error: %v\n", err)` output exactly so existing logs aren't disturbed.
- Multi-line error (contains \n after trimming the trailing newline) → "<header>:\n <line1>\n <line2>\n…", indented by two spaces, with red coloring when ANSI colors are enabled. Preserves the full stderr a tool produced instead of collapsing it to its first line.
The two-space indent matches the rest of sprout's CLI conventions (tool timeline, footer padding) so a multi-line error reads as part of the same chrome rather than a foreign block.
func FormatHunkSummary ¶ added in v0.16.12
func FormatHunkSummary(hunk ReviewHunk) string
FormatHunkSummary returns a compact one-line description of a hunk for use in list views.
func FormatYesNoPrompt ¶
FormatYesNoPrompt returns a y/N or Y/n prompt string with the default letter bolded. When yesDefault is true, the Y is bolded (Y/n). When yesDefault is false, the N is bolded (y/N).
ANSI codes are only applied when the stderr is a TTY. When stderr is not a terminal (e.g., piped to a file), the plain text is returned without any escape codes.
func FormatYesNoPromptStdout ¶
FormatYesNoPromptStdout returns a y/N or Y/n prompt string with the default letter bolded, checking stdout for terminal status (same logic as FormatYesNoPrompt but uses os.Stdout instead of os.Stderr for the TTY check).
func HideCursorSeq ¶
func HideCursorSeq() string
HideCursorSeq returns the escape sequence to hide the cursor.
func HomeCursorSeq ¶
func HomeCursorSeq() string
HomeCursorSeq returns the escape sequence to move cursor to home position (1,1).
func IsLikelyMarkdown ¶
IsLikelyMarkdown checks if text contains markdown patterns More selective to avoid formatting code blocks, shell output, or other non-summary text
func MoveCursorDownSeq ¶
MoveCursorDownSeq returns the escape sequence to move cursor down by n lines.
func MoveCursorLeftSeq ¶
MoveCursorLeftSeq returns the escape sequence to move cursor left by n columns.
func MoveCursorSeq ¶
MoveCursorSeq returns the escape sequence to move the cursor to (x,y) Note: ANSI uses row (y) first, then column (x).
func MoveCursorToColumnSeq ¶
MoveCursorToColumnSeq returns the escape sequence to move cursor to column n (1-based).
func MoveCursorUpSeq ¶
MoveCursorUpSeq returns the escape sequence to move cursor up by n lines.
func PersonaBadge ¶
PersonaBadge renders a colored "[persona]" prefix for a tool-timeline line. Returns the empty string for depth 0 or empty persona — the primary agent's own tool lines get no badge so the existing UX is preserved.
Example: PersonaBadge(1, "coder") → "\033[36m[coder]\033[0m "
PersonaBadge(0, "orchestrator") → ""
func PersonaColor ¶
PersonaColor returns the ANSI color escape for the given persona ID, or the empty string when colors are disabled (NO_COLOR / non-TTY default).
Unknown personas get a dim-gray fallback so they're still visually grouped without colliding with any of the well-known IDs.
func PersonaIndent ¶
PersonaIndent returns the leading whitespace for a depth-N tool line. Two spaces per depth level keeps the timeline scannable without taking over the line. Depth 0 returns "" so primary-agent output is unchanged.
func RegisterGlobalIndicator ¶
func RegisterGlobalIndicator(ind *ActivityIndicator)
RegisterGlobalIndicator installs ind as the process-wide indicator that SuspendIndicator and clihooks.SuspendIndicator both target. Pass nil to clear. Safe to call multiple times.
func RegisterGlobalStatusFooter ¶
func RegisterGlobalStatusFooter(f *StatusFooter)
RegisterGlobalStatusFooter installs f as the process-wide footer that StopGlobalStatusFooter targets. Pass nil to clear. Safe to call multiple times. Mirrors RegisterGlobalIndicator.
func RenderColoredDiff ¶ added in v0.16.12
func RenderColoredDiff(w io.Writer, hunk ReviewHunk)
RenderColoredDiff renders a hunk's diff lines with ANSI colors: green for additions, red for removals, dim for context.
func ResetScrollRegionSeq ¶
func ResetScrollRegionSeq() string
ResetScrollRegionSeq resets the scrolling region to the full screen.
func SavePastedImage ¶
SavePastedImage saves raw image data to .sprout/pasted-images/ under the provided base directory (typically the workspace root). It returns a relative path like "./.sprout/pasted-images/paste_20260320_145959_abc123.png". If baseDir is empty, it falls back to os.Getwd().
func SavePastedText ¶
SavePastedText writes content to .sprout/pastes/ with a timestamped random-suffixed filename and returns the workspace-relative path (e.g. "./.sprout/pastes/paste_20260520_145959_abc123.txt"). The path is suitable for insertion as a `@path` reference the agent can read. SP-048-4d. Mirrors SavePastedImage.
func SetScrollRegionSeq ¶
SetScrollRegionSeq returns the escape sequence to set the scrolling region (1-based, inclusive).
func ShouldSmartSavePaste ¶
ShouldSmartSavePaste reports whether content is large enough to merit auto-saving via SavePastedText. Threshold-only helper so the caller can short-circuit without computing both counters at every call site.
func ShowCursorSeq ¶
func ShowCursorSeq() string
ShowCursorSeq returns the escape sequence to show the cursor.
func SinkFromPrintf ¶
func SinkFromPrintf() func(string)
SinkFromPrintf is a convenience that writes to stdout via fmt.Print. It exists so callsites don't have to spell out the closure.
func StderrIsTerminal ¶
func StderrIsTerminal() bool
StderrIsTerminal returns true if os.Stderr is connected to a terminal.
func StdoutIsTerminal ¶
func StdoutIsTerminal() bool
StdoutIsTerminal returns true if os.Stdout is connected to a terminal.
func StopGlobalStatusFooter ¶
func StopGlobalStatusFooter()
StopGlobalStatusFooter resets the registered global footer's scroll region and clears its row. Safe to call when no footer is registered or when it's already stopped (no-op). Use from signal handlers immediately before os.Exit so the user's terminal isn't left in a weird state.
func SuspendIndicator ¶
func SuspendIndicator()
SuspendIndicator stops the registered global activity indicator if one is active. Safe to call when no indicator is registered (no-op) or when the indicator is already stopped (idempotent). Use this immediately before rendering an interactive CLI prompt to keep the spinner from overwriting the prompt text. Mirrored by clihooks.SuspendIndicator for callers that can't import pkg/console.
func UnlockOutput ¶ added in v0.16.7
func UnlockOutput()
UnlockOutput releases the console output mutex.
func WithOutput ¶ added in v0.16.7
func WithOutput(fn func())
WithOutput runs fn while holding the console output mutex. Use this wrapper for short, self-contained ANSI render sequences.
Types ¶
type ActivityIndicator ¶
type ActivityIndicator struct {
// contains filtered or unexported fields
}
ActivityIndicator renders a transient single-line spinner that updates on a timer. It's designed for the "agent is doing something" gap between user submit and visible output, and for showing per-tool progress during tool execution.
All output goes to a Writer (default os.Stderr). When the writer is not a TTY, all methods are no-ops so piped or redirected output stays clean.
The zero value is unusable — construct via NewActivityIndicator.
func NewActivityIndicator ¶
func NewActivityIndicator(w io.Writer) *ActivityIndicator
NewActivityIndicator constructs an indicator that writes to w. If w is nil, os.Stderr is used. TTY detection runs against the underlying file descriptor; when w is not an *os.File it is treated as not-a-TTY.
func (*ActivityIndicator) Elapsed ¶
func (a *ActivityIndicator) Elapsed() time.Duration
Elapsed returns how long the current spinner has been running. Returns zero if the indicator is not active.
func (*ActivityIndicator) IsActive ¶
func (a *ActivityIndicator) IsActive() bool
IsActive reports whether the spinner is currently rendering.
func (*ActivityIndicator) Replace ¶
func (a *ActivityIndicator) Replace(line string)
Replace atomically stops the spinner and prints line in its place, terminated with a newline. Use this when a transient spinner should resolve into a permanent result line (e.g. ✓ tool · 0.3s).
On a non-TTY writer, line is still printed (so non-interactive logs still see the resolved result).
func (*ActivityIndicator) ReplaceLast ¶
func (a *ActivityIndicator) ReplaceLast(line string)
ReplaceLast is shorthand for ReplaceLastN(line, 1).
func (*ActivityIndicator) ReplaceLastN ¶
func (a *ActivityIndicator) ReplaceLastN(line string, n int)
ReplaceLastN stops the spinner and OVERWRITES the previous N rows before printing line. Used by the tool-collapse subscriber to merge a series of identical tool-end lines (separated by spinner-frame blank rows) into a single "✓ read_file × N (foo.go, bar.go, …)" line updated in place.
Caller is responsible for knowing N matches the actual row layout:
- n=1: overwrites the immediately preceding row (e.g. a spinner)
- n=2: overwrites the prev row + the blank line above it (the pattern emitted between consecutive tool spinners in the CLI's ToolStart path)
Only safe to call when the caller knows those rows belong to this indicator — no streaming text or unrelated chrome has written there since. On a non-TTY writer this degenerates to a regular Fprintln so logs still show each iteration (slightly noisier but never corrupted).
func (*ActivityIndicator) Start ¶
func (a *ActivityIndicator) Start(msg string)
Start begins rendering the spinner with the given message. If the indicator is already active, the message is updated in place and the spinner continues from its current frame.
msg should be a single line; embedded newlines and carriage returns are stripped to keep the render loop on one row.
func (*ActivityIndicator) Stop ¶
func (a *ActivityIndicator) Stop()
Stop halts the ticker and erases the spinner line. Idempotent — safe to call when the indicator is already stopped.
func (*ActivityIndicator) Update ¶
func (a *ActivityIndicator) Update(msg string)
Update changes the spinner's message without restarting it. No-op if the indicator is not currently active.
type AssistantTurnRenderer ¶
type AssistantTurnRenderer struct {
// contains filtered or unexported fields
}
AssistantTurnRenderer wraps the streaming-callback path for one assistant turn. It does two things:
- Indents every emitted line of assistant prose with a configurable prefix (default " ") so the model's text visually separates from chrome (tool-log lines, agent messages, system info).
- Buffers the *current* prose segment so it can be re-rendered with markdown formatting at the end of the turn.
A "segment" is a contiguous run of stream chunks with no interleaved non-prose terminal output between them. Tool logs and any other writeTerminalMessage call must notify the renderer via OnExternalWrite to finalize the current segment (no re-render of older segments) and start a fresh one. At turn end, FinalizeAtTurnEnd potentially re-renders the final segment with markdown formatting — clearing the streamed version via ANSI cursor manipulation and emitting the colorized version in its place.
The re-render only fires if (a) stdout is a TTY, (b) the segment contains markdown features worth formatting, and (c) a usable terminal width is available. Otherwise the streamed raw version stays — fail-safe rather than risk a scrollback-destroying cursor glitch on non-TTY targets.
func NewAssistantTurnRenderer ¶
func NewAssistantTurnRenderer(width int, formatter *MarkdownFormatter) *AssistantTurnRenderer
NewAssistantTurnRenderer constructs a renderer with the given terminal width snapshot and markdown formatter. width <= 0 disables soft-wrap accounting and the post-stream re-render path (the indent still works).
func (*AssistantTurnRenderer) EndReasoning ¶ added in v0.16.2
func (r *AssistantTurnRenderer) EndReasoning()
EndReasoning is the exported counterpart of endReasoningLocked for callers that drive the lifecycle directly (e.g. an explicit "end of thinking" event). The CLI today doesn't need it — WriteChunk and FinalizeAtTurnEnd both call the locked form — but it's exposed for completeness and tests.
func (*AssistantTurnRenderer) FinalizeAtTurnEnd ¶
func (r *AssistantTurnRenderer) FinalizeAtTurnEnd()
FinalizeAtTurnEnd is called once the assistant's turn has completed (after the spinner stops, after any post-turn book-keeping). If the current segment has substantial markdown content and stdout is a TTY, the streamed raw text is cleared and the markdown-formatted version is emitted in its place. Otherwise the streamed text is left as-is.
func (*AssistantTurnRenderer) OnExternalWrite ¶
func (r *AssistantTurnRenderer) OnExternalWrite()
OnExternalWrite finalizes the current segment without re-rendering it. Wire this into the OutputRouter's writeTerminalMessage so that tool-log lines, agent messages, and any other non-prose terminal output break the prose segment cleanly. A fresh segment begins on the next WriteChunk.
func (*AssistantTurnRenderer) WriteChunk ¶
func (r *AssistantTurnRenderer) WriteChunk(chunk string)
WriteChunk emits a chunk of assistant text to stdout, prefixing each line with the configured indent. The chunk is also appended to the current segment buffer for potential post-segment re-render.
func (*AssistantTurnRenderer) WriteReasoningChunk ¶ added in v0.16.2
func (r *AssistantTurnRenderer) WriteReasoningChunk(chunk string)
WriteReasoningChunk consumes one chunk of reasoning/thinking output from the streaming pipeline and renders the collapsed form. On the FIRST chunk of a reasoning segment it prints a single dim "▽ Thinking…" header; on subsequent chunks it only accumulates the byte count so the terminal stays clean even when the model emits tens of KiB of internal monologue. The header is finalized into "▽ Thinking · N kB (~N tokens)" by the next prose chunk (via WriteChunk) or by FinalizeAtTurnEnd.
No-op when the chunk is empty. Safe to call concurrently with other renderer methods — internal mutex guards the state.
type CIOutputHandler ¶
type CIOutputHandler struct {
// contains filtered or unexported fields
}
CIOutputHandler manages output formatting for CI/non-interactive environments
func NewCIOutputHandler ¶
func NewCIOutputHandler(writer io.Writer) *CIOutputHandler
NewCIOutputHandler creates a new CI output handler
func (*CIOutputHandler) IsCI ¶
func (h *CIOutputHandler) IsCI() bool
IsCI returns true if running in CI environment
func (*CIOutputHandler) IsInteractive ¶
func (h *CIOutputHandler) IsInteractive() bool
IsInteractive returns true if running in an interactive terminal
func (*CIOutputHandler) PrintProgress ¶
func (h *CIOutputHandler) PrintProgress()
PrintProgress prints a progress update in CI-friendly format
func (*CIOutputHandler) PrintSummary ¶
func (h *CIOutputHandler) PrintSummary()
PrintSummary prints a final summary
func (*CIOutputHandler) Printf ¶
func (h *CIOutputHandler) Printf(format string, args ...interface{})
Printf writes formatted output
func (*CIOutputHandler) ShouldShowProgress ¶
func (h *CIOutputHandler) ShouldShowProgress() bool
ShouldShowProgress returns true if progress should be shown
func (*CIOutputHandler) UpdateMetrics ¶
func (h *CIOutputHandler) UpdateMetrics(totalTokens, contextTokens, maxContextTokens, iteration int, totalCost float64)
UpdateMetrics updates the tracked metrics
func (*CIOutputHandler) Write ¶
func (h *CIOutputHandler) Write(p []byte) (n int, err error)
Write implements io.Writer interface
func (*CIOutputHandler) WriteString ¶
func (h *CIOutputHandler) WriteString(s string) error
WriteString writes a string with appropriate formatting
type CompletionProvider ¶
CompletionProvider returns candidate completions for the current input state. It receives the current line and cursor position and should return a list of full-line replacements ordered by likelihood. An empty result means "no completion available."
type ContentSource ¶
type ContentSource interface {
Model() string
ContextTokens() (used, limit int)
TotalCost() float64
WorkingDir() string
}
ContentSource supplies the current values rendered in the footer. The footer reads from it on every Refresh; the source must be safe for concurrent calls.
type ContextMenu ¶
type ContextMenu struct {
Items []*ContextMenuItem
Selected int
Visible bool
Row int // Screen row where menu appears
Col int // Screen column where menu appears
Width int // Menu width in characters
Height int // Menu height in lines
OnSelect func(item *ContextMenuItem)
OnEscape func()
}
ContextMenu represents the right-click context menu
func (*ContextMenu) AddItem ¶
func (cm *ContextMenu) AddItem(id, label, description, shortcut string, enabled bool, subMenu ...[]*ContextMenuItem)
AddItem adds a menu item to the context menu
func (*ContextMenu) ClearItems ¶
func (cm *ContextMenu) ClearItems()
ClearItems removes all items from the menu
func (*ContextMenu) NavigateDown ¶
func (cm *ContextMenu) NavigateDown()
NavigateDown moves selection down
func (*ContextMenu) Render ¶
func (cm *ContextMenu) Render()
Render draws the context menu to the terminal
func (*ContextMenu) SelectCurrent ¶
func (cm *ContextMenu) SelectCurrent() *ContextMenuItem
SelectCurrent selects the currently highlighted item
func (*ContextMenu) SetPosition ¶
func (cm *ContextMenu) SetPosition(row, col int)
SetPosition sets the screen position for the menu
type ContextMenuItem ¶
type ContextMenuItem struct {
ID string
Label string
Description string
Shortcut string
Enabled bool
SubMenu []*ContextMenuItem
}
ContextMenuItem represents a single item in the context menu
type EditReviewResult ¶ added in v0.16.12
type EditReviewResult struct {
AcceptedHunks []string // hunk IDs the user accepted
Rejected bool // true if user chose reject-all
Edited string // non-empty if user edited content via $EDITOR
}
EditReviewResult captures the user's decisions from the CLI diff review.
func RenderEditReview ¶ added in v0.16.12
func RenderEditReview(w io.Writer, hunks []ReviewHunk) EditReviewResult
RenderEditReview displays all hunks with colored diffs and returns the user's per-hunk decisions. Non-interactive callers (no TTY) get approve-all automatically.
The prompt for each hunk is:
[a]ccept / [r]eject / [s]kip (default: accept)
At the end, a summary shows accepted vs rejected counts.
type EscapeParser ¶
type EscapeParser struct {
// contains filtered or unexported fields
}
EscapeParser handles escape sequences using a simple state machine
func NewEscapeParser ¶
func NewEscapeParser() *EscapeParser
NewEscapeParser creates a new escape sequence parser
func (*EscapeParser) Parse ¶
func (ep *EscapeParser) Parse(b byte) *InputEvent
Parse processes a byte and returns an event if complete
type Glyph ¶
type Glyph int
Glyph encodes a single semantic category for CLI status lines. Every output line that announces a status (success, error, warning, progress, …) should pick exactly one of these. The rendered prefix is `<glyph> ` in the canonical color; consistency makes the scroll region scannable at a glance — green ticks = good, red marks = problems, amber = needs attention.
Honors NO_COLOR / FORCE_COLOR via envutil.ResolveColorPreference. In no-color mode the glyph still renders (it's UTF-8, not ANSI) so the semantic is preserved; only the color escape is suppressed.
const ( // GlyphSuccess marks a completed action / success state. // Replaces: [OK], [clean], [done] GlyphSuccess Glyph = iota // GlyphError marks a failure / error state. // Replaces: [FAIL] GlyphError // GlyphWarning marks something that needs attention but is non-fatal. // Replaces: [WARN], [skip] (some) GlyphWarning // GlyphInfo marks a system / informational message. // Replaces: [bot], [web], [skills], [chart] (welcome banner uses) GlyphInfo // GlyphAction marks an action in flight / submitted. // Replaces: [tool], [chart] (progress uses), [RELOAD] GlyphAction // GlyphPaused marks paused / queued state — waiting for something. // Replaces: [||] (interrupting), [queued] GlyphPaused // GlyphStopped marks a stopped / interrupted / aborted state. // Replaces: [STOP], [!] GlyphStopped // GlyphDim marks secondary / continuation / metric lines that // shouldn't draw the eye. Replaces: [skip] (some), [debug] GlyphDim )
func (Glyph) Fprintln ¶
Fprintln writes the glyph-prefixed message to an explicit writer. Tests use this to capture output to a buffer.
func (Glyph) Prefix ¶
Prefix returns the colored glyph plus a single trailing space, ready to lead a line:
fmt.Fprintf(os.Stderr, "%sresumed: %s\n", console.GlyphSuccess.Prefix(), label) → ✓ resumed: foo
In no-color mode the glyph still appears (the color escape is just empty). The reset escape only emits when a color was emitted.
func (Glyph) Print ¶
Print writes "<glyph> <msg>\n" to stderr. Convenience for the most common call shape. Use Printf for format-string callers, or Fprintln/Fprintf if you need to target a specific writer (tests).
type GroundTruthTermios ¶ added in v0.16.1
type GroundTruthTermios struct {
// contains filtered or unexported fields
}
GroundTruthTermios holds a pristine snapshot of the terminal's termios state taken once at REPL startup — before any raw-mode / steer-mode manipulation. All subsequent mode transitions should restore toward this snapshot (not toward whatever state the previous mode happened to save), preventing termios-state descent across PauseSteer / ResumeSteer cycles.
func CaptureGroundTruth ¶ added in v0.16.1
func CaptureGroundTruth() *GroundTruthTermios
CaptureGroundTruth snapshots the current termios of stdin. Call once at REPL startup when the terminal is in its default cooked state. Returns nil on non-TTY or error (callers degrade gracefully).
If the captured state is not actually cooked (some bootstrap path left the terminal in raw mode before we got here), the snapshot is normalized so the cooked flags we depend on are forced on. Without this, every later Restore() would set ICANON-off and the recovery mechanism would be self-defeating.
func (*GroundTruthTermios) EnsureCooked ¶ added in v0.16.2
func (g *GroundTruthTermios) EnsureCooked()
EnsureCooked unconditionally writes a known-cooked termios derived from the ground-truth snapshot. Unlike EnsureSane, it does not first check whether the terminal "looks" sane — ICANON alone doesn't catch every way input can be broken (VMIN=0 leftover from steer mode, IXOFF stop, missing OPOST). Call at the top of every ReadLine to guarantee a clean baseline before MakeRaw saves the to-be-restored state.
func (*GroundTruthTermios) EnsureSane ¶ added in v0.16.1
func (g *GroundTruthTermios) EnsureSane() bool
EnsureSane restores the ground-truth state if the terminal appears stuck in raw mode (ICANON off when we expect cooked). Returns true if a restore was performed.
func (*GroundTruthTermios) Fd ¶ added in v0.16.1
func (g *GroundTruthTermios) Fd() int
Fd returns the file descriptor the ground truth was captured from.
func (*GroundTruthTermios) IsTerminalSane ¶ added in v0.16.1
func (g *GroundTruthTermios) IsTerminalSane() bool
IsTerminalSane checks whether the terminal is currently in an ICANON-on state (i.e. cooked mode). Returns false when the terminal appears stuck in raw / steer mode. Returns true on non-TTY (nothing to check) or when the terminal is healthy.
func (*GroundTruthTermios) Restore ¶ added in v0.16.1
func (g *GroundTruthTermios) Restore() error
Restore resets the terminal to the ground-truth state. Returns an error if the ioctl fails (caller can log and continue — a failed restore is not fatal, just means the terminal might be in a weird mode).
type InputEvent ¶
type InputEvent struct {
Type InputEventType
Data string
}
InputEvent represents a key press or input event
type InputEventType ¶
type InputEventType int
const ( EventChar InputEventType = iota EventUp EventDown EventLeft EventRight EventHome EventEnd EventBackspace EventDelete EventEnter EventTab EventInterrupt EventSuspend EventEscape EventPasteStart EventPasteEnd // Mouse events EventMouse EventWordLeft EventWordRight EventDeleteWordBackward )
type InputReader ¶
type InputReader struct {
// contains filtered or unexported fields
}
InputReader handles interactive input with proper escape sequence handling
func NewInputReader ¶
func NewInputReader(prompt string) *InputReader
NewInputReader creates a new input reader
func (*InputReader) AddToHistory ¶
func (ir *InputReader) AddToHistory(command string)
AddToHistory adds a command to history
func (*InputReader) Backspace ¶
func (ir *InputReader) Backspace()
Backspace deletes the character before the cursor
func (*InputReader) Delete ¶
func (ir *InputReader) Delete()
Delete deletes the character at the cursor position
func (*InputReader) DeleteWordBackward ¶ added in v0.16.12
func (ir *InputReader) DeleteWordBackward()
DeleteWordBackward deletes the word before the cursor (Ctrl-W / Meta-Backspace).
func (*InputReader) GetHistory ¶
func (ir *InputReader) GetHistory() []string
GetHistory returns the command history
func (*InputReader) HandleEvent ¶
func (ir *InputReader) HandleEvent(event *InputEvent)
HandleEvent processes an input event
func (*InputReader) InsertChar ¶
func (ir *InputReader) InsertChar(char string)
InsertChar inserts a character string at the current cursor position.
func (*InputReader) KillToEndOfLine ¶ added in v0.16.12
func (ir *InputReader) KillToEndOfLine()
KillToEndOfLine deletes from the cursor to the end of the line (Ctrl-K).
func (*InputReader) KillToStartOfLine ¶ added in v0.16.12
func (ir *InputReader) KillToStartOfLine()
KillToStartOfLine deletes from the start of the line to the cursor (Ctrl-U).
func (*InputReader) MoveCursor ¶
func (ir *InputReader) MoveCursor(delta int)
MoveCursor moves the cursor left or right
func (*InputReader) MoveWord ¶ added in v0.16.12
func (ir *InputReader) MoveWord(direction int)
MoveWord moves the cursor by one word in the given direction (-1 backward / Alt-B / Ctrl-Left, +1 forward / Alt-F / Ctrl-Right). A word is a maximal run of non-whitespace (unicode.IsSpace).
func (*InputReader) NavigateHistory ¶
func (ir *InputReader) NavigateHistory(direction int)
NavigateHistory navigates through command history
func (*InputReader) NavigateVertically ¶
func (ir *InputReader) NavigateVertically(direction int)
NavigateVertically handles both history navigation and multi-line text navigation direction: -1 for up, 1 for down
func (*InputReader) ReadLine ¶
func (ir *InputReader) ReadLine() (string, error)
ReadLine reads a line of input with proper escape sequence handling
func (*InputReader) Refresh ¶
func (ir *InputReader) Refresh()
Refresh redraws the current input line
func (*InputReader) SetCompleter ¶
func (ir *InputReader) SetCompleter(c CompletionProvider)
SetCompleter installs a completion provider that is invoked when the user presses Tab. Pass nil to disable completion. The provider receives the current buffer + cursor position and returns ordered candidate replacements.
func (*InputReader) SetCursor ¶
func (ir *InputReader) SetCursor(pos int)
SetCursor sets the cursor to an absolute position
func (*InputReader) SetGroundTruth ¶ added in v0.16.1
func (ir *InputReader) SetGroundTruth(gt *GroundTruthTermios)
SetGroundTruth installs the terminal's pristine cooked-mode termios snapshot for pre-flight sanity checks. Call once at REPL startup, before the first ReadLine.
func (*InputReader) SetHistory ¶
func (ir *InputReader) SetHistory(history []string)
SetHistory sets the command history
func (*InputReader) SetInitialContent ¶ added in v0.16.1
func (ir *InputReader) SetInitialContent(content string)
SetInitialContent pre-fills the input buffer with text that should appear as if the user typed it. Used by the REPL loop to carry over unsent steer-panel text into the main prompt after a turn ends. The content is consumed on the next ReadLine call and then cleared.
func (*InputReader) SetPrompt ¶
func (ir *InputReader) SetPrompt(p string)
SetPrompt updates the input reader's prompt prefix. Call this between ReadLine invocations (not during) to reflect state changes such as the active model name after a `/model` switch. SP-048-5d follow-up.
type LineCapWriter ¶
type LineCapWriter struct {
// CharLimit is the maximum characters allowed on one line before
// truncation kicks in. Zero or negative disables capping.
CharLimit int
// Sink receives all bytes that are not clipped.
Sink func(string)
// contains filtered or unexported fields
}
LineCapWriter wraps a sink (typically the streaming-output `fmt.Print`) and clamps each *visual* line to a maximum character count. When a line exceeds the cap, the writer emits the head, then a single `… [+N chars]` truncation marker, then swallows further bytes on that line until the next newline.
This exists because the LLM sometimes streams a tool result that contains a single very long line (minified JS/JSON, a base64 blob, an unbroken log line) and terminals soft-wrap that into hundreds of visual rows, blowing up the user's scrollback. The LLM's view of the content is unchanged — only what the terminal renders is clipped.
Not goroutine-safe; callers are expected to serialize writes (the streaming callback path naturally does this — one chunk at a time from a single producer).
func NewLineCapWriter ¶
func NewLineCapWriter(charLimit int, sink func(string)) *LineCapWriter
NewLineCapWriter constructs a writer with the given char limit and downstream sink. Use SinkFromPrintf for the typical stdout case.
func (*LineCapWriter) Flush ¶
func (w *LineCapWriter) Flush()
Flush is intended for end-of-stream cleanup. If the stream ends without a trailing newline on a suppressed line, the marker still needs to land so the user sees what was dropped.
func (*LineCapWriter) Write ¶
func (w *LineCapWriter) Write(chunk string)
Write processes one streaming chunk. The chunk can contain any mix of newlines and long runs; the writer tracks position across calls.
type MarkdownFormatter ¶
type MarkdownFormatter struct {
// contains filtered or unexported fields
}
MarkdownFormatter converts markdown to ANSI-colored terminal output
func NewMarkdownFormatter ¶
func NewMarkdownFormatter(enableColors, enableInline bool) *MarkdownFormatter
NewMarkdownFormatter creates a new markdown formatter.
The caller's enableColors preference is overridden by the environment per the no-color.org convention (SP-048-4a):
- NO_COLOR set to any non-empty value → colors OFF (always wins)
- FORCE_COLOR set to any non-empty value → colors ON (unless NO_COLOR)
This lets users opt out of ANSI escapes globally (`NO_COLOR=1 sprout`) and CI pipelines opt in (`FORCE_COLOR=1 sprout > log.txt`) without individual call sites needing to know. The resolver lives in pkg/envutil (a zero-dep leaf) to avoid the import cycle pkg/utils → pkg/console.
func (*MarkdownFormatter) Format ¶
func (f *MarkdownFormatter) Format(text string) string
Format formats markdown text to colored terminal output
func (*MarkdownFormatter) SetWidth ¶ added in v0.16.8
func (f *MarkdownFormatter) SetWidth(w int) *MarkdownFormatter
SetWidth sets the content width used for width-aware rendering (e.g. the horizontal rule spans this many columns). Returns the receiver for chaining.
type MouseButton ¶
type MouseButton int
MouseButton represents which mouse button was pressed
const ( MouseButtonLeft MouseButton = iota MouseButtonMiddle MouseButtonRight MouseButtonExtra1 MouseButtonExtra2 )
type MouseEvent ¶
type MouseEvent struct {
Kind MouseEventKind
Button MouseButton
Modifiers MouseModifier
Row int // 1-based row
Col int // 1-based column
Flags int // Additional flags (e.g., motion flags)
}
MouseEvent represents a complete mouse event from the terminal
func ParseMouseEvent ¶
func ParseMouseEvent(data string) (*MouseEvent, error)
ParseMouseEvent parses a mouse escape sequence into a MouseEvent Format: ESC [ M Cb Cx Cy (X10 mode)
ESC [ < Cb;Cx;Cy M (SGR mode)
type MouseEventKind ¶
type MouseEventKind int
Mouse event types
const ( MouseEventPress MouseEventKind = iota MouseEventRelease MouseEventMotion MouseEventWheelUp MouseEventWheelDown MouseEventWheelLeft MouseEventWheelRight )
type MouseModifier ¶
MouseModifier represents modifier keys pressed with mouse event
type ReviewDiffLine ¶ added in v0.16.12
ReviewDiffLine is a single line in a review hunk.
type ReviewHunk ¶ added in v0.16.12
type ReviewHunk struct {
ID string
OldStart int
OldLines int
Lines []ReviewDiffLine
}
ReviewHunk is a console-local view of a diff hunk, avoiding an import cycle with pkg/agent. The agent's Hunk type is adapted to this struct at the call site.
type SelectItem ¶
SelectItem is a single entry in a SelectList.
Label — primary text shown to the user
Detail — optional dim-rendered suffix, right-aligned ("anthropic · 200k")
Value — payload returned when the item is chosen
type SelectList ¶
type SelectList struct {
// contains filtered or unexported fields
}
SelectList drives a single-column picker UI. The zero value is unusable — construct via NewSelectList.
func NewSelectList ¶
func NewSelectList(opts SelectListOptions) *SelectList
NewSelectList constructs a picker with the given options. Items shorter than PageSize render compactly without scroll; longer lists page with arrow keys.
type SelectListOptions ¶
type SelectListOptions struct {
// Title is rendered above the list, glyph-prefixed (GlyphInfo).
Title string
// Items is the full set to choose from. Filter narrows in place.
Items []SelectItem
// Searchable enables type-to-filter mode. Printable characters
// append to the filter buffer and the list reranks against the
// filter via the shared fuzzy matcher.
Searchable bool
// PageSize is how many rows of items are rendered at once. 0 picks
// a sensible default (10).
PageSize int
// SelectList renders a default hint matching the current mode.
Footer string
// DismissOnAnyKey makes any printable key (that isn't navigation or
// Enter) dismiss the picker with ("", false, nil). Useful for
// "press any key to continue"-style dismissal so the user doesn't
// have to reach for Esc or Enter. Ignored when Searchable is true.
DismissOnAnyKey bool
}
SelectListOptions configures a SelectList run.
type StatusFooter ¶
type StatusFooter struct {
// Cost-warn thresholds (USD). Costs above warn render yellow; above
// alert render red. Sane defaults; future config wiring possible.
// contains filtered or unexported fields
}
StatusFooter renders a single pinned line at the bottom of the terminal showing live session state: model, context-window usage, cumulative cost, and working directory.
Mechanism: when started, the footer sets a terminal scroll region of rows 1..(N-1) where N is the terminal height. Subsequent output scrolls within that region; row N stays put for the footer. On Stop (and on signal-driven shutdown) the scroll region is reset so the user's terminal isn't left in a broken state.
Suppressed entirely on non-TTY writers — Render is a no-op, scroll region is never touched.
func NewStatusFooter ¶
func NewStatusFooter(w io.Writer, source ContentSource) *StatusFooter
NewStatusFooter constructs a footer that writes to w. If w is nil os.Stderr is used (the same channel the spinner uses). Non-TTY writers produce a no-op footer.
func (*StatusFooter) ClearSteerLine ¶
func (f *StatusFooter) ClearSteerLine()
ClearSteerLine drops the steer panel, blanks the rows it occupied, and contracts the scroll region back to 2 reserved rows. Called when the SteerInputReader stops (e.g. ProcessQuery returned). SP-055.
func (*StatusFooter) Refresh ¶
func (f *StatusFooter) Refresh()
Refresh re-reads the source and redraws the footer. Idempotent and cheap; safe to call from event subscribers on each ToolEnd.
func (*StatusFooter) Resize ¶
func (f *StatusFooter) Resize()
Resize handles a terminal-size change (SIGWINCH). The OLD footer rows (tracked via lastRows) are cleared first so a grow doesn't leave the previous footer stranded mid-screen, then the scroll region is re-applied for the new height and the footer is redrawn at the new bottom.
func (*StatusFooter) SetSteerLine ¶
func (f *StatusFooter) SetSteerLine(text string)
SetSteerLine reserves one or more pinned rows above the rule and renders the supplied text there. Newlines (`\n`) in `text` produce additional rows up to maxSteerRows. Called by SteerInputReader as the user types — each keystroke replaces the prior content. Safe to call repeatedly; the scroll region is re-applied only when the row count changes. SP-055.
func (*StatusFooter) SetSteerLineWithCursor ¶ added in v0.16.12
func (f *StatusFooter) SetSteerLineWithCursor(text string, cursorByteOffset int)
SetSteerLineWithCursor is like SetSteerLine but also specifies the byte offset within text where the input caret (▏) should appear. Used by SteerInputReader to render a mid-buffer cursor for readline cursor movement (Ctrl-A/E/B/F, Alt-B/F, etc.). An offset of -1 falls back to caret-at-end (legacy) behavior.
func (*StatusFooter) Start ¶
func (f *StatusFooter) Start()
Start declares the scroll region, spawns a SIGWINCH watcher, and renders the initial footer line. Safe to call multiple times; redundant calls just re-render (idempotent on the watcher).
func (*StatusFooter) Stop ¶
func (f *StatusFooter) Stop()
Stop resets the scroll region to full-screen, clears the footer row, and halts the SIGWINCH watcher. MUST be called on every exit path (including signal-driven shutdown) or the user's terminal is left with a broken scroll region. Idempotent — safe to call when already stopped.
type SteerInputReader ¶
type SteerInputReader struct {
// contains filtered or unexported fields
}
SteerInputReader captures keystrokes during an active model turn and renders them into a pinned line above the status footer (SP-055). It is distinct from InputReader, which owns stdin only during the REPL prompt; SteerInputReader takes over stdin between ReadLine() calls, while the model is processing.
Lifecycle:
r := NewSteerInputReader(footer, submitFn, interruptFn) r.Start() // puts terminal in raw mode, starts read loop ... ProcessQuery runs ... r.Stop() // restores cooked mode, clears the pinned line
Key handling (raw mode — ICANON / ISIG disabled, so signals must be re-implemented by reading the byte directly):
Enter (CR/LF) → submitFn(buffer); buffer cleared Backspace (DEL) → remove rune before cursor Escape (alone) → clear buffer (does not exit steer mode) Ctrl+C (0x03) → interruptFn() — caller routes to TriggerInterrupt Ctrl+A/E → move cursor to start / end Ctrl+B/F → move cursor back / forward one rune Ctrl+D → forward-delete rune at cursor Ctrl+K/U → kill from cursor to end / start of buffer Ctrl+W → delete word before cursor Alt+B/F → move cursor back / forward one word Ctrl+Left/Right → move cursor back / forward one word Left/Right → move cursor back / forward one rune ESC [ ... ~/A-Z → swallow common escape-sequence (arrows, fn keys)
Submission UX: when Enter is pressed, submitFn receives the buffer. Caller is expected to forward to Agent.InjectInputContext (or equivalent). The buffer is then cleared and the pinned line shows the prompt prefix again, ready for the next steer.
Suppressed entirely on non-TTY stdin (Start is a no-op), matching the behavior of StatusFooter / ActivityIndicator. Callers can construct the reader unconditionally; the gating happens here.
func NewSteerInputReader ¶
func NewSteerInputReader(footer *StatusFooter, submitFn, queueFn, interruptFn func(string)) *SteerInputReader
NewSteerInputReader builds a reader that draws into the given footer and reports submitted/interrupt events via the callbacks. The callbacks fire on the reader's read goroutine — keep them quick or dispatch to another goroutine to avoid blocking the input loop.
queueFn is optional: when nil the user has no way to switch into queue mode (Tab becomes a no-op). When non-nil, Tab toggles between STEER and QUEUE submit modes; pressing Enter in QUEUE mode calls queueFn(text) instead of submitFn(text).
func (*SteerInputReader) DrainUnsentBuffer ¶ added in v0.16.1
func (r *SteerInputReader) DrainUnsentBuffer() string
DrainUnsentBuffer returns any text the user typed into the steer panel but did not submit (no Enter pressed). The caller (typically the REPL loop via SteerCoordinator) can carry this into the next ReadLine call so the text is not silently discarded when a turn ends. The buffer is left intact; call ResetBuffer afterwards to clear it.
func (*SteerInputReader) IsActive ¶
func (r *SteerInputReader) IsActive() bool
IsActive reports whether the reader is currently capturing input. Used by callers that need to coordinate (e.g. signal handlers).
func (*SteerInputReader) ResetBuffer ¶ added in v0.16.1
func (r *SteerInputReader) ResetBuffer()
ResetBuffer clears the in-progress steer buffer. Called by the coordinator after draining the unsent text into the InputReader, so the next Start() begins with a clean slate.
func (*SteerInputReader) SetGroundTruth ¶ added in v0.16.1
func (r *SteerInputReader) SetGroundTruth(gt *GroundTruthTermios)
SetGroundTruth installs the REPL's pristine cooked-mode termios snapshot. Stop() uses this instead of per-enter oldState for restoration, preventing termios descent across PauseSteer / ResumeSteer cycles.
func (*SteerInputReader) Start ¶
func (r *SteerInputReader) Start()
Start puts the terminal in raw mode and spawns the read goroutine. Idempotent. No-op on non-TTY. The pinned line is rendered immediately so the user sees the empty prompt as soon as a turn begins.
func (*SteerInputReader) Stop ¶
func (r *SteerInputReader) Stop()
Stop restores cooked mode, clears the pinned line, and waits for the read goroutine to exit. Idempotent. MUST be called on every exit path (including signal-driven shutdown) or the terminal will be left in steer mode.
Ordering matters: we wait for the goroutine to exit BEFORE calling exitSteerMode. In steer mode VMIN=0/VTIME=0 makes Read return immediately with 0 bytes, so the goroutine's poll loop observes stopCh within one tick (5ms). If we restored cooked mode first, the goroutine's next Read would block forever (cooked VMIN=1) and leak.
func (*SteerInputReader) SubmitMode ¶
func (r *SteerInputReader) SubmitMode() SteerSubmitMode
SubmitMode reports the current Enter-binding. Exposed for tests.
type SteerSubmitMode ¶
type SteerSubmitMode int
SteerSubmitMode controls what happens on Enter (SP-055 Phase 3b). STEER (default) injects mid-turn via the submit callback (typically Agent.InjectInputContext → seed.InjectInput). QUEUE buffers the message into the agent's deferred queue, which the REPL drains and prepends to the next user-typed prompt.
const ( SteerSubmitModeNow SteerSubmitMode = iota // mid-turn injection (default) SteerSubmitModeQueue // hold until next turn )
type TerminalManager ¶
type TerminalManager interface {
// SaveCursor saves the current cursor position
SaveCursor() error
// RestoreCursor restores the cursor to the previously saved position
RestoreCursor() error
// MoveCursor moves the cursor to the specified position (x, y)
MoveCursor(x, y int) error
// WriteText writes text at the current cursor position
WriteText(text string) error
// Flush ensures all output is written to the terminal
Flush() error
// GetSize returns the terminal dimensions
GetSize() (width, height int, err error)
}
TerminalManager defines the interface for terminal operations used by the UI rendering system.
Source Files
¶
- activity_indicator.go
- ansi.go
- assistant_turn_renderer.go
- ci_output_handler.go
- console_lock.go
- display_width.go
- edit_review.go
- error_block.go
- glyphs.go
- image_paste.go
- input_completion.go
- input_context_menu.go
- input_core.go
- input_editing.go
- input_editor_escape.go
- input_escape_parser.go
- input_history.go
- input_mouse.go
- input_paste.go
- input_render.go
- input_search.go
- input_terminal.go
- line_cap.go
- markdown_formatter.go
- mouse_menu.go
- persona_style.go
- security_prompt.go
- select_list.go
- signal_compat_unix.go
- status_footer.go
- steer_input.go
- steer_termios_unix.go
- terminal_health_unix.go
- terminal_manager.go
- text_paste.go