Help us shape the future of Go! Take the 2026 Go Developer Survey

modes

package
v0.19.12 Latest Latest
Warning

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

Go to latest
Published: Oct 22, 2026 License: MIT Imports: 48 Imported by: 0

Documentation

Overview

Package modes contains coding-agent run-mode orchestration.

Index

Constants

View Source
const (
	StartupDiagnosticCollision = "collision"
	StartupDiagnosticExtension = "extension"
	StartupDiagnosticOther     = "other"
)

StartupDiagnostic kinds; anything else renders as a plain message.

Variables

View Source
var AppKeybindingDefinitions = []tui.KeybindingDefinition{
	{ID: "app.commandPalette", DefaultKeys: []tui.KeyID{"ctrl+p"}, Description: "Open command palette"},
	{ID: "app.interrupt", DefaultKeys: []tui.KeyID{"escape"}, Description: "Cancel or abort"},
	{ID: "app.clear", DefaultKeys: []tui.KeyID{"ctrl+c"}, Description: "Clear editor or exit when empty"},
	{ID: "app.exit", DefaultKeys: []tui.KeyID{"ctrl+d"}, Description: "Exit when editor is empty"},
	{ID: "app.suspend", DefaultKeys: []tui.KeyID{"ctrl+z"}, Description: "Suspend to background"},
	{ID: "app.thinking.cycle", DefaultKeys: []tui.KeyID{"shift+tab"}, Description: "Cycle thinking level"},
	{ID: "app.model.cycleForward", DefaultKeys: nil, Description: "Cycle to next model"},
	{ID: "app.model.cycleBackward", DefaultKeys: nil, Description: "Cycle to previous model"},
	{ID: "app.model.select", DefaultKeys: []tui.KeyID{"ctrl+m"}, Description: "Open model selector"},
	{ID: "app.tools.expand", DefaultKeys: []tui.KeyID{"ctrl+o"}, Description: "Toggle tool output"},
	{ID: "app.thinking.toggle", DefaultKeys: []tui.KeyID{"ctrl+t"}, Description: "Toggle thinking blocks"},
	{ID: "app.session.toggleNamedFilter", DefaultKeys: []tui.KeyID{"ctrl+n"}, Description: "Toggle named session filter"},
	{ID: "app.editor.external", DefaultKeys: []tui.KeyID{"ctrl+g"}, Description: "Open external editor"},
	{ID: "app.message.copy", DefaultKeys: []tui.KeyID{"ctrl+x"}, Description: "Copy message to clipboard"},
	{ID: "app.message.followUp", DefaultKeys: []tui.KeyID{"alt+enter"}, Description: "Queue follow-up message"},
	{ID: "app.message.dequeue", DefaultKeys: []tui.KeyID{"alt+up"}, Description: "Restore queued messages"},
	{ID: "app.clipboard.pasteImage", DefaultKeys: []tui.KeyID{"ctrl+v"}, Description: "Paste image from clipboard"},
	{ID: "app.session.new", DefaultKeys: []tui.KeyID{"ctrl+n"}, Description: "Start a new session"},
	{ID: "app.session.tree", DefaultKeys: nil, Description: "Open session tree"},
	{ID: "app.session.fork", DefaultKeys: nil, Description: "Fork current session"},
	{ID: "app.session.resume", DefaultKeys: nil, Description: "Resume a session"},
	{ID: "app.tree.foldOrUp", DefaultKeys: treeBranchKeys("left"), Description: "Jump to the previous tree fork"},
	{ID: "app.tree.unfoldOrDown", DefaultKeys: treeBranchKeys("right"), Description: "Jump to the next tree fork"},
	{ID: "app.tree.editLabel", DefaultKeys: []tui.KeyID{"shift+l"}, Description: "Edit tree label"},
	{ID: "app.tree.toggleLabelTimestamp", DefaultKeys: []tui.KeyID{"shift+t"}, Description: "Toggle tree label timestamps"},
	{ID: "app.tree.filter.default", DefaultKeys: []tui.KeyID{"ctrl+d"}, Description: "Show one tree row per turn"},
	{ID: "app.tree.filter.noTools", DefaultKeys: []tui.KeyID{"ctrl+t"}, Description: "Show every tree message"},
	{ID: "app.tree.filter.userOnly", DefaultKeys: []tui.KeyID{"ctrl+u"}, Description: "Show one tree row per turn"},
	{ID: "app.tree.filter.labeledOnly", DefaultKeys: []tui.KeyID{"ctrl+l"}, Description: "Jump to the next labeled tree row"},
	{ID: "app.tree.filter.all", DefaultKeys: []tui.KeyID{"ctrl+a"}, Description: "Show every tree message"},
	{ID: "app.tree.filter.cycleForward", DefaultKeys: []tui.KeyID{"ctrl+o"}, Description: "Switch tree turns and messages"},
	{ID: "app.tree.filter.cycleBackward", DefaultKeys: []tui.KeyID{"shift+ctrl+o"}, Description: "Switch tree turns and messages"},
	{ID: "app.session.togglePath", DefaultKeys: []tui.KeyID{"ctrl+p"}, Description: "Toggle session path display"},
	{ID: "app.session.toggleSort", DefaultKeys: []tui.KeyID{"ctrl+s"}, Description: "Toggle session sort"},
	{ID: "app.session.rename", DefaultKeys: []tui.KeyID{"ctrl+r"}, Description: "Rename session"},
	{ID: "app.session.delete", DefaultKeys: []tui.KeyID{"ctrl+d"}, Description: "Delete session"},
	{ID: "app.session.deleteNoninvasive", DefaultKeys: []tui.KeyID{"alt+d"}, Description: "Delete session (no confirm)"},
	{ID: "app.models.save", DefaultKeys: []tui.KeyID{"ctrl+s"}, Description: "Save model selection"},
	{ID: "app.models.enableAll", DefaultKeys: []tui.KeyID{"ctrl+a"}, Description: "Enable all models"},
	{ID: "app.models.clearAll", DefaultKeys: []tui.KeyID{"ctrl+x"}, Description: "Clear all models"},
	{ID: "app.models.toggleProvider", DefaultKeys: []tui.KeyID{"ctrl+p"}, Description: "Toggle provider models"},
	{ID: "app.models.reorderUp", DefaultKeys: []tui.KeyID{"alt+up"}, Description: "Move model up"},
	{ID: "app.models.reorderDown", DefaultKeys: []tui.KeyID{"alt+down"}, Description: "Move model down"},
}

AppKeybindingDefinitions are the app-level keybindings that extend TUI defaults.

Functions

func KeyHint

func KeyHint(binding, description string) string

KeyHint renders a dim key label plus muted description for the resolved keybinding.

func KeyText

func KeyText(binding string) string

KeyText formats the keys currently bound to a keybinding id (falling back to the id itself).

func MissingSessionCWDPrompt added in v0.19.1

func MissingSessionCWDPrompt(err *agent.MissingSessionCWDError) string

MissingSessionCWDPrompt asks whether to continue a session whose stored cwd no longer exists in the fallback cwd.

func NewAppKeybindings

func NewAppKeybindings(user tui.KeybindingsConfig) *tui.KeybindingsManager

NewAppKeybindings creates a keybindings manager with all TUI + app definitions.

func NewEditDiffView

func NewEditDiffView(diff, path, bandRole string) *editDiffView

NewEditDiffView parses the display diff produced by the edit tool. The row format is fixed upstream: marker byte, right-aligned line number (space-padded), one separator space, then the line text; elided context is a numberless "..." row. path picks the syntax-highlight language; bandRole names the tool-band background the view sits on — tinted spans re-open it instead of emitting \x1b[49m, because the band wrap only paints from column zero and a bare background reset would hole-punch it (the frame's final reset comes from that outer wrap).

func NewMermaidMarkdownTransformer

func NewMermaidMarkdownTransformer(getMode func() string, mermaidTheme MermaidTheme) extensions.MarkdownTransformer

NewMermaidMarkdownTransformer replaces top-level Mermaid code blocks with Unicode terminal diagrams. getMode returns the settings-manager mermaid rendering mode ("off" | "final" | "streaming"); a nil theme renders unstyled.

func RawKeyHint

func RawKeyHint(key, description string) string

RawKeyHint renders a dim literal key plus muted description without keybinding resolution.

func RunConfigSelector

func RunConfigSelector(ctx context.Context, options ConfigSelectorOptions) error

func RunConfigSelectorWithTerminal

func RunConfigSelectorWithTerminal(ctx context.Context, options ConfigSelectorOptions, terminal tui.Terminal) error

func RunInteractiveMode

func RunInteractiveMode(ctx context.Context, session *agent.SessionRuntime, options InteractiveModeOptions) int

RunInteractiveMode starts the full TUI interactive session.

func RunPrintMode

func RunPrintMode(ctx context.Context, session printSession, options PrintModeOptions) int

RunPrintMode sends each configured prompt serially and returns a process exit code. Model failures remain represented by the final assistant message.

func RunSessionSelectorWithOptions added in v0.8.0

func RunSessionSelectorWithOptions(ctx context.Context, options SessionSelectorOptions) (string, bool, error)

RunSessionSelectorWithOptions assembles native loaders and actions explicitly.

func RunStartupSelector

func RunStartupSelector(ctx context.Context, options StartupSelectorOptions) (string, bool, error)

func RunStartupSelectorWithTerminal

func RunStartupSelectorWithTerminal(ctx context.Context, options StartupSelectorOptions, terminal tui.Terminal) (string, bool, error)

func ShutdownExitCode added in v0.10.0

func ShutdownExitCode(received os.Signal) int

ShutdownExitCode is the exit code upstream reports after received.

func ShutdownSignals added in v0.10.0

func ShutdownSignals() []os.Signal

ShutdownSignals are the signals the headless modes (print, RPC) treat as a shutdown request, matching upstream's per-platform registration.

Types

type AssistantMessageComponent

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

func NewAssistantMessageComponent

func NewAssistantMessageComponent(
	message *ai.AssistantMessage,
	hideThinking bool,
	mdTheme tui.MarkdownTheme,
	thinkingLabel string,
	outputPad int,
	transformers []extensions.MarkdownTransformer,
) *AssistantMessageComponent

func (*AssistantMessageComponent) Fold added in v0.13.2

func (c *AssistantMessageComponent) Fold()

Fold moves the message into the tool group it sits between.

func (*AssistantMessageComponent) HandleMouse added in v0.8.0

func (c *AssistantMessageComponent) HandleMouse(event tui.MouseEvent) bool

func (*AssistantMessageComponent) Invalidate

func (c *AssistantMessageComponent) Invalidate()

func (*AssistantMessageComponent) Render

func (c *AssistantMessageComponent) Render(width int) []string

func (*AssistantMessageComponent) SetHiddenThinkingLabel

func (c *AssistantMessageComponent) SetHiddenThinkingLabel(label string)

func (*AssistantMessageComponent) SetHideThinkingBlock

func (c *AssistantMessageComponent) SetHideThinkingBlock(hidden bool, label string)

func (*AssistantMessageComponent) UpdateContent

func (c *AssistantMessageComponent) UpdateContent(message *ai.AssistantMessage)

func (*AssistantMessageComponent) UpdateContentStreaming

func (c *AssistantMessageComponent) UpdateContentStreaming(message *ai.AssistantMessage, isStreaming bool)

UpdateContentStreaming also records whether the message is still streaming, which feeds the markdown transformer context.

type BashExecutionComponent

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

func NewBashExecutionComponent

func NewBashExecutionComponent(command string, ui tui.RenderRequester, excludeFromContext bool) *BashExecutionComponent

func (*BashExecutionComponent) AppendOutput

func (c *BashExecutionComponent) AppendOutput(text string)

func (*BashExecutionComponent) HandleMouse added in v0.8.0

func (c *BashExecutionComponent) HandleMouse(event tui.MouseEvent) bool

func (*BashExecutionComponent) Invalidate

func (c *BashExecutionComponent) Invalidate()

func (*BashExecutionComponent) Render

func (c *BashExecutionComponent) Render(width int) []string

func (*BashExecutionComponent) SetComplete

func (c *BashExecutionComponent) SetComplete(exitCode *int, cancelled bool)

func (*BashExecutionComponent) SetExpanded

func (c *BashExecutionComponent) SetExpanded(expanded bool)

type ConfigSelector

type ConfigSelector struct {
	tui.Container
	// contains filtered or unexported fields
}

func NewConfigSelector

func NewConfigSelector(options ConfigSelectorOptions, onClose, onExit func(), requestRender func()) *ConfigSelector

func (*ConfigSelector) HandleInput

func (selector *ConfigSelector) HandleInput(event tui.KeyEvent)

func (*ConfigSelector) Render

func (selector *ConfigSelector) Render(width int) []string

func (*ConfigSelector) SetFocused

func (selector *ConfigSelector) SetFocused(focused bool)

func (*ConfigSelector) WriteScope

func (selector *ConfigSelector) WriteScope() ConfigWriteScope

type ConfigSelectorOptions

type ConfigSelectorOptions struct {
	ResolvedPaths        ScopedResolvedPaths
	SettingsManager      *config.SettingsManager
	CWD                  string
	AgentDir             string
	WriteScope           ConfigWriteScope
	ProjectModeAvailable bool
	TerminalHeight       int
}

type ConfigWriteScope

type ConfigWriteScope string
const (
	ConfigWriteGlobal  ConfigWriteScope = "global"
	ConfigWriteProject ConfigWriteScope = "project"
)

type CountdownTimer

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

CountdownTimer ticks each second and fires a callback on expiry.

func NewCountdownTimer

func NewCountdownTimer(durationMS int64, ui tui.RenderRequester, onTick func(int), onExpire func()) *CountdownTimer

func (*CountdownTimer) Dispose

func (ct *CountdownTimer) Dispose()

type CustomEditor

type CustomEditor struct {
	*tui.Editor

	OnEscape            func()
	OnCtrlD             func()
	OnPasteImage        func()
	OnExtensionShortcut func(string) bool
	// contains filtered or unexported fields
}

CustomEditor wraps tui.Editor with app-level keybinding dispatch.

func NewCustomEditor

func NewCustomEditor(ui *tui.TUI, editorTheme tui.EditorTheme, kb *tui.KeybindingsManager) *CustomEditor

func (*CustomEditor) HandleMouse

func (ce *CustomEditor) HandleMouse(event tui.MouseEvent) bool

HandleMouse rebases a click past the frame's left rail so the wrapped editor still lands the cursor on the character under the pointer.

func (*CustomEditor) OnAction

func (ce *CustomEditor) OnAction(action string, handler func())

func (*CustomEditor) Render

func (ce *CustomEditor) Render(width int) []string

type CustomMessageComponent

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

func NewCustomMessageComponent

func NewCustomMessageComponent(customType string, content any, mdTheme tui.MarkdownTheme) *CustomMessageComponent

func (*CustomMessageComponent) Invalidate

func (c *CustomMessageComponent) Invalidate()

func (*CustomMessageComponent) Render

func (c *CustomMessageComponent) Render(width int) []string

func (*CustomMessageComponent) SetExpanded

func (c *CustomMessageComponent) SetExpanded(expanded bool)

type DynamicBorder

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

DynamicBorder renders a horizontal line that stretches to fit the terminal width.

func NewDynamicBorder

func NewDynamicBorder() *DynamicBorder

func NewDynamicBorderWithColor

func NewDynamicBorderWithColor(colorFn func(string) string) *DynamicBorder

func (*DynamicBorder) Invalidate

func (border *DynamicBorder) Invalidate()

func (*DynamicBorder) Render

func (border *DynamicBorder) Render(width int) []string

type ExtensionEditorComponent

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

ExtensionEditorComponent is the bordered multi-line editor dialog behind ctx.ui.editor, exported for extension UI reuse.

func NewExtensionEditorComponent

func NewExtensionEditorComponent(
	uiInstance *tui.TUI,
	bindings *tui.KeybindingsManager,
	title string,
	prefill string,
	onSubmit func(string),
	onCancel func(),
	externalEditorCommand string,
) *ExtensionEditorComponent

NewExtensionEditorComponent builds the multi-line editor dialog.

func (*ExtensionEditorComponent) HandleInput

func (component *ExtensionEditorComponent) HandleInput(event tui.KeyEvent)

func (*ExtensionEditorComponent) Invalidate

func (component *ExtensionEditorComponent) Invalidate()

func (*ExtensionEditorComponent) Render

func (component *ExtensionEditorComponent) Render(width int) []string

func (*ExtensionEditorComponent) SetFocused

func (component *ExtensionEditorComponent) SetFocused(focused bool)

type ExtensionInputComponent

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

ExtensionInputComponent is the bordered single-line input dialog behind ctx.ui.input, exported for extension UI reuse.

func NewExtensionInputComponent

func NewExtensionInputComponent(
	title string,
	_ string,
	onSubmit func(string),
	onCancel func(),
	config *extensionDialogOptions,
) *ExtensionInputComponent

NewExtensionInputComponent builds the single-line input dialog.

func (*ExtensionInputComponent) Dispose

func (component *ExtensionInputComponent) Dispose()

func (*ExtensionInputComponent) HandleInput

func (component *ExtensionInputComponent) HandleInput(event tui.KeyEvent)

func (*ExtensionInputComponent) Invalidate

func (component *ExtensionInputComponent) Invalidate()

func (*ExtensionInputComponent) Render

func (component *ExtensionInputComponent) Render(width int) []string

func (*ExtensionInputComponent) SetFocused

func (component *ExtensionInputComponent) SetFocused(focused bool)

type ExtensionSelectorComponent

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

ExtensionSelectorComponent is the bordered option-list dialog behind ctx.ui.select, exported for extension UI reuse.

func NewExtensionSelectorItemsComponent

func NewExtensionSelectorItemsComponent(
	title string,
	options []tui.SelectItem,
	onSelect func(string),
	onCancel func(),
	config *extensionDialogOptions,
) *ExtensionSelectorComponent

NewExtensionSelectorItemsComponent builds the selector dialog from pre-labelled select items.

func (*ExtensionSelectorComponent) Dispose

func (component *ExtensionSelectorComponent) Dispose()

func (*ExtensionSelectorComponent) HandleInput

func (component *ExtensionSelectorComponent) HandleInput(event tui.KeyEvent)

func (*ExtensionSelectorComponent) HandleMouse

func (component *ExtensionSelectorComponent) HandleMouse(event tui.MouseEvent) bool

HandleMouse drives the shared list pointer semantic; a single click only highlights, so a stray click cannot approve a tool call.

func (*ExtensionSelectorComponent) Invalidate

func (component *ExtensionSelectorComponent) Invalidate()

func (*ExtensionSelectorComponent) ListConfirm

func (component *ExtensionSelectorComponent) ListConfirm()

ListConfirm confirms the current selection.

func (*ExtensionSelectorComponent) ListRowAt

func (component *ExtensionSelectorComponent) ListRowAt(row int) (int, bool)

ListRowAt maps a rendered row to its option index; options wrap at narrow widths, so their heights come from the recorded render.

func (*ExtensionSelectorComponent) ListScroll

func (component *ExtensionSelectorComponent) ListScroll(direction int)

ListScroll moves the selection one row per tick, like keyboard navigation.

func (*ExtensionSelectorComponent) ListSelectRow

func (component *ExtensionSelectorComponent) ListSelectRow(index int)

ListSelectRow keeps the current window when the pointed option is visible.

func (*ExtensionSelectorComponent) Render

func (component *ExtensionSelectorComponent) Render(width int) []string

Keep wrapped options inside the modal and use the same offsets for hit-testing.

func (*ExtensionSelectorComponent) SetFocused added in v0.8.0

func (component *ExtensionSelectorComponent) SetFocused(focused bool)

func (*ExtensionSelectorComponent) WantsMouseMotion

func (component *ExtensionSelectorComponent) WantsMouseMotion() bool

WantsMouseMotion turns on hover reports while the dialog holds focus.

type FooterComponent

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

func NewFooterComponent

func NewFooterComponent(session footerSession, provider footerDataProvider, verbose bool) *FooterComponent

func (*FooterComponent) HandleMouse added in v0.7.1

func (f *FooterComponent) HandleMouse(event tui.MouseEvent) bool

func (*FooterComponent) Invalidate

func (f *FooterComponent) Invalidate()

func (*FooterComponent) Render

func (f *FooterComponent) Render(width int) []string

type IdleStatus

type IdleStatus struct{}

IdleStatus renders two empty lines (same height as a status indicator).

func (IdleStatus) Invalidate

func (IdleStatus) Invalidate()

func (IdleStatus) Render

func (IdleStatus) Render(width int) []string

type InteractiveAuthOptions

type InteractiveAuthOptions struct {
	Login  []InteractiveAuthProvider
	Logout []InteractiveAuthProvider
}

type InteractiveAuthProvider

type InteractiveAuthProvider struct {
	ID             string
	Name           string
	AuthType       aiauth.AuthType
	MethodName     string
	LoginLabel     string
	Configured     bool
	Status         *InteractiveAuthStatus
	LoginAvailable bool
	AccountID      string
	AccountName    string
	AccountLogin   bool
}

type InteractiveAuthStatus

type InteractiveAuthStatus struct {
	Type   aiauth.AuthType
	Source string
}

type InteractiveForkResult

type InteractiveForkResult struct {
	Cancelled    bool
	SelectedText string
}

type InteractiveMode

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

func (*InteractiveMode) AvailableProviderCount

func (mode *InteractiveMode) AvailableProviderCount() int

func (*InteractiveMode) CurrentCWD

func (mode *InteractiveMode) CurrentCWD() string

func (*InteractiveMode) GitBranch

func (mode *InteractiveMode) GitBranch() string

func (*InteractiveMode) Height

func (mode *InteractiveMode) Height() int

func (*InteractiveMode) Invalidate

func (mode *InteractiveMode) Invalidate()

func (*InteractiveMode) SessionName

func (mode *InteractiveMode) SessionName() string

func (*InteractiveMode) SessionNameInEditor

func (mode *InteractiveMode) SessionNameInEditor(width int) bool

func (*InteractiveMode) StatusAction added in v0.7.1

func (mode *InteractiveMode) StatusAction(key string) func()

func (*InteractiveMode) StatusLabel added in v0.11.0

func (mode *InteractiveMode) StatusLabel(key string) string

StatusLabel is a footer item's hover tooltip: an extension command's settings label when the status key names that command.

func (*InteractiveMode) Statuses

func (mode *InteractiveMode) Statuses() map[string]string

func (*InteractiveMode) Width

func (mode *InteractiveMode) Width() int

type InteractiveModeOptions

type InteractiveModeOptions struct {
	Keybindings    tui.KeybindingsConfig
	InitialMessage string
	InitialImages  []*ai.ImageContent
	Messages       []string
	SessionHeader  *sessionstore.SessionHeader
	// Verbose forces verbose startup, overriding the quietStartup setting.
	Verbose     bool
	Diagnostics []StartupDiagnostic
	Terminal    tui.Terminal
	Host        InteractiveSessionHost
	// StartupVersionCheck runs without blocking startup; the interactive
	// package owns no update transport or policy.
	StartupVersionCheck func(context.Context, extensions.UI)
	StartupModelRefresh func(context.Context) error
	Changelog           string
	Output              io.Writer
	OutputTTY           bool
	// InitialThemeSetting is --use-theme: it overrides the persisted theme for
	// this run only, until the user picks a theme (which persists).
	InitialThemeSetting string
}

InteractiveModeOptions configures the interactive TUI mode.

type InteractiveProviderHost added in v0.7.1

type InteractiveProviderHost interface {
	ProviderAccounts(context.Context) ([]accounts.Account, error)
	ChangeAccount(context.Context, string, string, string, string) error
	LoginAccount(context.Context, string, aiauth.AuthType, string, string, aiauth.AuthInteraction) error
	AccountUsage(context.Context, string, string) (usage.Snapshot, error)
	CachedAccountUsage(string, string) (usage.Snapshot, bool)
	UsageEnabled() bool
	SetUsageEnabled(bool) error
}

InteractiveProviderHost is optional so existing embedders retain their host contract.

type InteractiveSessionHost

type InteractiveSessionHost interface {
	Session() *agent.SessionRuntime

	// SetRebindSession registers the TUI callback invoked after the replacement
	// becomes current and before its session_start fires.
	SetRebindSession(func(*agent.SessionRuntime) error)
	// SetBeforeSessionInvalidate registers synchronous listener teardown run
	// after session_shutdown and before the current runtime is disposed.
	SetBeforeSessionInvalidate(func())
	// SetAfterSessionStart registers the TUI callback invoked after the
	// replacement has discovered extension resources.
	SetAfterSessionStart(func(*agent.SessionRuntime) error)

	NewSession(ctx context.Context, options *extensions.NewSessionOptions) (extensions.SessionReplacementResult, error)
	SwitchSession(ctx context.Context, sessionPath, cwdOverride string, options *extensions.SwitchSessionOptions) (extensions.SessionReplacementResult, error)
	Fork(ctx context.Context, entryID string, options *extensions.ForkOptions) (InteractiveForkResult, error)
	ImportSession(ctx context.Context, inputPath, cwdOverride string) (extensions.SessionReplacementResult, error)
	Reload(ctx context.Context) error

	// ListProjectSessions lists sessions for the current cwd;
	// ListAllSessions lists every project's sessions.
	ListProjectSessions(onProgress sessionstore.SessionListProgress) []sessionstore.SessionInfo
	ListAllSessions(onProgress sessionstore.SessionListProgress) []sessionstore.SessionInfo

	TrustState() (InteractiveTrustState, error)
	// SetProjectTrust persists the trust decisions and rebuilds the runtime
	// through the reload path so resources and tools reflect the new trust.
	SetProjectTrust(ctx context.Context, updates []config.ProjectTrustUpdate) error

	AuthOptions(ctx context.Context) (InteractiveAuthOptions, error)
	Login(ctx context.Context, providerID string, authType aiauth.AuthType, interaction aiauth.AuthInteraction) error
	Logout(ctx context.Context, providerID string) error

	Dispose()
}

InteractiveSessionHost owns the live SessionRuntime behind the interactive TUI and executes every state-changing session command. Replacement methods shut down and dispose the current runtime before calling the full CLI creation path, apply and rebind the replacement without rollback, and only then let the replacement's session_start extension event fire.

UI selection stays with the TUI: /clone is Fork of the current leaf with position "at", and /tree navigation goes through the extension command context's NavigateTree, which the runtime serves itself.

type InteractiveTrustState

type InteractiveTrustState struct {
	CWD            string
	ProjectTrusted bool
	SavedDecision  *config.ProjectTrustStoreEntry
	Options        []config.ProjectTrustOption
}

type InteractiveUI

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

InteractiveUI backs the extensions.UI interface with TUI components.

func NewInteractiveUI

func NewInteractiveUI(mode *InteractiveMode) *InteractiveUI

func (*InteractiveUI) AddAutocompleteProvider

func (ui *InteractiveUI) AddAutocompleteProvider(factory extensions.AutocompleteProviderFactory)

func (*InteractiveUI) Confirm

func (ui *InteractiveUI) Confirm(ctx context.Context, title, message string, opts *extensions.DialogOptions) (bool, error)

func (*InteractiveUI) Custom

func (*InteractiveUI) Editor

func (ui *InteractiveUI) Editor(ctx context.Context, title string, prefill *string) (string, bool, error)

func (*InteractiveUI) GetAllThemes

func (ui *InteractiveUI) GetAllThemes() []extensions.ThemeInfo

func (*InteractiveUI) GetEditorComponent

func (ui *InteractiveUI) GetEditorComponent() extensions.EditorFactory

func (*InteractiveUI) GetEditorText

func (ui *InteractiveUI) GetEditorText() string

func (*InteractiveUI) GetTheme

func (ui *InteractiveUI) GetTheme(name string) extensions.Theme

func (*InteractiveUI) GetToolsExpanded

func (ui *InteractiveUI) GetToolsExpanded() bool

func (*InteractiveUI) Input

func (ui *InteractiveUI) Input(ctx context.Context, title string, placeholder *string, opts *extensions.DialogOptions) (string, bool, error)

func (*InteractiveUI) Notify

func (ui *InteractiveUI) Notify(message string, notifyType extensions.NotificationType)

func (*InteractiveUI) OnTerminalInput

func (ui *InteractiveUI) OnTerminalInput(handler extensions.TerminalInputHandler) func()

func (*InteractiveUI) PasteToEditor

func (ui *InteractiveUI) PasteToEditor(text string)

func (*InteractiveUI) Select

func (ui *InteractiveUI) Select(ctx context.Context, title string, options []string, opts *extensions.DialogOptions) (string, bool, error)

func (*InteractiveUI) SetEditorComponent

func (ui *InteractiveUI) SetEditorComponent(factory extensions.EditorFactory)

func (*InteractiveUI) SetEditorText

func (ui *InteractiveUI) SetEditorText(text string)

func (*InteractiveUI) SetFooter

func (ui *InteractiveUI) SetFooter(factory extensions.FooterFactory)

func (*InteractiveUI) SetHeader

func (ui *InteractiveUI) SetHeader(factory extensions.HeaderFactory)

func (*InteractiveUI) SetHiddenThinkingLabel

func (ui *InteractiveUI) SetHiddenThinkingLabel(label *string)

func (*InteractiveUI) SetStatus

func (ui *InteractiveUI) SetStatus(key string, text *string)

func (*InteractiveUI) SetTheme

func (ui *InteractiveUI) SetTheme(value any) extensions.ThemeSetResult

func (*InteractiveUI) SetTitle

func (ui *InteractiveUI) SetTitle(title string)

func (*InteractiveUI) SetToolsExpanded

func (ui *InteractiveUI) SetToolsExpanded(expanded bool)

func (*InteractiveUI) SetWidget

func (ui *InteractiveUI) SetWidget(key string, widget *extensions.Widget, opts *extensions.WidgetOptions)

func (*InteractiveUI) SetWorkingIndicator

func (ui *InteractiveUI) SetWorkingIndicator(opts *extensions.WorkingIndicatorOptions)

func (*InteractiveUI) SetWorkingMessage

func (ui *InteractiveUI) SetWorkingMessage(msg *string)

func (*InteractiveUI) SetWorkingVisible

func (ui *InteractiveUI) SetWorkingVisible(visible bool)

func (*InteractiveUI) Theme

func (ui *InteractiveUI) Theme() extensions.Theme

type MermaidTheme

type MermaidTheme interface {
	Fg(color, text string) string
	Bold(text string) string
}

MermaidTheme is the slice of the interactive theme the Mermaid transformer styles diagram spans with.

type ModelSelectorComponent

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

ModelSelectorComponent is the searchable picker used only by /model.

func NewModelSelectorComponent

func NewModelSelectorComponent(
	currentModel *ai.Model,
	models []ai.Model,
	scoped []agent.ScopedModel,
	onSelect func(ai.Model),
	onCancel func(),
	initialSearchInput string,
) *ModelSelectorComponent

func (*ModelSelectorComponent) HandleInput

func (component *ModelSelectorComponent) HandleInput(event tui.KeyEvent)

func (*ModelSelectorComponent) HandleMouse

func (component *ModelSelectorComponent) HandleMouse(event tui.MouseEvent) bool

HandleMouse drives the shared list pointer semantic.

func (*ModelSelectorComponent) Invalidate

func (component *ModelSelectorComponent) Invalidate()

func (*ModelSelectorComponent) ListConfirm

func (component *ModelSelectorComponent) ListConfirm()

ListConfirm confirms the current selection.

func (*ModelSelectorComponent) ListRowAt

func (component *ModelSelectorComponent) ListRowAt(row int) (int, bool)

ListRowAt maps a component-local row to the filtered-model index it renders.

func (*ModelSelectorComponent) ListScroll

func (component *ModelSelectorComponent) ListScroll(direction int)

ListScroll moves the selection one row per tick, recentring like keyboard navigation does.

func (*ModelSelectorComponent) ListSelectRow

func (component *ModelSelectorComponent) ListSelectRow(index int)

ListSelectRow moves the highlight without re-anchoring the window, so hover can never shift rows under the cursor.

func (*ModelSelectorComponent) Render

func (component *ModelSelectorComponent) Render(width int) []string

Render records where each visible row landed for mouse hit-testing; the emitted lines are the container's own.

func (*ModelSelectorComponent) SetFocused

func (component *ModelSelectorComponent) SetFocused(focused bool)

func (*ModelSelectorComponent) WantsMouseMotion

func (component *ModelSelectorComponent) WantsMouseMotion() bool

WantsMouseMotion turns on hover reports while the selector holds focus.

type OAuthSelectorComponent

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

OAuthSelectorComponent is the searchable auth-provider selector behind /login and /logout: a fuzzy-search input over name+id+authType+methodName, an 8-row visible window with a scroll counter, and per-row status indicators.

func NewOAuthSelectorComponent

func NewOAuthSelectorComponent(
	selectorMode string,
	providers []InteractiveAuthProvider,
	onSelect func(InteractiveAuthProvider),
	onCancel func(),
	initialSearchInput string,
) *OAuthSelectorComponent

NewOAuthSelectorComponent builds the selector; initialSearchInput pre-fills the search field so /login with an unmatched fuzzy ref opens the list already filtered.

func (*OAuthSelectorComponent) HandleInput

func (component *OAuthSelectorComponent) HandleInput(event tui.KeyEvent)

func (*OAuthSelectorComponent) HandleMouse

func (component *OAuthSelectorComponent) HandleMouse(event tui.MouseEvent) bool

HandleMouse drives the shared list pointer semantic.

func (*OAuthSelectorComponent) Invalidate

func (component *OAuthSelectorComponent) Invalidate()

func (*OAuthSelectorComponent) ListConfirm

func (component *OAuthSelectorComponent) ListConfirm()

ListConfirm confirms the current selection.

func (*OAuthSelectorComponent) ListRowAt

func (component *OAuthSelectorComponent) ListRowAt(row int) (int, bool)

ListRowAt maps a component-local row to the filtered-provider index it renders.

func (*OAuthSelectorComponent) ListScroll

func (component *OAuthSelectorComponent) ListScroll(direction int)

ListScroll moves the selection one row per tick, recentring like keyboard navigation does.

func (*OAuthSelectorComponent) ListSelectRow

func (component *OAuthSelectorComponent) ListSelectRow(index int)

ListSelectRow moves the highlight without re-anchoring the window, so hover can never shift rows under the cursor.

func (*OAuthSelectorComponent) Render

func (component *OAuthSelectorComponent) Render(width int) []string

Render records where each visible row landed for mouse hit-testing; the emitted lines are the container's own.

func (*OAuthSelectorComponent) SetFocused

func (component *OAuthSelectorComponent) SetFocused(focused bool)

func (*OAuthSelectorComponent) WantsMouseMotion

func (component *OAuthSelectorComponent) WantsMouseMotion() bool

WantsMouseMotion turns on hover reports while the selector holds focus.

type PrintModeOptions

type PrintModeOptions struct {
	Mode           PrintOutputMode
	Messages       []string
	InitialMessage string
	InitialImages  []*ai.ImageContent
	SessionHeader  *session.SessionHeader
	Stdout         io.Writer
	Stderr         io.Writer
}

type PrintOutputMode

type PrintOutputMode string
const (
	PrintOutputText PrintOutputMode = "text"
	PrintOutputJSON PrintOutputMode = "json"
)

type ScopedResolvedPaths

type ScopedResolvedPaths struct {
	Global  *agent.ResolvedPaths
	Project *agent.ResolvedPaths
}

type SessionDeleteMethod

type SessionDeleteMethod string
const (
	SessionDeleteTrash  SessionDeleteMethod = "trash"
	SessionDeleteUnlink SessionDeleteMethod = "unlink"
)

type SessionSelectorComponent

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

SessionSelectorComponent is the startup and interactive session picker. Loaders may block; scope loads run away from the TUI input loop and publish progress through RequestRender.

func NewSessionSelectorComponent

func NewSessionSelectorComponent(options SessionSelectorOptions, onSelect func(string), onCancel func()) *SessionSelectorComponent

func (*SessionSelectorComponent) HandleInput

func (selector *SessionSelectorComponent) HandleInput(event tui.KeyEvent)

func (*SessionSelectorComponent) HandleMouse

func (selector *SessionSelectorComponent) HandleMouse(event tui.MouseEvent) bool

HandleMouse drives the shared list pointer semantic; a double click resumes the selected session.

func (*SessionSelectorComponent) Invalidate

func (selector *SessionSelectorComponent) Invalidate()

func (*SessionSelectorComponent) ListConfirm

func (selector *SessionSelectorComponent) ListConfirm()

ListConfirm resumes the selected session.

func (*SessionSelectorComponent) ListRowAt

func (selector *SessionSelectorComponent) ListRowAt(row int) (int, bool)

ListRowAt maps a rendered row to its filtered-session index.

func (*SessionSelectorComponent) ListScroll

func (selector *SessionSelectorComponent) ListScroll(direction int)

ListScroll moves the selection three rows per tick, recentring like keyboard paging does.

func (*SessionSelectorComponent) ListSelectRow

func (selector *SessionSelectorComponent) ListSelectRow(index int)

ListSelectRow moves the highlight without re-anchoring the window, so hover can never shift rows under the cursor.

func (*SessionSelectorComponent) Render

func (selector *SessionSelectorComponent) Render(width int) []string

func (*SessionSelectorComponent) SetFocused

func (selector *SessionSelectorComponent) SetFocused(focused bool)

func (*SessionSelectorComponent) WantsMouseMotion

func (selector *SessionSelectorComponent) WantsMouseMotion() bool

WantsMouseMotion turns on hover reports while the selector holds focus.

type SessionSelectorContextLoader added in v0.7.0

type SessionSelectorContextLoader func(context.Context, session.SessionListUpdateFunc) ([]session.SessionInfo, error)

SessionSelectorContextLoader is the cancellable, progressive companion used by selectors backed by session.ListContext or session.ListAllContext.

type SessionSelectorLoader

type SessionSelectorLoader func(session.SessionListProgress) []session.SessionInfo

type SessionSelectorOptions

type SessionSelectorOptions struct {
	CurrentSessions        SessionSelectorLoader
	AllSessions            SessionSelectorLoader
	CurrentSessionsContext SessionSelectorContextLoader
	AllSessionsContext     SessionSelectorContextLoader
	CurrentSessionPath     string
	Keybindings            *tui.KeybindingsManager
	RequestRender          func()
	Now                    func() time.Time
	DeleteSession          func(string) (SessionDeleteMethod, error)
}

type StartupChoice

type StartupChoice struct {
	Label  string
	Value  string
	Cancel bool
}

type StartupDiagnostic

type StartupDiagnostic struct {
	Kind    string
	Path    string
	Message string
}

StartupDiagnostic carries one startup warning into interactive mode with the structure it was born with, so the warning band formats from fields instead of re-parsing flattened strings. Collision entries hold the quoted resource name in Message; extension entries hold the origin file in Path.

type StartupSelectorOptions

type StartupSelectorOptions struct {
	Title      string
	Choices    []StartupChoice
	MaxVisible int
}

type StatusIndicator

type StatusIndicator struct {
	*tui.Loader
	Kind StatusIndicatorKind
	// contains filtered or unexported fields
}

func NewBranchSummaryStatusIndicator

func NewBranchSummaryStatusIndicator(ui tui.RenderRequester) *StatusIndicator

func NewCompactionStatusIndicator

func NewCompactionStatusIndicator(ui tui.RenderRequester, reason string) *StatusIndicator

func NewRetryStatusIndicator

func NewRetryStatusIndicator(ui tui.RenderRequester, attempt, maxAttempts int, delayMS int64) *StatusIndicator

func NewWorkingStatusIndicator

func NewWorkingStatusIndicator(ui tui.RenderRequester, message string, options ...*extensions.WorkingIndicatorOptions) *StatusIndicator

func (*StatusIndicator) Dispose

func (si *StatusIndicator) Dispose()

type StatusIndicatorKind

type StatusIndicatorKind string
const (
	StatusWorking       StatusIndicatorKind = "working"
	StatusRetry         StatusIndicatorKind = "retry"
	StatusCompaction    StatusIndicatorKind = "compaction"
	StatusBranchSummary StatusIndicatorKind = "branchSummary"
)

type SummaryMessageComponent added in v0.14.0

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

func NewBranchSummaryMessage

func NewBranchSummaryMessage(summary string, mdTheme tui.MarkdownTheme) *SummaryMessageComponent

func NewCompactionSummaryMessage

func NewCompactionSummaryMessage(summary string, tokensBefore int64, mdTheme tui.MarkdownTheme) *SummaryMessageComponent

func (*SummaryMessageComponent) Invalidate added in v0.14.0

func (c *SummaryMessageComponent) Invalidate()

func (*SummaryMessageComponent) Render added in v0.14.0

func (c *SummaryMessageComponent) Render(width int) []string

func (*SummaryMessageComponent) SetExpanded added in v0.14.0

func (c *SummaryMessageComponent) SetExpanded(expanded bool)

type ToolExecutionComponent

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

func NewToolExecutionComponent

func NewToolExecutionComponent(
	toolName, toolCallID string,
	args any,
	showImages bool,
	toolDef *extensions.ToolDefinition,
	ui tui.RenderRequester,
	cwd string,
) *ToolExecutionComponent

func (*ToolExecutionComponent) HandleMouse added in v0.8.0

func (c *ToolExecutionComponent) HandleMouse(event tui.MouseEvent) bool

func (*ToolExecutionComponent) Invalidate

func (c *ToolExecutionComponent) Invalidate()

func (*ToolExecutionComponent) MarkExecutionStarted

func (c *ToolExecutionComponent) MarkExecutionStarted()

func (*ToolExecutionComponent) Render

func (c *ToolExecutionComponent) Render(width int) []string

func (*ToolExecutionComponent) SetArgsComplete

func (c *ToolExecutionComponent) SetArgsComplete()

func (*ToolExecutionComponent) SetExpanded

func (c *ToolExecutionComponent) SetExpanded(expanded bool)

func (*ToolExecutionComponent) UpdateArgs

func (c *ToolExecutionComponent) UpdateArgs(args any)

func (*ToolExecutionComponent) UpdateResult

func (c *ToolExecutionComponent) UpdateResult(content ai.ToolResultContent, isError bool, details any, partial bool)

type TreeSelectorComponent

type TreeSelectorComponent struct {
	OnCopy func(string)
	// OnFork forks the selected entry into a new session; before is set for
	// a user prompt, which is forked from just before it like /fork.
	OnFork func(entryID string, before bool)
	// contains filtered or unexported fields
}

TreeSelectorComponent is the session tree opened by /tree and double Escape.

func NewTreeSelectorComponent

func NewTreeSelectorComponent(
	roots []*sessionstore.SessionTreeNode,
	leafID string,
	terminalHeight int,
	onSelect func(string),
	onCancel func(),
	onLabelChange func(string, *string),
	initialSelectedID string,
	filterMode string,
) *TreeSelectorComponent

func (*TreeSelectorComponent) HandleInput

func (component *TreeSelectorComponent) HandleInput(event tui.KeyEvent)

func (*TreeSelectorComponent) HandleMouse

func (component *TreeSelectorComponent) HandleMouse(event tui.MouseEvent) bool

HandleMouse drives the shared list pointer semantic: hover highlights, a click jumps, the wheel scrolls.

func (*TreeSelectorComponent) Invalidate

func (component *TreeSelectorComponent) Invalidate()

func (*TreeSelectorComponent) ListConfirm

func (component *TreeSelectorComponent) ListConfirm()

ListConfirm goes to the selected row, as Enter does.

func (*TreeSelectorComponent) ListRowAt

func (component *TreeSelectorComponent) ListRowAt(row int) (int, bool)

ListRowAt maps a rendered row to its row index.

func (*TreeSelectorComponent) ListScroll

func (component *TreeSelectorComponent) ListScroll(direction int)

ListScroll moves the selection three rows per tick, recentring like keyboard paging does.

func (*TreeSelectorComponent) ListSelectRow

func (component *TreeSelectorComponent) ListSelectRow(index int)

ListSelectRow moves the highlight without re-anchoring the window, so hover can never shift rows under the cursor.

func (*TreeSelectorComponent) Render

func (component *TreeSelectorComponent) Render(width int) []string

Render lays out, top to bottom: the counts, the rows, the selected turn's reply and the key hints.

func (*TreeSelectorComponent) SetFocused

func (component *TreeSelectorComponent) SetFocused(focused bool)

func (*TreeSelectorComponent) SetMaxVisible added in v0.12.0

func (component *TreeSelectorComponent) SetMaxVisible(rows int)

SetMaxVisible sizes the list for the space its container offers.

func (*TreeSelectorComponent) WantsMouseMotion

func (component *TreeSelectorComponent) WantsMouseMotion() bool

WantsMouseMotion turns on hover reports while the selector holds focus.

type UserMessageComponent

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

func NewUserMessageComponent

func NewUserMessageComponent(text string, mdTheme tui.MarkdownTheme, outputPad int, transformers []extensions.MarkdownTransformer) *UserMessageComponent

func (*UserMessageComponent) HandleMouse added in v0.12.0

func (c *UserMessageComponent) HandleMouse(event tui.MouseEvent) bool

HandleMouse toggles the skill body on a click at or below the footer. Row 0 is the leading blank line and row 1 the band's top padding.

func (*UserMessageComponent) Invalidate

func (c *UserMessageComponent) Invalidate()

func (*UserMessageComponent) Render

func (c *UserMessageComponent) Render(width int) []string

func (*UserMessageComponent) SetExpanded added in v0.12.0

func (c *UserMessageComponent) SetExpanded(expanded bool)

SetExpanded shows or hides the skill body; plain messages ignore it.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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